ci: publish releases to GHCR via release-please on merge to main - #15
Conversation
Add a Release workflow that lets merging to main cut versioned releases and publish the container image to the GitHub Container Registry: - release-please (config + manifest) maintains a release PR from the Conventional-Commit history; merging it tags vX.Y.Z, writes CHANGELOG.md, and creates the GitHub Release. - A gated image job then builds the root Dockerfile and pushes ghcr.io/imariel2d/keepr tagged X.Y.Z / X.Y / latest, using the built-in GITHUB_TOKEN. The build is in the same workflow because a tag/release made with GITHUB_TOKEN does not trigger a second workflow. CI stays read-only; only this workflow holds packages/contents write. Manifest seeds at 0.0.0 so the first release proposes 0.1.0. Documented in the README "Releases & registry" section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
WalkthroughThe PR adds release-please automation for pushes to ChangesRelease automation
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant GitHubActions
participant release-please
participant DockerBuildx
participant GHCR
GitHubActions->>release-please: Process push to main
release-please-->>GitHubActions: Return release status and tag
GitHubActions->>DockerBuildx: Build the selected release-tagged image
DockerBuildx->>GHCR: Push exact and conditional semver tags
DockerBuildx->>GHCR: Publish provenance and SBOM metadata
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Around line 32-36: Review the release-please action configuration identified
by id “rp” and verify that release PRs trigger all required CI and
branch-protection checks. If the default GITHUB_TOKEN prevents those workflows
from running automatically, configure the action to use the repository’s
approved GitHub App or PAT credential instead, preserving the existing
release-please config and manifest settings.
- Around line 13-17: Scope permissions per job in the release workflow: grant
the release-please job contents: write, issues: write, and pull-requests: write,
while limiting the image job to contents: read and packages: write. Remove the
shared top-level write permissions and ensure repository settings allow GitHub
Actions to create and approve pull requests.
- Around line 45-47: Update the image job’s actions/checkout@v4 step to set
persist-credentials to false, and restrict that job’s permissions to contents:
read and packages: write only. Remove the unrelated contents: write and
pull-requests: write grants while preserving the existing tag ref checkout.
- Around line 28-41: Make the image job in the release workflow runnable when
republishing an existing release, not only when release-please reports a newly
created release. Add a durable manual-dispatch path accepting an explicit
release tag, and use that tag for image publication while preserving the current
automatic release-created flow; verify both rerunning all jobs and manually
dispatching with an existing tag.
In `@README.md`:
- Around line 129-132: Update the README deployment guidance around the App
Platform and GHCR image description: replace “immutable artifact” with
“versioned artifact,” and document that exact deployments must pin the image by
digest rather than using a mutable tag such as latest or X.Y.
In `@release-please-config.json`:
- Around line 1-12: Update the release-please package configuration to set
include-component-in-tag to false, preserving the existing package-name and
release settings so generated tags use plain semver rather than the
keepr-prefixed format.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: db8b2688-484d-4ccd-95d0-d17b45e887fd
📒 Files selected for processing (4)
.github/workflows/release.yml.release-please-manifest.jsonREADME.mdrelease-please-config.json
- release-please-config.json: set include-component-in-tag=false so tags are plain vX.Y.Z, not keepr-vX.Y.Z. The prefixed form fails docker/metadata-action semver parsing, which would drop the versioned image tags and publish only :latest. - release.yml: scope permissions per job (read-only floor; release-please gets contents/issues/pull-requests write, image gets only packages:write) and add issues:write for release-please label/issue management. - release.yml: set persist-credentials:false on the image job's checkout — it only builds/pushes to GHCR, never runs git, so GITHUB_TOKEN needn't persist. - release.yml: add a workflow_dispatch recovery path with an explicit tag input so a failed image push after the release was already tagged can be re-run without release-please reporting a new release. - README: describe the GHCR image as a versioned (not immutable) artifact and document digest pinning for exact deploys; correct the permissions note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The image is public on GHCR, so tighten what ships and how it's verified: - Add .dockerignore that excludes appsettings.Development.json from the production build context (verified: it's gone from the image while appsettings.json and wwwroot still ship). Also keeps host bin/obj/node_modules and local .env files out of the context. The dev compose builds from ./src/Api, so local development is unaffected. - .do/app.yaml: pin ASPNETCORE_ENVIRONMENT=Production so the app can never load the dev admin / MinIO defaults, even if the file were present. - release.yml: attach SLSA provenance + an SBOM to the pushed image so consumers can verify the build and pin by digest. - README: document the public-image hardening. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Around line 56-68: Update the release image publishing flow around RELEASE_TAG
and docker/metadata-action to query the GitHub Releases API for the newest
stable X.Y.Z release before generating Docker metadata. Always publish the exact
RELEASE_TAG during manual recovery, but only enable the mutable X.Y and latest
tags when RELEASE_TAG matches the newest stable release; preserve the existing
release-please and workflow_dispatch trigger behavior.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f416938c-cee0-425d-9b61-d76027463d73
📒 Files selected for processing (5)
.do/app.yaml.dockerignore.github/workflows/release.ymlREADME.mdrelease-please-config.json
The workflow_dispatch recovery path can rebuild any existing tag, but the image job published latest and X.Y unconditionally — so re-publishing an OLD release would drag those mutable tags back to older bytes. Gate latest and X.Y on "is this the newest stable release?" (GET /releases/latest, which excludes drafts and pre-releases); the exact X.Y.Z tag is always published. The automatic release-please path short-circuits to true since the tag it just cut is by definition the newest, so normal releases are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Adds a release pipeline so merging to
maincan cut versioned releases and publish the container image to the GitHub Container Registry (GHCR).The flow
mainas usual.feat:→ minor,fix:→ patch).vX.Y.Z, updatesCHANGELOG.md, and creates the GitHub Release.Dockerfileand pushesghcr.io/imariel2d/keeprtaggedX.Y.Z,X.Y, andlatest.The image build lives in the same workflow as release-please because a tag/release created with the built-in
GITHUB_TOKENdoes not trigger a second workflow.Files
.github/workflows/release.yml— release-please job → gated GHCR image build (buildx + GHA cache).release-please-config.json+.release-please-manifest.json— single root package,simpletype, seeded at0.0.0so the first release proposes0.1.0.README.md— new "Releases & registry" section.Security / scope
GITHUB_TOKEN— no PAT to manage.ci.yml) stays read-only; only this workflow holdspackages: write/contents: write.Before it fully works (post-merge, one-time)
docker pull..do/app.yaml); GHCR is a parallel immutable artifact (useful for the VPS/Droplet path). Optional: point App Platform at animage:source to deploy the exact released image.unit+e2echecks somainis green before a release is cut.🤖 Generated with Claude Code
Summary by CodeRabbit
latesttags.