Skip to content

Commit 2be0fcd

Browse files
committed
Match odd and renamed paths in the vlt gate
`git diff --name-only` split on whitespace dropped paths with spaces, quoted non-ASCII names, and reported only the new side of a rename, so a vlt file changed that way next to an inert ci.yml edit could read as "only ci.yml changed". Read NUL-separated paths with --no-renames and test it against a scratch repository. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YVLGaJFexMvqCdiWxbiHXB
1 parent 9b8fe12 commit 2be0fcd

2 files changed

Lines changed: 68 additions & 2 deletions

File tree

‎scripts/tests/test_vlt_compat_gate.py‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import contextlib
55
import importlib.util
66
import io
7+
import subprocess
8+
import tempfile
79
import unittest
810
from pathlib import Path
911

@@ -73,6 +75,66 @@ def test_no_base_runs(self):
7375
self.assertEqual(out.getvalue().split(), ["matrix=true"])
7476

7577

78+
class ChangedPaths(unittest.TestCase):
79+
"""main() on real commits: odd file names and renames still match."""
80+
81+
def commit_pair(self, before, after):
82+
tmp = tempfile.TemporaryDirectory()
83+
self.addCleanup(tmp.cleanup)
84+
repo = Path(tmp.name)
85+
86+
def run(*args):
87+
return subprocess.run(["git", *args], cwd=repo, check=True, capture_output=True,
88+
text=True).stdout.strip()
89+
90+
def write(files):
91+
for name, body in files.items():
92+
path = repo / name
93+
path.parent.mkdir(parents=True, exist_ok=True)
94+
path.write_text(body, encoding="utf-8")
95+
96+
run("init", "-q")
97+
run("config", "user.email", "t@example.com")
98+
run("config", "user.name", "t")
99+
write(before)
100+
run("add", "-A")
101+
run("commit", "-qm", "base")
102+
base = run("rev-parse", "HEAD")
103+
for name in [n for n in before if n not in after]:
104+
run("rm", "-q", name)
105+
write(after)
106+
run("add", "-A")
107+
run("commit", "-qm", "head")
108+
return repo, base
109+
110+
def decide(self, before, after):
111+
repo, base = self.commit_pair(before, after)
112+
out = io.StringIO()
113+
old_repo = gate.REPO
114+
gate.REPO = repo
115+
try:
116+
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(io.StringIO()):
117+
gate.main(["--event", "pull_request", "--base", base])
118+
finally:
119+
gate.REPO = old_repo
120+
return out.getvalue().split()
121+
122+
def base_tree(self):
123+
return {CI_PATH: CI, "scripts/check-vlt-legs.py": "x\n"}
124+
125+
def test_inert_ci_yml_edit_skips(self):
126+
after = dict(self.base_tree(), **{CI_PATH: CI + "\n# unrelated\n"})
127+
self.assertEqual(self.decide(self.base_tree(), after), ["matrix=false"])
128+
129+
def test_odd_names_and_renames_still_run(self):
130+
for name in ("crates/socket-patch-cli/tests/a vlt b.rs",
131+
"crates/socket-patch-cli/tests/\u00e9vlt.rs"):
132+
after = dict(self.base_tree(), **{CI_PATH: CI + "\n# unrelated\n", name: "x\n"})
133+
self.assertEqual(self.decide(self.base_tree(), after), ["matrix=true"], name)
134+
moved = {CI_PATH: CI + "\n# unrelated\n", "scripts/elsewhere.py": "x\n"}
135+
self.assertEqual(self.decide(self.base_tree(), moved), ["matrix=true"])
136+
137+
76138
class Workflow(unittest.TestCase):
77139
def test_heavy_jobs_wait_on_the_gate(self):
78140
for job in ("build", "plan"):

‎scripts/vlt-compat-gate.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
ROOT = Path(__file__).resolve().parents[1]
2222
WORKFLOW = ROOT / ".github" / "workflows" / "vlt-compatibility.yml"
23+
REPO = ROOT # where git runs; the tests point it at a scratch repository
2324
CI_PATH = ".github/workflows/ci.yml"
2425

2526

@@ -69,7 +70,7 @@ def ci_cells(text):
6970

7071

7172
def git(*args):
72-
return subprocess.run(["git", *args], cwd=ROOT, capture_output=True, text=True, check=True).stdout
73+
return subprocess.run(["git", *args], cwd=REPO, capture_output=True, text=True, check=True).stdout
7374

7475

7576
def needs_matrix(event, changed, filters, base_ci, head_ci):
@@ -92,7 +93,10 @@ def main(argv=None):
9293
matrix = True
9394
if args.event in ("pull_request", "push") and args.base:
9495
try:
95-
changed = git("diff", "--name-only", args.base, args.head).split()
96+
# NUL-separated paths are never quoted or split on spaces; with
97+
# --no-renames a moved file lists both its old and new path.
98+
out = git("diff", "-z", "--name-only", "--no-renames", args.base, args.head)
99+
changed = [p for p in out.split("\0") if p]
96100
filters = event_paths(WORKFLOW.read_text(encoding="utf-8"), args.event)
97101
base_ci = git("show", f"{args.base}:{CI_PATH}")
98102
head_ci = git("show", f"{args.head}:{CI_PATH}")

0 commit comments

Comments
 (0)