Skip to content

ci: update PRs merge themselves when they ship nothing, and report the rest - #60

Merged
Nawid3333 merged 4 commits into
mainfrom
claude/update-automation
Sep 29, 2026
Merged

Nawid3333 merged 4 commits into
mainfrom
claude/update-automation

Conversation

@Nawid3333

Copy link
Copy Markdown
Owner

Update pull requests now decide themselves once CI finishes. Routine ones merge when CI is green. Every other one reaches you as an @mention email that says whether CI is green or red and why the PR waits. docs/maintenance.md maps every update source. This PR ships nothing to Firefox: it changes only workflows, tools, tests and docs.

What merges itself, and what waits for you

update-prs.yml (new) runs after every completed CI run on this repo's dependabot/*, toolchain/*, patched/* and sync/upstream branches. It never checks out PR code.

  • CI red: the failed jobs are rerun once. If CI is still red, one comment @mentions you with:

    • a table of each failed job, the step that failed, and what that step checks;
    • the last 40 lines of each failed log;
    • main's own CI status.

    The PR gets the ci-failed label and is assigned to you.

  • CI green, merged: only a Dependabot npm minor/patch PR or a pnpm same-major PR, and only when all of these hold:

    • that bot opened it, it is not a draft, and it targets main;
    • its commits are the bot's own, or merges of main made by this workflow;
    • only package.json and pnpm-lock.yaml change (for pnpm, only the packageManager line);
    • it is not a major;
    • Dependabot's dependency review passed;
    • CI's build of the extension is file-for-file the latest release's zip, apart from the version number;
    • checked last, just before the merge: it is mergeable and contains the newest main. If not, the workflow updates the branch and reruns CI, at most 3 times.

    The build comparison is auto-release.yml's own test, so such a merge releases nothing. The merged branch is deleted.

  • CI green, everything else (Node, a pnpm major, GitHub Actions, patched libraries, the upstream sync, a shipped library, any major): one comment @mentions you with the reasons it waits, and the PR is assigned to you. The comment is edited in place while the PR keeps waiting. You get a new email only when the PR turns red, turns green, is merged, or fails at a different step.

  • Edge cases:

    • If another merge lands on main between the last check and the merge, the merged comment @mentions you, because that combination was never built.
    • A branch that moved on meanwhile, or a PR that was closed, is left alone. A cancelled CI run decides nothing.
    • If the workflow itself fails or times out, it opens one issue.

toolchain-updates.yml now opens pull requests instead of issues:

  • Node.js: a newer LTS major changes .nvmrc. This is always your decision. Node 26 comes as a PR when it becomes LTS, around late October.
  • pnpm, same major: the newest release that is at least 5 days old changes only packageManager, and update-prs.yml merges it. Nothing from npm runs in this job, which holds a write token. CI installs the unchanged lockfile with the new pnpm (--frozen-lockfile), so a pnpm that wants the lockfile rewritten fails CI and reaches you.
  • pnpm, next major: comes only once pnpm v12 env lockfile document is parsed as an empty dependency graph dependabot/dependabot-core#15904 is closed, and it is your decision.

How these PRs are kept tidy:

  • A title is never used twice, so closing a PR skips that version for good.
  • Open PRs close themselves once main reaches their version, or when a newer one on the same track gets its own PR. A push to main only closes.
  • Each week, a bot-only PR that main has moved into conflict with is rebuilt on a freshly fetched main.
  • Each week, a PR whose head has no CI run that decides gets one. That covers a lost dispatch or only cancelled runs.
  • Only the bot's own titles and PRs count. Anyone else's PR with such a title neither blocks an update nor is closed or rebuilt, and a fork's PR is never touched.
  • A failed run opens one issue.

.nvmrc names the Node major everywhere. Every setup-node step and tools/linux/setup.sh read it. The reason: this token may not push workflow files, so a Node update has to be a one-file change. A unit test fails if any workflow names its own Node version.

Dependabot:

  • npm minor/patch is split into shipped-minor-and-patch (fuse.js, pako, sortablejs) and tooling-minor-and-patch, so a tooling update is not held back by a shipped one. A test keeps the shipped group equal to the libraries tools/sync-vendor.mjs copies, minus the ignored ones.
  • Releases are proposed once they are 5 days old (cooldown).

