ci: run one workflow per pull request with concurrency groups - #722
Open
owenpearson wants to merge 1 commit into
Open
owenpearson wants to merge 1 commit into
owenpearson wants to merge 1 commit into
Conversation
All three CI workflows fire on `pull_request` and on `push` to main. A single push that moves several branches in a stacked chain makes GitHub fire a `pull_request` synchronize both for the PR whose head moved and for the PR whose base moved, so one PR gets two runs on the identical head SHA a second apart. Each duplicate costs a full seven-version check matrix plus lint and build. Group by workflow and pull request number so those two synchronizes share a group and the later one supersedes the earlier. Keying on `github.workflow` holds the three workflows in separate groups, so the 22-second lint run cannot cancel the 19-minute check run. The `github.ref` fallback covers `push` to main and `workflow_dispatch`, where `pull_request.number` is empty. `cancel-in-progress` is limited to pull request events: every merge commit on main gets a run that finishes, which keeps the required status check history intact. `check.yml` gains a name, so the Actions UI and the concurrency group use `Check` rather than the workflow's file path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 30 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This branch was successfully deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What
Adds a top-level
concurrencyblock tocheck.yml,lint.ymlandfeatures.yml:check.ymlalso gainsname: Check. Without aname:key itsgithub.workflowevaluates to the literal string.github/workflows/check.yml, which is both the run name the Actions UI shows and, now, part of the concurrency group key.lint.ymlandfeatures.ymlalready carry names.release.ymlis deliberately left alone — it runs on tags, not on the PR/push triggers this addresses.Why
All three workflows fire on the same triggers:
pull_requestpluspushtomain(check.ymladdsworkflow_dispatch). In a stacked-PR chain, onegit pushthat updates several branches makes GitHub fire apull_requestsynchronize both for the PR whose head moved and for the PR whose base moved. The result is two runs of the same workflow, for the same PR, on the same commit.Every run currently on PR #716's head SHA
b9a4f00a, straight from the API:36569873822.github/workflows/check.yml2026-09-29T12:42:07Z36569876066.github/workflows/check.yml2026-09-29T12:42:08Z365698737752026-09-29T12:42:07Z365698756782026-09-29T12:42:08Z365698769332026-09-29T12:42:08Z365698781452026-09-29T12:42:09ZSix runs where three would do — every workflow duplicated, one second apart, all
pull_requestevents on an identical commit. PR #717 shows the same pattern: runs36569872967(12:42:06Z) and36569873206(12:42:07Z), both on headec5d1b19.Each duplicated
checkrun costs a full 7-version matrix (~16-19 minutes), plus the duplicated lint and build.Design notes
github.workflowbelongs in the group key. Without it the three workflows share one group and cancel each other. Lint finishes in ~22 seconds and would kill the 19-minute check run.github.event.pull_request.number— the PR, not the branch — is what actually de-duplicates, because the duplicate events are two synchronizes for the same PR.|| github.reffallback is required.pull_request.numberis empty forpush: mainand forworkflow_dispatch; without a fallback every non-PR run collapses into one group named<workflow>-, and consecutive pushes tomainwould cancel each other. With it,maingetsrefs/heads/mainand aworkflow_dispatchon a branch getsrefs/heads/<branch>— a different group from that branch's PR group, so a manual re-run cannot be cancelled by a PR event.cancel-in-progressis gated ongithub.event_name == 'pull_request'on purpose. Onpush: mainevery merge commit should get a run that completes; cancelling would leave commits onmainwith no finished check and degrade required-status-check history.Tradeoff
When merging down a stack one PR at a time with minutes between merges, a base-branch update can cancel a run that is already 15 minutes into the 19-minute suite and restart it from zero. Total CI minutes still drop, but time-to-green for that one PR can get worse.
cancel-in-progress: falseis the alternative: it collapses the duplicate by queueing instead of replacing, which saves concurrency slots but not minutes. The cancelling variant is the right default — a superseded run is testing a commit nobody is waiting on.Note for tooling
Superseded runs conclude
cancelled, notsuccess. The PR status rollup is unaffected, since GitHub uses the latest run per check name, but any tooling that asserts "every run on this SHA succeeded" needs to treatcancelledas skippable.Validation
yaml.safe_loadsucceeds on each. (on:parsing as the boolean keyTrueunder YAML 1.1 is expected.)concurrencyis top-level (column 0) in exactly the three files, not nested underjobs:.ruff check .passes.check.yml,lint.ymlandfeatures.yml.🤖 Generated with Claude Code