diff --git a/tools/pr_overlap.py b/tools/pr_overlap.py index 40a5efb9d..d42e24592 100644 --- a/tools/pr_overlap.py +++ b/tools/pr_overlap.py @@ -16,7 +16,7 @@ MARKER = "" def git(*args): - return subprocess.run(["git", *args], capture_output=True, text=True, encoding="utf-8", check=True).stdout + return subprocess.run(["git", *args], capture_output=True, text=True, encoding="utf-8", errors="replace", check=True).stdout def gh(*args): @@ -49,7 +49,7 @@ def fetch(base, prs): def merge(*args): result = subprocess.run(["git", "merge-tree", "--write-tree", "--name-only", "--no-messages", *args], - capture_output=True, text=True, encoding="utf-8") + capture_output=True, text=True, encoding="utf-8", errors="replace") lines = result.stdout.splitlines() if result.returncode not in (0, 1) or not lines: raise RuntimeError(f"git merge-tree {' '.join(args)} failed: {result.stderr.strip()}") diff --git a/tools/tests/test_pr_overlap_encoding.py b/tools/tests/test_pr_overlap_encoding.py index 9a4c3f449..2d2b92c42 100644 --- a/tools/tests/test_pr_overlap_encoding.py +++ b/tools/tests/test_pr_overlap_encoding.py @@ -1,5 +1,6 @@ from contextlib import contextmanager import json +import os from pathlib import Path import subprocess import sys @@ -74,6 +75,25 @@ class EncodingTests(unittest.TestCase): with self.assertRaisesRegex(RuntimeError, UNICODE): pr_overlap.merge("main", "topic") + def test_git_diff_survives_invalid_utf8(self): + with TemporaryDirectory() as directory: + repo = Path(directory) + source = repo / "core" / "libs" / "prx" / "x" / "a.cpp" + source.parent.mkdir(parents=True) + ident = ["-c", "user.name=t", "-c", "user.email=t@example.test"] + for args in (["init", "-q"], ["commit", "-q", "--allow-empty", "-m", "base"]): + subprocess.run(["git", *ident, *args], cwd=repo, check=True, capture_output=True) + source.write_bytes(b"int APS5_VABI f() {} // caf\xe9\n") + for args in (["add", "."], ["commit", "-q", "-m", "add"]): + subprocess.run(["git", *ident, *args], cwd=repo, check=True, capture_output=True) + old = os.getcwd() + os.chdir(repo) + try: + diff = pr_overlap.git("diff", "-U0", "--no-color", "HEAD~1", "HEAD", "--", "core/libs/prx/*.cpp") + finally: + os.chdir(old) + self.assertEqual(pr_overlap.exports(diff), {"f"}) + def test_report_is_written_as_utf8(self): with TemporaryDirectory() as directory: path = Path(directory) / "1.md"