Maintaining a release line¶
Customers on :latest track a release tag, not main. Keeping their libraries
current therefore means updating the branch those tags are cut from — which is
what a release line is.
Today that line is release/5.9, branched from v5.9.1.
v5.9.1 ──→ release/5.9 ──→ 5.9.2 ──→ 5.9.3 … what customers run
↑
Dependabot lands production updates here, daily
main ─────────────────────────────────────────→ :edge, feature work
main is unaffected and keeps its own weekly Dependabot schedule. The two
never merge into one another; they are updated independently from upstream.
What happens without anyone doing anything¶
- Dependabot checks the manifests on
release/5.9every day and opens one grouped PR per ecosystem for production dependencies that moved. - CI runs —
pr.ymlandpr-integration.ymlalready trigger onrelease/**. - Auto-merge lands it once the required checks are green
(
.github/workflows/dependabot-auto-merge.yml). The Protect release branches ruleset requires no approving review, so nothing waits on a person. - You cut the patch release when you want one: Actions → Cut Release, with
ref: release/5.9and the next patch version. The release notes name every dependency that moved, derived from the lockfiles rather than the changelog.
Step 4 is the only manual step, and it is deliberate: publishing to :latest
puts a build in front of customers, which is a decision rather than a
consequence.
Two things about Dependabot that are easy to get wrong¶
The config is read from the default branch. .github/dependabot.yml on
main is the only copy Dependabot ever reads. The release-line entries live
there and describe work done on release/5.9 via target-branch. Copying
them onto the release branch does nothing.
target-branch does not route security updates. It is a version-updates-only
option. Alert-driven security updates ignore it and are always raised against
the default branch — GitHub's
Dependabot options reference
states it plainly under target-branch:
Options defined for this
package-ecosystemno longer apply to security updates because security updates always use the default branch for the repository.
This is why the release-line entries run daily instead of weekly. We cannot route security alerts to the branch, so we do not rely on them: a daily version check picks up the fixed release of a vulnerable package within a day by itself, with no cherry-pick and nobody watching an alert feed.
What reaches the line, and what does not¶
| On the release line | |
|---|---|
Production npm dependencies (app/api, app/ui) |
✅ Daily, grouped |
Container base images (app/api, setup/docker) |
✅ Daily |
| Dev dependencies — eslint, vitest, vite, playwright | ❌ Never |
| GitHub Actions versions | ❌ Never |
| Node major versions | ❌ Ignored, as on main |
Features and fixes from main |
❌ Not automatically — see below |
Dev dependencies are excluded by allow: dependency-type: production. They are
not arbitrary noise-trimming: the API image is built with npm ci --omit=dev
and the UI ships compiled dist/, so none of them is present in anything a
customer runs. On main they are worth taking; on a stable line they are risk
with no upside.
Actions updates are excluded for the same reason — they change CI, not the product.
Patch and minor merge themselves; majors do not¶
A major version is the one update expected to break callers. On a line whose purpose is not surprising anyone, taking one unattended is the wrong trade. Majors still get a PR; it waits for a person, and the workflow comments on it saying so. They are rare among production dependencies.
To change where that boundary sits, edit the if: on the auto-merge step in
.github/workflows/dependabot-auto-merge.yml.
Getting a fix from main onto the line¶
Dependency updates arrive from upstream, so they need no porting. A code fix does — and it does not flow automatically:
git checkout release/5.9 && git pull
git checkout -b bugfixes/fix-foo-on-5.9
git cherry-pick <sha-from-main>
gh pr create --base release/5.9 --title "fix: …"
The PR needs no approval but must pass CI. Fix on main first so the fix is not
lost when the next line is cut.
Starting the next line¶
When you cut 5.10.0 and want to maintain it instead:
- Create
release/5.10from thev5.10.0tag. - Repoint the four
target-branch: "release/5.9"entries in.github/dependabot.ymltorelease/5.10. - Decide what happens to
release/5.9— supporting two lines doubles the surface. The current position is to support the latest line only.
Nothing else is per-line: the auto-merge workflow and the ruleset both match
release/**.
Why the ruleset requires the checks it does¶
The Protect release branches ruleset requires no approving review — that is what lets dependency updates land unattended — so its status checks are the only thing standing between a Dependabot PR and the branch customers' releases are cut from.
It must therefore require the real CI aggregates, CI Passed and
Integration CI Passed. It must not rely on PR Summary, which is a stub
job (if: always(), a bare echo) that exists only to overshadow a stuck check
suite in the UI — it reports success even when CI has failed.