Files
codex/.github/scripts/test_v8_canary_changes.py
Adam Perry @ OpenAI bd5c860abe ci: route build IO through Dev Drives (#31357)
## Why

Windows Cargo and Bazel jobs spend significant time in filesystem-heavy
build and cache directories. Route those directories through one CI
build root so Windows can use its Dev Drive and Unix can use a stable
cache root.

## What

- Have `setup-ci` define `CI_BUILD_ROOT`, `CARGO_TARGET_DIR`, Bazel
cache/output paths, and temp paths.
- Require Windows to find or provision a verified Dev Drive instead of
falling back to `C:`.
- Pass the shared Bazel output base to `setup-bazel` so its explicit
`output_base` does not defeat Dev Drive routing.
- Point nextest, release, and V8 source-build paths at the shared
environment contract.

## Benchmark results

One-off cold-cache WPR/ETW traces show the explicit Bazel output-base
routing removes the dominant `C:` traffic:

| sample | `C:\_bazel` | summed `C:` traffic | traced test step |
|---|---:|---:|---:|
| shard 1 before | 62.2 GiB | 85.2 GiB | 16m22s |
| shard 1 updated | 0 | 16.5 GiB | 12m05s |
| shard 3 before | 67.2 GiB | 84.6 GiB | 16m48s |
| shard 3 updated | 0 | 13.5 GiB | 11m08s |

For a cold x64 V8 source build, the retained build-tail sample showed
`D:\cargo-target` at ~1.29 GiB while measured `C:` roots totaled ~0.45
GiB (`C:\Users` ~0.33 GiB, `C:\Program Files` ~0.06 GiB, `C:\Windows`
~0.03 GiB). The full cold build took 2h20m36s.

The Bazel timing improvement is directional because both refreshed
shards failed tests. The V8 trace is a bounded build-tail sample, not
the full build. All final samples had zero lost ETW events; VHDX traffic
was excluded from the optimization ranking.

Runs: [baseline
Bazel](https://github.com/openai/codex/actions/runs/28911908527),
[updated
Bazel](https://github.com/openai/codex/actions/runs/28917133701), [V8
build tail](https://github.com/openai/codex/actions/runs/28933626678).

## Manual validation

- Ran `just fmt`.
- Ran `just test-github-scripts` (35 tests).
- Parsed GitHub Actions YAML with `yq`.
- Ran `git diff --check`.

## Stack

- [#31332](https://github.com/openai/codex/pull/31332) — parameterize
Cargo target paths
- [#31356](https://github.com/openai/codex/pull/31356) — Windows 2025
runner bump
- [#31357](https://github.com/openai/codex/pull/31357) — Dev Drive I/O
routing
2026-07-08 14:06:37 -07:00

112 lines
3.6 KiB
Python

import subprocess
import tempfile
import unittest
from pathlib import Path
from v8_canary_changes import changed_files
from v8_canary_changes import canary_required
from v8_canary_changes import merge_base
from v8_canary_changes import resolved_v8_version
from v8_canary_changes import windows_source_required
class V8CanaryChangesTest(unittest.TestCase):
def test_resolved_v8_version(self) -> None:
cargo_lock = b"""\
[[package]]
name = "other"
version = "1.0.0"
[[package]]
name = "v8"
version = "149.2.0"
"""
self.assertEqual(resolved_v8_version(cargo_lock), "149.2.0")
def test_unrelated_cargo_manifest_change_does_not_require_source_build(
self,
) -> None:
self.assertFalse(
windows_source_required(
{"codex-rs/Cargo.toml"},
"149.2.0",
"149.2.0",
)
)
def test_v8_version_change_requires_source_build(self) -> None:
self.assertTrue(windows_source_required(set(), "149.2.0", "150.0.0"))
def test_module_helper_change_requires_source_build(self) -> None:
self.assertTrue(
windows_source_required(
{".github/scripts/rusty_v8_module_bazel.py"},
"149.2.0",
"149.2.0",
)
)
def test_shared_ci_setup_changes_require_canary_and_source_build(self) -> None:
for path in (
".github/actions/setup-ci/action.yml",
".github/scripts/setup-dev-drive.ps1",
):
with self.subTest(path=path):
changed_files = {path}
self.assertTrue(canary_required(changed_files, "149.2.0", "149.2.0"))
self.assertTrue(
windows_source_required(changed_files, "149.2.0", "149.2.0")
)
def test_manual_dispatch_requires_source_build(self) -> None:
self.assertTrue(
windows_source_required(
set(),
"149.2.0",
"149.2.0",
force=True,
)
)
def test_changed_files_excludes_changes_made_only_on_base_branch(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
root = Path(temp_dir)
self.run_git(root, "init", "--initial-branch=main")
self.run_git(root, "config", "user.name", "Test User")
self.run_git(root, "config", "user.email", "test@example.com")
self.write_and_commit(root, "initial", "initial.txt")
common = self.run_git(root, "rev-parse", "HEAD")
self.run_git(root, "switch", "-c", "feature")
self.run_git(root, "switch", "main")
self.write_and_commit(root, "base-only", "base-only.txt")
base = self.run_git(root, "rev-parse", "HEAD")
self.run_git(root, "switch", "feature")
self.write_and_commit(root, "feature-only", "feature-only.txt")
head = self.run_git(root, "rev-parse", "HEAD")
self.assertEqual(
changed_files(base, head, root=root),
{"feature-only.txt"},
)
self.assertEqual(merge_base(base, head, root=root), common)
def write_and_commit(self, root: Path, contents: str, path: str) -> None:
(root / path).write_text(contents)
self.run_git(root, "add", path)
self.run_git(root, "commit", "-m", contents)
def run_git(self, root: Path, *args: str) -> str:
return subprocess.check_output(
["git", *args],
cwd=root,
stderr=subprocess.PIPE,
text=True,
).strip()
if __name__ == "__main__":
unittest.main()