diff --git a/Dockerfile b/Dockerfile index 8dbde761f8bf..3575d578d727 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,7 +60,7 @@ COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./ COPY openclaw.mjs ./ COPY ui/package.json ./ui/package.json COPY patches ./patches -COPY scripts/postinstall-bundled-plugins.mjs scripts/preinstall-package-manager-warning.mjs scripts/npm-runner.mjs scripts/windows-cmd-helpers.mjs ./scripts/ +COPY scripts/postinstall-bundled-plugins.mjs scripts/preinstall-package-manager-warning.mjs scripts/npm-runner.mjs scripts/windows-cmd-helpers.mjs scripts/prepare-git-hooks.mjs ./scripts/ COPY scripts/lib/package-dist-imports.mjs ./scripts/lib/package-dist-imports.mjs COPY --from=workspace-deps /out/packages/ ./packages/ diff --git a/src/dockerfile.test.ts b/src/dockerfile.test.ts index 6e603c700b7b..6fecb55b6502 100644 --- a/src/dockerfile.test.ts +++ b/src/dockerfile.test.ts @@ -127,6 +127,7 @@ describe("Dockerfile", () => { const dockerfile = await readFile(dockerfilePath, "utf8"); const installIndex = dockerfile.indexOf("pnpm install --frozen-lockfile"); const postinstallIndex = dockerfile.indexOf("COPY scripts/postinstall-bundled-plugins.mjs"); + const prepareIndex = dockerfile.indexOf("scripts/prepare-git-hooks.mjs"); const distImportHelperIndex = dockerfile.indexOf( "COPY scripts/lib/package-dist-imports.mjs ./scripts/lib/package-dist-imports.mjs", ); @@ -138,6 +139,7 @@ describe("Dockerfile", () => { ); expect(postinstallIndex).toBeGreaterThan(-1); + expect(prepareIndex).toBeGreaterThan(-1); expect(distImportHelperIndex).toBeGreaterThan(-1); expect(packageManifestIndex).toBeGreaterThan(-1); expect(extensionManifestIndex).toBeGreaterThan(-1); @@ -146,11 +148,42 @@ describe("Dockerfile", () => { `if [ -f "/tmp/\${OPENCLAW_BUNDLED_PLUGIN_DIR}/$ext/package.json" ]; then`, ); expect(postinstallIndex).toBeLessThan(installIndex); + expect(prepareIndex).toBeLessThan(installIndex); expect(distImportHelperIndex).toBeLessThan(installIndex); expect(packageManifestIndex).toBeLessThan(installIndex); expect(extensionManifestIndex).toBeLessThan(installIndex); }); + it("copies root package lifecycle scripts before pnpm install", async () => { + const [dockerfile, packageJsonText] = await Promise.all([ + readFile(dockerfilePath, "utf8"), + readFile(join(repoRoot, "package.json"), "utf8"), + ]); + const installIndex = dockerfile.indexOf("pnpm install --frozen-lockfile"); + const packageJson = JSON.parse(packageJsonText) as { + scripts?: Record; + }; + const installLifecycleScripts = ["preinstall", "install", "postinstall", "prepare"] as const; + + for (const lifecycleScript of installLifecycleScripts) { + const command = packageJson.scripts?.[lifecycleScript]; + const scriptPath = command?.match(/\bnode\s+(scripts\/[^\s]+)/)?.[1]; + if (!scriptPath) { + continue; + } + + const copyIndex = dockerfile.indexOf(scriptPath); + expect( + copyIndex, + `${lifecycleScript} must copy ${scriptPath} before pnpm install`, + ).toBeGreaterThan(-1); + expect( + copyIndex, + `${lifecycleScript} must copy ${scriptPath} before pnpm install`, + ).toBeLessThan(installIndex); + } + }); + it("does not let pnpm resync the full source workspace during Docker build scripts", async () => { const dockerfile = await readFile(dockerfilePath, "utf8");