Skip to content

Commit 4fe372a

Browse files
committed
docs: add ADR 0012 — pinned prerelease versioning for beta lines
1 parent bf7c97f commit 4fe372a

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Pin beta release lines to a fixed 3.0.0-beta.N series with release-please prerelease versioning
2+
3+
- **Status:** Proposed
4+
- **Date:** 2026-07-20
5+
- **Decision makers:** Frida Erdal, EDS Core Team
6+
7+
## Context
8+
9+
Two packages are in a beta phase ahead of a `3.0.0` major: `eds-core-react-next` (the `/next` EDS 2.0 components) and `@equinor/eds-tokens` (the Tokens Studio rework, [ADR-0011](./0011-adopt-tokens-studio-platform-pipeline.md)).
10+
11+
The `/next` beta channel originally rolled its version base on every `feat(next)`: `2.6.0-beta.0 → 2.7.0-beta.1 → 2.8.0-beta.1`. That presented the betas as previews of stable 2.x minors, when EDS 2.0 actually graduates as `3.0.0` ([#5141](https://github.com/equinor/design-system/issues/5141)). The betas needed to be a fixed `3.0.0-beta.N` series where only the counter climbs, regardless of commit type.
12+
13+
The same question arose for `eds-tokens`: during the Tokens Studio transition there is no stable release channel — consumers on `latest` stay on the last stable `2.3.1` — and every pipeline or code change should cut the next `3.0.0-beta.N`.
14+
15+
An extra constraint applies to `eds-tokens`: four packages (`eds-core-react`, `eds-utils`, `eds-lab-react`, `eds-data-grid-react`) depend on it via `workspace:^`, and `pnpm publish` rewrites that to the version in eds-tokens' `package.json`. If `package.json` carried the beta version, stable releases of those packages would depend on beta tokens.
16+
17+
## Decision Drivers
18+
19+
- The version base must never move during beta — every commit type (`fix`, `feat`, `feat!`) bumps only the beta counter
20+
- Breaking changes must still surface as a "⚠ BREAKING CHANGES" changelog section for beta consumers
21+
- Stable releases of dependent packages must keep depending on stable tokens (`workspace:^` rewrite)
22+
- Graduation to `3.0.0` must be a config flip, not re-plumbing
23+
- Prefer configuration release-please owns over custom version automation in workflows
24+
25+
## Options Considered
26+
27+
### Option 1: Custom version automation in the publish workflows
28+
29+
What [#5141](https://github.com/equinor/design-system/issues/5141) originally prescribed, on the premise that release-please cannot pin a prerelease base: compute `3.0.0-beta.N` in `publish_core_react.yaml` at publish time.
30+
31+
**Pros:**
32+
33+
- Full control of the version string
34+
35+
**Cons:**
36+
37+
- The premise is outdated — verified against release-please v17 source (`src/versioning-strategies/prerelease.ts`, bundled as 17.6.0 in `release-please-action@v5`), the `prerelease` strategy pins the base natively
38+
- Version would live in workflow logic, drifting from the manifest/`version.txt` release-please owns
39+
- Changelogs and GitHub releases would not match what is published
40+
41+
### Option 2: Separate beta component/package per line
42+
43+
A dedicated release-please component (or package) per beta line with independent versioning, discarded at graduation.
44+
45+
**Pros:**
46+
47+
- Beta and stable lines cannot interfere by construction
48+
49+
**Cons:**
50+
51+
- Breaks tag and changelog continuity — history splits across components
52+
- More moving parts to dismantle at graduation
53+
54+
### Option 3: release-please `versioning: "prerelease"` + `prerelease: true` (chosen)
55+
56+
Configure the existing components with release-please's prerelease versioning strategy, base seeded at `3.0.0-beta.N`.
57+
58+
**Pros:**
59+
60+
- release-please owns the version end to end (manifest, `version.txt`, changelog, tags)
61+
- Verified by running release-please's actual versioning code: `fix`, `feat` and `feat!` all produce `beta.N+1` while minor and patch are 0
62+
- Graduation is flipping `"prerelease": false` (or a `Release-As: 3.0.0` footer)
63+
64+
**Cons:**
65+
66+
- Subtle: `prerelease-type: beta` **alone** does not pin — without `prerelease: true` the default strategy bumps the base and carries the suffix (the exact #5141 drift), and a `fix` on `3.0.0-beta.0` would release **stable `3.0.0`**
67+
- The pin only holds while minor and patch are both 0
68+
69+
## Decision
70+
71+
**Use release-please's `versioning: "prerelease"` + `prerelease: true` + `prerelease-type: "beta"` on both beta lines**, with the base seeded at `3.0.0-beta.N` in the manifest. Every commit type bumps only the beta counter; `feat!`/`fix!` additionally emit a "⚠ BREAKING CHANGES" changelog section. The former "no `!` in beta commits" rule is inverted: `!` is now safe (the base cannot roll) and preferred, because it surfaces breaking changes to beta consumers.
72+
73+
For **`eds-tokens`**, the entry additionally uses `release-type: simple`, which tracks the version in `version.txt` instead of `package.json`. `package.json` stays at the last stable (`2.3.1`) so `pnpm publish`'s `workspace:^` rewrite keeps stable releases of dependent packages on stable tokens; the publish workflow applies the `version.txt` beta version at publish time. The existing component, tags, and CHANGELOG continue seamlessly — no separate `-next` component.
74+
75+
At graduation, flip `"prerelease": false` and switch the npm dist-tag from `beta` back to `latest`; the same configuration then emits stable `3.0.0`.
76+
77+
### Consequences
78+
79+
- Good, because betas present honestly as `3.0.0-beta.N` — previews of the actual next major, not of fictional 2.x minors
80+
- Good, because breaking changes in beta are encouraged to carry `!` and get a changelog section, instead of being banned
81+
- Good, because both beta lines share one validated configuration pattern, and graduation is a config flip
82+
- Good, because stable releases of `workspace:^` dependents keep resolving to stable tokens throughout the transition
83+
- Bad, because an urgent stable 2.x tokens patch during the transition is a manual publish from the `eds-tokens@v2.3.1` tag (accepted — no stable tokens work is planned; exercised once for the docs-only `2.3.2`)
84+
- Bad, because the eds-tokens version lives in two places with different meanings (`version.txt` = beta line, `package.json` = stable line) — a known sharp edge for anyone touching the publish flow
85+
- Bad, because the pin silently stops working if minor/patch ever leave 0 (e.g. a stray `Release-As` footer) — the base would start rolling again
86+
87+
### Confirmation
88+
89+
Validated in production: the 2026-07-20 release moved `eds-tokens` `3.0.0-beta.0 → 3.0.0-beta.1` from a `feat` without rolling the base. The next `/next` merge to main must produce a release PR with `eds-core-react-next: 3.0.0-beta.2`. `documentation/how-to/BETA_RELEASE_GUIDE.md` and `.github/release-please-config.md` document the day-to-day rules.
90+
91+
## Related
92+
93+
- [ADR-0011](./0011-adopt-tokens-studio-platform-pipeline.md) — the Tokens Studio pipeline whose releases feed the eds-tokens beta line
94+
- [`documentation/how-to/BETA_RELEASE_GUIDE.md`](../how-to/BETA_RELEASE_GUIDE.md) — beta commit conventions and channel overview
95+
- [`.github/release-please-config.md`](../../.github/release-please-config.md) — config field documentation
96+
- Issues [#5141](https://github.com/equinor/design-system/issues/5141), [#5120](https://github.com/equinor/design-system/issues/5120)
97+
- PRs [#5180](https://github.com/equinor/design-system/pull/5180) (eds-tokens), [#5190](https://github.com/equinor/design-system/pull/5190) (eds-core-react-next)

0 commit comments

Comments
 (0)