Skip to content

ci(update-prs): every update merges itself once CI is green (issue #10) - #120

Merged
Nawid3333 merged 2 commits into
mainfrom
claude/everything-merges-itself
Oct 1, 2026
Merged

Nawid3333 merged 2 commits into
mainfrom
claude/everything-merges-itself

Conversation

@Nawid3333

@Nawid3333 Nawid3333 commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Second part of making issue #10 closable. Your decision (2026-10-01): every update merges itself once CI is green, majors included. The hold label still stops any PR.

Now merges itself (before, it waited for you):

Update Extra check before it merges
Node LTS major (toolchain/node-*) changes only .nvmrc; the build is unchanged
pnpm's next major changes only packageManager. One that wants the lockfile rewritten fails CI and still waits
Dependabot npm majors a tooling major must leave the build unchanged. A shipped library's major runs CI on main afterwards, like the shipped group
patched-library majors as for minor and patch: a clean re-cut, then CI on main
fsaunpack changes only fsaunpack/package.json and fsaunpack/package-lock.json, and every version that lockfile adds is 7 days old (the npm lockfile is read with jq)
actionlint / zizmor images changes only the two Dockerfiles, and passes the dependency review
GitHub Actions changes only workflow and action files, and passes the dependency review. Needs your token (below)
upstream sync merged with --merge, keeping upstream's commits. Conditions: no conflict commit; nothing under .github/; no added file that main's history already has (something this fork deleted); every commit exists in Andrew's repository

Anything that fails a check still waits for you with one comment naming the check. A shipped library's major is recognised by its dependency-name matching the shipped-minor-and-patch patterns in main's .github/dependabot.yml. If that file can't be read, the update counts as tooling, whose build must not change, so it waits rather than merging untested.

Your token for GitHub Actions updates: GitHub's own workflow token may not merge or update a branch that changes workflow files. So update-prs.yml uses UPDATE_PRS_TOKEN, a fine-grained token of yours limited to this repository (Contents, Pull requests, Workflows: read and write), and only for those PRs. It never runs the PR's code. docs/maintenance.md, "A token for workflow updates", has the clicks. Until the secret exists, those PRs wait and say so.

Tests:

  • tests/workflows/update-prs-decide.test.sh: 354 checks, up from 293, with new scenarios for every kind above and each way it should wait.
  • Mutation check: I undid each of the 23 new guards one at a time. Every one made its own scenario fail.
  • actionlint, zizmor (no findings), all workflow tests, and lint, typecheck and the unit tests (935) pass.

Independent review (GLM), fixed in 8afe5b7, each with a scenario that fails when the fix is undone:

  • 100-item cap: gh pr view reads at most 100 files and 100 commits (measured: a 789-file, 217-commit PR gave 100 of each). A big upstream sync could have hidden a .github/ change or a foreign commit past the cap. Now the PR's real counts are compared, and a bigger PR waits.
  • Added-files list: for upstream syncs it was read through a process substitution, so a failed API call let the sync merge. Now a failure stops the run.
  • Upstream lockfiles: they get the 7-day age check too.
  • Broken token: an expired or revoked UPDATE_PRS_TOKEN is detected up front, and the PR says to renew it, instead of failing every run.
  • fsaunpack parser: only node_modules/ entries count as packages.
  • Format guard: a unit test pins the dependabot.yml layout the shipped-library list is read from.

Checked, no change needed: the dependency review runs on every PR to main, Actions and Docker ones included. The policy point stands as you chose it: third-party actions and images now merge after 5 days, a passing dependency review and green CI. Test count: 372 checks.

Docs: the docs/maintenance.md table and its "What update-prs.yml checks" section, CLAUDE.md, and the comments in dependabot.yml, sync-upstream.yml and toolchain-updates.yml.

Ships nothing.

🤖 Generated with Claude Code

Nawid3333 and others added 2 commits October 1, 2026 18:06
The owner's choice, 2026-10-01: Node majors, pnpm's next major, Dependabot's
majors (tooling and shipped libraries), patched-library majors, fsaunpack,
GitHub Actions, the actionlint and zizmor images and the upstream sync merge
themselves, as minor and patch updates already did. The hold label still stops
any of them. Each kind keeps or gains a check that holds it back when it is not
what it should be:

- only its bot's commits (the owner's merges of main too, made with their
  token); an upstream sync's commits must each exist in upstream's repository;
- only the files its kind changes: .nvmrc; workflow and action files; the two
  Dockerfiles; fsaunpack's package.json and package-lock.json; for an upstream
  sync anything but .github/, with no conflict commit and no added file that
  main's history has (one this project deleted, Chromium or YouTube say);
- the dependency review, now for Actions and Docker updates too;
- every version the lockfile adds 7 days old, fsaunpack's npm lockfile read
  with jq;
- the build unchanged for what must not ship. A shipped library's major comes
  on its own branch: it ships when its dependency-name is one of the patterns of
  main's shipped-minor-and-patch group, and CI then runs on main.

GitHub Actions updates change workflow files, which GITHUB_TOKEN may not merge
or update: update-prs uses the owner's fine-grained token, secret
UPDATE_PRS_TOKEN, for those alone (docs/maintenance.md says how to make it);
without it they wait, saying so. An upstream sync merges as a merge commit,
keeping upstream's commits; everything else squashes.

tests/workflows/update-prs-decide.test.sh: 354 checks (was 293), and each of
the 23 new guards, undone, fails its own scenario. actionlint, zizmor, all
workflow tests and the unit tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GLM (glm-5.3-flash) reviewed this PR; each finding that held is fixed here,
with a scenario that fails when the fix is undone:

- gh pr view reads at most 100 files and 100 commits (measured on gh 2.101:
  nodejs/node#66163, 789 files and 217 commits, gave 100 of each). A bigger
  upstream sync could have hidden a .github/ change or a foreign commit
  past that. The pull request's own counts (REST) are compared now; more, or
  unreadable counts, and it waits.
- The list of files an upstream sync adds was read through a process
  substitution, so a failed call gave the deleted-file check nothing and the
  sync merged. It goes through a file now: a failure stops the run.
- An upstream sync's lockfile gets the 7-day age check, as Dependabot's does.
- An expired or revoked UPDATE_PRS_TOKEN failed this workflow on every run with
  no word on the pull request. It is tried first now, and a broken one is a
  reason: renew it.
- fsaunpack's lockfile check counted any packages entry with a version (an npm
  workspace folder would have looked like an unknown package); only
  node_modules/ entries now.
- tests/unit/checkToolchain.test.mjs pins the layout update-prs.yml reads the
  shipped libraries from: one flow-style patterns line of quoted names, each a
  dependency of package.json (a block list made it fail, as meant).

Checked and left: the dependency review runs on every pull request to main
(Actions and Docker updates too). 372 checks pass (was 354).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Nawid3333
Nawid3333 merged commit 89d5ee7 into main Oct 1, 2026
10 checks passed
@Nawid3333
Nawid3333 deleted the claude/everything-merges-itself branch October 1, 2026 19:08
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.

1 participant