# Lint phase. The linter is 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. # # In every stage, ARG CACHEBUST comes right after the step that installs # system packages. script/ passes a new value on every build. That value # reruns every RUN step below the ARG line, and the install step keeps # its layer. node and yarn come from the distribution, which is trusted, # so they need no version and no hash. # # alpine 3.24.3, 2026-11-04 FROM alpine@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a AS lint RUN apk add --no-cache git make nodejs yarn ARG CACHEBUST WORKDIR /app COPY script/ script/ COPY package.json yarn.lock ./ RUN script/bootstrap COPY . . RUN yarn run prettier --check '**/*.md' --tab-width 4 --prose-wrap always # Test phase, same shape and for the same reason. # # alpine 3.24.3, 2026-11-04 FROM alpine@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a AS test RUN apk add --no-cache git make nodejs yarn ARG CACHEBUST WORKDIR /app COPY script/ script/ COPY package.json yarn.lock ./ RUN script/bootstrap COPY . . RUN echo "No tests defined." # Development environment, 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. # # alpine 3.24.3, 2026-11-04 FROM alpine@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a RUN apk add --no-cache git make nodejs yarn ARG CACHEBUST WORKDIR /app COPY --from=lint /app/package.json /dev/null COPY --from=test /app/package.json /dev/null # script/bootstrap finds the system packages above and installs the node # packages. COPY script/ script/ COPY package.json yarn.lock ./ RUN script/bootstrap COPY . . # Nothing here is compiled and a LABEL cannot run git, so the version is # the VERSION build argument that script/docker and script/cibuild pass; # a plain `docker build .` leaves it empty. ARG VERSION LABEL org.opencontainers.image.version="${VERSION}"