ci(release): harden release publishing#273
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
📝 WalkthroughWalkthroughRelease workflow restructured: Changes
Sequence Diagram(s)sequenceDiagram
participant GH as "GitHub Actions"
participant DockerJob as "docker job\n(buildx push by digest)"
participant Registry as "Container Registry"
participant Promote as "docker-promote job"
participant GoReleaser as "goreleaser job"
GH->>DockerJob: start release workflow
DockerJob->>Registry: build & push multi-arch image (by digest)
Registry-->>DockerJob: return image digest
DockerJob-->>GH: set job output `digest`
GH->>GoReleaser: run after docker/promote (job-level `contents: write`)
GoReleaser->>GH: publish GitHub release
GH->>Promote: compute tags (semver / latest) and validate digest
Promote->>Registry: `docker buildx imagetools create` (promote digest -> tags)
Registry-->>Promote: confirm tag promotion
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR hardens the release pipeline by (1) gating the GitHub release on a successful Docker image build/push rather than running them in parallel, (2) narrowing the workflow-level permission to Confidence Score: 5/5Safe to merge — changes are purely additive CI hardening with no logic regressions. All changes are correct: job ordering, permission scoping, concurrency guard, and .gitignore cleanup are all well-formed and achieve the stated goals. No P0 or P1 findings. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant GH as GitHub (tag push)
participant D as docker job
participant DHR as Docker Hub
participant GR as goreleaser job
participant GHR as GitHub Releases
GH->>D: trigger on v* tag
D->>DHR: build & push image (amd64/arm64/arm)
DHR-->>D: success
D-->>GR: needs: docker (gate)
GR->>GHR: goreleaser release --clean
GHR-->>GR: release published
Reviews (1): Last reviewed commit: "ci(release): harden release publishing" | Re-trigger Greptile |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)
72-98:⚠️ Potential issue | 🟠 MajorOrphan Docker image risk if
goreleaserfails after a successful Docker push.With
goreleasernowneeds: docker, the Docker image is pushed to Docker Hub (including the unconditionaltype=raw,value=latesttag set in thedockerjob) before the GitHub release is created. If GoReleaser fails for any reason (rate limits, transient network errors, GoReleaser config issues, missingid-token/packagesperms for sbom/sign steps later, etc.), you’ll be left with a published image — including:latest— without a corresponding GitHub release, which contradicts the new docs guarantee that "GitHub releases are published only after the Docker image build and push succeed."Consider one of:
- Move the
:latesttag promotion into thegoreleaserjob (or a third post-release job), so:latestis only updated once both succeed.- Add a third
needs: [docker, goreleaser]cleanup/promotion job, or afailure()-conditional rollback step that retags/deletes the just-pushed tags on Docker Hub whengoreleaserfails.- At minimum, document this partial-failure mode in
docs/DEVELOPMENT.mdso operators know to manually reconcile.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/release.yml around lines 72 - 98, The goreleaser job can fail after the docker job has pushed images (including the unconditional latest tag), leading to orphaned Docker images; update the workflow so tag promotion or deletion happens only after goreleaser succeeds by either moving the ":latest" promotion into the goreleaser job or adding a new job that needs: [docker, goreleaser] to perform promotion/cleanup (or add a failure()-conditional rollback step) — modify the existing goreleaser job (name: Publish GitHub release / uses: goreleaser/goreleaser-action@v7) or add a new job that runs post-release to retag/delete the just-pushed Docker tags, and/or document the partial-failure behavior in docs/DEVELOPMENT.md so operators can reconcile manually.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In @.github/workflows/release.yml:
- Around line 72-98: The goreleaser job can fail after the docker job has pushed
images (including the unconditional latest tag), leading to orphaned Docker
images; update the workflow so tag promotion or deletion happens only after
goreleaser succeeds by either moving the ":latest" promotion into the goreleaser
job or adding a new job that needs: [docker, goreleaser] to perform
promotion/cleanup (or add a failure()-conditional rollback step) — modify the
existing goreleaser job (name: Publish GitHub release / uses:
goreleaser/goreleaser-action@v7) or add a new job that runs post-release to
retag/delete the just-pushed Docker tags, and/or document the partial-failure
behavior in docs/DEVELOPMENT.md so operators can reconcile manually.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 509a558f-1521-4eab-b276-733b2cee32c7
⛔ Files ignored due to path filters (2)
tests/integration/.cache/.gitkeepis excluded by!**/.cache/**tests/integration/.cache/models.jsonis excluded by!**/.cache/**
📒 Files selected for processing (3)
.github/workflows/release.yml.gitignoredocs/DEVELOPMENT.md
eeb9bf0 to
bdfdecf
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/release.yml:
- Around line 101-106: The workflow currently runs jobs in order docker →
goreleaser → docker-promote which can publish a GitHub release before Docker
tags are promoted; reorder job dependencies so docker-promote runs immediately
after docker and before goreleaser: update the docker-promote job's needs to
only include docker (remove goreleaser) and make goreleaser depend on
docker-promote (add docker-promote to goreleaser's needs), ensuring the sequence
becomes docker → docker-promote → goreleaser so tags are promoted before the
release is published.
- Around line 130-134: The raw `latest` tag rule (type=raw,value=latest)
currently applies to prerelease tags too; update that entry to include an enable
guard so it only runs for non-prereleases (i.e., when attributes.prerelease is
false). Locate the tags block and modify the type=raw,value=latest line to add
an enable condition such as using the docker/metadata-action prerelease
attribute (e.g., enable: ${{ !attributes.prerelease }} or enable: ${{
attributes.prerelease == false }}) so `latest` is not assigned for prerelease
tags.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4cb4c74c-0bbb-4dd0-a9fd-8e98789d43b5
⛔ Files ignored due to path filters (2)
tests/integration/.cache/.gitkeepis excluded by!**/.cache/**tests/integration/.cache/models.jsonis excluded by!**/.cache/**
📒 Files selected for processing (3)
.github/workflows/release.yml.gitignoredocs/DEVELOPMENT.md
bdfdecf to
6d83cb8
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/release.yml:
- Around line 53-72: The meta step (id: meta, uses: docker/metadata-action@v6)
is computing tags that are never used by the build step (id: build, uses:
docker/build-push-action@v7); to stop generating unused tags add an explicit
empty/disabled tags input to the meta step (e.g. tags: '' or tags: | followed by
no entries) so the action only emits labels (steps.meta.outputs.labels) and
avoids producing a default :latest tag on pushes. Update the meta step inputs
accordingly and keep the build step using steps.meta.outputs.labels as before.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8c031ec8-b56a-45e7-be8b-dd4adb2fdbc1
⛔ Files ignored due to path filters (2)
tests/integration/.cache/.gitkeepis excluded by!**/.cache/**tests/integration/.cache/models.jsonis excluded by!**/.cache/**
📒 Files selected for processing (3)
.github/workflows/release.yml.gitignoredocs/DEVELOPMENT.md
| - name: Extract Docker labels | ||
| id: meta | ||
| uses: docker/metadata-action@v6 | ||
| with: | ||
| images: ${{ steps.build_meta.outputs.image }} | ||
|
|
||
| - name: Build and push by digest | ||
| id: build | ||
| uses: docker/build-push-action@v7 | ||
| with: | ||
| context: . | ||
| platforms: linux/amd64,linux/arm64,linux/arm/v7 | ||
| push: true | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| outputs: type=image,name=${{ steps.build_meta.outputs.image }},push-by-digest=true,name-canonical=true,push=true | ||
| build-args: | | ||
| VERSION=${{ steps.build_meta.outputs.version }} | ||
| COMMIT=${{ steps.build_meta.outputs.commit }} | ||
| DATE=${{ steps.build_meta.outputs.date }} | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Optional: meta step computes tags that are never used.
In the digest-only build, build-push-action doesn't consume steps.meta.outputs.tags (the outputs: line uses push-by-digest=true, and no tags: input is set). Only labels are consumed downstream. This is harmless but generates noise in the action output and a default :latest tag in the computed (unused) tag set on tag pushes. If you want to keep the step purely for labels, you can suppress tag generation explicitly:
♻️ Optional cleanup
- name: Extract Docker labels
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ steps.build_meta.outputs.image }}
+ tags: |
+ type=sha,enable=false
+ flavor: |
+ latest=false📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Extract Docker labels | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ steps.build_meta.outputs.image }} | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64,linux/arm/v7 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| outputs: type=image,name=${{ steps.build_meta.outputs.image }},push-by-digest=true,name-canonical=true,push=true | |
| build-args: | | |
| VERSION=${{ steps.build_meta.outputs.version }} | |
| COMMIT=${{ steps.build_meta.outputs.commit }} | |
| DATE=${{ steps.build_meta.outputs.date }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Extract Docker labels | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ steps.build_meta.outputs.image }} | |
| tags: | | |
| type=sha,enable=false | |
| flavor: | | |
| latest=false | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64,linux/arm/v7 | |
| labels: ${{ steps.meta.outputs.labels }} | |
| outputs: type=image,name=${{ steps.build_meta.outputs.image }},push-by-digest=true,name-canonical=true,push=true | |
| build-args: | | |
| VERSION=${{ steps.build_meta.outputs.version }} | |
| COMMIT=${{ steps.build_meta.outputs.commit }} | |
| DATE=${{ steps.build_meta.outputs.date }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/release.yml around lines 53 - 72, The meta step (id: meta,
uses: docker/metadata-action@v6) is computing tags that are never used by the
build step (id: build, uses: docker/build-push-action@v7); to stop generating
unused tags add an explicit empty/disabled tags input to the meta step (e.g.
tags: '' or tags: | followed by no entries) so the action only emits labels
(steps.meta.outputs.labels) and avoids producing a default :latest tag on
pushes. Update the meta step inputs accordingly and keep the build step using
steps.meta.outputs.labels as before.
Summary
Validation
Summary by CodeRabbit
Documentation
Chores