From eb36ffef26027269aa7669635c1043daa0a6dda9 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Wed, 7 Oct 2026 19:22:33 -0400 Subject: [PATCH 1/3] Skip draft PRs and run macOS legs off the PR path The Actions queue jammed on 2026-10-07: about 140 macOS jobs queued against the roughly 20 that run at once, and no PR merged for five hours. One PR push asked for about 28 macOS jobs from ci.yml and dozens more from the compatibility workflows (Gradle cells, Bun, Poetry, vlt, PDM, Composer, Go, Pipenv, sbt), and agents push every few minutes, so 160 of 253 CI runs since noon were cancelled part-way. Drafts now skip every job: each pull_request trigger adds ready_for_review, and the root jobs gate on `github.event.pull_request.draft != true`, so marking a PR ready runs the full set. macOS legs no longer run on pull_request. Matrices that list `os:` explicitly exclude macos-latest on that event. Matrices built only from `include:` rows move their macOS rows into a sibling `-macos` job gated on `github.event_name != 'pull_request'`, which reuses the original steps through a YAML anchor. In ci.yml the macOS legs still run in the merge queue (the required ci-ok gate), on push to main and nightly; ci-ok now also needs e2e-macos, yarn-berry-e2e-macos and cargo-vex-matrix-macos. The compatibility workflows have no merge_group trigger, so their macOS legs run on push to main and on their schedules. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/bench.yml | 8 +- .github/workflows/bun-compatibility.yml | 11 ++ .github/workflows/ci.yml | 162 ++++++++++++++----- .github/workflows/composer-compatibility.yml | 25 ++- .github/workflows/go-compatibility.yml | 25 ++- .github/workflows/gradle-compatibility.yml | 8 + .github/workflows/npm-compatibility.yml | 2 + .github/workflows/pdm-compatibility.yml | 30 +++- .github/workflows/pipenv-compatibility.yml | 23 ++- .github/workflows/pnpm-compatibility.yml | 2 + .github/workflows/poetry-compatibility.yml | 8 + .github/workflows/sbt-compatibility.yml | 7 + .github/workflows/vlt-compatibility.yml | 57 +++++-- 13 files changed, 292 insertions(+), 76 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 7ae9f211e..f8ff48804 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -23,7 +23,7 @@ name: Benchmarks on: pull_request: - types: [opened, synchronize, reopened, labeled, unlabeled] + types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] paths: - '.github/workflows/bench.yml' - '.cargo/**' @@ -69,8 +69,10 @@ jobs: name: scan performance # Labels re-trigger the workflow; only this one changes the outcome. if: >- - (github.event.action != 'labeled' && github.event.action != 'unlabeled') - || github.event.label.name == 'performance-regression-accepted' + github.event.pull_request.draft != true && ( + (github.event.action != 'labeled' && github.event.action != 'unlabeled') + || github.event.label.name == 'performance-regression-accepted' + ) # Job-level, so an unrelated label (skipped above) cannot cancel a run # in progress. A newer push to the same PR supersedes the older run. concurrency: diff --git a/.github/workflows/bun-compatibility.yml b/.github/workflows/bun-compatibility.yml index 9894fe3b4..a60fe94d6 100644 --- a/.github/workflows/bun-compatibility.yml +++ b/.github/workflows/bun-compatibility.yml @@ -15,6 +15,7 @@ name: Bun patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - '.github/actions/pin-socket-hosts/**' @@ -111,10 +112,14 @@ env: jobs: build: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: @@ -171,6 +176,8 @@ jobs: - {os: windows-latest, bun: '0.8.1'} - {os: windows-latest, bun: '1.0.0'} - {os: windows-latest, bun: '1.0.36'} + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: @@ -363,10 +370,14 @@ jobs: binary: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, ubuntu-22.04, macos-latest, windows-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6dedff584..8038c9bd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: # workflow (cache-poisoning). branches: [main] pull_request: + types: [opened, synchronize, reopened, ready_for_review] # The merge queue tests each queued PR merged onto the tip of main (plus # the PRs ahead of it) before it lands. `ci-ok` below is the required # check, so this event has to run the same pull_request-tier job set. @@ -44,6 +45,7 @@ concurrency: jobs: clippy: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 20 steps: @@ -76,6 +78,7 @@ jobs: # The napi addon is only ever loaded by Node, so cargo's own tests never # exercise its JS loader or the engine/provider boundary. node-addon: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 30 steps: @@ -108,6 +111,7 @@ jobs: # Check the standalone installer, release scripts, and native installer # test harnesses. lint-ecosystems: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -199,6 +203,7 @@ jobs: # CHANGELOG has a dated, non-empty section for the new version and the # tag doesn't already exist. release-readiness: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest steps: - name: Checkout @@ -236,6 +241,7 @@ jobs: bash scripts/release-lint.sh --sync-only test: + if: github.event.pull_request.draft != true # No ubuntu-latest leg: `coverage` runs this same `cargo test # --workspace` (debug, default features, plus Go and vexctl) on ubuntu, # instrumented, and fails on any test failure. A plain ubuntu leg ran @@ -244,6 +250,9 @@ jobs: fail-fast: false matrix: os: [macos-latest, windows-latest] + exclude: + # macOS legs run on main, the merge queue and nightly, not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 50 env: @@ -395,6 +404,7 @@ jobs: cargo test --workspace --no-fail-fast test-release: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest # Every tests/ target is its own optimized link (~240 test binaries). # The manifest-less VEX suites share two multi-module binaries @@ -429,6 +439,7 @@ jobs: run: cargo test --workspace --profile ci-release coverage: + if: github.event.pull_request.draft != true # Code coverage via cargo-llvm-cov (LLVM source-based instrumentation). # Reports as a markdown table in the job summary and uploads the raw # lcov.info file as a workflow artifact. No threshold gating — the @@ -541,6 +552,7 @@ jobs: # Dockerfile.base compiles the full-LTO release binary inside Docker, with # no cache. Build it once per run and hand the image to every docker leg. docker-base: + if: github.event.pull_request.draft != true runs-on: ubuntu-22.04 timeout-minutes: 30 permissions: @@ -790,6 +802,7 @@ jobs: retention-days: 30 dispatch-tests: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -825,10 +838,14 @@ jobs: # test binaries directly from the same checkout path, so `CARGO_BIN_EXE_*` # and `CARGO_MANIFEST_DIR` resolve as they did under `cargo test`. e2e-build: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + exclude: + # macOS legs run on main, the merge queue and nightly, not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} # Windows compiles the same ~240 targets ~1.6x slower (see `test`). timeout-minutes: ${{ matrix.os == 'windows-latest' && 60 || 45 }} @@ -954,8 +971,6 @@ jobs: # every cargo-vex-matrix leg (ubuntu, macOS and Windows). - os: ubuntu-latest suite: e2e_safety_pnpm - - os: macos-latest - suite: e2e_safety_pnpm # pnpm-on-Windows uses junctions for symlinks and copies # (not hardlinks) by default, so the CoW invariant holds # vacuously. Test still runs to verify apply doesn't error @@ -981,15 +996,10 @@ jobs: - os: ubuntu-latest suite: e2e_redirect_npm_build npm_required: '1' - - os: macos-latest - suite: e2e_redirect_npm_build - npm_required: '1' - os: windows-latest suite: e2e_redirect_npm_build - os: ubuntu-latest suite: e2e_redirect_rush_sim - - os: macos-latest - suite: e2e_redirect_rush_sim - os: windows-latest suite: e2e_redirect_rush_sim # Hermetic real-bun capstones (wiremock patch service, real `bun @@ -1020,10 +1030,6 @@ jobs: suite: e2e_redirect_bun_build bun: '1.4.2' test_filter: --include-ignored - - os: macos-latest - suite: e2e_redirect_bun_build - bun: '1.4.2' - test_filter: --include-ignored - os: windows-latest suite: e2e_redirect_bun_build bun: '1.4.2' @@ -1040,10 +1046,6 @@ jobs: suite: e2e_vendor_bun_build bun: '1.4.2' test_filter: --include-ignored - - os: macos-latest - suite: e2e_vendor_bun_build - bun: '1.4.2' - test_filter: --include-ignored - os: windows-latest suite: e2e_vendor_bun_build bun: '1.4.2' @@ -1060,10 +1062,6 @@ jobs: suite: mode_migration_bun bun: '1.4.2' test_filter: --include-ignored - - os: macos-latest - suite: mode_migration_bun - bun: '1.4.2' - test_filter: --include-ignored - os: windows-latest suite: mode_migration_bun bun: '1.4.2' @@ -1097,7 +1095,6 @@ jobs: # 0.0.0-32, B rc.12/rc.14 (rc.14 legs reach public npm), C rc.32, # D 1.0.4/1.0.7, E 1.1.1, F 1.2.0. - {os: ubuntu-latest, suite: e2e_redirect_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - - {os: macos-latest, suite: e2e_redirect_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: windows-latest, suite: e2e_redirect_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_redirect_vlt_build, vlt: '0.0.0-16', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_redirect_vlt_build, vlt: '0.0.0-32', test_filter: --include-ignored vlt_pinned_matrix} @@ -1106,7 +1103,6 @@ jobs: - {os: ubuntu-latest, suite: e2e_redirect_vlt_build, vlt: '1.0.4', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_redirect_vlt_build, vlt: '1.1.1', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_vendor_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - - {os: macos-latest, suite: e2e_vendor_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: windows-latest, suite: e2e_vendor_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_vendor_vlt_build, vlt: '0.0.0-32', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_vendor_vlt_build, vlt: '1.0.0-rc.14', test_filter: --include-ignored vlt_pinned_matrix} @@ -1114,7 +1110,6 @@ jobs: - {os: ubuntu-latest, suite: e2e_vendor_vlt_build, vlt: '1.0.4', test_filter: --include-ignored vlt_pinned_matrix} - {os: windows-latest, suite: e2e_vendor_vlt_build, vlt: '1.0.0-rc.14', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: mode_migration_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - - {os: macos-latest, suite: mode_migration_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: windows-latest, suite: mode_migration_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: mode_migration_vlt, vlt: '0.0.0-32', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: mode_migration_vlt, vlt: '1.0.0-rc.14', test_filter: --include-ignored vlt_pinned_matrix, vlt_upgrade: '1.2.0'} @@ -1123,12 +1118,10 @@ jobs: # explicit hardlink linker. - {os: ubuntu-latest, suite: e2e_safety_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_safety_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix, vlt_store_linker: 'hardlink'} - - {os: macos-latest, suite: e2e_safety_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix, vlt_store_linker: 'hardlink'} - {os: windows-latest, suite: e2e_safety_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix, vlt_store_linker: 'hardlink'} # rc.12 gets the definite no-hook advisory; windows rc.14 runs the # legacy DepIDs on NTFS with pre-junction symlinks. - {os: ubuntu-latest, suite: e2e_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - - {os: macos-latest, suite: e2e_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: windows-latest, suite: e2e_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_vlt, vlt: '0.0.0-32', test_filter: --include-ignored vlt_pinned_matrix} - {os: ubuntu-latest, suite: e2e_vlt, vlt: '1.0.0-rc.12', test_filter: --include-ignored vlt_pinned_matrix} @@ -1141,7 +1134,6 @@ jobs: # skip. Node 24 (step below): the # corepack pnpm@10/11 legs require it. - {os: ubuntu-latest, suite: e2e_redirect_pnpm_build, test_filter: '--ignored --skip pnpm_pinned_matrix'} - - {os: macos-latest, suite: e2e_redirect_pnpm_build, test_filter: '--ignored --skip pnpm_pinned_matrix'} - {os: windows-latest, suite: e2e_redirect_pnpm_build, test_filter: '--ignored --skip pnpm_pinned_matrix'} # Real-uv hosted/vendored capstones ending in manifest-less VEX: # the oldest and newest line + the 0.5.x boundary (0.5.4 still @@ -1152,12 +1144,10 @@ jobs: - {os: ubuntu-latest, suite: e2e_redirect_uv_build, uv: '0.5.4'} - {os: ubuntu-latest, suite: e2e_redirect_uv_build, uv: '0.5.5'} - {os: ubuntu-latest, suite: e2e_redirect_uv_build, uv: '0.12.17'} - - {os: macos-latest, suite: e2e_redirect_uv_build, uv: '0.12.17'} - {os: ubuntu-latest, suite: e2e_vendor_pypi_build, uv: '0.1.45', test_filter: --include-ignored} - {os: ubuntu-latest, suite: e2e_vendor_pypi_build, uv: '0.5.4', test_filter: --include-ignored} - {os: ubuntu-latest, suite: e2e_vendor_pypi_build, uv: '0.5.5', test_filter: --include-ignored} - {os: ubuntu-latest, suite: e2e_vendor_pypi_build, uv: '0.12.17', test_filter: --include-ignored} - - {os: macos-latest, suite: e2e_vendor_pypi_build, uv: '0.12.17', test_filter: --include-ignored} # The Poetry / PDM / Hatch / Pipenv / pip / deno manifest-less VEX # capstones share ONE test binary (`e2e_vex_build`, a module per # tool — one optimized link in test-release instead of six), so @@ -1172,7 +1162,6 @@ jobs: - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'poetry:: --ignored', poetry: '1.8.5'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'poetry:: --ignored', poetry: '2.0.1'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'poetry:: --ignored', poetry: '2.4.3'} - - {os: macos-latest, suite: e2e_vex_build, test_filter: 'poetry:: --ignored', poetry: '2.4.3'} # Real PDM / Hatch capstones (wiremock Socket API that also serves # the hosted wheel; PyPI for the tool bootstrap + six). # PDM: lock 2 (1.4), refused 3.1 (1.15) and 4.2 (2.7), 4.3 (2.8), @@ -1183,7 +1172,6 @@ jobs: - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'pdm:: --ignored', pdm: '2.8.2'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'pdm:: --ignored', pdm: '2.25.9'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'pdm:: --ignored', pdm: '2.29.2'} - - {os: macos-latest, suite: e2e_vex_build, test_filter: 'pdm:: --ignored', pdm: '2.29.2'} # Hatch: 1.0 (hatch.toml env vendoring refused, needs >= 1.2), # 1.2, the virtualenv<21 window (1.9, 1.14) and current. - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'hatch:: --ignored', hatch: '1.0.0'} @@ -1191,16 +1179,13 @@ jobs: - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'hatch:: --ignored', hatch: '1.9.7'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'hatch:: --ignored', hatch: '1.14.2'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'hatch:: --ignored', hatch: '1.18.1'} - - {os: macos-latest, suite: e2e_vex_build, test_filter: 'hatch:: --ignored', hatch: '1.18.1'} # Real Pipenv / pip capstones (mock patch server; the tools are # bootstrapped from PyPI). `pipenv:` / `pip:` hold one or more # space-separated releases the suite loops over. The middle # Pipenv releases are in e2e-full. - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'pipenv:: --ignored', pipenv: '2022.12.19'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'pipenv:: --ignored', pipenv: '2026.8.0'} - - {os: macos-latest, suite: e2e_vex_build, test_filter: 'pipenv:: --ignored', pipenv: '2022.12.19 2026.8.0'} - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'pip:: --ignored', pip: '22 23 24 25 26'} - - {os: macos-latest, suite: e2e_vex_build, test_filter: 'pip:: --ignored', pip: '22 26'} # Real-Maven hosted + vendored capstones, one leg per Maven line: # 3.6 (pre http-blocker), 3.8 (resolver 1.6: no trusted checksums), # 3.9 (trusted checksums), 4.0 rc. Hosted also runs both sides of @@ -1212,18 +1197,15 @@ jobs: - {os: ubuntu-latest, suite: e2e_redirect_maven_build, jvm_tool: maven, maven: '3.9.4'} - {os: ubuntu-latest, suite: e2e_redirect_maven_build, jvm_tool: maven, maven: '3.9.16'} - {os: ubuntu-latest, suite: e2e_redirect_maven_build, jvm_tool: maven, maven: '4.0.0-rc-6'} - - {os: macos-latest, suite: e2e_redirect_maven_build, jvm_tool: maven, maven: '3.9.16'} - {os: ubuntu-latest, suite: e2e_vendor_maven_build, jvm_tool: maven, maven: '3.6.3'} - {os: ubuntu-latest, suite: e2e_vendor_maven_build, jvm_tool: maven, maven: '3.8.9'} - {os: ubuntu-latest, suite: e2e_vendor_maven_build, jvm_tool: maven, maven: '3.9.16'} - {os: ubuntu-latest, suite: e2e_vendor_maven_build, jvm_tool: maven, maven: '4.0.0-rc-6'} - - {os: macos-latest, suite: e2e_vendor_maven_build, jvm_tool: maven, maven: '3.9.16'} - {os: ubuntu-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.6.3', test_filter: '--ignored maven_reactor'} - {os: ubuntu-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.8.9', test_filter: '--ignored maven_reactor'} - {os: ubuntu-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.9.2', test_filter: '--ignored maven_reactor'} - {os: ubuntu-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.9.16', test_filter: '--ignored maven_reactor'} - {os: ubuntu-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '4.0.0-rc-6', test_filter: '--ignored maven_reactor'} - - {os: macos-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.9.16', test_filter: '--ignored maven_reactor'} - {os: windows-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.9.16', test_filter: '--ignored maven_reactor'} # Real-Gradle capstones, PR tier: one leg per Gradle line x {agent + # hosted, vendor + multi-project} on ubuntu, each on its line's LTS @@ -1256,7 +1238,6 @@ jobs: # the oldest and newest here, 7-9 on ubuntu in e2e-full. - {os: ubuntu-latest, suite: e2e_nuget_dotnet_build, dotnet: '6'} - {os: ubuntu-latest, suite: e2e_nuget_dotnet_build, dotnet: '10'} - - {os: macos-latest, suite: e2e_nuget_dotnet_build, dotnet: '8'} # Real deno negative capstone (no hosted/vendored wiring exists for # deno; VEX must attest nothing), one leg per major. - {os: ubuntu-latest, suite: e2e_vex_build, test_filter: 'deno:: --ignored', deno: '1.46.3'} @@ -1711,6 +1692,67 @@ jobs: # and newest release of each tool and every vlt era there); main pushes, # v5 landings, the nightly schedule and dispatch run them with the `e2e` # steps. + + # The macOS rows of `e2e`: they run on main, the merge queue and + # nightly, not on every PR push, so PRs stop queueing on the small + # macOS runner pool. + e2e-macos: + if: github.event_name != 'pull_request' + # These jobs consume e2e-build's binaries and can run alongside unit tests. + needs: [e2e-build] + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + suite: e2e_safety_pnpm + - os: macos-latest + suite: e2e_redirect_npm_build + npm_required: '1' + - os: macos-latest + suite: e2e_redirect_rush_sim + - os: macos-latest + suite: e2e_redirect_bun_build + bun: '1.4.2' + test_filter: --include-ignored + - os: macos-latest + suite: e2e_vendor_bun_build + bun: '1.4.2' + test_filter: --include-ignored + - os: macos-latest + suite: mode_migration_bun + bun: '1.4.2' + test_filter: --include-ignored + - {os: macos-latest, suite: e2e_redirect_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} + - {os: macos-latest, suite: e2e_vendor_vlt_build, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} + - {os: macos-latest, suite: mode_migration_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} + - {os: macos-latest, suite: e2e_safety_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix, vlt_store_linker: 'hardlink'} + - {os: macos-latest, suite: e2e_vlt, vlt: '1.2.0', test_filter: --include-ignored vlt_pinned_matrix} + - {os: macos-latest, suite: e2e_redirect_pnpm_build, test_filter: '--ignored --skip pnpm_pinned_matrix'} + - {os: macos-latest, suite: e2e_redirect_uv_build, uv: '0.12.17'} + - {os: macos-latest, suite: e2e_vendor_pypi_build, uv: '0.12.17', test_filter: --include-ignored} + - {os: macos-latest, suite: e2e_vex_build, test_filter: 'poetry:: --ignored', poetry: '2.4.3'} + - {os: macos-latest, suite: e2e_vex_build, test_filter: 'pdm:: --ignored', pdm: '2.29.2'} + - {os: macos-latest, suite: e2e_vex_build, test_filter: 'hatch:: --ignored', hatch: '1.18.1'} + - {os: macos-latest, suite: e2e_vex_build, test_filter: 'pipenv:: --ignored', pipenv: '2022.12.19 2026.8.0'} + - {os: macos-latest, suite: e2e_vex_build, test_filter: 'pip:: --ignored', pip: '22 26'} + - {os: macos-latest, suite: e2e_redirect_maven_build, jvm_tool: maven, maven: '3.9.16'} + - {os: macos-latest, suite: e2e_vendor_maven_build, jvm_tool: maven, maven: '3.9.16'} + - {os: macos-latest, suite: e2e_vendor_jvm_build, jvm_tool: maven, maven: '3.9.16', test_filter: '--ignored maven_reactor'} + - {os: macos-latest, suite: e2e_nuget_dotnet_build, dotnet: '8'} + runs-on: ${{ matrix.os }} + # The real-toolchain capstones loop several releases per leg (pip, + # pipenv) or bootstrap a tool from PyPI before the suite (poetry, pdm, + # hatch), hence more than the 25 minutes the older legs needed. + timeout-minutes: 40 + # What .cargo/config.toml's [env] gives processes cargo launches; these + # legs launch the test binaries themselves. + env: + SOCKET_NO_CONFIG: '1' + SOCKET_NO_UPDATE_CHECK: '1' + # e2e-full runs these same steps over its rows. + steps: *e2e-steps + e2e-full: # merge_group runs the pull_request tier: the queue gates on ci-ok. if: (github.event_name != 'pull_request' && github.event_name != 'merge_group') || github.head_ref == 'release/v5-prerelease' @@ -1905,7 +1947,6 @@ jobs: - {os: ubuntu-latest, yarn: '4.0.2'} - {os: ubuntu-latest, yarn: '4.1.0'} - {os: ubuntu-latest, yarn: '4.18.0'} - - {os: macos-latest, yarn: '4.12.0'} - {os: windows-latest, yarn: '4.12.0'} runs-on: ${{ matrix.os }} timeout-minutes: 30 @@ -1932,6 +1973,26 @@ jobs: run: scripts/yarn-berry-vex-matrix.sh "$YARN_BERRY_RELEASE" # Skipped on pull_request (except v5 landings), like e2e-full. + + # The macOS rows of `yarn-berry-e2e`: they run on main, the merge queue and + # nightly, not on every PR push, so PRs stop queueing on the small + # macOS runner pool. + yarn-berry-e2e-macos: + if: github.event_name != 'pull_request' + name: yarn-berry ${{ matrix.yarn }} (${{ matrix.os }}) + needs: [test, coverage] + strategy: + fail-fast: false + matrix: + # 4.0.2 bare-hex checksum writer (4.0.0-4.0.2), 4.1.0 first + # `10c0/` writer, current, and 4.12.0 on macOS / Windows. The rest + # of the spread (4.6.0, 4.12.0 on ubuntu) is yarn-berry-full. + include: + - {os: macos-latest, yarn: '4.12.0'} + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + steps: *yarn-berry-steps + yarn-berry-full: name: yarn-berry ${{ matrix.yarn }} (${{ matrix.os }}) # merge_group runs the pull_request tier: the queue gates on ci-ok. @@ -1974,9 +2035,7 @@ jobs: - {os: ubuntu-latest, toolchain: stable, lock: '2'} - {os: ubuntu-latest, toolchain: '1.82.0', lock: '3'} - {os: ubuntu-latest, toolchain: '1.93.1', lock: '4'} - - {os: macos-latest, toolchain: stable, lock: '1'} - {os: windows-latest, toolchain: stable, lock: '1'} - - {os: macos-latest, toolchain: '1.93.1', lock: ''} - {os: windows-latest, toolchain: '1.93.1', lock: ''} steps: &cargo-vex-steps - name: Checkout @@ -2025,6 +2084,28 @@ jobs: "../../target/e2e-bin/e2e_safety_cargo_build$exe" --ignored || status=1 exit "$status" + # The macOS rows of `cargo-vex-matrix`: they run on main, the merge queue and + # nightly, not on every PR push, so PRs stop queueing on the small + # macOS runner pool. + cargo-vex-matrix-macos: + if: github.event_name != 'pull_request' + name: cargo ${{ matrix.toolchain }} lock-v${{ matrix.lock || 'own' }} (${{ matrix.os }}) + needs: [test, coverage, e2e-build] + runs-on: ${{ matrix.os }} + timeout-minutes: 40 + # What .cargo/config.toml's [env] gives processes cargo launches; these + # legs launch the test binaries themselves. + env: + SOCKET_NO_CONFIG: '1' + SOCKET_NO_UPDATE_CHECK: '1' + strategy: + fail-fast: false + matrix: + include: + - {os: macos-latest, toolchain: stable, lock: '1'} + - {os: macos-latest, toolchain: '1.93.1', lock: ''} + steps: *cargo-vex-steps + cargo-vex-matrix-full: name: cargo ${{ matrix.toolchain }} lock-v${{ matrix.lock || 'own' }} (${{ matrix.os }}) # merge_group runs the pull_request tier: the queue gates on ci-ok. @@ -2124,6 +2205,7 @@ jobs: # ---------------------------------------------------------------------- hosted-e2e: name: hosted-e2e # may be a required check; do not rename + if: github.event.pull_request.draft != true runs-on: ubuntu-latest permissions: contents: read @@ -2328,7 +2410,7 @@ jobs: ci-ok: name: ci-ok # registered as a required check; do not rename if: always() - needs: [clippy, node-addon, lint-ecosystems, release-readiness, test, test-release, coverage, docker-base, coverage-docker, coverage-merge, dispatch-tests, e2e-build, e2e, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e] + needs: [clippy, node-addon, lint-ecosystems, release-readiness, test, test-release, coverage, docker-base, coverage-docker, coverage-merge, dispatch-tests, e2e-build, e2e, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e, e2e-macos, yarn-berry-e2e-macos, cargo-vex-matrix-macos] runs-on: ubuntu-latest timeout-minutes: 5 steps: diff --git a/.github/workflows/composer-compatibility.yml b/.github/workflows/composer-compatibility.yml index e19c35340..99cdf0627 100644 --- a/.github/workflows/composer-compatibility.yml +++ b/.github/workflows/composer-compatibility.yml @@ -21,6 +21,7 @@ name: Composer patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/workflows/composer-compatibility.yml' - 'tests/docker/Dockerfile.composer' @@ -79,6 +80,7 @@ env: jobs: native: name: composer ${{ matrix.composer }} / php ${{ matrix.php }} / ${{ matrix.os }} + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: @@ -96,12 +98,9 @@ jobs: - {os: windows-latest, composer: '2.2.30', php: '8.3', sha256: 8c2b4478b64f8f7cdf1574838fdb0033b29049ca821dad452db7a3dcfcdbffc2} - {os: windows-latest, composer: '2.9.8', php: '8.4', sha256: 59b2c50e10cafa0d8efc19ede9a326d782f096c674a26baf98cf042ce23de890} - {os: windows-latest, composer: '2.10.3', php: '8.5', sha256: 7a2d379d5b8ffdaa028580ef26494c36d2feef4b178d3dd1473a4dbc5e17c8d6} - - {os: macos-latest, composer: '1.10.28', php: '8.1', sha256: 0915af36eb01e3f0e16cd309adff7051832b9ef014e38371756804b20425cd5a} - - {os: macos-latest, composer: '2.2.30', php: '8.3', sha256: 8c2b4478b64f8f7cdf1574838fdb0033b29049ca821dad452db7a3dcfcdbffc2} - - {os: macos-latest, composer: '2.10.3', php: '8.5', sha256: 7a2d379d5b8ffdaa028580ef26494c36d2feef4b178d3dd1473a4dbc5e17c8d6} runs-on: ${{ matrix.os }} timeout-minutes: 60 - steps: + steps: &native-steps - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -167,11 +166,29 @@ jobs: -- --ignored --nocapture cargo test -p socket-patch-cli --test e2e_vex_lockfile -- composer:: --nocapture + # The macOS rows of `native`: they run on push to main (and nightly + # where scheduled), not on every PR push, so PRs stop queueing on the + # small macOS runner pool. + native-macos: + name: composer ${{ matrix.composer }} / php ${{ matrix.php }} / ${{ matrix.os }} + if: github.event_name != 'pull_request' + strategy: + fail-fast: false + matrix: + include: + - {os: macos-latest, composer: '1.10.28', php: '8.1', sha256: 0915af36eb01e3f0e16cd309adff7051832b9ef014e38371756804b20425cd5a} + - {os: macos-latest, composer: '2.2.30', php: '8.3', sha256: 8c2b4478b64f8f7cdf1574838fdb0033b29049ca821dad452db7a3dcfcdbffc2} + - {os: macos-latest, composer: '2.10.3', php: '8.5', sha256: 7a2d379d5b8ffdaa028580ef26494c36d2feef4b178d3dd1473a4dbc5e17c8d6} + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + steps: *native-steps + docker: # The vendored Docker capstone against an exact composer image. Its # fixture resolves psr/log from packagist, which no longer serves # Composer 1, so 1.10.28 is covered by the native legs only. name: docker composer ${{ matrix.composer }} + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 35 strategy: diff --git a/.github/workflows/go-compatibility.yml b/.github/workflows/go-compatibility.yml index 3f0e6b9b7..eea8dbbf2 100644 --- a/.github/workflows/go-compatibility.yml +++ b/.github/workflows/go-compatibility.yml @@ -7,6 +7,7 @@ name: Go patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/workflows/go-compatibility.yml' - 'crates/socket-patch-core/src/vendor/go*.rs' @@ -38,19 +39,15 @@ env: jobs: go: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest] go: ['1.18.10', '1.21.13', '1.24.13', '1.26.3'] - include: - # macOS-latest dyld refuses binaries without LC_UUID (Go < 1.24 - # linkers; see ci.yml's vexctl step). - - {os: macos-latest, go: '1.24.13'} - - {os: macos-latest, go: '1.26.3'} runs-on: ${{ matrix.os }} timeout-minutes: 45 - steps: + steps: &go-steps - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -75,3 +72,19 @@ jobs: --test e2e_golang_hosted_build --test e2e_vendor_golang_build \ --test e2e_golang_build --test e2e_golang_workspace_build -- --nocapture cargo test -p socket-patch-cli --test e2e_vex_lockfile -- golang:: --nocapture + + # The macOS rows of `go`: they run on push to main (and nightly + # where scheduled), not on every PR push, so PRs stop queueing on the + # small macOS runner pool. + go-macos: + if: github.event_name != 'pull_request' + strategy: + fail-fast: false + matrix: + os: [macos-latest] + # macOS-latest dyld refuses binaries without LC_UUID (Go < 1.24 + # linkers; see ci.yml's vexctl step). + go: ['1.24.13', '1.26.3'] + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + steps: *go-steps diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index 9b17fe9b1..0f3944966 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -40,6 +40,7 @@ name: Gradle patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/workflows/gradle-compatibility.yml' - 'scripts/ci-e2e-bundle.py' @@ -98,10 +99,14 @@ env: jobs: build: name: build ${{ matrix.os }} + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 60 env: @@ -174,6 +179,9 @@ jobs: - {gradle: '7.6.6', java: '17', label: '', gradle_args: '', real_central: '', suites: '', test_filter: ''} - {gradle: '8.14.3', java: '21', label: '', gradle_args: '', real_central: '', suites: '', test_filter: ''} - {gradle: '9.8.0', java: '21', label: '', gradle_args: '', real_central: '', suites: '', test_filter: ''} + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: &cell-steps diff --git a/.github/workflows/npm-compatibility.yml b/.github/workflows/npm-compatibility.yml index 40d7a25f7..64f83abe2 100644 --- a/.github/workflows/npm-compatibility.yml +++ b/.github/workflows/npm-compatibility.yml @@ -11,6 +11,7 @@ on: # compile (a later `!` pattern excludes, a later plain one re-includes). # Main pushes stay unfiltered. pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - 'Cargo.lock' @@ -45,6 +46,7 @@ concurrency: jobs: build: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 25 steps: diff --git a/.github/workflows/pdm-compatibility.yml b/.github/workflows/pdm-compatibility.yml index 6f760d7c8..fcec586f6 100644 --- a/.github/workflows/pdm-compatibility.yml +++ b/.github/workflows/pdm-compatibility.yml @@ -9,6 +9,7 @@ name: PDM patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - '.github/workflows/pdm-compatibility.yml' @@ -60,10 +61,14 @@ env: jobs: build: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: @@ -107,13 +112,9 @@ jobs: # every Windows cell skipped; backtest-pdm.py now fails such a cell. os: [ubuntu-latest] pdm: ['0.12.3', '1.15.5', '2.0.3', '2.1.5', '2.3.4', '2.6.1', '2.7.4', '2.8.2', '2.9.3', '2.10.4', '2.11.2', '2.17.3', '2.20.1', '2.22.4', '2.25.9', '2.29.2'] - include: - - { os: macos-latest, pdm: '0.12.3' } - - { os: macos-latest, pdm: '2.8.2' } - - { os: macos-latest, pdm: '2.29.2' } runs-on: ${{ matrix.os }} timeout-minutes: 45 - steps: + steps: &native-steps - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -174,6 +175,23 @@ jobs: # formats (3.1, 4.0-4.2) must attest nothing. The cells ci.yml's `e2e` # job runs on every PR and main push are excluded here # (scripts/tests/test_ci_e2e_tiers.py keeps the two lists in step). + + # The macOS rows of `native`: they run on push to main (and nightly + # where scheduled), not on every PR push, so PRs stop queueing on the + # small macOS runner pool. + native-macos: + if: github.event_name != 'pull_request' + needs: build + strategy: + fail-fast: false + matrix: + # The ends of the range and the 2.8 lock-format boundary. + os: [macos-latest] + pdm: ['0.12.3', '2.8.2', '2.29.2'] + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + steps: *native-steps + capstone: needs: build strategy: @@ -189,6 +207,8 @@ jobs: - {os: ubuntu-latest, pdm: '2.25.9'} - {os: ubuntu-latest, pdm: '2.29.2'} - {os: macos-latest, pdm: '2.29.2'} + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: diff --git a/.github/workflows/pipenv-compatibility.yml b/.github/workflows/pipenv-compatibility.yml index c36335391..000f746c5 100644 --- a/.github/workflows/pipenv-compatibility.yml +++ b/.github/workflows/pipenv-compatibility.yml @@ -9,6 +9,7 @@ name: Pipenv compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - 'crates/socket-patch-core/src/patch/redirect/pipenv.rs' @@ -43,6 +44,7 @@ concurrency: jobs: matrix: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: @@ -55,12 +57,9 @@ jobs: - os: ubuntu-latest versions: 2022.12.19 2026.8.0 shapes: crlf marker-excluded extras category - - os: macos-latest - versions: 2018.11.26 2022.12.19 2023.12.1 2026.8.0 - shapes: direct runs-on: ${{ matrix.os }} timeout-minutes: 60 - steps: + steps: &matrix-steps - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -111,3 +110,19 @@ jobs: ${{ runner.temp }}/pipenv-compat/summary.md if-no-files-found: warn retention-days: 7 + + # The macOS rows of `matrix`: they run on push to main (and nightly + # where scheduled), not on every PR push, so PRs stop queueing on the + # small macOS runner pool. + matrix-macos: + if: github.event_name != 'pull_request' + strategy: + fail-fast: false + matrix: + include: + - os: macos-latest + versions: 2018.11.26 2022.12.19 2023.12.1 2026.8.0 + shapes: direct + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + steps: *matrix-steps diff --git a/.github/workflows/pnpm-compatibility.yml b/.github/workflows/pnpm-compatibility.yml index f742364c4..6abe6c81e 100644 --- a/.github/workflows/pnpm-compatibility.yml +++ b/.github/workflows/pnpm-compatibility.yml @@ -5,6 +5,7 @@ on: # compile (a later `!` pattern excludes, a later plain one re-includes). # Main pushes stay unfiltered. pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - 'Cargo.lock' @@ -37,6 +38,7 @@ concurrency: jobs: build: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 20 steps: diff --git a/.github/workflows/poetry-compatibility.yml b/.github/workflows/poetry-compatibility.yml index 3b397b89f..abcae8402 100644 --- a/.github/workflows/poetry-compatibility.yml +++ b/.github/workflows/poetry-compatibility.yml @@ -13,6 +13,7 @@ name: Poetry patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - '.github/actions/pin-socket-hosts/**' @@ -52,10 +53,14 @@ env: jobs: build: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 30 steps: @@ -81,6 +86,9 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] poetry: ['1.0.10', '1.1.15', '1.2.2', '1.3.2', '1.4.2', '1.5.1', '1.6.1', '1.7.1', '1.8.5', '2.0.1', '2.1.4', '2.2.1', '2.3.4', '2.4.3'] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 45 steps: diff --git a/.github/workflows/sbt-compatibility.yml b/.github/workflows/sbt-compatibility.yml index 22ea35660..0c2edb03f 100644 --- a/.github/workflows/sbt-compatibility.yml +++ b/.github/workflows/sbt-compatibility.yml @@ -21,6 +21,7 @@ name: sbt / Mill / scala-cli compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] # Everything the agent, hosted and vendored cells run through, shared # engine code included (as composer-compatibility.yml does). paths: @@ -68,6 +69,7 @@ env: jobs: image: + if: github.event.pull_request.draft != true # Builds the sbt image once (base image first: Dockerfile.sbt is # `FROM socket-patch-test-base:latest`) and hands it to every leg. runs-on: ubuntu-latest @@ -117,6 +119,7 @@ jobs: retention-days: 3 linux-bins: + if: github.event.pull_request.draft != true # The Linux socket-patch and the real-tool test binaries (docker_e2e_sbt's # host side too, so no leg compiles), built once in the script's pinned # rust container. Absolute paths are kept (`tar -P`): @@ -261,6 +264,7 @@ jobs: # from sbt/setup-sbt, a Temurin JDK 17, the tests' own native runner. # The warm-seed step boots sbt once so the tests share its caches. name: sbt 1.13.0 ${{ matrix.suite }} / ${{ matrix.os }} + if: github.event.pull_request.draft != true runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: @@ -268,6 +272,9 @@ jobs: matrix: os: [macos-latest, windows-latest] suite: [e2e_sbt_build, e2e_sbt_vendor_build] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/.github/workflows/vlt-compatibility.yml b/.github/workflows/vlt-compatibility.yml index a30976d9c..e80d4c0eb 100644 --- a/.github/workflows/vlt-compatibility.yml +++ b/.github/workflows/vlt-compatibility.yml @@ -19,6 +19,7 @@ name: vlt patch compatibility on: pull_request: + types: [opened, synchronize, reopened, ready_for_review] paths: - '.github/actions/upload-artifact/**' - '.github/actions/pin-socket-hosts/**' @@ -139,6 +140,7 @@ env: jobs: matrix-coverage: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 5 steps: @@ -149,10 +151,14 @@ jobs: run: python3 -B -m unittest scripts/tests/test_ci_vlt_rows.py -v build: + if: github.event.pull_request.draft != true strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 40 steps: @@ -233,17 +239,6 @@ jobs: - {os: ubuntu-latest, vlt: '1.0.10'} - {os: ubuntu-latest, vlt: '1.1.1'} - {os: ubuntu-latest, vlt: '1.2.0'} - - {os: macos-latest, vlt: '0.0.0-16'} - - {os: macos-latest, vlt: '0.0.0-30'} - - {os: macos-latest, vlt: '1.0.0-rc.8'} - - {os: macos-latest, vlt: '1.0.0-rc.13'} - - {os: macos-latest, vlt: '1.0.0-rc.14'} - - {os: macos-latest, vlt: '1.0.0-rc.15'} - - {os: macos-latest, vlt: '1.0.0-rc.22'} - - {os: macos-latest, vlt: '1.0.0-rc.33'} - - {os: macos-latest, vlt: '1.0.8'} - - {os: macos-latest, vlt: '1.1.1'} - - {os: macos-latest, vlt: '1.2.0'} - {os: windows-latest, vlt: '0.0.0-11'} - {os: windows-latest, vlt: '0.0.0-19'} - {os: windows-latest, vlt: '0.0.0-30'} @@ -270,14 +265,12 @@ jobs: - {os: ubuntu-latest, vlt: '1.2.0', linker: hardlink, suites: e2e_safety_vlt} - {os: ubuntu-latest, vlt: '1.2.0', linker: copy, suites: e2e_safety_vlt} - {os: ubuntu-latest, vlt: '1.2.0', linker: unpack, suites: e2e_safety_vlt} - - {os: macos-latest, vlt: '1.2.0', linker: auto, suites: e2e_safety_vlt} - - {os: macos-latest, vlt: '1.2.0', linker: hardlink, suites: e2e_safety_vlt} - {os: windows-latest, vlt: '1.2.0', linker: auto, suites: e2e_safety_vlt} - {os: windows-latest, vlt: '1.2.0', linker: hardlink, suites: e2e_safety_vlt} - {os: ubuntu-latest, vlt: '1.2.0', linker: hardlink, cache_root: /dev/shm/vlt-e2e-cache, suites: e2e_safety_vlt} runs-on: ${{ matrix.os }} timeout-minutes: 45 - steps: + steps: &install-proof-steps # The capstones resolve fixtures through the build job's checkout path, # which is the same on every runner of one OS. - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -365,7 +358,36 @@ jobs: path: logs/ retention-days: 14 + # The macOS rows of `install-proof`: they run on push to main (and nightly + # where scheduled), not on every PR push, so PRs stop queueing on the + # small macOS runner pool. + install-proof-macos: + if: github.event_name != 'pull_request' + needs: build + strategy: + fail-fast: false + max-parallel: 8 + matrix: + include: + - {os: macos-latest, vlt: '0.0.0-16'} + - {os: macos-latest, vlt: '0.0.0-30'} + - {os: macos-latest, vlt: '1.0.0-rc.8'} + - {os: macos-latest, vlt: '1.0.0-rc.13'} + - {os: macos-latest, vlt: '1.0.0-rc.14'} + - {os: macos-latest, vlt: '1.0.0-rc.15'} + - {os: macos-latest, vlt: '1.0.0-rc.22'} + - {os: macos-latest, vlt: '1.0.0-rc.33'} + - {os: macos-latest, vlt: '1.0.8'} + - {os: macos-latest, vlt: '1.1.1'} + - {os: macos-latest, vlt: '1.2.0'} + - {os: macos-latest, vlt: '1.2.0', linker: auto, suites: e2e_safety_vlt} + - {os: macos-latest, vlt: '1.2.0', linker: hardlink, suites: e2e_safety_vlt} + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + steps: *install-proof-steps + plan: + if: github.event.pull_request.draft != true runs-on: ubuntu-latest timeout-minutes: 5 outputs: @@ -374,6 +396,8 @@ jobs: - id: plan env: VERSIONS_OVERRIDE: ${{ github.event.inputs.versions }} + # macOS legs run on main and nightly, not on every PR push. + EVENT_NAME: ${{ github.event_name }} run: | python3 - <<'PY' >> "$GITHUB_OUTPUT" import json, os @@ -383,6 +407,8 @@ jobs: 'windows-latest': ['1.0.0-rc.14', '1.2.0'], } override = os.environ.get('VERSIONS_OVERRIDE', '').split() + if os.environ.get('EVENT_NAME') == 'pull_request': + del defaults['macos-latest'] rows = [{'os': o, 'vlt': v} for o, vs in defaults.items() for v in (override or vs)] print('native=' + json.dumps({'include': rows})) PY @@ -499,6 +525,9 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] + exclude: + # macOS legs run on push to main (and nightly where scheduled), not per PR push. + - os: ${{ github.event_name == 'pull_request' && 'macos-latest' || '' }} runs-on: ${{ matrix.os }} timeout-minutes: 45 steps: From d31250a4987fe19a291afe2511f2cc08c7e65261 Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Wed, 7 Oct 2026 19:24:06 -0400 Subject: [PATCH 2/3] Move the install-proof steps comment above the anchor zizmor 1.30 cannot parse a comment as the first node of an anchored sequence ('unexpected node: comment' in its self-repository audit), which failed the org's Audit GHA Workflows check. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/vlt-compatibility.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/vlt-compatibility.yml b/.github/workflows/vlt-compatibility.yml index e80d4c0eb..85fe5a1ef 100644 --- a/.github/workflows/vlt-compatibility.yml +++ b/.github/workflows/vlt-compatibility.yml @@ -270,9 +270,9 @@ jobs: - {os: ubuntu-latest, vlt: '1.2.0', linker: hardlink, cache_root: /dev/shm/vlt-e2e-cache, suites: e2e_safety_vlt} runs-on: ${{ matrix.os }} timeout-minutes: 45 + # The capstones resolve fixtures through the build job's checkout path, + # which is the same on every runner of one OS. steps: &install-proof-steps - # The capstones resolve fixtures through the build job's checkout path, - # which is the same on every runner of one OS. - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From d78941e60cfce8d761cac97c293dc6f21905aa8b Mon Sep 17 00:00:00 2001 From: Mikola Lysenko Date: Wed, 7 Oct 2026 20:01:32 -0400 Subject: [PATCH 3/3] Read the -macos sibling rows in the CI row readers Moving the macOS include rows into `-macos` jobs hid them from every script that reads a job's matrix by name. ci-e2e-bundle.py bundled 5 of the 24 macOS suites, so e2e-macos would have failed in the merge queue. ci-vlt-proof-suites.py also stopped deduplicating vlt proof cells against ci.yml's macOS rows, and the matrix pin tests in scripts/tests failed. Add `job_rows()` to the shared reader in test_ci_vlt_rows.py. It returns a job's include rows plus its `-macos` sibling's. Use it in the bundler, the vlt proof dedupe and the tests. Per OS, the bundle and the dedupe set now match main exactly. The PDM capstone test ignores the event-gated macOS exclude row. vlt lock-diff required Linux, macOS and Windows locks for its pinned cells. Pull requests run no macOS cells now, so on pull_request it requires none and still compares the Linux and Windows locks. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/vlt-compatibility.yml | 7 +++++-- scripts/ci-e2e-bundle.py | 2 +- scripts/ci-vlt-proof-suites.py | 2 +- scripts/tests/test_ci_e2e_tiers.py | 7 ++++--- scripts/tests/test_ci_gradle_prefixes.py | 4 ++-- scripts/tests/test_ci_vlt_rows.py | 13 +++++++++++-- scripts/tests/test_vlt_coverage.py | 4 ++-- 7 files changed, 26 insertions(+), 13 deletions(-) diff --git a/.github/workflows/vlt-compatibility.yml b/.github/workflows/vlt-compatibility.yml index 85fe5a1ef..a4435a561 100644 --- a/.github/workflows/vlt-compatibility.yml +++ b/.github/workflows/vlt-compatibility.yml @@ -499,12 +499,15 @@ jobs: VERSIONS_OVERRIDE: ${{ github.event.inputs.versions }} SHAPES_OVERRIDE: ${{ github.event.inputs.shapes }} MODES_OVERRIDE: ${{ github.event.inputs.modes }} + EVENT_NAME: ${{ github.event_name }} run: | required=() modes=(hosted vendored agent) if [ -n "$MODES_OVERRIDE" ]; then read -r -a modes <<<"$MODES_OVERRIDE"; fi - # The required set only covers cells the native jobs were asked to run. - if [ -z "$VERSIONS_OVERRIDE" ] && { [ -z "$SHAPES_OVERRIDE" ] || [[ " $SHAPES_OVERRIDE " == *" direct "* ]]; }; then + # The required set only covers cells the native jobs were asked to + # run. Pull requests run no macOS cells, so nothing is required there; + # the Linux and Windows locks are still compared. + if [ "$EVENT_NAME" != pull_request ] && [ -z "$VERSIONS_OVERRIDE" ] && { [ -z "$SHAPES_OVERRIDE" ] || [[ " $SHAPES_OVERRIDE " == *" direct "* ]]; }; then for v in 1.2.0 1.0.0-rc.14; do for m in "${modes[@]}"; do required+=("$v:$m:direct"); done done diff --git a/scripts/ci-e2e-bundle.py b/scripts/ci-e2e-bundle.py index 1dc3a010c..2b29f8699 100644 --- a/scripts/ci-e2e-bundle.py +++ b/scripts/ci-e2e-bundle.py @@ -119,7 +119,7 @@ def suites_for(os_name, text=None): jobs = reader.jobs(text if text is not None else CI.read_text(encoding="utf-8")) suites = set(CARGO_VEX_SUITES) for job in MATRIX_JOBS: - for row in reader.matrix_include(jobs[job]): + for row in reader.job_rows(jobs, job): if row["os"] == os_name: suites.update(row_suites(row)) return sorted(suites) diff --git a/scripts/ci-vlt-proof-suites.py b/scripts/ci-vlt-proof-suites.py index 8a119d680..6dbc5d138 100644 --- a/scripts/ci-vlt-proof-suites.py +++ b/scripts/ci-vlt-proof-suites.py @@ -39,7 +39,7 @@ def proof_upgrade(vlt, node): def ci_cells(text=None): reader = load_reader() - rows = reader.matrix_include(reader.jobs(text if text is not None else CI.read_text(encoding="utf-8"))["e2e"]) + rows = reader.job_rows(reader.jobs(text if text is not None else CI.read_text(encoding="utf-8")), "e2e") return {(r["suite"], r["os"], r["vlt"], r.get("vlt_store_linker", ""), r.get("vlt_upgrade", "")) for r in rows if r.get("vlt") and r.get("test_filter") == "--include-ignored vlt_pinned_matrix"} diff --git a/scripts/tests/test_ci_e2e_tiers.py b/scripts/tests/test_ci_e2e_tiers.py index 37d8195ed..9ed68b8c1 100644 --- a/scripts/tests/test_ci_e2e_tiers.py +++ b/scripts/tests/test_ci_e2e_tiers.py @@ -31,7 +31,7 @@ def load(name, path): def rows(job): - return rows_mod.matrix_include(JOBS[job]) + return rows_mod.job_rows(JOBS, job) def job_text(job): @@ -266,7 +266,8 @@ class PdmCapstone(unittest.TestCase): job = rows_mod.jobs(PDM.read_text(encoding="utf-8"))["capstone"] def test_excludes_exactly_the_cells_ci_runs_on_every_pr(self): - excluded = rows_mod.matrix_include([l.replace("exclude:", "include:") for l in self.job]) + excluded = [r for r in rows_mod.matrix_include([l.replace("exclude:", "include:") for l in self.job]) + if not r["os"].startswith("${{")] # the PR-only macOS exclude ci = {(r["os"], r["pdm"]) for r in rows("e2e") if "pdm" in r} self.assertEqual({(r["os"], r["pdm"]) for r in excluded}, ci) self.assertEqual(len(excluded), len(ci)) @@ -287,7 +288,7 @@ class VltProofDedupe(unittest.TestCase): def test_only_identical_ci_cells_are_left_out(self): cells = proof.ci_cells(TEXT) compat = rows_mod.jobs(COMPAT.read_text(encoding="utf-8")) - for row in rows_mod.matrix_include(compat["install-proof"]): + for row in rows_mod.job_rows(compat, "install-proof"): suites = row.get("suites", " ".join(self.suites)).split() keep = proof.remaining(suites, row["os"], row["vlt"], row.get("node", ""), row.get("linker", ""), row.get("cache_root", ""), TEXT) diff --git a/scripts/tests/test_ci_gradle_prefixes.py b/scripts/tests/test_ci_gradle_prefixes.py index 833221bc5..2a52cd027 100644 --- a/scripts/tests/test_ci_gradle_prefixes.py +++ b/scripts/tests/test_ci_gradle_prefixes.py @@ -143,7 +143,7 @@ def test_every_admitted_prefix_runs_in_both_tiers(self): row that runs that suite and by the gradle-compatibility.yml mode that runs it, so a conforming test runs on every PR and in every grid cell of its mode.""" - rows = [r for r in rows_mod.matrix_include(rows_mod.jobs(CI.read_text(encoding="utf-8"))["e2e"]) + rows = [r for r in rows_mod.job_rows(rows_mod.jobs(CI.read_text(encoding="utf-8")), "e2e") if r.get("jvm_tool") == "gradle" and r["os"] == "ubuntu-latest"] modes = compat_modes() self.assertEqual(set(modes), {"agent", "hosted", "vendor"}) @@ -176,7 +176,7 @@ def test_compat_overrides_select_admitted_tests(self): class AllowEmpty(unittest.TestCase): - rows = rows_mod.matrix_include(rows_mod.jobs(CI.read_text(encoding="utf-8"))["e2e"]) + rows = rows_mod.job_rows(rows_mod.jobs(CI.read_text(encoding="utf-8")), "e2e") def test_allow_empty_only_while_a_suite_is_unlanded(self): """The allowance is for rows whose owning package has not landed. Once diff --git a/scripts/tests/test_ci_vlt_rows.py b/scripts/tests/test_ci_vlt_rows.py index 567900f50..b5c105fbb 100644 --- a/scripts/tests/test_ci_vlt_rows.py +++ b/scripts/tests/test_ci_vlt_rows.py @@ -126,6 +126,15 @@ def matrix_include(job_lines): return rows +def job_rows(jobs_by_id, job): + """`matrix_include` of a job plus its `-macos` sibling, which holds + the macOS rows that run off the pull_request path.""" + rows = matrix_include(jobs_by_id[job]) + if f"{job}-macos" in jobs_by_id: + rows += matrix_include(jobs_by_id[f"{job}-macos"]) + return rows + + def steps(job_lines): """[(name, text)] of a job's steps.""" out, current = [], None @@ -148,7 +157,7 @@ def step(job_lines, name): class CiE2eVltRows(unittest.TestCase): ci = jobs(CI.read_text(encoding="utf-8")) - rows = matrix_include(ci["e2e"]) + rows = job_rows(ci, "e2e") vlt_rows = [r for r in rows if "vlt" in r or "vlt" in r.get("suite", "")] def test_every_vlt_row_pins_a_release_and_includes_the_ignored_legs(self): @@ -241,7 +250,7 @@ def test_hosted_e2e_proves_vlt_against_production(self): class CompatibilityWorkflow(unittest.TestCase): compat = jobs(COMPAT.read_text(encoding="utf-8")) - rows = matrix_include(compat["install-proof"]) + rows = job_rows(compat, "install-proof") def covered(self): cells = set() diff --git a/scripts/tests/test_vlt_coverage.py b/scripts/tests/test_vlt_coverage.py index e7262432b..e0868ace5 100644 --- a/scripts/tests/test_vlt_coverage.py +++ b/scripts/tests/test_vlt_coverage.py @@ -118,9 +118,9 @@ def ci_ids(self): compat = self.rows.jobs( (ROOT / ".github/workflows/vlt-compatibility.yml").read_text(encoding="utf-8")) ids = {f"ci:{r['suite']}:{r['os']}:{r['vlt']}" - for r in self.rows.matrix_include(ci["e2e"]) if "vlt" in r} + for r in self.rows.job_rows(ci, "e2e") if "vlt" in r} ids |= {f"compat:{r['os']}:{r['vlt']}" - for r in self.rows.matrix_include(compat["install-proof"])} + for r in self.rows.job_rows(compat, "install-proof")} return ids def test_every_code_is_mapped_and_documented(self):