forked from emberjs/rfcs
-
Notifications
You must be signed in to change notification settings - Fork 5
Move off the release train to a simpler release model #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
NullVoxPopuli
merged 19 commits into
NullVoxPopuli:nvp/move-off-the-release-train-to-simpler-release-model
from
NullVoxPopuli-ai-agent:nvp/move-off-the-release-train-to-simpler-release-model
Jun 6, 2026
Merged
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
fab3938
Add RFC: move off the release train to a simpler release model
NullVoxPopuli 95b8c2b
Drop the develop branch; release from a single `main`
NullVoxPopuli 9e1543a
Keep the six-week cadence; drop only the canary/beta channels
NullVoxPopuli 94aff16
Correct canary/beta channel facts; alpha auto-published from main
NullVoxPopuli 87e46df
Holistic pass: reconcile cadence with release-plan and RFC 830
NullVoxPopuli ad52c78
Address review: no canary branch, accurate release-plan, drop ember-data
NullVoxPopuli 618d3da
Reflow: one line per paragraph and list item, no hard wrapping
NullVoxPopuli c9d1183
Resolve open decisions: nightly @alpha, drop beta, timing-lockstep, m…
NullVoxPopuli 170408e
Clarify canary is unchanged; alpha scheme is release-plan default; be…
NullVoxPopuli 50a3b23
Unresolved questions: n/a
NullVoxPopuli cd12ee0
Rewrite in NullVoxPopuli's RFC voice; remove all em-dashes
NullVoxPopuli 489a4ca
Drop the status-quo alternative
NullVoxPopuli 1ded125
Alternatives: drop keep-beta and changesets options
NullVoxPopuli 6fa1d83
Address PR review: trim drawbacks, drop Steering, keep LTS backports
NullVoxPopuli 39cbdfe
Don't frame the cadence as in question; state the cost directly
NullVoxPopuli a3363d1
Apply suggestion from @NullVoxPopuli
NullVoxPopuli 01c82b9
Apply suggestion from @NullVoxPopuli
NullVoxPopuli c2952c2
Apply suggestion from @NullVoxPopuli
NullVoxPopuli 8d6ed76
Tone down marketing language
NullVoxPopuli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
152 changes: 152 additions & 0 deletions
152
text/0000-move-off-the-release-train-to-simpler-release-model.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| --- | ||
| stage: accepted | ||
| start-date: 2026-06-05T00:00:00.000Z | ||
| release-date: # In format YYYY-MM-DDT00:00:00.000Z | ||
| release-versions: | ||
| teams: # delete teams that aren't relevant | ||
| - cli | ||
| - framework | ||
| prs: | ||
| accepted: # Fill this in with the URL for the Proposal RFC PR | ||
| project-link: | ||
| suite: | ||
| --- | ||
|
|
||
| # Move off the release train to a simpler release model | ||
|
|
||
| ## Summary | ||
|
|
||
| Ember's "release train" today is really two things bundled together: | ||
|
|
||
| 1. A six-week release cadence. A new minor ships on a steady, predictable clock. | ||
| 2. A multi-branch promotion pipeline. Code gets promoted from the default branch through dedicated `beta` and `release` branches (plus LTS branches), shepherded by a small number of folks who manage each release. | ||
|
|
||
| This RFC keeps (1) and replaces (2). The six-week cadence is the part that works, so it stays exactly as it is. What goes away is the extra release branches and the bespoke, per-cycle process that goes with them. | ||
|
|
||
| Concretely: | ||
|
|
||
| - Just `main`. No `beta` or `release` branches. | ||
| - Stable releases are cut from `main` by [`release-plan`][release-plan] on the same six-week schedule. The `npm publish` is gated behind a protected [GitHub deployment environment][gh-environments], so a maintainer approves before anything publishes. | ||
| - We drop the `beta` channel. `@alpha` prerelease is nearly the same as before, but published nightly from `main`, and `ember-source@beta` users either move to `@alpha` or drop the scenario. | ||
|
|
||
| SemVer, the six-week cadence, the deprecation policy, LTS, and the major-version process from [RFC #0830][rfc-830] are all unchanged. The only things that change are the branch structure and the publishing mechanics. | ||
|
|
||
| [release-plan]: https://github.com/embroider-build/release-plan | ||
| [gh-environments]: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment | ||
| [rfc-830]: https://github.com/emberjs/rfcs/blob/master/text/0830-evolving-embers-major-version-process.md | ||
|
|
||
| ## Motivation | ||
|
|
||
| The expensive part of the release train is all the machinery around it, plus the time it takes maintainers with limited availability to keep it running. | ||
|
|
||
| ### Releases depend on too few people | ||
|
|
||
| We don't actually have a formal release-manager rotation. In practice the release comes down to essentially one person per project: Katie for `ember.js`, Chris for `ember-cli`. That's a real bus-factor and burnout risk, because when that person isn't around, the release slips. | ||
|
|
||
| The biggest win of getting off the train is that releasing stops being specialized knowledge. With [`release-plan`][release-plan], _any_ maintainer can trivially cut a release: they look over the release-preview PR and approve a deployment. No npm keys on anyone's laptop, no checklist, no tribal knowledge. | ||
|
NullVoxPopuli marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### Extra release branches are overhead | ||
|
|
||
| Keeping `beta`, `release`, and the LTS branches alive next to the default branch means constant backporting and branch bookkeeping that only exists to service the shape of the train. A single `main` gets rid of all of it. | ||
|
|
||
| ### release-plan automates the mechanical work | ||
|
|
||
| Working out the next version number and assembling the changelog are exactly the mechanical, error-prone steps that shouldn't be done by hand, and this is the important bit: release-plan does this for us, deterministically, from the labels and titles of the PRs that got merged. The ecosystem has already standardized on release-plan for almost every addon, so the framework doesn't need a bespoke process that's strictly more work than the tooling everyone else already trusts. | ||
|
|
||
| ### Keep the cadence | ||
|
|
||
| The six-week cadence is predictable, well understood, and well loved, so we keep it. We're moving off the branch-and-process model, not the calendar. | ||
|
|
||
| ## Detailed design | ||
|
|
||
| ### Branching model | ||
|
|
||
| Everything merges to `main`. It's both where work integrates and the source of every release. There are no `beta` or `release` branches, and none of the backporting onto them that the train needs. | ||
|
|
||
| ### Per-PR release metadata | ||
|
|
||
| release-plan uses these labels: | ||
|
|
||
| - `breaking` (major impact) | ||
| - `enhancement` (minor impact) | ||
| - `bug` (patch impact) | ||
| - `documentation`, `internal` (recorded, but don't cause a release on their own) | ||
|
|
||
| The changelog entry for a release _is_ the set of merged PR titles (you can edit a title later to fix it up), so there's nothing extra to write. release-plan reads the labels and titles of everything merged since the last release, then works out the next version and assembles the changelog. The judgment a maintainer used to apply by reading the diff is captured by the label on each PR when it lands. | ||
|
|
||
| ### Releasing | ||
|
|
||
| The cadence is unchanged. The mechanics are just release-plan's defaults: | ||
|
|
||
| 1. release-plan keeps a release-preview PR up to date. It bumps the version in `package.json`, edits `CHANGELOG.md`, and records the plan from the labels and titles merged since the last release. | ||
| 2. On the scheduled six-week date, a maintainer merges that preview PR, which kicks off the publish workflow. (The schedule is the rhythm. Nothing forces a release between scheduled dates, and a date can still be held or moved like it can today.) | ||
| 3. The publish job targets a protected GitHub environment (say, `npm-publish`) with a required-reviewers rule. The npm token / trusted-publishing identity is scoped to that environment, so nothing publishes until a required reviewer hits Approve on the pending deployment. Maintainers never need npm keys locally. | ||
| 4. Once approved, the CI job runs `release-plan publish`: it tags, pushes, and publishes to npm (with provenance via OIDC trusted publishing). | ||
|
|
||
| Across a cycle, release-plan collapses everything merged into a single version bump (highest impact wins), so six weeks of `enhancement` PRs becomes one minor, exactly like one stable minor per cycle does today. `@alpha` publishes the in-progress version nightly (e.g. `6.5.0-alpha.N`), and the scheduled stable cut publishes the finished version (`6.5.0`) as `@latest`. That stable release is just a snapshot of `main` on the scheduled date, which is the same thing promoting `release` from `beta` produced before. | ||
|
|
||
| The approval click is the entire ceremony that's left. No manual version edit, no manual changelog, no manual publish, and no branch to cut or promote. Because the gate is a GitHub environment, the normal GitHub permission and audit model applies, so who can approve and who approved what are just repo configuration instead of tribal knowledge. | ||
|
|
||
| ### Channels | ||
|
|
||
| - Stable (`latest`): published from `main` through the gated environment, on the six-week cadence, as above. | ||
| - Canary: _unchanged by this RFC._ Canary is the default branch (`main`) consumed from git, and that keeps working exactly like it does today. | ||
| - `alpha`: new. A published, npm-installable prerelease of `main`, cut nightly the way Embroider and Glint _used to_ publish theirs. It gives `main` a turnkey npm dist-tag (`ember-source@alpha`) for folks who want canary's code without consuming from git. release-plan's defaults handle the version scheme, so there's nothing special to set up. | ||
| - `beta`: removed. The `beta` branch and the `ember-source@beta` dist-tag both go away. Anything that needs extra baking can still merge early and get exercised via canary or `@alpha` before the next scheduled stable release. | ||
|
|
||
| ### Deprecations, majors, and LTS | ||
|
|
||
| Since we keep the six-week cadence, everything layered on top of it is unaffected: | ||
|
|
||
| - Deprecations still land as SemVer-minor and get removed in majors, on the same deprecation-freeze schedule. | ||
| - Majors aren't a manual process either. A PR gets labeled `breaking`, and because RFC #0830 puts a major on the normal cadence (roughly one major every twelve 6-week minors, after the `M.10` deprecation freeze), `breaking` PRs only merge in that window. So release-plan's label-driven bump produces the major right on schedule, with no manual version work. The major-version process itself doesn't change; it just runs through release-plan from `main`. | ||
| - LTS keeps working like it does today. | ||
|
|
||
| So this RFC changes _how_ a release is cut and _which branches exist_, not _when_ releases happen or _what_ they guarantee. | ||
|
|
||
| ### Lockstep across packages | ||
|
|
||
| `ember-source` and `ember-cli` keep releasing in lockstep, but lockstep here is a timing thing, not a coupling. Each repo releases independently through release-plan (its natural per-repo mode), and the releases don't need to know about each other. Since both cut stable on the same six-week date, their versions stay lined up. There's no cross-repo coordination step in the workflow; the shared cadence is what keeps them in step. | ||
|
|
||
| ### What this removes | ||
|
|
||
| - The `beta` and `release` branches, and the `ember-source@beta` dist-tag. | ||
| - The backporting onto the `beta` and `release` branches. | ||
| - The bespoke per-cycle release process. Version bumps, changelog assembly, and the cut/promote steps are all release-plan's job now. | ||
|
|
||
| ### What this keeps | ||
|
NullVoxPopuli-ai-agent marked this conversation as resolved.
NullVoxPopuli-ai-agent marked this conversation as resolved.
|
||
|
|
||
| - The six-week release cadence, unchanged. | ||
| - SemVer and every compatibility guarantee we make today. | ||
| - The deprecation policy, LTS, and the major-version process (RFC #0830). | ||
| - Backports to LTSes, when needed. | ||
| - A deliberate human gate before every publish. | ||
| - From a consumer's point of view, nothing changes. They won't notice a difference. | ||
|
|
||
| ## How we teach this | ||
|
|
||
| Contributors keep doing what they already do in basically every addon: label each PR with a release-plan label. The PR title becomes the changelog entry. | ||
|
|
||
| Maintainers get the ability to release. The role shrinks from "shepherd the branches and the cut" down to "look over the release-preview PR and approve the deployment," which any maintainer can do, from anywhere, without npm keys. | ||
|
|
||
| `beta` users are the folks whose workflow moves. If your `ember-try` config or CI matrix tests `ember-source@beta`, you remove that scenario, since `@beta` won't exist anymore. You can add `@alpha` if you want a published prerelease. Canary testing (consuming `main` from git) is unaffected. | ||
|
|
||
| Docs work: | ||
|
|
||
| - Rewrite the website Releases page: `main` is the release line, the six-week cadence is unchanged, the prerelease stream is `@alpha` (published nightly from `main`), and `beta` is gone. | ||
| - Update the contributor guide with the labeling workflow. | ||
| - Document the environment, who can approve, and how approval works. | ||
| - A migration / announcement blog post about dropping `@beta`. | ||
|
|
||
| ## Drawbacks | ||
|
|
||
| - Dropping `@beta` moves some consumers. Any `ember-try` scenario or addon CI matrix pinned to `ember-source@beta` has to remove that scenario (and can adopt `@alpha` if it wants). It's a one-time, mechanical cleanup rather than a lost capability, since canary testing is unaffected, but it's still ecosystem-wide churn that needs coordinating. | ||
| - Cultural change. `beta` is a long-standing, load-bearing part of Ember's testing culture and infrastructure, so removing it isn't only a mechanical change. | ||
|
|
||
| ## Alternatives | ||
|
|
||
| - Drop the cadence too (fully continuous releases). A more radical model where every merge can release. We're explicitly _not_ proposing that here, because the six-week cadence works. | ||
|
|
||
| ## Unresolved questions | ||
|
|
||
| n/a | ||
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.
Uh oh!
There was an error while loading. Please reload this page.