@@ -72,6 +72,12 @@ concurrency:
7272# runs (test-release, e2e-full, yarn-berry-full, cargo-vex-matrix-full) and
7373# hosted-e2e still run. API errors, missing evidence and direct pushes run
7474# everything.
75+ # MERGE-MAIN REUSE: a pull_request push that only merged the base branch,
76+ # with the PR's own diff unchanged and the previous head green
77+ # (scripts/ci-reuse-pr-head.py, run by clippy), runs only clippy, the cheap
78+ # preflight jobs, test-release and hosted-e2e. The merge queue re-tests the
79+ # PR on the latest main before it lands; PRs into other branches and the
80+ # release/v5-prerelease PR never reuse.
7581jobs :
7682 # Required independently of ci-ok so the merge queue sees a compile/lint
7783 # failure immediately. Expensive jobs also depend on this preflight.
8490 actions : read
8591 outputs :
8692 reuse : ${{ steps.merge-queue.outputs.reuse }}
93+ pr_unchanged : ${{ steps.pr-head.outputs.unchanged }}
8794 steps :
8895 - name : Checkout
8996 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -99,6 +106,22 @@ jobs:
99106 GH_TOKEN : ${{ github.token }}
100107 run : python3 scripts/ci-reuse-merge-group.py
101108
109+ # A PR push that only merged the base branch, with the PR's own diff
110+ # unchanged and the previous head green, skips the test jobs: the
111+ # merge queue re-tests every entry on the latest main anyway (#1373).
112+ # This job and hosted-e2e still run. Only PRs into main (the only
113+ # queue), and never the v5 integration PR, whose full tier the queue
114+ # does not run.
115+ - name : Check for an unchanged PR diff
116+ id : pr-head
117+ if : github.event_name == 'pull_request' && github.base_ref == 'main' && github.head_ref != 'release/v5-prerelease'
118+ env :
119+ GH_TOKEN : ${{ github.token }}
120+ PR_HEAD_SHA : ${{ github.event.pull_request.head.sha }}
121+ PR_BASE_REF : ${{ github.base_ref }}
122+ PR_HEAD_REPOSITORY : ${{ github.event.pull_request.head.repo.full_name }}
123+ run : python3 scripts/ci-reuse-pr-head.py
124+
102125 - name : Install Rust
103126 # rustup is pre-installed on GitHub-hosted runners. `toolchain
104127 # install` with no name reads rust-toolchain.toml in the repo root,
@@ -133,7 +156,7 @@ jobs:
133156 # The napi addon is only ever loaded by Node, so cargo's own tests never
134157 # exercise its JS loader or the engine/provider boundary.
135158 node-addon :
136- if : github.event.pull_request.draft != true
159+ if : ( github.event.pull_request.draft != true) && needs.clippy.outputs.pr_unchanged != 'true'
137160 needs : clippy
138161 runs-on : ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }}
139162 timeout-minutes : 30
@@ -299,7 +322,7 @@ jobs:
299322 bash scripts/release-lint.sh --sync-only
300323
301324 test :
302- if : (github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
325+ if : (( github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) && needs.clippy.outputs.pr_unchanged != 'true'
303326 needs : clippy
304327 # No ubuntu-latest leg: `coverage` runs this same `cargo test
305328 # --workspace` (debug, default features, plus Go and vexctl) on ubuntu,
@@ -488,7 +511,8 @@ jobs:
488511
489512 test-release :
490513 # Each PR and main push runs the complete release-mode suite. The merge
491- # queue already skips this job because each constituent PR ran it.
514+ # queue already skips this job because each constituent PR ran it, so
515+ # an unchanged merge-main PR push (pr_unchanged) still runs it too.
492516 if : (github.event.pull_request.draft != true && github.event_name != 'merge_group') && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
493517 needs : clippy
494518 runs-on : ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-16' }}
@@ -535,7 +559,7 @@ jobs:
535559 run : python3 scripts/ci-test-shard.py "$TEST_SHARD" "$TEST_SHARD_COUNT" --locked --profile ci-release
536560
537561 coverage :
538- if : github.event.pull_request.draft != true
562+ if : ( github.event.pull_request.draft != true) && needs.clippy.outputs.pr_unchanged != 'true'
539563 needs : clippy
540564 # Code coverage via cargo-llvm-cov (LLVM source-based instrumentation).
541565 # Reports as a markdown table in the job summary and uploads the raw
@@ -662,7 +686,7 @@ jobs:
662686 # Dockerfile.base compiles the full-LTO release binary inside Docker, with
663687 # no cache. Build it once per run and hand the image to every docker leg.
664688 docker-base :
665- if : (github.event.pull_request.draft != true && needs.clippy.outputs.reuse != 'true') && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.head_ref == 'release/v5-prerelease')
689+ if : (( github.event.pull_request.draft != true && needs.clippy.outputs.reuse != 'true') && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.head_ref == 'release/v5-prerelease')) && needs.clippy.outputs.pr_unchanged != 'true'
666690 needs : clippy
667691 runs-on : ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-22.04' || 'depot-ubuntu-22.04-4' }}
668692 timeout-minutes : 30
@@ -952,7 +976,7 @@ jobs:
952976 # test binaries directly from the same checkout path, so `CARGO_BIN_EXE_*`
953977 # and `CARGO_MANIFEST_DIR` resolve as they did under `cargo test`.
954978 e2e-build :
955- if : github.event.pull_request.draft != true
979+ if : ( github.event.pull_request.draft != true) && needs.clippy.outputs.pr_unchanged != 'true'
956980 needs : clippy
957981 outputs :
958982 reuse : ${{ needs.clippy.outputs.reuse }}
@@ -1018,7 +1042,7 @@ jobs:
10181042 # Lean scope still compiles every test target on Windows in the merge
10191043 # queue (one job): lean pull_request runs skip Windows, and a cfg(unix)
10201044 # slip only shows up here (#1324). Its consumers stay full-scope only.
1021- if : (github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'merge_group' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
1045+ if : (( github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'merge_group' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) && needs.clippy.outputs.pr_unchanged != 'true'
10221046 needs : clippy
10231047 outputs :
10241048 reuse : ${{ needs.clippy.outputs.reuse }}
@@ -2115,7 +2139,7 @@ jobs:
21152139 # Dropping that `needs` also dropped the draft skip it inherited, so
21162140 # gate on draft here directly (push/merge_group/schedule still run).
21172141 # Only wait for the clippy preflight.
2118- if : github.event.pull_request.draft != true && needs.clippy.outputs.reuse != 'true'
2142+ if : ( github.event.pull_request.draft != true && needs.clippy.outputs.reuse != 'true') && needs.clippy.outputs.pr_unchanged != 'true'
21192143 needs : clippy
21202144 runs-on : ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }}
21212145 timeout-minutes : 40
@@ -2159,7 +2183,7 @@ jobs:
21592183 # Dropping that `needs` also dropped the draft skip it inherited, so
21602184 # gate on draft here directly (push/merge_group/schedule still run).
21612185 # Only wait for the clippy preflight.
2162- if : github.event.pull_request.draft != true && needs.clippy.outputs.reuse != 'true'
2186+ if : ( github.event.pull_request.draft != true && needs.clippy.outputs.reuse != 'true') && needs.clippy.outputs.pr_unchanged != 'true'
21632187 needs : clippy
21642188 strategy :
21652189 fail-fast : false
@@ -2398,7 +2422,7 @@ jobs:
23982422 # Dropping that `needs` also dropped the draft skip it inherited, so
23992423 # gate on draft here directly (push/merge_group/schedule still run).
24002424 # Only wait for the clippy preflight.
2401- if : (github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
2425+ if : (( github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')) && needs.clippy.outputs.pr_unchanged != 'true'
24022426 needs : clippy
24032427 runs-on : ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }}
24042428 timeout-minutes : 30
0 commit comments