patched-libraries.yml:

  • A newer version's PR closes the older issue and PR for the same library. This runs as a sweep on every run, so a close that failed is retried.
  • Only the bot's own titles count.

Docs:

  • docs/maintenance.md is new.
  • CLAUDE.md is updated.
  • docs/amo-source-submission.md now points to packageManager instead of naming a pnpm version, which the first pnpm merge would have made stale.

Tests

  • update-prs.yml: its decide step runs in a harness, with gh, sleep and unzip stubbed and jq, sed, diff and real zips used as is. 152 checks pass. 35 mutants were made, each removing one safety condition, and all 35 were caught. shellcheck is clean.
  • toolchain-updates.yml: its step runs against real git with a local bare origin and a stub gh. 80 checks pass, and 25 of 25 mutants were caught.
  • patched-libraries.yml: the supersede sweep passes 16 of 16 checks against a stub gh.
  • Local run: pnpm run lint, pnpm run typecheck and pnpm test all pass (616 tests). actionlint 1.7.12 with shellcheck 0.11.0 is clean on every workflow.
  • Reviews: GLM 5.3 did adversarial reviews of update-prs.yml, toolchain-updates.yml with check-toolchain.mjs, their interplay, and the rest of the diff, plus a fact-check of the docs against the code. Every finding was checked against the code and fixed where real:
    • the merge race;
    • false alarms when a branch moves or a PR closes mid-run;
    • the timeout reporting;
    • close-only planning on push;
    • closing a PR that was already merged;
    • a lost or cancelled CI run;
    • a conflicting next-major PR;
    • strangers' and forks' PRs;
    • a supersede close that was never retried;
    • guard tests that a quoted uses: line would slip past.

After merging

  • Close Toolchain update: Node.js 24 #11. Node 24 is skipped on purpose, and Node 26 comes as a PR when it becomes LTS.
  • Add a ruleset on main that blocks force-pushes and deletion. It has no required checks, so your direct pushes, auto-release and mpv-updates.yml's pin commits keep working.
  • Run Toolchain updates by hand. It should open "Toolchain update: pnpm 11.27.1", run CI, and update-prs.yml should merge it.
  • Run CI once on a throwaway branch with .nvmrc set to 26, as an early look at Node 26.

🤖 Generated with Claude Code

Nawid3333 and others added 3 commits September 29, 2026 20:25
update-prs.yml decides every update pull request once its CI completes:
red is rerun once, then reported with the failed steps and log tails;
green merges only when nothing the extension ships changes, otherwise
it waits for the owner with the reason. toolchain-updates.yml opens
pull requests instead of issues, and .nvmrc is the one place the Node
major is named.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rive

update-prs.yml: the behind-main check is the last call before the
merge, and a merge that still lands on a moved main is reported; a
branch that moved meanwhile is no failure; the decide step times out
into the failure report; a pnpm pull request merges only when
package.json changes nothing but packageManager.

toolchain-updates.yml: the pnpm update changes packageManager alone,
so nothing from npm runs beside the write token; a push only closes
what an open pull request replaces; closes check state first; the CI
dispatch is retried; the weekly run rebuilds a bot-only pull request
that main has moved into conflict with, and starts CI on one without.

patched-libraries.yml: a newer version supersedes the older issue and
pull request. docs/maintenance.md maps every update source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the bots' own pull requests and titles count: a stranger's pull
request with such a title neither blocks an update nor is closed or
rebuilt, and a fork's is never touched. The weekly repair rebuilds on a
freshly fetched main, and starts CI where the head has no run that
decides (a cancelled one does not). A close that fails, or a pull
request closed while update-prs.yml decides, is no failure. A merged
branch is deleted. patched-libraries.yml supersedes in a sweep on every
run, so a close that failed once is retried. toolchain-updates.yml
reports its own failure as an issue. The guard tests read setup-node
steps however they are quoted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread tests/unit/checkPatchedUpdates.test.mjs Fixed
CodeQL flagged the regex built from the pattern list for escaping
dots and brackets but not backslashes. Both lists are now parsed the
same way and compared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Toolchain update: Node.js 24

2 participants