Root cause of remaining cache misses: the base stage declared
ARG VERSION, and the build job passed VERSION=${{ github.sha }}.
Since VERSION changes every commit, every base/app layer cache key
changed with it — so layers rebuilt every run regardless of scope.
Additionally the test job passed no build-args while the build job
passed GITHUB_BUILD=true + VERSION, so test's cached base/app layers
had different keys from build's — cross-job reuse never hit either.
Fix:
- Dockerfile: move ARG VERSION / ENV VERSION from base to the final
runtime stage (FROM app). VERSION is only read at runtime by
src.consts via Pydantic settings; base/app layers don't use it.
base/app now cache without per-commit VERSION variation.
- workflow: pass --build-arg GITHUB_BUILD=true in the test step so
test and build share identical base/app cache keys (cross-job reuse).
VERSION is intentionally NOT passed to the test job: the test stage
(FROM app AS test) doesn't read VERSION, and omitting it keeps the
base/app cache keys identical between test and build.
push: branches: ["*"] matched feature branches, so every push to a
branch with an open PR fired both a 'push' and a 'pull_request' event.
Their concurrency groups differ (refs/heads/<branch> vs refs/pull/<n>/merge),
so cancel-in-progress could not dedup them — the full multi-arch build
ran twice on each push, doubling CI minutes.
Scope push to branches: ["main"]; pull_request remains the validator for
feature branches. Tag pushes (v*.*.*), schedule, and workflow_dispatch
are under separate filters and are unaffected.
- test job: scope x64 -> amd64 to match build matrix amd64 leg
- build job: scope ${{ matrix.platform }} -> ${{ steps.vars.outputs.SURFIX }}
(yields amd64/arm64), avoiding the gha backend's / path-separator
bug that mangled scope=linux/arm64 and broke arm64 cache reuse
test (amd64) and build-amd64 now share scope=amd64 so build reuses
the app/base layers the test job cached earlier in the same run.
build-arm64 gets a working scope=arm64 that persists across runs.
metadata-action emits tags newline-separated, so FIRST_TAG=${TAGS%% *}
kept the entire multi-line value and expanded to 4 args on tag releases,
making `imagetools inspect` fail before the manifest could be signed.
Split on the first line instead.
* Skip build and review for Renovate PRs, only run tests
Modified CI workflows to optimize Renovate PRs:
- Skip Docker build and merge-and-push jobs for Renovate PRs
- Skip Claude code review for Renovate PRs
- Tests still run for all PRs including Renovate
This reduces CI time and resource usage for dependency update PRs.
* Remove redundant condition from merge-and-push job
The merge-and-push job depends on build job, so it won't run if build is skipped.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: Build Docker images for PRs with branch name labels
- Remove condition preventing PR builds
- Add branch name extraction and sanitization
- Add branch labels to Docker images (org.opencontainers.image.branch and branch)
- Enable pushing of PR Docker images
- Sanitize branch names for Docker tags (replace / with -)
This allows PR images to be built and tagged with their branch names,
making it easier to test specific PR builds.
* feat: Add path filters to Docker workflow
Only build Docker images when relevant files change:
- Source code (src/**, main.py, tests/**)
- Docker configuration (Dockerfile, compose.yaml)
- Dependencies (pyproject.toml, uv.lock)
- Workflow file itself
This prevents unnecessary builds when only documentation or
other non-functional files are changed.
* feat: Add automatic cleanup of PR Docker images
Create a new workflow that automatically deletes Docker images
when a PR is closed or merged. This prevents accumulation of
old PR images in the container registry.
Features:
- Triggers on PR close/merge events
- Deletes images tagged with PR number and SHA
- Handles both architecture variants (amd64, arm64)
- Supports both organization and user repositories
- Provides detailed logging of cleanup operations
* refactor: Remove redundant branch label preparation
Remove duplicate branch name preparation step in merge-and-push job.
Branch labels are already added during the build step, so no need
to add them again when creating the manifest.
* refactor: Remove redundant label configurations
Remove custom label configurations from docker-publish workflow.
The docker/metadata-action already sets standard OCI labels by
default, so explicit label configuration is unnecessary.
Also removed unused BRANCH_TAG variable preparation.
* refactor: Use PR number for Docker image tags instead of SHA
Changed Docker image tagging strategy for pull requests:
- Use pr-{number}-{arch} for individual platform builds
- Use pr-{number} for final manifest
- Non-PR builds still use SHA-based tags
Benefits:
- Simpler, more readable tags for PRs
- Easier to identify which PR an image belongs to
- Cleanup script simplified to match only PR number tags
Updated cleanup workflow to match new tag pattern.
* docs: Add PR Docker image tags to README
Document the pr-{number} tag pattern used for pull request images.
These images are automatically built for PRs and cleaned up when
the PR is closed.
---------
Co-authored-by: Claude <noreply@anthropic.com>