ci: preserve weekly Docker tool cache across commits (#13190)
Keep stable Docker tool installation layers independent of application build version and commit metadata. Preserve the existing weekly tool refresh and runtime build stamp. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
399daa1f25
commit
3fd556b8f6
15
Dockerfile
15
Dockerfile
|
|
@ -103,14 +103,6 @@ RUN rm -rf packages/paperclip-runner/runner/target
|
|||
FROM base AS production
|
||||
ARG USER_UID=1000
|
||||
ARG USER_GID=1000
|
||||
# Real version for this build, computed from `git describe` on the CI runner
|
||||
# (the image has no .git, so the server cannot derive it at runtime). Empty for
|
||||
# local `docker build`, which just leaves the server on its normal fallbacks.
|
||||
ARG PAPERCLIP_BUILD_VERSION=""
|
||||
# The exact commit this image was built from, for the same reason: server-info
|
||||
# falls back to PAPERCLIP_BUILD_COMMIT when git is unavailable, which feeds the
|
||||
# /api/health `commit` field that deploy tooling verifies. Empty locally.
|
||||
ARG PAPERCLIP_BUILD_COMMIT=""
|
||||
# Refreshes the tool layer below when it changes (CI stamps an ISO week, so
|
||||
# the @latest CLI tools advance weekly). Without it the cached layer would
|
||||
# freeze the tools until an unrelated cache bust.
|
||||
|
|
@ -133,6 +125,13 @@ RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
|||
|
||||
COPY --chown=node:node --from=build /app /app
|
||||
|
||||
# Declare per-build metadata after the stable RUN layers. Docker includes
|
||||
# in-scope ARG values in a RUN's environment even when its command does not
|
||||
# mention them; declaring these earlier invalidates the weekly tool cache.
|
||||
# The build stage still receives the commit before writing dist/build-info.json.
|
||||
# Empty for local builds, preserving the server's normal version fallbacks.
|
||||
ARG PAPERCLIP_BUILD_VERSION=""
|
||||
ARG PAPERCLIP_BUILD_COMMIT=""
|
||||
ENV NODE_ENV=production \
|
||||
HOME=/paperclip \
|
||||
HOST=0.0.0.0 \
|
||||
|
|
|
|||
|
|
@ -18,6 +18,14 @@ Build arguments:
|
|||
|-----|---------|---------|
|
||||
| `USER_UID` | `1000` | UID for the container `node` user (match your host UID to avoid permission issues on bind mounts) |
|
||||
| `USER_GID` | `1000` | GID for the container `node` group |
|
||||
| `CLI_TOOLS_CACHE_EPOCH` | empty | Refresh the CLI-install layer; CI supplies the current ISO week |
|
||||
| `PAPERCLIP_BUILD_VERSION` | empty | Runtime version when Git metadata is unavailable |
|
||||
| `PAPERCLIP_BUILD_COMMIT` | empty | Source commit written into the server build stamp and runtime environment |
|
||||
|
||||
Changing the build version or commit preserves the CLI-install cache. The
|
||||
tool layer refreshes when its weekly epoch, base image, installation command,
|
||||
or earlier build inputs change. Local builds can set a new epoch explicitly
|
||||
to refresh tools without clearing the entire build cache.
|
||||
|
||||
```sh
|
||||
docker build -t paperclip-local \
|
||||
|
|
|
|||
|
|
@ -35,6 +35,25 @@ function stageBody(source: string, stageName: string): string {
|
|||
return source.slice(start, end);
|
||||
}
|
||||
|
||||
it("keeps per-build runtime metadata out of the weekly CLI-install cache", () => {
|
||||
const production = stageBody(dockerfile, "production");
|
||||
const tools = production.search(/^RUN echo "cli-tools-epoch:/m);
|
||||
const entrypoint = production.search(/^RUN chmod \+x \/usr\/local\/bin\/docker-entrypoint\.sh/m);
|
||||
const runtime = production.search(/^ENV NODE_ENV=production/m);
|
||||
const epoch = production.search(/^ARG CLI_TOOLS_CACHE_EPOCH\b/m);
|
||||
expect(tools).toBeGreaterThanOrEqual(0);
|
||||
expect(entrypoint).toBeGreaterThan(tools);
|
||||
expect(epoch).toBeGreaterThanOrEqual(0);
|
||||
expect(epoch).toBeLessThan(tools);
|
||||
for (const name of ["PAPERCLIP_BUILD_VERSION", "PAPERCLIP_BUILD_COMMIT"]) {
|
||||
const declarations = [...production.matchAll(new RegExp(`^ARG ${name}\\b`, "gm"))];
|
||||
expect(declarations).toHaveLength(1);
|
||||
expect(declarations[0].index).toBeGreaterThan(entrypoint);
|
||||
expect(declarations[0].index).toBeLessThan(runtime);
|
||||
expect(production.slice(runtime)).toContain(`${name}=\${${name}}`);
|
||||
}
|
||||
});
|
||||
|
||||
describe("docker build-stamp wiring", () => {
|
||||
it("declares PAPERCLIP_BUILD_COMMIT in the build stage before the server build", () => {
|
||||
const build = stageBody(dockerfile, "build");
|
||||
|
|
|
|||
Loading…
Reference in New Issue