mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(package): reuse bundled artifact for install smoke
This commit is contained in:
@@ -133,6 +133,7 @@ export function parseArgs(argv) {
|
||||
const options = {
|
||||
outputDir: "",
|
||||
outputName: "",
|
||||
packJson: "",
|
||||
skipBuild: false,
|
||||
sourceDir: ROOT_DIR,
|
||||
};
|
||||
@@ -164,6 +165,15 @@ export function parseArgs(argv) {
|
||||
"outputName",
|
||||
readEqualsOptionValue(arg.slice("--output-name=".length), "--output-name"),
|
||||
);
|
||||
} else if (arg === "--pack-json") {
|
||||
setOnce("--pack-json", "packJson", readOptionValue(argv, index, arg));
|
||||
index += 1;
|
||||
} else if (arg?.startsWith("--pack-json=")) {
|
||||
setOnce(
|
||||
"--pack-json",
|
||||
"packJson",
|
||||
readEqualsOptionValue(arg.slice("--pack-json=".length), "--pack-json"),
|
||||
);
|
||||
} else if (arg === "--skip-build") {
|
||||
setOnce(arg, "skipBuild", true);
|
||||
} else if (arg === "--source-dir") {
|
||||
@@ -373,6 +383,20 @@ async function runCapture(command, args, cwd, options = {}) {
|
||||
|
||||
async function newestOpenClawTarball(outputDir, packOutput) {
|
||||
let fromOutput = "";
|
||||
try {
|
||||
const parsed = JSON.parse(packOutput);
|
||||
if (Array.isArray(parsed)) {
|
||||
for (const entry of parsed) {
|
||||
if (typeof entry?.filename !== "string") {
|
||||
continue;
|
||||
}
|
||||
const filename = resolvePackedOpenClawFileName(entry.filename);
|
||||
if (filename) {
|
||||
fromOutput = filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
for (const line of packOutput.split(/\r?\n/u)) {
|
||||
const filename = resolvePackedOpenClawFileName(line);
|
||||
if (filename) {
|
||||
@@ -400,6 +424,30 @@ async function newestOpenClawTarball(outputDir, packOutput) {
|
||||
return path.join(outputDir, packed);
|
||||
}
|
||||
|
||||
async function writePackJson(packOutput, tarball, packJsonPath, sourceDir) {
|
||||
if (!packJsonPath) {
|
||||
return;
|
||||
}
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(packOutput);
|
||||
} catch (error) {
|
||||
throw new Error("npm pack --json output was not valid JSON", { cause: error });
|
||||
}
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new Error("npm pack --json output must be an array");
|
||||
}
|
||||
const filename = path.basename(tarball);
|
||||
for (const entry of parsed) {
|
||||
if (entry && typeof entry === "object" && typeof entry.filename === "string") {
|
||||
entry.filename = filename;
|
||||
}
|
||||
}
|
||||
const target = path.resolve(sourceDir, packJsonPath);
|
||||
await fs.mkdir(path.dirname(target), { recursive: true });
|
||||
await fs.writeFile(target, `${JSON.stringify(parsed, null, 2)}\n`);
|
||||
}
|
||||
|
||||
async function cleanPackedOpenClawTarballs(outputDir) {
|
||||
let entries;
|
||||
try {
|
||||
@@ -597,9 +645,17 @@ export async function packOpenClawPackageForDocker(sourceDir, outputDir, options
|
||||
try {
|
||||
await cleanPackedOpenClawTarballs(outputDir);
|
||||
cleanupBundledAiRuntime = await prepareBundledAiRuntime(sourceDir, outputDir, runCaptureImpl);
|
||||
const packArgs = [
|
||||
"pack",
|
||||
...(options.packJsonPath ? ["--json"] : []),
|
||||
"--silent",
|
||||
"--ignore-scripts",
|
||||
"--pack-destination",
|
||||
outputDir,
|
||||
];
|
||||
packOutput = await runCaptureImpl(
|
||||
"npm",
|
||||
["pack", "--silent", "--ignore-scripts", "--pack-destination", outputDir],
|
||||
packArgs,
|
||||
sourceDir,
|
||||
{
|
||||
deferForwardedSignalExit: true,
|
||||
@@ -616,7 +672,17 @@ export async function packOpenClawPackageForDocker(sourceDir, outputDir, options
|
||||
await restoreChangelog(sourceDir);
|
||||
}
|
||||
}
|
||||
return await newestOpenClawTarball(outputDir, packOutput);
|
||||
let tarball = await newestOpenClawTarball(outputDir, packOutput);
|
||||
if (options.outputName) {
|
||||
const target = path.join(outputDir, options.outputName);
|
||||
if (target !== tarball) {
|
||||
await fs.rm(target, { force: true });
|
||||
await fs.rename(tarball, target);
|
||||
tarball = target;
|
||||
}
|
||||
}
|
||||
await writePackJson(packOutput, tarball, options.packJsonPath, sourceDir);
|
||||
return tarball;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@@ -651,16 +717,10 @@ async function main() {
|
||||
},
|
||||
);
|
||||
|
||||
let tarball = await packOpenClawPackageForDocker(sourceDir, outputDir);
|
||||
|
||||
if (options.outputName) {
|
||||
const target = path.join(outputDir, options.outputName);
|
||||
if (target !== tarball) {
|
||||
await fs.rm(target, { force: true });
|
||||
await fs.rename(tarball, target);
|
||||
tarball = target;
|
||||
}
|
||||
}
|
||||
const tarball = await packOpenClawPackageForDocker(sourceDir, outputDir, {
|
||||
outputName: options.outputName,
|
||||
packJsonPath: options.packJson,
|
||||
});
|
||||
|
||||
console.error("==> Checking OpenClaw package tarball");
|
||||
const checkStartedAt = Date.now();
|
||||
|
||||
@@ -299,6 +299,8 @@ prepare_update_tarball() {
|
||||
local baseline_pack_json
|
||||
local pack_json_file
|
||||
local baseline_pack_json_file
|
||||
local package_args
|
||||
local package_tgz
|
||||
local packed_update_version
|
||||
pack_json_file="${UPDATE_DIR}/pack.json"
|
||||
baseline_pack_json_file="${UPDATE_DIR}/baseline-pack.json"
|
||||
@@ -316,13 +318,20 @@ prepare_update_tarball() {
|
||||
UPDATE_EXPECT_VERSION="$(
|
||||
node -p 'JSON.parse(require("node:fs").readFileSync("package.json", "utf8")).version'
|
||||
)"
|
||||
node --import tsx scripts/write-package-dist-inventory.ts
|
||||
node scripts/check-package-dist-imports.mjs "$ROOT_DIR"
|
||||
quiet_npm pack --ignore-scripts --json --pack-destination "$UPDATE_DIR" >"$pack_json_file"
|
||||
package_args=(
|
||||
--output-dir "$UPDATE_DIR"
|
||||
--pack-json "$pack_json_file"
|
||||
--skip-build
|
||||
)
|
||||
package_tgz="$(node scripts/package-openclaw-for-docker.mjs "${package_args[@]}")"
|
||||
UPDATE_TGZ_FILE="$(basename "$package_tgz")"
|
||||
fi
|
||||
UPDATE_TGZ_FILE="$(read_pack_tarball_filename "$pack_json_file")"
|
||||
if [[ -z "$UPDATE_PACKAGE_SPEC" ]]; then
|
||||
node scripts/check-openclaw-package-tarball.mjs "${UPDATE_DIR}/${UPDATE_TGZ_FILE}"
|
||||
node scripts/check-openclaw-package-tarball.mjs \
|
||||
--require-bundled-workspace-deps \
|
||||
"${UPDATE_DIR}/${UPDATE_TGZ_FILE}"
|
||||
else
|
||||
UPDATE_TGZ_FILE="$(read_pack_tarball_filename "$pack_json_file")"
|
||||
fi
|
||||
print_pack_audit "update" "$pack_json_file"
|
||||
assert_pack_unpacked_size_budget "update" "$pack_json_file"
|
||||
|
||||
@@ -86,6 +86,8 @@ describe("package-openclaw-for-docker", () => {
|
||||
"--output-dir",
|
||||
".artifacts/docker",
|
||||
"--output-name=openclaw-current.tgz",
|
||||
"--pack-json",
|
||||
".artifacts/docker/pack.json",
|
||||
"--source-dir",
|
||||
"/repo",
|
||||
"--skip-build",
|
||||
@@ -93,6 +95,7 @@ describe("package-openclaw-for-docker", () => {
|
||||
).toEqual({
|
||||
outputDir: ".artifacts/docker",
|
||||
outputName: "openclaw-current.tgz",
|
||||
packJson: ".artifacts/docker/pack.json",
|
||||
skipBuild: true,
|
||||
sourceDir: "/repo",
|
||||
});
|
||||
@@ -112,6 +115,7 @@ describe("package-openclaw-for-docker", () => {
|
||||
const duplicateCases = [
|
||||
["--output-dir", ["--output-dir", "one", "--output-dir=two"]],
|
||||
["--output-name", ["--output-name", "one.tgz", "--output-name=two.tgz"]],
|
||||
["--pack-json", ["--pack-json", "one.json", "--pack-json=two.json"]],
|
||||
["--source-dir", ["--source-dir", "/repo-a", "--source-dir=/repo-b"]],
|
||||
["--skip-build", ["--skip-build", "--skip-build"]],
|
||||
] satisfies Array<[string, string[]]>;
|
||||
@@ -383,6 +387,61 @@ describe("package-openclaw-for-docker", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("writes npm pack metadata for renamed package artifacts", async () => {
|
||||
const outputDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-docker-pack-json-"));
|
||||
const packJsonPath = path.join(outputDir, "pack.json");
|
||||
|
||||
try {
|
||||
const tarball = await packOpenClawPackageForDocker("/repo", outputDir, {
|
||||
outputName: "openclaw-current.tgz",
|
||||
packJsonPath,
|
||||
prepareBundledAiRuntime: skipBundledAiRuntime,
|
||||
prepareChangelog: async () => {},
|
||||
restoreChangelog: async () => {},
|
||||
runCaptureImpl: async (
|
||||
command: string,
|
||||
args: string[],
|
||||
_cwd: string,
|
||||
options: { deferForwardedSignalExit?: boolean },
|
||||
) => {
|
||||
expect(command).toBe("npm");
|
||||
expect(args).toEqual([
|
||||
"pack",
|
||||
"--json",
|
||||
"--silent",
|
||||
"--ignore-scripts",
|
||||
"--pack-destination",
|
||||
outputDir,
|
||||
]);
|
||||
expect(options.deferForwardedSignalExit).toBe(true);
|
||||
fs.writeFileSync(path.join(outputDir, "openclaw-2026.5.28.tgz"), "package");
|
||||
return JSON.stringify([
|
||||
{
|
||||
entryCount: 1,
|
||||
filename: "openclaw-2026.5.28.tgz",
|
||||
size: 7,
|
||||
unpackedSize: 7,
|
||||
version: "2026.5.28",
|
||||
},
|
||||
]);
|
||||
},
|
||||
});
|
||||
|
||||
expect(tarball).toBe(path.join(outputDir, "openclaw-current.tgz"));
|
||||
expect(JSON.parse(fs.readFileSync(packJsonPath, "utf8"))).toEqual([
|
||||
{
|
||||
entryCount: 1,
|
||||
filename: "openclaw-current.tgz",
|
||||
size: 7,
|
||||
unpackedSize: 7,
|
||||
version: "2026.5.28",
|
||||
},
|
||||
]);
|
||||
} finally {
|
||||
fs.rmSync(outputDir, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects path-like npm pack stdout before resolving Docker package tarballs", async () => {
|
||||
for (const filename of [
|
||||
"../openclaw-2026.6.17.tgz",
|
||||
|
||||
@@ -612,6 +612,7 @@ describe("test-install-sh-docker", () => {
|
||||
const script = readFileSync(SCRIPT_PATH, "utf8");
|
||||
|
||||
expect(script).toContain("read_pack_tarball_filename()");
|
||||
expect(script).toContain('UPDATE_TGZ_FILE="$(basename "$package_tgz")"');
|
||||
expect(script).toContain('UPDATE_TGZ_FILE="$(read_pack_tarball_filename "$pack_json_file")"');
|
||||
expect(script).toContain(
|
||||
'BASELINE_TGZ_FILE="$(read_pack_tarball_filename "$baseline_pack_json_file")"',
|
||||
@@ -644,13 +645,16 @@ describe("test-install-sh-docker", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("writes the package dist inventory before packing ignore-scripts tarballs", () => {
|
||||
it("uses the package artifact helper for local update tarballs", () => {
|
||||
const script = readFileSync(SCRIPT_PATH, "utf8");
|
||||
|
||||
expect(script).toContain("node --import tsx scripts/write-package-dist-inventory.ts");
|
||||
expect(script).toContain('node scripts/check-package-dist-imports.mjs "$ROOT_DIR"');
|
||||
expect(script).toContain("quiet_npm pack --ignore-scripts");
|
||||
expect(script).toContain("node scripts/package-openclaw-for-docker.mjs");
|
||||
expect(script).toContain('--pack-json "$pack_json_file"');
|
||||
expect(script).toContain("--skip-build");
|
||||
expect(script).not.toContain("node --import tsx scripts/write-package-dist-inventory.ts");
|
||||
expect(script).not.toContain("quiet_npm pack --ignore-scripts --json");
|
||||
expect(script).toContain("node scripts/check-openclaw-package-tarball.mjs");
|
||||
expect(script).toContain("--require-bundled-workspace-deps");
|
||||
});
|
||||
|
||||
it("runs candidate tarballs through the installer script instead of direct npm", () => {
|
||||
|
||||
Reference in New Issue
Block a user