Files
redefined-designs/Dockerfile
bermudalambandClaude Opus 5 a02214108a
Linting / lint (pull_request) Successful in 2m19s
SonarQube Analysis / sonarqube (pull_request) Successful in 25m44s
feat(build): pass the commit to the image as a build arg (#248)
The admin version stamp has reported commit "unknown" everywhere. #233 read it out of .git during the build and #235 removed that, because Portainer's build context has no repository history and the COPY failed every deploy — the version stamp became the thing that stopped deployments. #237 then established that building in Gitea Actions does not help: the Dockerfile no longer copies .git, so where the build runs is irrelevant.

So the builder hands the commit over rather than the build going to look for it. ARG GIT_COMMIT, empty by default, passed through to writeBuildInfo, which prefers it and still falls back to reading .git so a local build stamps itself with no argument needed.

An empty value is treated as absent rather than stamped. `--build-arg GIT_COMMIT=` is what an unset shell variable expands to, and a blank commit reads as one that happens to be empty rather than one nobody supplied.

Nothing regresses for Portainer. It cannot pass the argument, so its images keep saying "unknown" exactly as today, and they still deploy — the property #235 was bought with.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 17:39:24 -05:00

54 lines
2.6 KiB
Docker
Executable File

FROM node:20-bookworm-slim AS frontend-build
WORKDIR /app/frontend
COPY frontend/package.json ./
RUN npm install
COPY frontend/ ./
RUN npm run build
FROM node:20-bookworm-slim AS backend-build
WORKDIR /app/backend
COPY backend/package.json ./
RUN npm install
COPY backend/ ./
# There is deliberately no `COPY .git` here. It was tried in #233 and broke
# every Portainer deploy with `"/.git": not found` — Portainer's build context
# does not contain the repository history, whatever a local `docker build`
# suggests. That was the version stamp becoming the thing that stopped a
# deploy, which is the one outcome it must never be (#235).
#
# The consequence is that `commit` reads "unknown" in any environment Portainer
# builds. `builtAt` is still real, and is the half that matters most here:
# Portainer already reports which commit it cloned, but it cannot tell you
# whether the running container is actually that build. A build time can.
#
# writeBuildInfo runs against the compiled output, so it has to follow tsc, and
# it warns rather than fails when it finds no .git.
# Passed in rather than discovered. Whoever builds knows the commit; the build
# does not go looking for it, which is what broke every deploy when it did
# (#235) and what building in CI did not fix (#237). Empty by default, so a
# build that does not pass one behaves exactly as before — Portainer cannot
# supply it and still deploys, which is the property that must not regress.
#
# docker build --build-arg GIT_COMMIT="$(git rev-parse --short HEAD)" .
ARG GIT_COMMIT=
RUN GIT_COMMIT="$GIT_COMMIT" npm run build && GIT_COMMIT="$GIT_COMMIT" node dist/writeBuildInfo.js
FROM node:20-bookworm-slim
WORKDIR /app
COPY --from=backend-build /app/backend/package.json ./
RUN npm install --omit=dev
COPY --from=backend-build /app/backend/dist ./dist
COPY --from=backend-build /app/backend/migrate.js ./migrate.js
COPY --from=backend-build /app/backend/migrations ./migrations
COPY --from=frontend-build /app/frontend/dist ./public
ENV NODE_ENV=production
EXPOSE 3000
# Migrations run before the app serves, so deployed code can never be ahead of
# the database schema. Previously this was a separate, manual
# `docker exec ... node migrate.js up` that was easy to forget — and forgetting
# it meant every item query referenced tables that did not exist yet, which
# surfaced as an empty storefront rather than an error.
#
# `&&` matters: migrate.js exits non-zero on failure, so a bad migration stops
# the container instead of letting it serve against a half-migrated schema.
CMD ["sh", "-c", "node migrate.js up && node dist/server.js"]