mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-19 23:01:40 +00:00
fix(release): pack local AI runtime for release checks (#103941)
This commit is contained in:
committed by
GitHub
parent
d395a8e6ec
commit
b5f3fe900f
@@ -390,10 +390,11 @@ function runPackDry(): PackResult[] {
|
||||
return JSON.parse(raw) as PackResult[];
|
||||
}
|
||||
|
||||
function runPack(packDestination: string): PackResult[] {
|
||||
function runPack(packDestination: string, cwd?: string): PackResult[] {
|
||||
const raw = execPnpm(
|
||||
["--config.ignore-scripts=true", "pack", "--json", "--pack-destination", packDestination],
|
||||
{
|
||||
cwd,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
maxBuffer: 1024 * 1024 * 100,
|
||||
@@ -455,6 +456,25 @@ export function resolveReleaseCheckLocalPackageTarballs(
|
||||
return tarballs;
|
||||
}
|
||||
|
||||
export function prepareReleaseCheckLocalPackageTarballs(params: {
|
||||
tmpRoot: string;
|
||||
tarballDir?: string;
|
||||
packLocalAi?: (packDestination: string) => PackResult[];
|
||||
}): string[] {
|
||||
if (params.tarballDir) {
|
||||
return resolveReleaseCheckLocalPackageTarballs(params.tarballDir);
|
||||
}
|
||||
|
||||
// The root tarball requires the exact sibling AI version. Never fall back to
|
||||
// registry bytes, which could silently validate an older publication.
|
||||
const packDir = join(params.tmpRoot, "ai-pack");
|
||||
mkdirSync(packDir);
|
||||
const packResults = params.packLocalAi
|
||||
? params.packLocalAi(packDir)
|
||||
: runPack(packDir, resolve("packages/ai"));
|
||||
return [resolvePackedTarballPath(packDir, packResults)];
|
||||
}
|
||||
|
||||
export function createPackedTarballInstallArgs(prefixDir: string): string[] {
|
||||
return ["install", "--prefix", prefixDir, "--ignore-scripts", "--no-audit", "--no-fund"];
|
||||
}
|
||||
@@ -464,17 +484,16 @@ export function writePackedTarballInstallManifest(
|
||||
tarballPath: string,
|
||||
localPackageTarballs: string[],
|
||||
): void {
|
||||
if (localPackageTarballs.length > 1) {
|
||||
const aiTarball = localPackageTarballs[0];
|
||||
if (localPackageTarballs.length !== 1 || !aiTarball) {
|
||||
throw new Error(
|
||||
`release-check: packed install accepts at most one @openclaw/ai tarball; found ${localPackageTarballs.length}.`,
|
||||
`release-check: packed install requires exactly one @openclaw/ai tarball; found ${localPackageTarballs.length}.`,
|
||||
);
|
||||
}
|
||||
const dependencies: Record<string, string> = {
|
||||
"@openclaw/ai": pathToFileURL(aiTarball).href,
|
||||
openclaw: pathToFileURL(tarballPath).href,
|
||||
};
|
||||
if (localPackageTarballs[0]) {
|
||||
dependencies["@openclaw/ai"] = pathToFileURL(localPackageTarballs[0]).href;
|
||||
}
|
||||
mkdirSync(prefixDir, { recursive: true });
|
||||
writeFileSync(
|
||||
join(prefixDir, "package.json"),
|
||||
@@ -493,7 +512,7 @@ function installPackedTarball(
|
||||
prefixDir: string,
|
||||
tarballPath: string,
|
||||
cwd: string,
|
||||
localPackageTarballs: string[] = [],
|
||||
localPackageTarballs: string[],
|
||||
): void {
|
||||
writePackedTarballInstallManifest(prefixDir, tarballPath, localPackageTarballs);
|
||||
execNpm(createPackedTarballInstallArgs(prefixDir), {
|
||||
@@ -921,7 +940,10 @@ function runPackedBundledChannelEntrySmoke(): void {
|
||||
const packResults = runPack(packDir);
|
||||
const tarballPath = resolvePackedTarballPath(packDir, packResults);
|
||||
const prefixDir = join(tmpRoot, "prefix");
|
||||
const localPackageTarballs = resolveReleaseCheckLocalPackageTarballs();
|
||||
const localPackageTarballs = prepareReleaseCheckLocalPackageTarballs({
|
||||
tmpRoot,
|
||||
tarballDir: process.env[RELEASE_CHECK_LOCAL_PACKAGE_TARBALL_DIR_ENV],
|
||||
});
|
||||
installPackedTarball(prefixDir, tarballPath, tmpRoot, localPackageTarballs);
|
||||
|
||||
const packageRoot = join(prefixDir, "node_modules", "openclaw");
|
||||
|
||||
@@ -5,6 +5,7 @@ import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
createPackedTarballInstallArgs,
|
||||
prepareReleaseCheckLocalPackageTarballs,
|
||||
RELEASE_CHECK_LOCAL_PACKAGE_TARBALL_DIR_ENV,
|
||||
resolveReleaseCheckLocalPackageTarballs,
|
||||
writePackedTarballInstallManifest,
|
||||
@@ -62,18 +63,55 @@ describe("release-check", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("preserves the no-env local release check path", () => {
|
||||
it("packs the local AI workspace when no prepared tarball is supplied", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "openclaw-release-check-ai-pack-test-"));
|
||||
try {
|
||||
const tarballs = prepareReleaseCheckLocalPackageTarballs({
|
||||
tmpRoot: root,
|
||||
packLocalAi: (packDestination) => {
|
||||
const filename = "openclaw-ai-2026.7.1-beta.3.tgz";
|
||||
writeFileSync(join(packDestination, filename), "fixture");
|
||||
return [{ filename }];
|
||||
},
|
||||
});
|
||||
expect(tarballs).toEqual([join(root, "ai-pack", "openclaw-ai-2026.7.1-beta.3.tgz")]);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("prefers the prepared AI tarball over packing the workspace", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "openclaw-release-check-ai-pack-test-"));
|
||||
try {
|
||||
const preparedDir = join(root, "prepared");
|
||||
mkdirSync(preparedDir);
|
||||
const preparedTarball = join(preparedDir, "openclaw-ai-2026.7.1-beta.3.tgz");
|
||||
writeFileSync(preparedTarball, "fixture");
|
||||
const tarballs = prepareReleaseCheckLocalPackageTarballs({
|
||||
tmpRoot: root,
|
||||
tarballDir: preparedDir,
|
||||
packLocalAi: () => {
|
||||
throw new Error("workspace pack should not run");
|
||||
},
|
||||
});
|
||||
expect(tarballs).toEqual([preparedTarball]);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects a packed install without the local AI tarball", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "openclaw-release-check-install-test-"));
|
||||
try {
|
||||
writePackedTarballInstallManifest(root, "/tmp/openclaw.tgz", []);
|
||||
const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as {
|
||||
dependencies?: Record<string, string>;
|
||||
private?: boolean;
|
||||
};
|
||||
expect(manifest.private).toBe(true);
|
||||
expect(manifest.dependencies).toEqual({
|
||||
openclaw: "file:///tmp/openclaw.tgz",
|
||||
});
|
||||
expect(() => writePackedTarballInstallManifest(root, "/tmp/openclaw.tgz", [])).toThrow(
|
||||
"requires exactly one @openclaw/ai tarball",
|
||||
);
|
||||
expect(() =>
|
||||
writePackedTarballInstallManifest(root, "/tmp/openclaw.tgz", [
|
||||
"/tmp/openclaw-ai-one.tgz",
|
||||
"/tmp/openclaw-ai-two.tgz",
|
||||
]),
|
||||
).toThrow("requires exactly one @openclaw/ai tarball");
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user