Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/cancel-closed-pr-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: Cancel CI for closed PRs

# A PR's concurrency group only cancels its in-flight runs when a newer run of
# the same PR starts. Merging or closing starts none, so without this the runs
# keep holding the GPU runners until they finish.
#
# Why a sweep rather than reacting to the close event:
# - pull_request: closed sets GITHUB_REF to refs/heads/main on merge, so the
# workflows' cancel-in-progress is false in exactly the case that matters,
# and a fork contributor's run of it waits for maintainer approval.
# - pull_request_target is never held for approval, but it is a HIGH
# dangerous-triggers finding in the security scan.
# A scheduled run comes from main, is never held for approval, and needs no
# exception. The cost is up to one interval before a closed PR's runs stop.
on:
schedule:
- cron: "7-59/10 * * * *"
workflow_dispatch:

permissions:
actions: write
pull-requests: read

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
cancel:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Cancel in-flight runs of closed PRs
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
inflight=$(for status in queued in_progress waiting pending; do
gh api --paginate "repos/$REPO/actions/runs?event=pull_request&status=$status&per_page=100" \
--jq '.workflow_runs[] | [.id, .name, .head_repository.full_name, .head_branch, .head_sha] | @tsv'
done)
if [ -z "$inflight" ]; then
echo "No in-flight PR runs"
exit 0
fi

# Branch names come from PR authors: they are only ever data here,
# URL-encoded for the query and compared, never evaluated.
declare -A pr_state
while IFS=$'\t' read -r id name head_repo branch sha; do
key="$head_repo:$branch:$sha"
if [ -z "${pr_state[$key]+set}" ]; then
head=$(printf '%s:%s' "${head_repo%%/*}" "$branch" | jq -sRr @uri)
# Fork runs carry no PR number, so find the PR by its head branch.
# Only a PR whose head is this commit counts, and any open one wins.
pr_state[$key]=$(SHA="$sha" gh api "repos/$REPO/pulls?state=all&head=$head&per_page=100" \
--jq '[.[] | select(.head.sha == env.SHA) | .state] | if index("open") then "open" elif length > 0 then "closed" else "none" end')
fi
if [ "${pr_state[$key]}" != "closed" ]; then
continue
fi
# A run can finish between listing and cancelling; that's fine.
if gh api -X POST "repos/$REPO/actions/runs/$id/cancel" > /dev/null 2>&1; then
echo "Cancelled $name ($id) from closed PR $head_repo:$branch"
else
echo "Could not cancel $name ($id); it has probably just finished"
fi
done <<< "$inflight"
3 changes: 2 additions & 1 deletion .github/workflows/iris-external-validation-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
# PR number, not head branch: two forks' "patch-1" branches must not cancel each other.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/iris-performance-regression-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
# PR number, not head branch: two forks' "patch-1" branches must not cancel each other.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/iris-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
# PR number, not head branch: two forks' "patch-1" branches must not cancel each other.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
Expand Down
Loading