From 6a4fa1b6a81c07bb00df31db279dfe0f19306c8c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:44:08 +0000 Subject: [PATCH 1/7] Speed up Windows CI by scoping targets and adding cache/profile Co-authored-by: tameware <4573152+tameware@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 57 ++++++++++++++++++++----- python/tests/ci_windows_cppopts_test.py | 32 ++++++++++++-- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 94e97789..86d08108 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -9,6 +9,14 @@ jobs: build_and_test: runs-on: windows-latest timeout-minutes: 20 + env: + BAZEL_DISK_CACHE: ${{ github.workspace }}\.bazel-cache\disk + BAZEL_PROFILE_JSON: ${{ github.workspace }}\windows-fastbuild-profile.json.gz + BAZEL_PROFILE_TXT: ${{ github.workspace }}\windows-fastbuild-profile.txt + WINDOWS_FASTBUILD_TARGETS: >- + //library/... //examples/... //python/... //jni/... + WINDOWS_OPT_TARGETS: >- + //library/src:dds //examples:analyse_play_pbn steps: # Checkout the repository - name: Checkout repository @@ -18,13 +26,23 @@ jobs: - 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', '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: | + $fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split ' ' $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 +51,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: | + $fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split ' ' + 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: | + $opt_targets = $env:WINDOWS_OPT_TARGETS -split ' ' $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,9 +76,10 @@ 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 //... + # Summarize profile hotspots for follow-up CI tuning + - name: Analyze Bazel profile + shell: pwsh + run: bazelisk analyze-profile "$env:BAZEL_PROFILE_JSON" | Out-File -FilePath "$env:BAZEL_PROFILE_TXT" -Encoding utf8 # Upload test logs - name: Upload test logs - Windows @@ -65,3 +90,15 @@ 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 + ${{ github.workspace }}\windows-fastbuild-profile.txt + 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..3fe1b5d9 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,37 @@ 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.assertIn("bazelisk analyze-profile", 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", ) From dd111446e6da467cd6c50e58bafbacd96ad4c10c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 21:37:30 +0000 Subject: [PATCH 2/7] Cache Bazelisk downloads in Windows CI Co-authored-by: tameware <4573152+tameware@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 86d08108..12b27204 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -10,6 +10,7 @@ jobs: 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 BAZEL_PROFILE_TXT: ${{ github.workspace }}\windows-fastbuild-profile.txt @@ -22,6 +23,15 @@ jobs: - 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 From 541f8a76724233bf3615f0e9b3e28668d231e5ad Mon Sep 17 00:00:00 2001 From: Adam Wildavsky Date: Mon, 10 Aug 2026 22:52:15 +0100 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 12b27204..d09c1173 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -41,7 +41,7 @@ jobs: uses: actions/cache@v4 with: path: ${{ github.workspace }}\.bazel-cache\disk - key: windows-bazel-disk-cache-${{ runner.os }}-${{ hashFiles('.bazelversion', '.bazelrc', 'MODULE.bazel', 'BUILD.bazel', 'CPPVARIABLES.bzl') }} + 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 }}- @@ -88,8 +88,14 @@ jobs: # Summarize profile hotspots for follow-up CI tuning - name: Analyze Bazel profile + if: always() shell: pwsh - run: bazelisk analyze-profile "$env:BAZEL_PROFILE_JSON" | Out-File -FilePath "$env:BAZEL_PROFILE_TXT" -Encoding utf8 + run: | + if (Test-Path "$env:BAZEL_PROFILE_JSON") { + bazelisk analyze-profile "$env:BAZEL_PROFILE_JSON" | Out-File -FilePath "$env:BAZEL_PROFILE_TXT" -Encoding utf8 + } else { + Write-Host "No Bazel profile found at $env:BAZEL_PROFILE_JSON; skipping analyze-profile." + } # Upload test logs - name: Upload test logs - Windows From a7606633f41475fd27533942308f0053a4ae9bd6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 21:55:20 +0000 Subject: [PATCH 4/7] Fix Windows CI: use PowerShell array splatting (@arr) to pass Bazel targets as separate args Previously, $arr passed to a native command in PowerShell joined array elements into a single space-separated string, so Bazel received the full target list as one invalid package name. Switching to @arr splatting passes each element as a distinct argument across all PowerShell versions. Also use -split '\s+' with a non-empty filter to tolerate any whitespace variation in the env var value. Co-authored-by: tameware <4573152+tameware@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index d09c1173..74b6c6e9 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -49,10 +49,10 @@ jobs: - name: Prefetch external repos shell: pwsh run: | - $fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split ' ' + [string[]]$fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split '\s+' | Where-Object { $_ -ne '' } $max = 3 for ($i = 1; $i -le $max; $i++) { - bazelisk fetch --disk_cache="$env:BAZEL_DISK_CACHE" --verbose_failures $fastbuild_targets + 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..." @@ -65,17 +65,17 @@ jobs: - name: Run Windows test targets shell: pwsh run: | - $fastbuild_targets = $env:WINDOWS_FASTBUILD_TARGETS -split ' ' - bazelisk test --disk_cache="$env:BAZEL_DISK_CACHE" --profile="$env:BAZEL_PROFILE_JSON" --verbose_failures $fastbuild_targets + [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: | - $opt_targets = $env:WINDOWS_OPT_TARGETS -split ' ' + [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 --disk_cache="$env:BAZEL_DISK_CACHE" --verbose_failures $opt_targets + 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..." From 98d42034c1aba8b53693041e679a94e457c69641 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 22:18:06 +0000 Subject: [PATCH 5/7] ci: remove analyze-profile step removed in Bazel 9 Co-authored-by: tameware <4573152+tameware@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 74b6c6e9..89603f6f 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -13,7 +13,6 @@ jobs: 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 - BAZEL_PROFILE_TXT: ${{ github.workspace }}\windows-fastbuild-profile.txt WINDOWS_FASTBUILD_TARGETS: >- //library/... //examples/... //python/... //jni/... WINDOWS_OPT_TARGETS: >- @@ -86,17 +85,6 @@ jobs: } exit 1 - # Summarize profile hotspots for follow-up CI tuning - - name: Analyze Bazel profile - if: always() - shell: pwsh - run: | - if (Test-Path "$env:BAZEL_PROFILE_JSON") { - bazelisk analyze-profile "$env:BAZEL_PROFILE_JSON" | Out-File -FilePath "$env:BAZEL_PROFILE_TXT" -Encoding utf8 - } else { - Write-Host "No Bazel profile found at $env:BAZEL_PROFILE_JSON; skipping analyze-profile." - } - # Upload test logs - name: Upload test logs - Windows if: always() @@ -115,6 +103,5 @@ jobs: name: bazel-profile-windows path: | ${{ github.workspace }}\windows-fastbuild-profile.json.gz - ${{ github.workspace }}\windows-fastbuild-profile.txt if-no-files-found: ignore retention-days: 30 From f0b6189bc85803852c0b4420c222ab82f9652b45 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Aug 2026 06:15:01 +0000 Subject: [PATCH 6/7] ci: add bazelisk analyze-profile step to Windows workflow Co-authored-by: tameware <4573152+tameware@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 89603f6f..2b5ccac8 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -85,6 +85,15 @@ jobs: } exit 1 + # Summarise the profile captured during the test run + - name: Analyze Bazel profile + if: always() + shell: pwsh + run: | + if (Test-Path "$env:BAZEL_PROFILE_JSON") { + bazelisk analyze-profile "$env:BAZEL_PROFILE_JSON" + } + # Upload test logs - name: Upload test logs - Windows if: always() From 3ce36a2b2ad68f71646fe0df28e6fa4a74a5dd1e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Aug 2026 06:23:16 +0000 Subject: [PATCH 7/7] ci: remove bazelisk analyze-profile step and its test assertion Co-authored-by: tameware <4573152+tameware@users.noreply.github.com> --- .github/workflows/ci_windows.yml | 9 --------- python/tests/ci_windows_cppopts_test.py | 1 - 2 files changed, 10 deletions(-) diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 2b5ccac8..89603f6f 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -85,15 +85,6 @@ jobs: } exit 1 - # Summarise the profile captured during the test run - - name: Analyze Bazel profile - if: always() - shell: pwsh - run: | - if (Test-Path "$env:BAZEL_PROFILE_JSON") { - bazelisk analyze-profile "$env:BAZEL_PROFILE_JSON" - } - # Upload test logs - name: Upload test logs - Windows if: always() diff --git a/python/tests/ci_windows_cppopts_test.py b/python/tests/ci_windows_cppopts_test.py index 3fe1b5d9..79e0db21 100644 --- a/python/tests/ci_windows_cppopts_test.py +++ b/python/tests/ci_windows_cppopts_test.py @@ -385,7 +385,6 @@ def test_windows_ci_limits_scope_and_collects_profile(self) -> None: self.assertNotIn("bazelisk fetch //...", text) self.assertNotIn("bazelisk test --verbose_failures //...", text) self.assertNotIn("bazelisk build --config=opt --verbose_failures //...", text) - self.assertIn("bazelisk analyze-profile", text) self.assertRegex( text, r"actions/cache@v4",