From 4007f69e704b26169c331e40d9431f910c214f9e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 7 Jul 2026 12:54:08 +0900 Subject: [PATCH] Throttle central PR workflow queue --- .github/workflows/close-empty-pr.yml | 4 ++ .github/workflows/codeql-pr.yml | 6 ++- .github/workflows/noema-review.yml | 5 ++- .github/workflows/osv-scanner-pr.yml | 4 ++ .../workflows/pr-review-merge-scheduler.yml | 7 ++-- .github/workflows/scorecard-pr.yml | 4 ++ .github/workflows/security-scan.yml | 4 ++ scripts/ci/pr_review_merge_scheduler.py | 2 +- .../test_required_workflow_queue_contract.py | 38 +++++++++++++++++++ 9 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 tests/test_required_workflow_queue_contract.py diff --git a/.github/workflows/close-empty-pr.yml b/.github/workflows/close-empty-pr.yml index 530384a2..0a3c7b01 100644 --- a/.github/workflows/close-empty-pr.yml +++ b/.github/workflows/close-empty-pr.yml @@ -12,6 +12,10 @@ on: pull_request_target: types: [opened, synchronize, reopened, ready_for_review] +concurrency: + group: close-empty-pr-${{ github.event.pull_request.base.repo.full_name || github.repository }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: pull-requests: write contents: read diff --git a/.github/workflows/codeql-pr.yml b/.github/workflows/codeql-pr.yml index 85145296..74023d03 100644 --- a/.github/workflows/codeql-pr.yml +++ b/.github/workflows/codeql-pr.yml @@ -9,6 +9,10 @@ on: pull_request: branches: [main, master, develop] +concurrency: + group: codeql-pr-${{ github.event.pull_request.base.repo.full_name || github.repository }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: contents: read @@ -121,4 +125,4 @@ jobs: category: "/language:${{ matrix.language }}-merge" upload: always ref: ${{ format('refs/pull/{0}/merge', github.event.pull_request.number) }} - sha: ${{ github.event.pull_request.merge_commit_sha }} \ No newline at end of file + sha: ${{ github.event.pull_request.merge_commit_sha }} diff --git a/.github/workflows/noema-review.yml b/.github/workflows/noema-review.yml index ca4cdaf6..b8ff3113 100644 --- a/.github/workflows/noema-review.yml +++ b/.github/workflows/noema-review.yml @@ -44,7 +44,10 @@ jobs: runs-on: ubuntu-latest if: >- github.event_name == 'workflow_dispatch' - || github.event_name == 'workflow_run' + || ( + github.event_name == 'workflow_run' + && github.event.workflow_run.conclusion != 'cancelled' + ) || ( github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository diff --git a/.github/workflows/osv-scanner-pr.yml b/.github/workflows/osv-scanner-pr.yml index b3c8a58b..0523887f 100644 --- a/.github/workflows/osv-scanner-pr.yml +++ b/.github/workflows/osv-scanner-pr.yml @@ -8,6 +8,10 @@ on: pull_request: branches: [main, master, develop] +concurrency: + group: osv-scanner-pr-${{ github.event.pull_request.base.repo.full_name || github.repository }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: # Upload SARIF to Security > Code Scanning. See github/codeql-action#2117. actions: read diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index cb143bb8..3810c021 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -33,7 +33,7 @@ on: review_dispatch_limit: description: Maximum OpenCode/Strix review dispatch actions per scheduler run required: false - default: "-1" + default: "1" type: string enable_auto_merge: description: Enable auto-merge for current-head approved PRs @@ -95,7 +95,7 @@ on: review_dispatch_limit: description: Maximum OpenCode/Strix review dispatch actions per scheduler run required: false - default: "-1" + default: "1" enable_auto_merge: description: Enable auto-merge for current-head approved PRs required: false @@ -129,6 +129,7 @@ concurrency: jobs: scan-pr-queue: + if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion != 'cancelled' runs-on: ubuntu-latest permissions: actions: write @@ -145,7 +146,7 @@ jobs: PROJECT_FLOW_INPUT: ${{ inputs.project_flow || vars.PROJECT_FLOW || '' }} PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number || github.event.workflow_run.pull_requests[0].number || inputs.pr_number || '' }} TRIGGER_REVIEWS: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_run' || github.event_name == 'push' || github.event_name == 'pull_request_target' || inputs.trigger_reviews == true }} - REVIEW_DISPATCH_LIMIT_INPUT: ${{ inputs.review_dispatch_limit || vars.REVIEW_DISPATCH_LIMIT || '' }} + REVIEW_DISPATCH_LIMIT_INPUT: ${{ inputs.review_dispatch_limit || vars.REVIEW_DISPATCH_LIMIT || '1' }} ENABLE_AUTO_MERGE: ${{ github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'pull_request_target' || github.event_name == 'workflow_run' || inputs.enable_auto_merge == true }} MERGE_MODE: ${{ inputs.merge_mode || vars.PR_MERGE_MODE || 'direct_or_auto' }} UPDATE_BRANCHES: ${{ github.event_name == 'schedule' || github.event_name == 'push' || github.event_name == 'pull_request_target' || github.event_name == 'workflow_run' || inputs.update_branches == true }} diff --git a/.github/workflows/scorecard-pr.yml b/.github/workflows/scorecard-pr.yml index f5436bfa..ad154f84 100644 --- a/.github/workflows/scorecard-pr.yml +++ b/.github/workflows/scorecard-pr.yml @@ -15,6 +15,10 @@ on: pull_request: branches: [main, master, develop] +concurrency: + group: scorecard-pr-${{ github.event.pull_request.base.repo.full_name || github.repository }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: contents: read diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 908a07b0..ffbc8075 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -25,6 +25,10 @@ on: pull_request: branches: [main, master, develop] +concurrency: + group: security-scan-${{ github.event.pull_request.base.repo.full_name || github.repository }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: actions: read contents: read diff --git a/scripts/ci/pr_review_merge_scheduler.py b/scripts/ci/pr_review_merge_scheduler.py index 6d83ae90..b85e981a 100644 --- a/scripts/ci/pr_review_merge_scheduler.py +++ b/scripts/ci/pr_review_merge_scheduler.py @@ -2720,7 +2720,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace: parser.add_argument( "--review-dispatch-limit", type=int, - default=int(os.environ.get("REVIEW_DISPATCH_LIMIT", "-1")), + default=int(os.environ.get("REVIEW_DISPATCH_LIMIT", "1")), help="Maximum OpenCode/Strix review dispatch actions per scheduler run; -1 means unlimited", ) parser.add_argument("--enable-auto-merge", action=argparse.BooleanOptionalAction, default=True) diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py new file mode 100644 index 00000000..19e443e0 --- /dev/null +++ b/tests/test_required_workflow_queue_contract.py @@ -0,0 +1,38 @@ +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] + + +def workflow_text(name: str) -> str: + return (REPO_ROOT / ".github" / "workflows" / name).read_text(encoding="utf-8") + + +def test_merge_scheduler_dispatches_one_review_by_default() -> None: + workflow = workflow_text("pr-review-merge-scheduler.yml") + + assert workflow.count('default: "1"') >= 2 + assert "vars.REVIEW_DISPATCH_LIMIT || '1'" in workflow + + +def test_required_pull_request_workflows_cancel_superseded_runs() -> None: + for filename in ( + "close-empty-pr.yml", + "codeql-pr.yml", + "osv-scanner-pr.yml", + "security-scan.yml", + "scorecard-pr.yml", + ): + workflow = workflow_text(filename) + + assert "concurrency:" in workflow + assert "github.event.pull_request.base.repo.full_name || github.repository" in workflow + assert "github.event.pull_request.number" in workflow + assert "cancel-in-progress: true" in workflow + + +def test_cancelled_review_workflow_runs_do_not_spawn_more_queue_work() -> None: + for filename in ("noema-review.yml", "pr-review-merge-scheduler.yml"): + workflow = workflow_text(filename) + + assert "github.event.workflow_run.conclusion != 'cancelled'" in workflow