fix(docker): include patch files in runtime image

This commit is contained in:
Peter Steinberger
2026-04-26 06:25:32 +01:00
parent 0e58654dba
commit 9f4b155c47
4 changed files with 30 additions and 1 deletions

View File

@@ -114,7 +114,21 @@ jobs:
- name: Run root Dockerfile CLI smoke
run: |
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc '
which openclaw &&
openclaw --version &&
node -e "
const fs = require(\"node:fs\");
const path = require(\"node:path\");
const pkg = require(\"/app/package.json\");
for (const [dep, rel] of Object.entries(pkg.pnpm?.patchedDependencies ?? {})) {
const absolute = path.join(\"/app\", rel);
if (!fs.existsSync(absolute)) {
throw new Error(`missing patch for ${dep}: ${rel}`);
}
}
"
'
- name: Run agents delete shared workspace Docker CLI smoke
env:

View File

@@ -70,6 +70,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Docker: copy patched dependency files into runtime images so downstream `pnpm install` layers keep working. Fixes #69224. Thanks @gucasbrg.
- Agents/runtime: submit heartbeat, cron, and exec wakeups as transient runtime context instead of visible user prompts, keeping synthetic system work out of chat transcripts. Fixes #66496 and #66814. Thanks @jeades and @mandomaker.
- Telegram: preserve exact selected quote text when sending native quote replies, and retry with legacy replies if Telegram rejects quote parameters. (#71952) Thanks @rubencu.
- Plugins/CLI: preserve manifest name, description, format, and source metadata in cold `openclaw plugins list` output without importing plugin runtime. Thanks @shakkernerd.

View File

@@ -173,6 +173,7 @@ RUN chown node:node /app
COPY --from=runtime-assets --chown=node:node /app/dist ./dist
COPY --from=runtime-assets --chown=node:node /app/node_modules ./node_modules
COPY --from=runtime-assets --chown=node:node /app/package.json .
COPY --from=runtime-assets --chown=node:node /app/patches ./patches
COPY --from=runtime-assets --chown=node:node /app/openclaw.mjs .
COPY --from=runtime-assets --chown=node:node /app/${OPENCLAW_BUNDLED_PLUGIN_DIR} ./${OPENCLAW_BUNDLED_PLUGIN_DIR}
COPY --from=runtime-assets --chown=node:node /app/skills ./skills

View File

@@ -6,6 +6,7 @@ import { BUNDLED_PLUGIN_ROOT_DIR } from "../test/helpers/bundled-plugin-paths.js
const repoRoot = resolve(fileURLToPath(new URL(".", import.meta.url)), "..");
const dockerfilePath = join(repoRoot, "Dockerfile");
const packageJsonPath = join(repoRoot, "package.json");
function collapseDockerContinuations(dockerfile: string): string {
return dockerfile.replace(/\\\r?\n[ \t]*/g, " ");
@@ -68,6 +69,18 @@ describe("Dockerfile", () => {
);
});
it("keeps package manager patch files in runtime images", async () => {
const dockerfile = await readFile(dockerfilePath, "utf8");
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8")) as {
pnpm?: { patchedDependencies?: Record<string, string> };
};
expect(Object.keys(packageJson.pnpm?.patchedDependencies ?? {})).not.toHaveLength(0);
expect(dockerfile).toContain(
"COPY --from=runtime-assets --chown=node:node /app/patches ./patches",
);
});
it("does not override bundled plugin discovery in runtime images", async () => {
const dockerfile = collapseDockerContinuations(await readFile(dockerfilePath, "utf8"));
expect(dockerfile).toContain(`ARG OPENCLAW_BUNDLED_PLUGIN_DIR=${BUNDLED_PLUGIN_ROOT_DIR}`);