feat: add target/N-x-y labels to main branch Chromium roll PRs - #207
Conversation
When rolling Chromium on main, label the roll PR with target/N-x-y for every supported release branch whose scheduled Chromium version (per https://releases.electronjs.org/schedule.json) is >= the Chromium major being rolled to, so the roll is backported to the branches that will ship it. no-backport is now only applied when no target branch applies. If the release schedule cannot be fetched, the roll still proceeds and falls back to the previous no-backport behavior.
Skip the independent Chromium roll for a release branch whose scheduled Chromium version is >= the major the main branch roll targets (the latest Canary) - such branches receive the main roll via their target/N-x-y label instead, so rolling them separately would produce a duplicate roll PR. The check uses the same schedule predicate as the target label computation; if it cannot be determined, the branch rolls independently as before. Since the main roll PR is updated daily and labels were add-only, also remove roller-managed labels that no longer apply on each update: stale target/N-x-y labels that no longer qualify, and no-backport when target labels currently apply. Other labels are never touched, and removal failures are non-fatal.
ckerr
left a comment
There was a problem hiding this comment.
AI-assisted review: Sol xhigh doing adversarial review on the PR, and then Opus 5 high doing an adversarial review on both the PR and on Sol's findings. Inline comments generated by Sol & Opus. All findings reviewed manually by me before submitting.
- Roll main first and pass the release branches its roll PR actually covers (successfully created/updated and labeled) down to the release branch rolls, instead of re-deriving schedule eligibility per branch. A covered branch is skipped only while its DEPS Chromium version has caught up to the main roll target, so a branch whose backports stall pulls itself forward with its own roll. Explicitly targeted rolls are never suppressed. - Treat the backport label set as a state machine: replacement labels are only added once every conflicting label is confirmed removed (404s count as removed), and on any failure the PR's existing backport labels are left exactly as they were - only a brand-new PR falls back to no-backport. The PR can never carry both no-backport and target/ labels. - Reconcile labels on the open main roll PR even when the DEPS version is unchanged, since the release schedule (e.g. a newly cut branch) moves independently of Chromium. - Widen the stale label pattern to the older N-M-x branch form and guard the Chromium major parse against invalid versions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011v4QNjFUH5wLUj8eMUigbB
The skip condition compared the branch's DEPS Chromium version against the version the open main roll PR targets, which a backport-fed branch can never reach - it is at most level with main's landed version - so the skip was unreachable in steady state and every tracked branch still rolled independently alongside its backport. Compare against main's landed DEPS version instead: level with main means take the backport, behind main means roll independently and self-heal. MainRollResult now carries currentVersion (the version main is on) rather than the roll target, and the handler tests cover the kept-pace skip, the everyday case of a branch level with main while the roll PR is ahead of both, and a lagging branch rolling itself forward. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011v4QNjFUH5wLUj8eMUigbB
| previousVersion?: string; | ||
| } | ||
|
|
||
| const TARGET_BRANCH_LABEL_PATTERN = /^target\/\d+-(?:\d+-x|x-y)$/; |
There was a problem hiding this comment.
| const TARGET_BRANCH_LABEL_PATTERN = /^target\/\d+-(?:\d+-x|x-y)$/; | |
| const TARGET_BRANCH_LABEL_PATTERN = /^target\/\d+-x-y$/; |
This was supporting a very old branch naming pattern (<major>-x) that we never use for target branch labels.
| const branches: ReposListBranchesResponseItem[] = await octokit.paginate( | ||
| octokit.repos.listBranches.endpoint.merge({ | ||
| ...REPOS.electron, | ||
| protected: true, | ||
| }), | ||
| ); |
There was a problem hiding this comment.
We should move away from this pattern , as it is quite slow (as in 20+ seconds, see electron/sudowoodo#419). There was a time historically when protected: true filtered us down to release branches for free as they were the only ones protected, but with our modern branch protection rulesets on e/e all branches count as protected, so this just paginates all branches (which at the time of this writing, is 478).
I'll open a follow up PR for speeding this up, as the changes in this PR add another pagination to the main code paths so we're going to be losing nearly a minute of wall time just paginating branches from e/e.
Requested by John Kleinschmidt · Slack thread
Before: Chromium roll PRs against
mainalways get theno-backportlabel, so a roll to a Chromium major that a supported release branch is scheduled to ship is never flagged for backporting to that branch. That branch instead gets its own independent Chromium roll PR — so a branch like45-x-y(scheduled for Chromium 156, currently on the same milestone asmain) would end up with both the backported main roll and a duplicate independent roll.After: Chromium roll PRs against
mainget atarget/N-x-ylabel for every supported release branch whose scheduled Chromium version is >= the Chromium major being rolled to, andno-backportis only applied when no target branch applies. The main branch is rolled first, and a release branch skips its own Chromium roll only when the main roll PR was successfully created/updated and labeled withtarget/for it and the branch's DEPS has kept pace with the Chromium version main has actually landed — so a branch whose backports stall (or when the main roll fails, is paused, or mislabeled) still pulls itself forward with its own roll, and an explicitly targeted roll of a single branch is never suppressed. The backport labels on the long-lived main roll PR are reconciled on every run (including runs with no DEPS change, since the schedule moves independently): staletarget/N-x-ylabels and a conflictingno-backportare removed before the current set is added, the PR can never carry bothno-backportandtarget/, and on any reconciliation failure the PR's existing backport labels are left untouched. All other labels (merged/*, trop's,semver/*, ...) are never touched, and Node.js rolls are unchanged.This makes roller label main Chromium roll PRs for backport to the release branches that will ship that Chromium, per the release schedule, instead of rolling those branches separately.
How: a new
getBranchesTrackedByMain()util fetches https://releases.electronjs.org/schedule.json (the JSON API behind the schedule page, served by electron/release-status), intersects it with the supported release branches (viagetSupportedBranches()on protected branches), and returns every branch whosechromiumVersionmilestone is >= the given major.updateLabels()inroll.tsmaps that totarget/N-x-ylabels for Chromium rolls onmain, transitions the backport label set only after every conflicting label is confirmed removed (a 404 counts as removed; only a brand-new PR falls back tono-backporton failure), and reports the covered branches back throughroll();handleChromiumCheck()rollsmainfirst and passes that coverage (plus main's landed DEPS version) torollReleaseBranch(), which skips only branches that are covered and level with what main has landed. If the schedule fetch fails, the roll itself still proceeds.Example: with Electron 45 (
45-x-y) scheduled for Chromium 156 and Electron 44 (44-x-y) for 152, a main roll to Chromium 154 getstarget/45-x-y, and45-x-yskips its own roll while its DEPS is level with what main has landed; a roll to 152 gets both labels; a roll to 157+ getsno-backportand both branches roll independently.🤖 Generated with Claude Code