Repository navigation
ci(release): support prerelease versions such as 1.0.0-alpha.1 - #156
Merged
Merged
Conversation
A v* tag always published to npm latest, the Docker latest/major/minor tags and a stable GitHub Release; auto-release.yml's npm version patch turns a prerelease into the stable release; the nightly version became 1.0.NaN-nightly.<stamp>; and changelog-guard ranked v1.0.0-alpha.1 above v1.0.0 and could not order or link prerelease sections. scripts/release-version.mjs now classifies a version for the workflows: prereleases publish under their own dist-tag, push only :X.Y.Z-pre.N and :pre to GHCR, create a GitHub pre-release, and make auto-release fail loudly. Stable releases are unchanged. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ESxuEjCeVsRAAxAb29Yjr
Contributor
Coverage Report
File CoverageNo changed files found. |
CodeQL (js/identity-replacement) flagged replacing the alpha.1 header with itself; the test only needs the 1.0.0 section inserted below it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ESxuEjCeVsRAAxAb29Yjr
…a/rc Prereleases must be X.Y.Z-(alpha|beta|rc).N and all publish to a single next channel (npm dist-tag, Docker :next) instead of one tag per stage that goes stale. next follows the newest tagged release of any kind: a stable release that is the newest tag moves it too, it never moves backwards, and a prerelease older than an existing tag is refused. Moving the npm dist-tag after a stable publish is continue-on-error and prints the manual command, since it needs an opt-in permission. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ESxuEjCeVsRAAxAb29Yjr
3 of 12 tasks
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.
Summary
Prerequisite for releasing a
1.0.0-alpha.1(or any prerelease). The release pipeline assumed every version is a plainX.Y.Z; tagging a prerelease today would have hijackedlatesteverywhere. Stable releases are unchanged, except that the newnextchannel follows them.What was wrong (each verified, not assumed):
publish.ymlv*tag publishes npmlatest, Docker:latest/:X/:X.Y, and a stable GitHub Releaseauto-release.ymlnpm version patchon1.0.0-alpha.1gives1.0.0, so the next Dependabot security merge would publish a stable 1.0.0 unannouncedpublish.ymlnightlyNumber('0-alpha1')isNaN, giving version1.0.NaN-nightly.<stamp>changelog-guard.mjsbaselineTagreturnsv1.0.0-alpha.1oncev1.0.0exists (git version sort ranks the longer name first); a prerelease[X-pre]:link definition is swallowed into the oldest section; a prerelease section listed below its stable release is not flagged (NaN <= 0is false)The channel model
X.Y.Z-alpha.N,-beta.Nor-rc.N(dot, number, no leading zero). Anything else (-alpha1,-dev.1,-foo.2,-1) fails the tag push before any output is written. The three stages sort in maturity order on their own (alpha < beta < rc < stable).next(not one tag per stage, which goes stale): npm dist-tagnextand Docker:next.nextis the newest tagged release of any kind. A prerelease moves it; a stable release moves it only when it is newer than every existingv*tag, so@nextnever trails@latest.nextonly moves forward: a stable hotfix on an old line (0.5.7while1.0.0-rc.1exists) leaves it alone, and a prerelease older than an existing tag (1.0.0-rc.2after1.0.0) is refused.next(neverlatest); Docker:X.Y.Z-pre.Nand:nextonly (no:latest,:X,:X.Y); GitHub pre-release withmake_latest: false.latest,:latest,:X.Y.Z,:X.Y,:X), plusnextwhen it is the newest tag.develop, never tagged) and keeps working.What changes
scripts/release-version.mjs(new):classify,is-newest,nightly-base,assert-stable.publish.yml: uses it for the tag channel, theupdate_nextdecision and the nightly base. New step after the npm publish moves thenextdist-tag to a stable release. It iscontinue-on-errorbecause it needs the opt-in Allow npm dist-tag permission on the package's trusted-publisher config (or a token); without it the release stays good and the run printsnpm dist-tag add @daften/fireflyiii-mcp@X.Y.Z next.auto-release.yml: fails loudly instead of bumping over a prerelease.changelog-guard.mjs: semver-precedencecompareVersions(exported), prerelease link definitions, andbaselineTagre-sorted by precedence rather than git's version sort.release-version.node-test.mjs(new, 60 automation tests in total) and prerelease cases inchangelog-guard.node-test.mjs. The old guard accepted a mis-ordered prerelease section; the new one flags it.AGENTS.md: "Prerelease releases" section.CHANGELOG.md: one### Changedbullet.Merge as a merge commit, never squash or rebase.
Verification
run:block of the setup step, extracted frompublish.yml, was executed underbash -eagainst throwaway git repos with different existing tags: stable and prerelease tags produce the rightprerelease/npm_tag/update_next; a hotfix below the newest tag getsupdate_next=false; a prerelease older than a stable tag,-foo.1and-alpha1exit 1.{{version}}(never{{major}}/{{major}}.{{minor}}),latest=autonever addslatestfor a prerelease, and an explicittype=rawentry still produces its tag.Not verified (cannot be exercised before a real prerelease tag exists)
softprops/action-gh-releaseacceptsprerelease/make_latestas written, and thatnpm dist-tag addworks from the trusted-publisher OIDC session once the permission is enabled (based on a GitHub changelog dated 2026-09-30 that could not be opened from the build environment). Watch the first prerelease run and the first stable run after it.auto-releaserun the workflow file frommain, so none of this takes effect on them until it ships in a release.Type of change
Checklist
npm testpasses locally (598 passed, 29 skipped);node --test tests/automation/*.node-test.mjs60 passednpx tsc --noEmitpasses locally🤖 Generated with Claude Code
https://claude.ai/code/session_012ESxuEjCeVsRAAxAb29Yjr