From 8a479bc301d0ca27ada600e76a52034f5e5e2fb9 Mon Sep 17 00:00:00 2001 From: owenpearson Date: Tue, 29 Sep 2026 14:02:31 +0100 Subject: [PATCH] ci: run one workflow per pull request with concurrency groups 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) --- .github/workflows/check.yml | 8 ++++++++ .github/workflows/features.yml | 6 ++++++ .github/workflows/lint.yml | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f69bf097..36089c36 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -4,6 +4,8 @@ # As directed from: # https://docs.github.com/en/actions/guides/building-and-testing-python#starting-with-the-python-workflow-template +name: Check + on: workflow_dispatch: pull_request: @@ -11,6 +13,12 @@ on: branches: - main +# One run per pull request; a new event supersedes the one in flight. +# Pushes to main and manual runs group by ref and always run to completion. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + permissions: {} jobs: diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 03c6b07d..47f9bc36 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -6,6 +6,12 @@ on: branches: - main +# One run per pull request; a new event supersedes the one in flight. +# Pushes to main and manual runs group by ref and always run to completion. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + permissions: {} jobs: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d1027713..cfbcfed0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,6 +6,12 @@ on: branches: - main +# One run per pull request; a new event supersedes the one in flight. +# Pushes to main and manual runs group by ref and always run to completion. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + permissions: {} jobs: