Files
quak/Dockerfile
T
clawbot eaf839442f docker build . stamps the git tag or short commit, not dev (closes #154)
script/build writes the version script/version prints into
dist/package.json, which quak --version reports: the VERSION environment
variable or build arg when one is given, otherwise git describe --tags
--always, otherwise package.json's version. A checkout with .git whose
version comes out empty, dev or unknown fails the build.

.dockerignore no longer leaves out .git, and ARG VERSION has no default,
so a plain docker build . of a clone stamps its commit. script/docker and
script/cibuild still pass the host's version. make build-bin bundles the
built dist/, so the single binary reports the same version.

Model: opus-5-5
2026-10-02 02:50:23 +00:00

73 lines
2.4 KiB
Docker

# Lint phase. The linters are invoked directly rather than through `make
# lint` or `script/lint`, which are themselves a docker build and would
# recurse into a daemon that does not exist in a build step.
#
# node 22.22.0 on Alpine 3.23.3 (node:22-alpine), 2026-08-09
FROM node@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34 AS lint
WORKDIR /app
COPY script/ script/
COPY package.json yarn.lock ./
RUN script/bootstrap
COPY . .
RUN yarn run eslint .
RUN yarn run prettier --check .
# Test phase, same shape and for the same reason. The suite runs without
# verbose output first and is rerun verbosely only if it fails; the timeout
# catches a hung test.
#
# node 22.22.0 on Alpine 3.23.3 (node:22-alpine), 2026-08-09
FROM node@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34 AS test
WORKDIR /app
COPY script/ script/
COPY package.json yarn.lock ./
RUN script/bootstrap
COPY . .
# Unlike the template, the suite runs as the image's non-root `node` user:
# root ignores directory permissions, so the tests of a destination that is
# not writable would otherwise fail. vitest writes into /app.
RUN chown -R node:node /app
USER node
RUN timeout 90 yarn run vitest run --reporter=dot || \
{ echo "--- Rerunning with verbose for details ---"; \
timeout 90 yarn run vitest run --reporter=verbose; exit 1; }
# Build stage, and the last stage: a plain `docker build .` names no target
# and so builds this one. Nothing is wanted from the two phases above; the
# copies are what make BuildKit build them first, so this image cannot be
# produced unless lint and test passed. A stage appended after this one
# would drop all three out of a plain build.
#
# node 22.22.0 on Alpine 3.23.3 (node:22-alpine), 2026-08-09
FROM node@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34
WORKDIR /app
COPY --from=lint /app/package.json /dev/null
COPY --from=test /app/package.json /dev/null
COPY script/ script/
COPY package.json yarn.lock ./
RUN script/bootstrap
COPY . .
# Version stamped into the build: the VERSION build arg when one is given,
# otherwise what script/version derives from the .git the build context
# carries (script/bootstrap installed git), so any `docker build .` of a
# clone stamps its commit. The label can only carry the build arg, and is
# empty without one.
ARG VERSION
LABEL org.opencontainers.image.version="${VERSION}"
RUN make build