diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81e5ad4d8..c1e4c5509 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,8 +58,8 @@ concurrency: # the repository variable CI_SCOPE is `full`, pull_request, merge_group and # push runs use one targeted e2e row per package manager (the rest are in # e2e-extended), one row each of the yarn and cargo VEX matrices, and skip -# the Windows/macOS legs (except e2e-build-windows, which still compiles every -# test target on Windows in the merge queue), test, test-release, old cargo toolchains and the +# the Windows/macOS legs (except windows-compile-check, which still +# type-checks every CLI test target on Windows in the merge queue), test, test-release, old cargo toolchains and the # sbt Docker coverage slice. Everything runs in the nightly schedule and on # workflow_dispatch. Set CI_SCOPE=full to restore the old gate without a # commit. ci-ok treats skipped jobs as passing. hosted-e2e is not scoped: @@ -1038,11 +1038,46 @@ jobs: if-no-files-found: error retention-days: 3 + # Lean merge queue: type-check the CLI (lib and bin, as shipped) and every + # CLI test target on Windows. Lean pull_request runs skip Windows, and a + # cfg(unix) slip only shows up here (#1324). A check, not a build: nothing + # in lean scope runs the Windows binaries, and linking ~60 test binaries + # made this the queue's critical path (#1385). No `needs: clippy`, so it + # starts at once; merge-queue fail-fast cancels it if clippy fails. Full + # scope, nightly and dispatch build and run everything in + # e2e-build-windows. The nightly run also runs this job, only to save its + # check-mode cache on main: queue refs can't share a saved cache, and a + # build-mode cache doesn't satisfy `cargo check`. + windows-compile-check: + if: (github.event_name == 'merge_group' && vars.CI_SCOPE != 'full') || github.event_name == 'schedule' + runs-on: windows-latest + timeout-minutes: 30 + env: *e2e-build-env + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Install Rust + shell: bash + run: scripts/rustup-retry.sh toolchain install + + - name: Cache cargo + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + shared-key: check-windows-latest + save-if: ${{ github.ref == 'refs/heads/main' }} + + - name: Type-check the CLI and every CLI test target + shell: bash + run: cargo check --locked -p socket-patch-cli --all-features --lib --bins --tests + e2e-build-windows: - # Lean scope still compiles every test target on Windows in the merge - # queue (one job): lean pull_request runs skip Windows, and a cfg(unix) - # slip only shows up here (#1324). Its consumers stay full-scope only. - 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' + # Builds the Windows test binaries for e2e-windows and + # cargo-vex-matrix-windows. The lean merge queue runs + # windows-compile-check instead. + 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' needs: clippy outputs: reuse: ${{ needs.clippy.outputs.reuse }} @@ -2697,7 +2732,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-build-windows, e2e-build-macos, e2e, e2e-windows, e2e-extended, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-windows, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e, e2e-macos, yarn-berry-e2e-macos, cargo-vex-matrix-macos] + needs: [clippy, node-addon, lint-ecosystems, release-readiness, test, test-release, coverage, docker-base, coverage-docker, coverage-merge, dispatch-tests, e2e-build, windows-compile-check, e2e-build-windows, e2e-build-macos, e2e, e2e-windows, e2e-extended, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-windows, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e, e2e-macos, yarn-berry-e2e-macos, cargo-vex-matrix-macos] runs-on: ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} timeout-minutes: 5 steps: diff --git a/scripts/tests/test_ci_scheduling.py b/scripts/tests/test_ci_scheduling.py index 74a28c030..3a9ea6137 100644 --- a/scripts/tests/test_ci_scheduling.py +++ b/scripts/tests/test_ci_scheduling.py @@ -41,9 +41,14 @@ def test_required_verdict_includes_every_job(self): def test_expensive_jobs_cannot_start_after_a_failed_preflight(self): cheap = {"clippy", "lint-ecosystems", "release-readiness", "dispatch-tests", "ci-ok"} + # windows-compile-check is the lean queue's only Windows job and sits + # on its critical path, so it starts in parallel with clippy; + # merge-queue fail-fast cancels it when clippy fails. + parallel = {"windows-compile-check"} for job in set(JOBS) - cheap: with self.subTest(job=job): - self.assertIn("clippy", ancestors(job)) + if job not in parallel: + self.assertIn("clippy", ancestors(job)) # Job-level always() would defeat failure/skip propagation. self.assertFalse(any(line.startswith(" if:") and "always()" in line for line in JOBS[job])) @@ -81,6 +86,29 @@ def test_os_builds_use_the_same_artifact_contract(self): self.assertTrue(condition.endswith(" && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule'" " || github.event_name == 'workflow_dispatch')"), condition) + def test_lean_queue_type_checks_windows_and_full_scope_builds_it(self): + # The lean merge queue type-checks the CLI and every CLI test target + # on Windows (#1324) without linking (#1385); full scope, nightly and + # dispatch build the binaries their consumers download. Lean PR and + # push runs do neither. The nightly also runs the check, only so main + # saves the check-mode cache the queue restores. + check = JOBS["windows-compile-check"] + self.assertIn(" if: (github.event_name == 'merge_group' && vars.CI_SCOPE != 'full')" + " || github.event_name == 'schedule'", check) + self.assertIn(" runs-on: windows-latest", check) + self.assertEqual(dependencies("windows-compile-check"), set()) + body = "\n".join(check) + self.assertIn("cargo check --locked -p socket-patch-cli --all-features --lib --bins --tests", body) + self.assertIn(" env: *e2e-build-env", check) + self.assertIn("shared-key: check-windows-latest", body) + self.assertIn("save-if: ${{ github.ref == 'refs/heads/main' }}", body) + self.assertNotIn("upload-artifact", body) + self.assertNotIn("--no-run", body) + build = next(line for line in JOBS["e2e-build-windows"] if line.startswith(" if:")) + self.assertEqual(build, " 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'") + def test_reused_push_keeps_cache_writers_and_unqueued_jobs(self): # A push whose SHA passed the merge queue still compiles (main is the # only cache writer) and still runs what the queue never ran.