Skip to content

Commit 2d54909

Browse files
Phlogistiqueclaude
andauthored
Serialize workflow runs per PR (#47)
Two runs can act on the same PR concurrently: the push that finishes a conflict resolution fires a `synchronize` event while the conflict label is still attached (the label is the gate and only comes off at the end), so the follow-up run races the one that triggered it. A per-PR concurrency group queues the follow-up instead; `cancel-in-progress: false` so a running update is never killed mid-mutation. The group is keyed by PR number rather than repo-wide on purpose: GitHub keeps only the newest *pending* run per group, so a repo-wide group could silently drop the stack update for one merge when several land in quick succession. Also added to both README example workflows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX --- _Generated by [Claude Code](https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 856685e commit 2d54909

3 files changed

Lines changed: 17 additions & 2 deletions

File tree

.github/workflows/update-pr-stack.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ permissions:
99
contents: write
1010
pull-requests: write
1111

12+
# Serialize runs per PR: the push that finishes a conflict resolution fires a
13+
# synchronize event while the conflict label is still attached, so without a
14+
# group the follow-up run races the one that triggered it.
15+
concurrency:
16+
group: update-pr-stack-${{ github.event.pull_request.number }}
17+
cancel-in-progress: false
18+
1219
jobs:
1320
update-pr-stack:
1421
runs-on: ubuntu-latest

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ on:
8080
pull_request:
8181
types: [closed, synchronize]
8282

83+
concurrency:
84+
group: update-pr-stack-${{ github.event.pull_request.number }}
85+
cancel-in-progress: false
86+
8387
jobs:
8488
update-pr-stack:
8589
runs-on: ubuntu-latest
@@ -111,6 +115,10 @@ permissions:
111115
contents: write
112116
pull-requests: write
113117

118+
concurrency:
119+
group: update-pr-stack-${{ github.event.pull_request.number }}
120+
cancel-in-progress: false
121+
114122
jobs:
115123
update-pr-stack:
116124
runs-on: ubuntu-latest

tests/test_e2e.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ wait_for_synchronize_workflow() {
558558
log_cmd gh run view "$target_run_id" --repo "$REPO_FULL_NAME" --log || echo >&2 "Could not fetch logs for run $target_run_id"
559559
return 1
560560
fi
561-
elif [[ "$run_status" == "queued" || "$run_status" == "in_progress" || "$run_status" == "waiting" ]]; then
561+
elif [[ "$run_status" == "queued" || "$run_status" == "in_progress" || "$run_status" == "waiting" || "$run_status" == "pending" ]]; then
562562
echo >&2 "Workflow $target_run_id is $run_status. Sleeping $sleep_time seconds."
563563
else
564564
echo >&2 "Workflow $target_run_id has unexpected status: $run_status. Conclusion: $run_conclusion"
@@ -665,7 +665,7 @@ wait_for_workflow() {
665665
log_cmd gh run view "$target_run_id" --repo "$REPO_FULL_NAME" --log || echo >&2 "Could not fetch logs for run $target_run_id"
666666
return 1
667667
fi
668-
elif [[ "$run_status" == "queued" || "$run_status" == "in_progress" || "$run_status" == "waiting" ]]; then
668+
elif [[ "$run_status" == "queued" || "$run_status" == "in_progress" || "$run_status" == "waiting" || "$run_status" == "pending" ]]; then
669669
echo >&2 "Workflow $target_run_id is $run_status. Sleeping $sleep_time seconds."
670670
else
671671
echo >&2 "Workflow $target_run_id has unexpected status: $run_status. Conclusion: $run_conclusion"

0 commit comments

Comments
 (0)