Repository navigation
chore(ci): create the GitHub Release from the release workflow - #455
Conversation
release.yml only published to Maven Central, and the GitHub Release had to be created by hand. That step was missed for v0.0.22. Add a final step that creates it with gh after a successful deploy: title is the tag, notes are generated, and it is marked latest, matching earlier releases. It skips if the release already exists. Document the automatic step and a manual fallback in AGENTS.md and the README. Co-authored-by: Claude Opus 5.5 <[email protected]> Signed-off-by: Marc Nuri <[email protected]>
manusa
left a comment
There was a problem hiding this comment.
Pull Request Review: #455
State: OPEN, not a draft, merge state UNKNOWN (not yet computed), head c2246b1
Summary
Adds a final Create GitHub Release step to .github/workflows/release.yml. After make maven-deploy succeeds, the step runs gh release create "$GITHUB_REF_NAME" --verify-tag --title "$GITHUB_REF_NAME" --generate-notes --latest, and skips if a release for the tag already exists. The job gets permissions: contents: write. AGENTS.md (Releasing step 4 and the CI line) and README.md ("Create GitHub Release") now describe the automatic step and a manual fallback.
Linked Issues and Tickets
None referenced, so spec compliance was checked against the description only. The diff does everything the description claims, and nothing else:
- The step runs after Maven Release (
.github/workflows/release.yml:45-54), so it only runs when the deploy succeeded. - The tag comes from the
GITHUB_REF_NAMEenv var, not${{ }}interpolation (release.yml:47-50). GH_TOKENandGH_REPOare set (release.yml:52-54).- The job-level
contents: writeis atrelease.yml:15-16. - The description says the token was read-only before. Confirmed:
gh api repos/manusa/helm-java/actions/permissions/workflowreturns"default_workflow_permissions":"read", so without this blockgh release createwould get a 403. gh release listshows v0.0.22 exists (Latest), so the next run's--generate-notescompares against v0.0.22 as intended.
Review Verdict
COMMENT
Findings
Critical Issues (Must Fix)
None.
Important Issues (Should Fix)
-
Put the release in its own job instead of raising the build job's token to
contents: write(.github/workflows/release.yml:15-16,:45-54). Only the last step needs write, but job-levelpermissionsapplies to every step. Two consequences:- Least privilege.
actions/checkoutpersists the job token for later git calls by default (persist-credentials: true).make build-allandmake maven-deploythen run third-party code with a token that can now push to the repo: Go modules, the xgo containers, Maven plugins. Before this PR that token was read-only. - Re-runs. "Re-run failed jobs" re-runs the whole job. That's why
AGENTS.mdstep 4 has to warn "Don't re-run the whole job just to get the release: that would also redeploy to Maven Central". With a separate job (needs: release,permissions: contents: write, just theghstep, no checkout needed sinceGH_REPOis set and--verify-tagchecks the remote tag), a failed release step re-runs on its own without touching Central. Thereleasejob can then drop tocontents: read(or keep no block and inherit the repo's read default). This also makes the existence check at:47the real re-run guard it's meant to be, and the doc caveat becomes optional.
If you keep a single job, consider
persist-credentials: falseon the checkout at:18-19at least. Nothing after checkout runs git:build/release.mk:4-5is justmvn -Prelease clean deploy. - Least privilege.
Minor Comments (Nice to Have)
- The README fallback covers less than AGENTS.md (
README.md:891-892vsAGENTS.mdReleasing step 4). The README fallback only covers "if that step fails". It leaves out the "deploy was finished by hand" case, thegh release create ... --generate-notes --latestone-liner, and the warning not to re-run the whole job (which would redeploy to Central). A short note in the README would keep the two in step. This goes away if finding 1 is adopted. gh release view ... > /dev/null 2>&1(release.yml:47) treats any failure (auth, network) as "no release" and falls through tocreate. That's acceptable:createthen fails loudly with the real error. Not worth changing, noted only so the behaviour is intentional.
Security Concerns
- Good: the tag reaches the script via
$GITHUB_REF_NAMEenv, quoted, not${{ github.ref_name }}insiderun:, so there's no expression injection (release.yml:47-50). - The elevated token's scope is the one concern (Important #1).
Testing Assessment
release.yml only runs on v* tag pushes (release.yml:3-6), so PR CI can't exercise it. The next release is the first real run. I didn't run anything: diff-reading review only. The PR is your own and touches CI config and AGENTS.md, so per policy I didn't build it, and a build doesn't exercise the workflow anyway. The step's logic is straightforward, and its gh flags match the documented gh release create options (--verify-tag, --title, --generate-notes, --latest).
Overall Assessment
A small, well-motivated change that closes a real gap (the missed v0.0.22 release), with correct injection-safe scripting and docs that match the workflow. My main suggestion is structural: move the step into its own job so the build doesn't get a write token and a failed release re-runs on its own. Mergeable as-is if you accept the wider token scope.
| name: Release | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # gh release create |
There was a problem hiding this comment.
Important: this raises the token for every step in the job. actions/checkout persists it by default, so make build-all and make maven-deploy, which run third-party Go modules, xgo containers and Maven plugins, now hold a token that can push. The repo default is read (default_workflow_permissions: read).
Suggestion: move the release step to its own job:
github-release:
name: GitHub Release
needs: release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Create GitHub Release
run: |
...
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}The release job then needs no write block. As a bonus, "Re-run failed jobs" re-runs only this job and never redeploys to Central.
|
|
||
| Once the release is published to Maven Central, create a new [GitHub release](https://github.com/manusa/helm-java/releases/new) for the released tag. | ||
| The `Release to Maven Central` workflow creates the GitHub release for the pushed tag, with generated release notes, after the Maven Central deployment succeeds. | ||
| If that step fails, create a new [GitHub release](https://github.com/manusa/helm-java/releases/new) for the released tag manually and use "Generate release notes". |
There was a problem hiding this comment.
Minor: the fallback here only covers "if that step fails". AGENTS.md step 4 also covers the deploy being finished by hand, gives the gh release create v0.0.X --verify-tag --title v0.0.X --generate-notes --latest one-liner, and warns not to re-run the whole job (it would redeploy to Central). A short mention here would keep the two docs in step, unless the release moves to its own job, which makes the re-run warning moot.
Raising the release job to contents: write gave that write token to every step, including the third-party build and deploy code run by make build-all and make maven-deploy, through the credentials checkout persists. Move the release creation into its own github-release job (needs: release) that alone gets contents: write, and pin the build job to contents: read. A failed GitHub Release can now be retried with "Re-run failed jobs" without redeploying to Maven Central, so update AGENTS.md and the README to match. Co-authored-by: Claude Opus 5.5 <[email protected]> Signed-off-by: Marc Nuri <[email protected]>
manusa
left a comment
There was a problem hiding this comment.
Pull Request Review: #455 (re-review)
State: OPEN, not a draft, merge state CLEAN, head 5946803
This re-reviews the full current diff at 5946803. The previous review was at c2246b1.
Summary
The release now runs as two jobs in .github/workflows/release.yml:
release(build and Maven Central deploy) is pinned tocontents: read.- A new
github-releasejob (needs: release,contents: write, no checkout) runsgh release create "$GITHUB_REF_NAME" --verify-tag --title "$GITHUB_REF_NAME" --generate-notes --latest. It skips if the release already exists.
AGENTS.md (CI line, Releasing step 4) and README.md ("Create GitHub Release") describe the job, the "Re-run failed jobs" retry, and a manual fallback.
Earlier findings: status at 5946803
| # | Earlier finding | Status | Evidence |
|---|---|---|---|
| Important 1 | Separate job / token scope | Resolved | See below. |
| Minor 1 | README fallback narrower than AGENTS.md | Resolved | README.md:891-897 now matches AGENTS.md:78. |
| Minor 2 | gh release view swallows every error |
Unchanged, as intended | release.yml:54. No change was requested. |
Important 1, separate job / token scope: resolved.
- Write is scoped to one job.
contents: writeis now only ongithub-release(release.yml:49-50). The build/deploy job is explicitlycontents: read(release.yml:15-16), so the token persisted byactions/checkout(release.yml:18-19) is read-only again. That matches the repo default, re-checked now:gh api repos/manusa/helm-java/actions/permissions/workflowreturns"default_workflow_permissions":"read". - Re-runs no longer touch Central. The release is its own job (
release.yml:45-61) withneeds: release(release.yml:47). "Re-run failed jobs" retries a failedgithub-releaseon its own, without redeploying to Central. - The doc caveat is gone. The old "don't re-run the whole job" warning was replaced by the retry guidance (
AGENTS.md:78,README.md:892).
Minor 1, README vs AGENTS.md fallback: resolved. README.md:891-897 and AGENTS.md:78 now cover the same things:
- the automatic job;
- the skip when the release already exists;
- the "Re-run failed jobs" retry, with the note that it doesn't redeploy to Central;
- the fallback when the re-run fails too or the deploy was finished by hand;
- the
gh release create ... --verify-tag --title ... --generate-notes --latestone-liner.
The README writes it as vX.Y.Z (README.md:896), matching the README's own vX.Y.Z convention in the section above. AGENTS.md uses v0.0.X.
Minor 2, gh release view error handling: unchanged, as intended. The check is the same at release.yml:54. The earlier note said it needed no change: a non-404 failure (auth, network) falls through to gh release create (release.yml:57), which then fails loudly with the real error. Nothing to do.
What the restructure introduced
I checked the new structure and found nothing new to fix:
- Job dependency.
needs: release(release.yml:47) meansgithub-releaseonly runs after the wholereleasejob succeeds, includingmake maven-deploy(release.yml:39-44). Ifreleasefails,github-releaseis skipped. Re-running the failedreleasejob also re-runs its dependentgithub-release, which is the right order. - Permissions on both jobs.
release(release.yml:15-16): job-levelpermissionssets every unlisted scope tonone, so it getscontents: readand nothing else. Its steps need nothing more: checkout reads contents, the setup-go/setup-java caches use the runtime cache token rather thanGITHUB_TOKENscopes, and the deploy authenticates with the Central secrets.github-release(release.yml:49-50):gh release createneeds onlycontents: write.
- No-checkout job.
ghdoesn't need a local git repo here:GH_REPO(release.yml:61) names the repository, andGH_TOKENisgithub.token(release.yml:60).--verify-tag(release.yml:57) aborts if the tag isn't on the remote.--generate-notesis computed server-side.ghis preinstalled on GitHub-hostedubuntu-latestrunners (release.yml:48).- Without a checkout, no third-party code runs in the job that holds the write token.
- Injection safety is unchanged. The tag still comes from the quoted
$GITHUB_REF_NAMEenv var, not${{ }}insiderun:(release.yml:54-57). - The docs match the workflow.
AGENTS.md:68names thegithub-releasejob.AGENTS.md:78correctly says it isneeds: releaseand "the only job withcontents: write" (release.yml:15-16vs:49-50).README.md:891refers to the job by its display nameGitHub Release(release.yml:46) and the workflow by its nameRelease to Maven Central(release.yml:1). Both are correct.AGENTS.md:77(step 3, "don't re-run blindly" after a partial deploy) andAGENTS.md:78(step 4, "if onlygithub-releasefailed") don't contradict each other: step 4's retry advice applies only when the deploy job succeeded.
Linked Issues and Tickets
None referenced, so spec compliance was checked against the replaced PR description only. The diff matches it:
- the separate job with
needs: release; contents: writeonly ongithub-release,contents: readonrelease;- no checkout,
GH_REPOplus--verify-tag; - the "Re-run failed jobs" behaviour;
- the env-var tag;
- the docs in both files.
There are no unrelated changes: the diff touches only .github/workflows/release.yml, AGENTS.md and README.md.
Review Verdict
COMMENT
Findings
Critical Issues (Must Fix)
None.
Important Issues (Should Fix)
None. The earlier Important finding is resolved (see above).
Minor Comments (Nice to Have)
None new. Minor 1 is resolved. Minor 2 needed no change.
Security Concerns
None. The write-scoped token now lives only in a job that runs one gh command and no third-party code (release.yml:45-61). The build/deploy job is read-only (release.yml:15-16).
Testing Assessment
release.yml only runs on v* tag pushes (release.yml:3-6), so PR CI can't exercise it. The next release is the first real run. This is a diff-reading review only: nothing was built or run. The only commands were read-only GETs: the repo's default workflow permissions and the PR data. The skip branch can be predicted against v0.0.22, which already exists as a release.
Overall Assessment
All earlier findings are addressed. The release is now least-privilege, re-runs are safe, and the docs agree with each other and with the workflow. Ready to merge from my side.
Summary
release.ymlpublishes to Maven Central, but the GitHub Release has always been created by hand afterwards. That step was missed for v0.0.22. This PR has the workflow create it.Workflow (
.github/workflows/release.yml)github-releasejob (needs: release) runs only after the Maven Central deployment succeeded:github-releasegetspermissions: contents: write. Thereleasejob, which runs the build and deploy tooling, is pinned tocontents: read. The repo default is already read-only, so the token those steps see is unchanged.github-releasehas no checkout.GH_REPOnames the repository, and--verify-tagchecks that the tag exists on the remote.gh release viewalready finds a release for the tag, the job logs a notice and skips.GITHUB_REF_NAMEenv var, not${{ }}interpolation insiderun:.GH_TOKENisgithub.token.Docs
AGENTS.md(CLAUDE.mdis a symlink to it): "Releasing" step 4 describes thegithub-releasejob and the "Re-run failed jobs" retry, plus a fallback for creating the release by hand. The CI summary line mentions the job.README.md: the "Create GitHub Release" section says the same, including thegh release createfallback one-liner.Testing
PR CI does not run
release.yml; the nextv*tag push is the first real run. Until then, the job's logic can be checked against v0.0.22:gh release view v0.0.22finds the existing release, so a run on that tag would take the skip branch.