fix(version-dispatch): keep prereleases in their rc cycle#86
Merged
Conversation
A commit-driven \`major\`/\`minor\`/\`patch\` bump on a package whose current version is itself a prerelease (\`5.0.0-rc.96\`) used to return \`semver.inc\`'s raw output — for \`major\`, that's \`5.0.0\`, i.e. drop the rc and ship the long-awaited stable release. That's almost certainly the wrong policy when a \`refactor!:\` lands on a package that's been sitting in rc for 96 iterations. Detect prerelease state from the current version (presence of \`-\`) and downgrade the bump level to \`prerelease\` so the rc counter advances instead (\`5.0.0-rc.96\` → \`5.0.0-rc.97\`). Stable versions are unchanged. Caught by exodus-hydra#16379's preview comment: @exodus/headless | major | 5.0.0-rc.96 | 5.0.0 ← wrong Now reads: @exodus/headless | major | 5.0.0-rc.96 | 5.0.0-rc.97 ← correct The team must explicitly promote an rc to stable via a separate workflow when they're ready. Both the preview's \`nextVersion\` and \`versionPackagesExplicit\`'s real bump path apply the same downgrade. The \`isMajorBump\` check (consumer-pin walker) keeps the workspace symlink resolving — an rc → next-rc bump doesn't move the major, so no consumer pins are touched. 193/193 tests passing (was 181, +12 across preview.spec and version-packages.spec — covering rc.X → rc.X+1, no consumer pin walk, and the stable-version path staying on the original semver.inc).
Contributor
Author
E2E verified in actions-playgroundRun 26119756534 — Fixture state at run time:
Action logs: Release PR produced: actions-playground#709 — Confirms:
|
exo-mv
approved these changes
May 19, 2026
| // prerelease counter rather than dropping the rc — a `feat!:` commit | ||
| // shouldn't accidentally promote a long-lived rc to a stable release. | ||
| // The caller can promote to stable via a separate workflow when ready. | ||
| const effectiveBump = isPrerelease(current) ? 'prerelease' : (bump as ReleaseType) |
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
Caught by exodus-hydra#16379's preview comment:
```
@exodus/headless | major | 5.0.0-rc.96 | 5.0.0 ← wrong
```
`semver.inc('5.0.0-rc.96', 'major')` returns `'5.0.0'` — semver's "drop the prerelease, ship the release" semantics. That's the wrong policy when a `refactor!:` lands on a package that's been sitting in rc for 96 iterations; an unrelated breaking commit shouldn't accidentally promote a long-lived rc to stable.
Fix
Detect prerelease state from the current version (presence of `-`) and downgrade the bump level to `prerelease` so the rc counter advances instead:
Applied symmetrically to both:
The team must explicitly promote an rc to stable via a separate workflow when they're ready.
Consumer pins
The `isMajorBump` check in `versionPackagesExplicit` still gates the consumer-pin walker. An rc.X → rc.X+1 bump doesn't move the major number, so consumer pins like `^5.0.0-rc.0` keep resolving via the workspace symlink. No churn.
Tests
193/193 passing (was 181, +12):