5402: Switch image build pipeline to GHCR - #410
Merged
turegjorup merged 7 commits intoApr 29, 2026
Merged
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Consolidate the develop and tag DockerHub workflows into a single multi-arch build that pushes to ghcr.io/os2display/*, authenticated via GITHUB_TOKEN. Provide repository-root as a named build context so the Dockerfiles' COPY --from=repository-root steps resolve. Add per-image GHA cache (mode=max) so multi-arch builds reuse builder stages across runs instead of re-running npm ci + composer install per platform. Align infrastructure/build-n-push.sh with the workflow: drop the turegjorup namespace, single-pass docker buildx --push for multi-arch manifests, and add a BUILD_LOAD=1 flag for local builds that load into the host docker daemon instead of pushing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The nginx Dockerfile had:
COPY --from=api_app_builder ... ./public
RUN chmod -R g+w /var/www/html
The RUN re-wrote every file's permissions, producing a second 19 MB
layer with byte-identical content. Replacing with --chmod on the COPY
itself drops the duplicate layer; image goes from 135 MB to 108 MB,
dive efficiency from 78.7% to 99.5%.
Apply the same pattern to docker-entrypoint.sh in the API Dockerfile
for consistency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The API Dockerfile does a wholesale 'COPY --from=repository-root ./' that brings in everything not excluded. Without these additions, editing a docker-compose.yml, Taskfile.yml, or any quality-tool config (phpstan, psalm, rector, playwright) invalidated the cache from that COPY onward. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RC images are now produced by tagging on a release branch (e.g. tag
'3.0.0-RC1' on release/3.0.0), not by every push to release/*. This
keeps RC builds explicit and reviewable instead of running on every
push to a release branch.
Add 'flavor: latest=auto' so non-prerelease semver tags ('3.0.0') also
update ':latest', while pre-release semver tags ('3.0.0-RC1') do not.
This is the metadata-action default but is set explicitly with a
comment so the behavior is obvious.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…r-mono-repo' into feature/5402-build-pipeline-ghcr # Conflicts: # CHANGELOG.md
…r-mono-repo' into feature/5402-build-pipeline-ghcr # Conflicts: # CHANGELOG.md
turegjorup
merged commit Apr 29, 2026
795d70c
into
feature/update-infrastructure-for-mono-repo
18 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
docker_build_images_from_develop.ymlanddocker_build_images_from_tag.yml) into a singlebuild-images.ymlthat pushes toghcr.io/os2display/*. Authenticates with the built-inGITHUB_TOKEN— no DockerHub secrets to manage.APP_VERSIONbuild-arg is sourced fromdocker/metadata-action's computedversion, so it always matches the image tag (norefs/tags/3.0.0leakage).mode=max, scoped per image) so multi-arch builds reuseclient_app_builderandapi_app_builderstages instead of re-runningnpm ci+composer installper platform per run.infrastructure/build-n-push.shwith the workflow (single-passbuildx --push, GHCR), and adds aBUILD_LOAD=1flag for local builds that load into the host docker daemon.chmodininfrastructure/nginx/Dockerfileinto the COPY itself, eliminating a duplicate-content layer. Nginx image: 135 MB → 108 MB (efficiency 78.7% → 99.5% perdive)..dockerignoreso editing dev-tooling configs (compose files, Taskfile, phpstan/psalm/rector, Playwright config, IDE state, broader.docker/) no longer invalidates the image build cache.actions/checkout@v6,actions/upload-artifact@v7,go-task/setup-task@v2, alldocker/*actions to their current majors).Resulting trigger semantics
develop:develop3.0.0-RC1(RC, on a release branch):3.0.0-RC1(no:latestupdate)3.0.0(final release):3.0.0,:latestflavor: latest=autoondocker/metadata-actionis what makes:latesttrack non-prerelease semver tags only. RC tags follow normal semver pre-release conventions and are excluded automatically.Bugs fixed in passing
The two deleted workflows had several issues that the new file does not inherit:
platforms:, so production tag images were silently amd64-only.${{ github.ref }}(refs/tags/3.0.0) intoAPP_VERSION. Now usessteps.meta-*.outputs.version(3.0.0).echo ::set-outputsyntax.docker/build-push-action@v5while develop pinned@v6. Now uniform on@v7.build-contexts: repository-root=., which the Dockerfiles'COPY --from=repository-rootsteps require.Local validation
BUILD_LOAD=1 infrastructure/build-n-push.shproduces working API + Nginx images (single-arch native).dive --cion both images: 99.32% (API) and 99.46% (Nginx) efficiency.--cache-from/--cache-to type=local,mode=maxround-trip: cold 41 s → warm 17 s (-59%); after a real PHP source change, 21.5 s withnpm ci,npm run build, and the initialcomposer install --no-scriptsall cache-hit.Test plan
developand producesghcr.io/os2display/display-api-service:developand…-nginx:develop(multi-arch manifest).3.0.0-RC1(cut from a release branch), confirm:3.0.0-RC1is produced and:latestis not updated.3.0.0, confirm:3.0.0is produced and:latestis updated.actions/upload-artifact@v7inplaywright.yamlstill uploads the report on a Playwright run (no matrix, single artifact name → no immutability conflict expected).Commits
5402: Bump GitHub Actions to current major versions5402: Switch image build pipeline to GHCR5402: Fold chmod into COPY to drop duplicate image layers5402: Expand .dockerignore for build-cache stability5402: Make RC builds tag-only and adopt rolling latest tag🤖 Generated with Claude Code