release: mark prereleases, and publish via a draft for immutability - #44
Merged
Conversation
GoReleaser defaults release.prerelease to false, so v1.0.0-alpha.1 published as an ordinary release and took GitHub's "Latest" badge — an alpha presented to anyone landing on the repository as the current stable version. The release workflow reported success, because from its point of view nothing had gone wrong. That release has been corrected by hand; this stops the next -beta or -rc repeating it. "auto" reads the semver prerelease suffix. Verified only so far as 'goreleaser check' accepting the config — the behaviour itself is not observable until a prerelease tag is pushed, so watch the next one. The changelog is deliberately left as it is. The first release's changelog spanned the whole history only because there was no previous tag to diff against; subsequent tags diff from their predecessor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0136bDtWBAdKtufTHcXoSwQK
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the GoReleaser configuration to ensure semver prerelease tags (e.g., v1.0.0-alpha.1) are published on GitHub as prereleases, preventing them from taking the repository’s “Latest” release badge.
Changes:
- Add
release.prerelease: autoto.goreleaser.yamlso prerelease status is inferred from the tag’s semver prerelease component. - Document in-config why this is needed (to avoid prerelease tags being treated as stable releases).
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
GitHub's immutable releases lock a release's assets and its git tag the moment it is published. The workflow published first and uploaded into the live release, which is the order that has to fight the lock. GoReleaser now creates the release as a draft with every archive attached, and a separate step flips it live. That is the order GitHub prescribes for immutability: "Create the release as a draft. Attach all associated assets to the draft release. Publish the draft release." It is the better failure mode regardless of whether immutability is on. A run that dies partway now leaves an unpublished draft holding whatever it managed to build, rather than a published release missing half its binaries — and a draft can be finished by hand, where a published immutable release cannot. The tag reaches the shell through env rather than inline expansion, matching the other workflows. Two things this cannot verify from config alone, both observable at the next tag: that `gh release edit --draft=false` leaves the prerelease flag GoReleaser set (it sends only the fields named, so it should), and that a draft release is addressable by tag name (the tag exists before the workflow runs, so it should). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0136bDtWBAdKtufTHcXoSwQK
The comment said auto "marks -alpha, -beta and -rc accordingly", which reads as an exhaustive list and would leave someone tagging -preview thinking they had to add it. GoReleaser documents the rule only as "in case there is an indicator for this in the tag e.g. v1.0.0-rc1" -- vague, and notably not a list. The comment now says that, including that the precise rule is undocumented, so an unusual suffix gets checked rather than assumed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0136bDtWBAdKtufTHcXoSwQK
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two release-publishing fixes, both prompted by
v1.0.0-alpha.1.The alpha published as the latest stable release
GoReleaser defaults
release.prereleasetofalse, sov1.0.0-alpha.1went out as an ordinary release and took GitHub's "Latest" badge — an alpha presented as the current stable version to anyone landing on the repository. The release workflow reported success, because from its point of view nothing had gone wrong, which is what makes this worth fixing in config rather than remembering.That release has been corrected by hand.
prerelease: autoreads the semver prerelease suffix, so the next-betaor-rcis marked without anyone having to notice.Preparing for immutable releases
GitHub's immutable releases lock a release's assets and its git tag the moment it is published. This workflow published first and uploaded into the live release, which is precisely the order that has to fight the lock.
GoReleaser now builds the release as a draft with every archive attached, and a separate step publishes it — the order GitHub prescribes:
This is the better failure mode either way. A run that dies partway now leaves an unpublished draft holding whatever it built, rather than a published release missing half its binaries — and a draft can be finished by hand, where a published immutable release cannot.
Note that immutability itself is not enabled by this PR. It has no REST API —
PATCH /repos/{owner}/{repo}withimmutable_releasesis silently ignored — so it has to be switched on in Settings → Releases → Enable release immutability. These changes are safe to land before or after that, and are worth having regardless.Verification
goreleaser checkpasses andactionlintis clean. The tag reaches the shell throughenv:rather than inline expansion, matching the other workflows.Three things config cannot prove, all observable at the next tag and worth a glance then:
prerelease: automarking a-rc/-betatag — accepted bygoreleaser check, but the behaviour only shows on a real prerelease.gh release edit --draft=falsepreserving the prerelease flag GoReleaser set. It sends only the fields named, so it should.The changelog is deliberately untouched. The first release's spanned the entire history only because there was no previous tag to diff against; subsequent tags diff from their predecessor.
🤖 Generated with Claude Code
https://claude.ai/code/session_0136bDtWBAdKtufTHcXoSwQK