ci: build (and conditionally push) bake targets to ghcr #35
No reviewers
Labels
No labels
bug
commercial
documentation
duplicate
enhancement
feature
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jasoncouture/llama-shears!35
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "ci/container-publish"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Container build pipeline. One workflow handles both pushes to
main/release/**(build + push) and PRs against the same bases (build only, no push). One shared composite action does the actual build so the trigger-specific logic doesn't drift.Bake targets are enumerated dynamically via
docker/bake-action/subaction/list-targets@v6, fanned out into a matrix — currently justllamashears, future services pick up with no workflow edit.What's in here
.github/actions/build-container/action.ymlComposite action; one bake target per invocation. Inputs:
target,tags(newline-separated full image refs),push("true"/"false"). Steps:docker/setup-buildx-action@v3.docker/login-action@v3toghcr.io— only whenpush == "true".docker buildx bake --set <target>.cache-from=type=gha --set <target>.cache-to=type=gha,mode=max --set <target>.tags=<tag>... [--push] <target>..github/workflows/container-publish.ymlTwo jobs:
prepare— checkout, setup-dotnet,list-targets@v6, installnbgvglobal tool, computeSemVer2(sanitised by replacing+with_so the OCI tag rules don't reject build metadata).build— matrix over targets. Per-job: compute the lowercased GHCR image refghcr.io/<owner>/<repo>/<service>, decide tag list (always version; onrelease/**push, add:latestif this version is the highest stable semver across existing GHCR tags + this build), invoke the localbuild-containeraction withpush: ${{ github.event_name == 'push' }}.Tag strategy (per spec)
+→_).main: pre-release, since NBGV'sversion.jsonproduces1.0-pre.<height>. No:latest.release/**: stable when NBGV is configured to treat the branch as public-release.:latestis added only when this build's version is the highest stable semver among the existing GHCR tags plus itself. First-ever publish qualifies."Latest" detection
Uses the GitHub API package endpoint —
/users/<owner>/packages/container/<repo>%2F<service>/versions— to enumerate existing tags, filters to stable semver (^[0-9]+\.[0-9]+\.[0-9]+$), takes the max, and tags:latestonly when this build's version is that max. 404 on first-ever run is swallowed and treats this build as the latest.Why the bake-action subaction (not a static matrix)
A static matrix would need a workflow edit every time a service is added or removed.
list-targetsreads the currentdocker-bake.hcl+compose.yamlso the build set tracks the source of truth.Caching
type=gha, mode=maxfor cache-to. Subsequent builds reuse layers across PRs and main runs at no manual cache management cost.Action-pinning policy
Per repo policy: floating major (
@v3,@v4,@v6).Test plan
docs-api-up-to-datepre-push check passed.docker buildx bake --printlocally returns{ target: { llamashears: {...} } }; matrix will receive["llamashears"].mainexercises the build-only path of the publish job;:latestcorrectness needs an actualrelease/**cut.Stacking note
Targets
ci/nuget-publish(PR #34). Will retargetmainautomatically as the chain merges.🤖 Generated with Claude Code
All committers have signed the CLA.
Pull request overview
Adds a unified GitHub Actions pipeline for container builds using Docker Bake, with conditional publishing to GHCR on
pushevents and build-only validation on PRs. This introduces a reusable composite action to keep build logic consistent while dynamically discovering bake targets.Changes:
.github/workflows/container-publish.ymlto build on PRs and build+push onmain/release/**, dynamically generating a matrix from Bake targets..github/actions/build-containercomposite action to build a single bake target with GHA cache wiring and optional registry push.:latesttagging onrelease/**pushes).Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
docker buildx bakewith cache and optional push/login.💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
docker buildx bake --set <target>.tags=...is being emitted once per tag. Buildx treats--setas an override for the field, so repeating it typically results in only the last tag being applied. Consider joining all tags into a single comma-separated value (or otherwise passing them in one--set) so all requested tags are applied consistently (e.g., version tag andlatest).@ -0,0 +1,76 @@name: Build/Push ContainersThe
existing=$(gh api ... | jq ... || true)pattern will treat any API failure (rate limit, 403, transient network, etc.) the same as a 404, which can incorrectly cause:latestto be added. It would be safer to only swallow the expected 404-for-first-publish case and fail (or retry) on other non-success responses solatestcan't be minted on an incomplete view of existing tags.@ -0,0 +13,4 @@permissions:contents: readThe workflow requests
packages: writeat the top level, but PR runs only need read access (and shouldn't be able to push). Consider defaulting to minimal permissions (e.g.,packages: read) and grantingpackages: writeonly for the push/build job that actually publishes, to reduce the blast radius if a PR workflow step is ever expanded.