#!/usr/bin/env python3 import argparse import subprocess import tomllib from pathlib import Path ROOT = Path(__file__).resolve().parents[2] WINDOWS_SOURCE_BUILD_PATHS = { ".github/scripts/rusty_v8_bazel.py", ".github/scripts/rusty_v8_module_bazel.py", ".github/scripts/v8_canary_changes.py", ".github/workflows/rusty-v8-release.yml", ".github/workflows/v8-canary.yml", } def resolved_v8_version(cargo_lock: bytes) -> str: versions = sorted( { package["version"] for package in tomllib.loads(cargo_lock.decode())["package"] if package["name"] == "v8" } ) if len(versions) != 1: raise ValueError(f"expected exactly one resolved v8 version, found: {versions}") return versions[0] def windows_source_required( changed_files: set[str], base_v8_version: str, head_v8_version: str, *, force: bool = False, ) -> bool: return ( force or base_v8_version != head_v8_version or not changed_files.isdisjoint(WINDOWS_SOURCE_BUILD_PATHS) ) def git_output(*args: str, root: Path = ROOT) -> bytes: return subprocess.check_output(["git", *args], cwd=root) def v8_version_at_revision(revision: str, *, root: Path = ROOT) -> str: return resolved_v8_version( git_output("show", f"{revision}:codex-rs/Cargo.lock", root=root) ) def merge_base(base: str, head: str, *, root: Path = ROOT) -> str: return git_output("merge-base", base, head, root=root).decode().strip() def changed_files(base: str, head: str, *, root: Path = ROOT) -> set[str]: output = git_output( "diff", "--name-only", "--no-renames", f"{base}...{head}", root=root, ) return set(output.decode().splitlines()) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser() parser.add_argument("--base") parser.add_argument("--head") parser.add_argument("--force", action="store_true") return parser.parse_args() def main() -> None: args = parse_args() if args.force: required = True reason = "manual workflow dispatch" elif not args.base or not args.head: raise SystemExit("--base and --head are required unless --force is set") else: files = changed_files(args.base, args.head) base_version = v8_version_at_revision(merge_base(args.base, args.head)) head_version = v8_version_at_revision(args.head) required = windows_source_required(files, base_version, head_version) if base_version != head_version: reason = f"v8 version changed from {base_version} to {head_version}" else: matched_paths = sorted(files & WINDOWS_SOURCE_BUILD_PATHS) reason = ( ", ".join(matched_paths) if matched_paths else "no relevant changes" ) print(f"windows_source_required={str(required).lower()}") print(f"windows_source_reason={reason}") if __name__ == "__main__": main()