Skip to content

Commit c626095

Browse files
committed
fix(parallels): pack self-contained workspace artifact
1 parent 1797f44 commit c626095

3 files changed

Lines changed: 69 additions & 21 deletions

File tree

scripts/e2e/parallels/package-artifact.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ export async function packOpenClaw(input: {
185185
input.destination,
186186
"--output-name",
187187
path.basename(tgzPath),
188+
"--pnpm-pack",
188189
],
189190
{ quiet: true },
190191
).stdout.trim();

scripts/package-openclaw-for-docker.mjs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ export function parseArgs(argv) {
134134
outputDir: "",
135135
outputName: "",
136136
packJson: "",
137+
pnpmPack: false,
137138
skipBuild: false,
138139
sourceDir: ROOT_DIR,
139140
};
@@ -174,6 +175,8 @@ export function parseArgs(argv) {
174175
"packJson",
175176
readEqualsOptionValue(arg.slice("--pack-json=".length), "--pack-json"),
176177
);
178+
} else if (arg === "--pnpm-pack") {
179+
setOnce(arg, "pnpmPack", true);
177180
} else if (arg === "--skip-build") {
178181
setOnce(arg, "skipBuild", true);
179182
} else if (arg === "--source-dir") {
@@ -192,6 +195,9 @@ export function parseArgs(argv) {
192195
if (options.outputName) {
193196
validateOutputName(options.outputName);
194197
}
198+
if (options.packJson && options.pnpmPack) {
199+
throw new Error("--pack-json cannot be combined with --pnpm-pack");
200+
}
195201
return options;
196202
}
197203

@@ -638,41 +644,45 @@ export async function packOpenClawPackageForDocker(sourceDir, outputDir, options
638644
const prepareChangelog = options.prepareChangelog ?? preparePackageChangelog;
639645
const restoreChangelog = options.restoreChangelog ?? restorePackageChangelog;
640646
const prepareBundledAiRuntime = options.prepareBundledAiRuntime ?? prepareBundledAiRuntimePackage;
647+
const packTool = options.pnpmPack ? "pnpm" : "npm";
648+
if (options.packJsonPath && options.pnpmPack) {
649+
throw new Error("packJsonPath cannot be combined with pnpmPack");
650+
}
641651
console.error("==> Packing OpenClaw package");
642652
await prepareChangelog(sourceDir);
643653
let packOutput;
644654
let cleanupBundledAiRuntime = async () => {};
645655
try {
646656
await cleanPackedOpenClawTarballs(outputDir);
647657
cleanupBundledAiRuntime = await prepareBundledAiRuntime(sourceDir, outputDir, runCaptureImpl);
648-
const packArgs = [
649-
"pack",
650-
...(options.packJsonPath ? ["--json"] : []),
651-
"--silent",
652-
"--ignore-scripts",
653-
"--pack-destination",
654-
outputDir,
655-
];
656-
packOutput = await runCaptureImpl(
657-
"npm",
658-
packArgs,
659-
sourceDir,
660-
{
661-
deferForwardedSignalExit: true,
662-
timeoutMs: resolveTimeoutMs(
663-
"OPENCLAW_DOCKER_PACKAGE_PACK_TIMEOUT_MS",
664-
DEFAULT_PACKAGE_PACK_TIMEOUT_MS,
665-
),
666-
},
667-
);
658+
const packArgs =
659+
packTool === "pnpm"
660+
? ["pack", "--silent", "--config.ignore-scripts=true", "--pack-destination", outputDir]
661+
: [
662+
"pack",
663+
...(options.packJsonPath ? ["--json"] : []),
664+
"--silent",
665+
"--ignore-scripts",
666+
"--pack-destination",
667+
outputDir,
668+
];
669+
packOutput = await runCaptureImpl(packTool, packArgs, sourceDir, {
670+
deferForwardedSignalExit: true,
671+
timeoutMs: resolveTimeoutMs(
672+
"OPENCLAW_DOCKER_PACKAGE_PACK_TIMEOUT_MS",
673+
DEFAULT_PACKAGE_PACK_TIMEOUT_MS,
674+
),
675+
});
668676
} finally {
669677
try {
670678
await cleanupBundledAiRuntime();
671679
} finally {
672680
await restoreChangelog(sourceDir);
673681
}
674682
}
675-
let tarball = await newestOpenClawTarball(outputDir, packOutput);
683+
// pnpm reports an absolute destination path. The directory was emptied before packing,
684+
// so scan that controlled destination instead of accepting a path from command output.
685+
let tarball = await newestOpenClawTarball(outputDir, options.pnpmPack ? "" : packOutput);
676686
if (options.outputName) {
677687
const target = path.join(outputDir, options.outputName);
678688
if (target !== tarball) {
@@ -720,6 +730,7 @@ async function main() {
720730
const tarball = await packOpenClawPackageForDocker(sourceDir, outputDir, {
721731
outputName: options.outputName,
722732
packJsonPath: options.packJson,
733+
pnpmPack: options.pnpmPack,
723734
});
724735

725736
console.error("==> Checking OpenClaw package tarball");

test/e2e/qa-lab/runtime/package-openclaw-for-docker.e2e.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ describe("package-openclaw-for-docker", () => {
9696
outputDir: ".artifacts/docker",
9797
outputName: "openclaw-current.tgz",
9898
packJson: ".artifacts/docker/pack.json",
99+
pnpmPack: false,
99100
skipBuild: true,
100101
sourceDir: "/repo",
101102
});
@@ -116,6 +117,7 @@ describe("package-openclaw-for-docker", () => {
116117
["--output-dir", ["--output-dir", "one", "--output-dir=two"]],
117118
["--output-name", ["--output-name", "one.tgz", "--output-name=two.tgz"]],
118119
["--pack-json", ["--pack-json", "one.json", "--pack-json=two.json"]],
120+
["--pnpm-pack", ["--pnpm-pack", "--pnpm-pack"]],
119121
["--source-dir", ["--source-dir", "/repo-a", "--source-dir=/repo-b"]],
120122
["--skip-build", ["--skip-build", "--skip-build"]],
121123
] satisfies Array<[string, string[]]>;
@@ -125,6 +127,13 @@ describe("package-openclaw-for-docker", () => {
125127
}
126128
});
127129

130+
it("rejects pnpm pack with npm metadata output", () => {
131+
expect(parseArgs(["--pnpm-pack"]).pnpmPack).toBe(true);
132+
expect(() => parseArgs(["--pnpm-pack", "--pack-json", "pack.json"])).toThrow(
133+
"--pack-json cannot be combined with --pnpm-pack",
134+
);
135+
});
136+
128137
it("rejects package artifact output names that escape the output directory", () => {
129138
for (const outputName of [
130139
"../openclaw-current.tgz",
@@ -387,6 +396,33 @@ describe("package-openclaw-for-docker", () => {
387396
]);
388397
});
389398

399+
it("uses pnpm pack when requested", async () => {
400+
const outputDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-pnpm-pack-"));
401+
const calls: string[] = [];
402+
const packedPath = path.join(outputDir, "openclaw-2026.5.28.tgz");
403+
404+
try {
405+
const tarball = await packOpenClawPackageForDocker("/repo", outputDir, {
406+
pnpmPack: true,
407+
prepareBundledAiRuntime: skipBundledAiRuntime,
408+
prepareChangelog: async () => {},
409+
restoreChangelog: async () => {},
410+
runCaptureImpl: async (command: string, args: string[], cwd: string) => {
411+
calls.push(`${command}:${args.join(" ")}:${cwd}`);
412+
fs.writeFileSync(packedPath, "package");
413+
return `${packedPath}\n`;
414+
},
415+
});
416+
417+
expect(tarball).toBe(packedPath);
418+
expect(calls).toEqual([
419+
`pnpm:pack --silent --config.ignore-scripts=true --pack-destination ${outputDir}:/repo`,
420+
]);
421+
} finally {
422+
fs.rmSync(outputDir, { force: true, recursive: true });
423+
}
424+
});
425+
390426
it("writes npm pack metadata for renamed package artifacts", async () => {
391427
const outputDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-docker-pack-json-"));
392428
const packJsonPath = path.join(outputDir, "pack.json");

0 commit comments

Comments
 (0)