From ba6b74beeaaddfcddb51f485d695ed8c3fbd98ad Mon Sep 17 00:00:00 2001 From: luo jiyin Date: Sat, 19 Sep 2026 15:23:52 +0800 Subject: [PATCH] perf(ci): parallelize and cache Windows compatibility checks (#9587) * perf(ci): parallelize and cache Windows compatibility checks * test(ci-plan): require both Windows jobs when bundle routing is selected --- .github/scripts/ci-gate.mjs | 4 ++-- .github/scripts/ci-plan.test.mjs | 32 +++++++++++++++++++++---- .github/scripts/ci-workflow.test.mjs | 17 ++++++++++++- .github/workflows/ci.yml | 36 +++++++++++++++++++++++----- 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/.github/scripts/ci-gate.mjs b/.github/scripts/ci-gate.mjs index ba362113d5..c44ea58798 100644 --- a/.github/scripts/ci-gate.mjs +++ b/.github/scripts/ci-gate.mjs @@ -9,8 +9,8 @@ export function gateFailures(needs, mode) { const flags = ["rust", "agents", "fast", "agent_java", "agent_go_changed", "agent_rust_changed", "agent_integration_changed"]; if (!flags.every((flag) => typeof plan[flag] === "boolean")) return ["incomplete CI plan"]; const routedJobs = { frontend: "frontend", packages: "packages", "github-scripts": "github_scripts", - "windows-win7-bundle": "windows_win7_bundle", "duckdb-windows-driver": "duckdb_windows", - jdbc: "jdbc", "offline-jdbc-release": "offline_jdbc", "nix-packaging": "nix" }; + "windows-standard-check": "windows_win7_bundle", "windows-win7-bundle": "windows_win7_bundle", + "duckdb-windows-driver": "duckdb_windows", jdbc: "jdbc", "offline-jdbc-release": "offline_jdbc", "nix-packaging": "nix" }; if (mode === "all" && !Object.values(routedJobs).every((output) => ["true", "false"].includes(needs.changes.outputs[output]))) { return ["missing or invalid job selection outputs"]; } diff --git a/.github/scripts/ci-plan.test.mjs b/.github/scripts/ci-plan.test.mjs index 604ce027ce..1fb15a9cd4 100644 --- a/.github/scripts/ci-plan.test.mjs +++ b/.github/scripts/ci-plan.test.mjs @@ -27,6 +27,11 @@ const metadata = { }; const plan = (files, options = {}) => planCi({ files, metadata, root, ...options }); const groups = (result) => result.rust_matrix.include.map((entry) => entry.group); +// Keep the gate fixtures in sync with ci-gate.mjs routedJobs. Both Windows jobs +// share the windows_win7_bundle routing output. +const routedJobs = { frontend: "frontend", packages: "packages", "github-scripts": "github_scripts", + "windows-standard-check": "windows_win7_bundle", "windows-win7-bundle": "windows_win7_bundle", + "duckdb-windows-driver": "duckdb_windows", jdbc: "jdbc", "offline-jdbc-release": "offline_jdbc", "nix-packaging": "nix" }; test("foundation changes select transitive consumers and standalone DuckDB", () => { const result = plan(["crates/dbx-types/src/lib.rs"]); @@ -214,15 +219,15 @@ test("git diff routing includes both sides of renames, deleted files, and unusua test("the final gate rejects absent routing outputs and skipped selected jobs", () => { const needs = results(["docs/README.md"]); - const routed = { frontend: "frontend", packages: "packages", "github-scripts": "github_scripts", - "windows-win7-bundle": "windows_win7_bundle", "duckdb-windows-driver": "duckdb_windows", jdbc: "jdbc", - "offline-jdbc-release": "offline_jdbc", "nix-packaging": "nix" }; needs.rust = needs.agents = { result: "success" }; - for (const [job, output] of Object.entries(routed)) { + for (const [job, output] of Object.entries(routedJobs)) { needs[job] = { result: "skipped" }; needs.changes.outputs[output] = "false"; } assert.deepEqual(gateFailures(needs, "all"), []); + needs["windows-standard-check"].result = "failure"; + assert.ok(gateFailures(needs, "all").length); + needs["windows-standard-check"].result = "skipped"; needs.changes.outputs.frontend = "true"; assert.ok(gateFailures(needs, "all").length); needs.frontend.result = "success"; @@ -231,6 +236,25 @@ test("the final gate rejects absent routing outputs and skipped selected jobs", assert.ok(gateFailures(needs, "all").length); }); +test("the final gate requires both Windows jobs when the bundle routing is selected", () => { + const needs = results(["docs/README.md"]); + needs.rust = needs.agents = { result: "success" }; + for (const [job, output] of Object.entries(routedJobs)) { + needs[job] = { result: "skipped" }; + needs.changes.outputs[output] = "false"; + } + needs.changes.outputs.windows_win7_bundle = "true"; + needs["windows-standard-check"].result = "success"; + needs["windows-win7-bundle"].result = "success"; + assert.deepEqual(gateFailures(needs, "all"), []); + + needs["windows-standard-check"].result = "skipped"; + assert.ok(gateFailures(needs, "all").length); + needs["windows-standard-check"].result = "success"; + needs["windows-win7-bundle"].result = "skipped"; + assert.ok(gateFailures(needs, "all").length); +}); + test("coverage audit rejects lost features, omitted packages, and overlapping group selection", () => { const coverage = { workspace: Object.fromEntries(Object.keys(graph).map((name) => [name, ["fixture"]])), ...Object.fromEntries(Object.entries(rustGroups).map(([group, packages]) => [group, Object.fromEntries(packages.map((name) => [name, ["fixture"]]))])) }; diff --git a/.github/scripts/ci-workflow.test.mjs b/.github/scripts/ci-workflow.test.mjs index c0ece323d3..0b6d4747ac 100644 --- a/.github/scripts/ci-workflow.test.mjs +++ b/.github/scripts/ci-workflow.test.mjs @@ -37,7 +37,7 @@ test("stable Rust, Agent and overall gates always inspect selected upstream resu for (const [name, mode, dependencies] of [["rust", "rust", ["fast-checks", "rust-fmt-clippy", "rust-test"]], ["agents", "agents", ["fast-checks", "agent-checks", "agent-rust", "agent-go", "agent-integration", "agent-java"]], ["frontend", "frontend", ["frontend-checks", "frontend-typecheck", "frontend-test"]], - ["ci", "all", ["rust", "agents", "frontend", "packages", "windows-win7-bundle", "duckdb-windows-driver", "nix-packaging"]]]) { + ["ci", "all", ["rust", "agents", "frontend", "packages", "windows-standard-check", "windows-win7-bundle", "duckdb-windows-driver", "nix-packaging"]]]) { const content = job(name); assert.match(content, /if: always\(\)/); assert.ok(content.includes(`node .github/scripts/ci-gate.mjs ${mode}`)); @@ -88,6 +88,21 @@ test("DuckDB Windows builds persist Rust and C++ compiler results", () => { assert.ok(content.includes('version: "v0.16.0"')); }); +test("standard Windows compatibility checks run separately with sccache", () => { + const standard = job("windows-standard-check"); + assert.ok(standard.includes("needs.changes.outputs.windows_win7_bundle == 'true'")); + assert.ok(standard.includes("RUSTC_WRAPPER: sccache")); + assert.ok(standard.includes('SCCACHE_GHA_ENABLED: "true"')); + assert.ok(standard.includes("SCCACHE_GHA_VERSION: windows-standard-v1")); + assert.ok(standard.includes("fc920bf0ec8de6ee65d409111f7ec508035751ba")); + assert.ok(standard.includes('version: "v0.16.0"')); + assert.ok(standard.includes("cargo check --locked --package dbx --no-default-features --target x86_64-pc-windows-msvc")); + assert.ok(standard.includes("sccache --show-stats")); + + const win7 = job("windows-win7-bundle"); + assert.doesNotMatch(win7, /x86_64-pc-windows-msvc|Setup Rust for standard Windows|RUSTC_WRAPPER: sccache/); +}); + test("the planner uses the exact event base and preserves a single workflow cancellation scope", () => { const changes = job("changes"); assert.ok(changes.includes("github.event.pull_request.base.sha || github.event.before")); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c4df280712..4704617ec6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,6 +269,35 @@ jobs: continue-on-error: true run: ${SCCACHE_PATH} --show-stats + windows-standard-check: + needs: changes + if: needs.changes.outputs.windows_win7_bundle == 'true' + runs-on: windows-2022 + timeout-minutes: 45 + env: + CARGO_INCREMENTAL: "0" + RUSTFLAGS: -C debuginfo=line-tables-only -C target-feature=+crt-static + RUSTC_WRAPPER: sccache + SCCACHE_GHA_ENABLED: "true" + SCCACHE_GHA_VERSION: windows-standard-v1 + steps: + - uses: actions/checkout@v5 + + - name: Setup Rust for standard Windows + uses: dtolnay/rust-toolchain@1.97.1 + + - uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11 + with: + version: "v0.16.0" + + - name: Check standard Windows dependency path + run: cargo check --locked --package dbx --no-default-features --target x86_64-pc-windows-msvc + + - name: Show sccache stats + if: always() + continue-on-error: true + run: sccache --show-stats + windows-win7-bundle: needs: changes if: needs.changes.outputs.windows_win7_bundle == 'true' @@ -294,12 +323,6 @@ jobs: - name: Install frontend dependencies run: pnpm install --frozen-lockfile - - name: Setup Rust for standard Windows - uses: dtolnay/rust-toolchain@1.97.1 - - - name: Check standard Windows dependency path - run: cargo check --locked --package dbx --no-default-features --target x86_64-pc-windows-msvc - - name: Setup Rust for Windows 7 uses: dtolnay/rust-toolchain@nightly with: @@ -1116,6 +1139,7 @@ jobs: - frontend - github-scripts - packages + - windows-standard-check - windows-win7-bundle - duckdb-windows-driver - jdbc