ADR-1348: Number release candidates with release-please's prerelease versioning¶
- Status: Accepted
- Date: 2026-09-27
- Deciders: lusoris
- Tags: release, ci
Context¶
ADR-1201 cuts release candidates before the final 1.0.0, and ADR-1341 orders them: RC1 for correctness, RC2 for benchmarks and tuning, RC3 for the retrain. release-please-config.json set "versioning": "default" with "prerelease": true and "prerelease-type": "rc".
Once v1.0.0-rc.1 was published, the fix commits that followed made release-please open release PR #1575 as 1.0.1-rc.1. The default strategy applies a patch bump to 1.0.0-rc.1 and keeps the prerelease identifier, so it never counts candidates. #1568 documented a workaround: a manual Release-As: 1.0.0-rc.2 footer on the last commit merged before each later cut. Forgetting it would publish the wrong version under an immutable tag.
In release-please 17.6 (the library the pinned release-please-action v5.0.0 depends on), src/versioning-strategies/prerelease.ts handles a version that already carries a prerelease identifier as follows:
- Fix commits:
PrereleasePatchVersionUpdateincrements the prerelease number. - Features:
PrereleaseMinorVersionUpdatedoes the same whilepatchis 0. - Breaking changes:
PrereleaseMajorVersionUpdatedoes the same whileminorandpatchare 0.
On 1.0.0-rc.N all three therefore produce 1.0.0-rc.N+1. When prerelease is false, the strategy keeps only major.minor.patch of that bump, so the final cut becomes 1.0.0. src/factory.ts passes the package's prerelease and prerelease-type settings to the strategy.
Decision¶
Set "versioning": "prerelease" for the root package. Release candidates are numbered 1.0.0-rc.2, 1.0.0-rc.3, … without a manual footer, and the final cut needs only "prerelease": false. The Release-As: X.Y.Z commit footer stays available as a one-shot override, but a routine candidate cut no longer needs it. The release PR remains a standing proposal: it is merged only when the next candidate is due.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
versioning: prerelease (chosen) | Candidates are counted automatically; the final 1.0.0 needs no version override; verified in the pinned library's source | The version depends on release-please's strategy code, which a major upgrade could change | The Release Script Contract job and the release PR title surface a change before any cut |
Keep versioning: default with a Release-As: 1.0.0-rc.N footer before each cut (#1568) | No config change | A manual step on every candidate; forgetting it tags 1.0.1-rc.1, which cannot be taken back | Error-prone for 4–8 candidates |
Pin release-as in the config per candidate | Explicit | release-as is persistent, swallows later bumps, and the release script contract forbids it after the first cut | Rejected by the existing contract |
Consequences¶
- Positive: release PR #1575 retitles itself to 1.0.0-rc.2 on the next push to master; later candidates need no manual version step.
- Negative: none known; a release-please upgrade that changes the strategy would show in the release PR title before any cut.
- Neutral / follow-ups:
docs/development/release.mdandscripts/release/AGENTS.mddrop the footer procedure; the Release Script Contract job inrule-enforcement.ymlfails while the manifest is a release candidate and the root package'sversioningis notprerelease.
References¶
- popup, 2026-09-27: "Switch to prerelease versioning (Recommended)" (maintainer answer to how the next candidate gets 1.0.0-rc.2).
- ADR-1201 — release candidates before 1.0.0.
- ADR-1341 — RC1/RC2/RC3 sequence.
- release-please v17.6.0 source:
src/versioning-strategies/prerelease.ts,src/factories/versioning-strategy-factory.ts,src/factory.ts.