diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 94e97789..89603f6f 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -9,22 +9,49 @@ jobs: build_and_test: runs-on: windows-latest timeout-minutes: 20 + env: + BAZELISK_HOME: ${{ github.workspace }}\.bazel-cache\bazelisk + BAZEL_DISK_CACHE: ${{ github.workspace }}\.bazel-cache\disk + BAZEL_PROFILE_JSON: ${{ github.workspace }}\windows-fastbuild-profile.json.gz + WINDOWS_FASTBUILD_TARGETS: >- + //library/... //examples/... //python/... //jni/... + WINDOWS_OPT_TARGETS: >- + //library/src:dds //examples:analyse_play_pbn steps: # Checkout the repository - name: Checkout repository uses: actions/checkout@v6 + # Reuse downloaded Bazel binaries across workflow runs + - name: Restore Bazelisk cache + uses: actions/cache@v4 + with: + path: ${{ env.BAZELISK_HOME }} + key: windows-bazelisk-cache-${{ runner.os }}-${{ hashFiles('.bazelversion') }} + restore-keys: | + windows-bazelisk-cache-${{ runner.os }}- + # Install Bazelisk (recommended Bazel launcher) - name: Setup Bazelisk uses: ./.github/actions/setup-bazelisk - # Warm external deps (emsdk, LLVM, …); retry transient network fetch failures + # Reuse compiled/action cache artifacts across workflow runs + - name: Restore Bazel disk cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}\.bazel-cache\disk + key: windows-bazel-disk-cache-${{ runner.os }}-${{ hashFiles('.bazelversion', '.bazelrc', 'MODULE.bazel', 'MODULE.bazel.lock', 'BUILD.bazel', 'CPPVARIABLES.bzl') }} + restore-keys: | + windows-bazel-disk-cache-${{ runner.os }}- + + # Warm external deps for the same scope tested on Windows - name: Prefetch external repos shell: pwsh run: | + [string[]]$fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split '\s+' | Where-Object { $_ -ne '' } $max = 3 for ($i = 1; $i -le $max; $i++) { - bazelisk fetch //... + bazelisk fetch --disk_cache="$env:BAZEL_DISK_CACHE" --verbose_failures @fastbuild_targets if ($LASTEXITCODE -eq 0) { exit 0 } if ($i -lt $max) { Write-Host "Fetch failed (attempt $i/$max). Retrying in 20s..." @@ -33,15 +60,21 @@ jobs: } exit 1 - # Build all targets (retry: fetch flakes can still surface on first analysis). - # --config=opt: DDS_CPPOPTS no longer forces /O2 (that fought Bazel's /Od and - # triggered MSVC D9025); opt mode is how Windows keeps release-level codegen. - - name: Bazel build (retry on transient fetch failure) + # Run Windows-native coverage in fastbuild (test-centric flow) + - name: Run Windows test targets + shell: pwsh + run: | + [string[]]$fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split '\s+' | Where-Object { $_ -ne '' } + bazelisk test --disk_cache="$env:BAZEL_DISK_CACHE" --profile="$env:BAZEL_PROFILE_JSON" --verbose_failures @fastbuild_targets + + # Keep a narrow release-level check on Windows with --config=opt + - name: Build Windows opt smoke targets (retry on transient fetch failure) shell: pwsh run: | + [string[]]$opt_targets = $env:WINDOWS_OPT_TARGETS -split '\s+' | Where-Object { $_ -ne '' } $max = 3 for ($i = 1; $i -le $max; $i++) { - bazelisk build --config=opt --verbose_failures //... + bazelisk build --config=opt --disk_cache="$env:BAZEL_DISK_CACHE" --verbose_failures @opt_targets if ($LASTEXITCODE -eq 0) { exit 0 } if ($i -lt $max) { Write-Host "Build failed (attempt $i/$max). Retrying in 20s..." @@ -52,10 +85,6 @@ jobs: } exit 1 - # Run all tests (including Python) — no retry so real test failures surface quickly - - name: Run all tests - run: bazelisk test --config=opt --verbose_failures //... - # Upload test logs - name: Upload test logs - Windows if: always() @@ -65,3 +94,14 @@ jobs: path: bazel-testlogs/ if-no-files-found: ignore retention-days: 30 + + # Upload profile artifacts + - name: Upload Bazel profile - Windows + if: always() + uses: actions/upload-artifact@v6 + with: + name: bazel-profile-windows + path: | + ${{ github.workspace }}\windows-fastbuild-profile.json.gz + if-no-files-found: ignore + retention-days: 30 diff --git a/python/tests/ci_windows_cppopts_test.py b/python/tests/ci_windows_cppopts_test.py index c31ea411..79e0db21 100644 --- a/python/tests/ci_windows_cppopts_test.py +++ b/python/tests/ci_windows_cppopts_test.py @@ -67,6 +67,10 @@ def _bazelisk_invocation_has_config_opt(text: str, subcommand: str) -> bool: return False +def _workflow_lines_with(text: str, needle: str) -> list[str]: + return [line for line in text.splitlines() if needle in line] + + class TestWindowsMsvcCppoptsAvoidD9025(unittest.TestCase): def test_windows_cppopts_do_not_override_bazel_optimization(self) -> None: """Bazel already sets /Od (fastbuild/dbg) or /O2 (opt); re-stating any @@ -360,17 +364,36 @@ def test_matches_when_config_opt_precedes_trailing_comment(self) -> None: class TestWindowsCiUsesOpt(unittest.TestCase): def test_windows_ci_passes_config_opt(self) -> None: - """Without /O2 in DDS_CPPOPTS, CI must opt in via --config=opt.""" + """Windows CI keeps opt only for a focused release validation step.""" text = ( _repo_root() / ".github" / "workflows" / "ci_windows.yml" ).read_text(encoding="utf-8") + self.assertFalse( + _bazelisk_invocation_has_config_opt(text, "test"), + "expected broad Windows test coverage to run in fastbuild", + ) self.assertTrue( _bazelisk_invocation_has_config_opt(text, "build"), - "expected Windows CI build to use --config=opt", + "expected a focused Windows build step to keep --config=opt", ) + + def test_windows_ci_limits_scope_and_collects_profile(self) -> None: + text = ( + _repo_root() / ".github" / "workflows" / "ci_windows.yml" + ).read_text(encoding="utf-8") + self.assertIn("WINDOWS_FASTBUILD_TARGETS", text) + self.assertNotIn("bazelisk fetch //...", text) + self.assertNotIn("bazelisk test --verbose_failures //...", text) + self.assertNotIn("bazelisk build --config=opt --verbose_failures //...", text) + self.assertRegex( + text, + r"actions/cache@v4", + "expected Windows workflow to enable cross-run Bazel caching", + ) + test_lines = _workflow_lines_with(text, "bazelisk test") self.assertTrue( - _bazelisk_invocation_has_config_opt(text, "test"), - "expected Windows CI test to use --config=opt", + any("--profile=" in line for line in test_lines), + "expected Windows test command to emit a Bazel profile", )