Skip to content

release: mark prereleases, and publish via a draft for immutability - #44

Merged
yesdevnull merged 3 commits into
mainfrom
fix/goreleaser-prerelease
Aug 18, 2026
Merged

release: mark prereleases, and publish via a draft for immutability#44
yesdevnull merged 3 commits into
mainfrom
fix/goreleaser-prerelease

Conversation

@yesdevnull

@yesdevnull yesdevnull commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Two release-publishing fixes, both prompted by v1.0.0-alpha.1.

The alpha published as the latest stable release

GoReleaser defaults release.prerelease to false, so v1.0.0-alpha.1 went 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: auto reads the semver prerelease suffix, so the next -beta or -rc is 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:

Create the release as a draft. Attach all associated assets to the draft release. Publish the draft release.

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} with immutable_releases is 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 check passes and actionlint is clean. The tag reaches the shell through env: 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: auto marking a -rc/-beta tag — accepted by goreleaser check, but the behaviour only shows on a real prerelease.
  • gh release edit --draft=false preserving the prerelease flag GoReleaser set. It sends only the fields named, so it should.
  • A draft release being addressable by tag name. The tag exists before the workflow runs, 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

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
Copilot AI lite review requested due to automatic review settings August 18, 2026 01:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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: auto to .goreleaser.yaml so 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.

Comment thread .goreleaser.yaml Outdated
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
@yesdevnull yesdevnull changed the title release: mark prerelease tags as prereleases release: mark prereleases, and publish via a draft for immutability Aug 18, 2026
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
@yesdevnull
yesdevnull merged commit c6c9b10 into main Aug 18, 2026
12 checks passed
@yesdevnull
yesdevnull deleted the fix/goreleaser-prerelease branch August 18, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants