From 758e69b56789d76761ca707452bab9a490f6895e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Ortellado?= Date: Wed, 14 Oct 2026 09:14:59 -0300 Subject: [PATCH 1/2] fix(tools): preserve main sync reports on limited encodings --- tools/check_main_sync.py | 2 ++ tools/tests/test_check_main_sync.py | 35 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/tools/check_main_sync.py b/tools/check_main_sync.py index f089a321d9..fa3265d310 100644 --- a/tools/check_main_sync.py +++ b/tools/check_main_sync.py @@ -1,6 +1,7 @@ import argparse import re import subprocess +import sys from pathlib import Path PULL_REQUEST = re.compile(r"Merge pull request #(\d+)") @@ -105,6 +106,7 @@ if __name__ == "__main__": data = report(args.repo, base, args.head) except RuntimeError as error: parser.error(str(error)) + sys.stdout.reconfigure(errors="backslashreplace") print(render(data)) if data["conflicts"]: raise SystemExit(1) diff --git a/tools/tests/test_check_main_sync.py b/tools/tests/test_check_main_sync.py index 14f70e94fc..26e72e7cc0 100644 --- a/tools/tests/test_check_main_sync.py +++ b/tools/tests/test_check_main_sync.py @@ -132,6 +132,41 @@ class CheckMainSyncTests(unittest.TestCase): self.assertEqual(result.returncode, 2) self.assertIn("no common ancestor", result.stderr) + def check_unicode_output(self, conflict): + name = "sp ace \u00e9 \u6e2c \U0001f680.txt" + self.repo.write(name, "one\ntwo\nthree\n") + self.repo.commit("add unicode path") + self.branch("feature") + self.repo.write(name, "one\nmine\nthree\n" if conflict else "zero\none\ntwo\nthree\n") + self.repo.commit("feature edit") + self.repo.git("checkout", "-q", "main") + self.repo.git("checkout", "-q", "-b", "theirs") + self.repo.write(name, "one\ntheirs\nthree\n" if conflict else "one\ntwo\nthree\nfour\n") + self.repo.commit("their edit") + self.repo.git("checkout", "-q", "main") + self.repo.merge_pull(9, "theirs") + expected = {"ascii": r"sp ace \xe9 \u6e2c \U0001f680.txt", + "cp1252": "sp ace \u00e9 " + r"\u6e2c \U0001f680.txt", + "utf-8": name} + for encoding, shown in expected.items(): + for strict in ((False,) if conflict else (False, True)): + with self.subTest(encoding=encoding, strict=strict): + result = subprocess.run([sys.executable, str(TOOL), "--repo", str(self.repo.path), + "--base", "main", "--head", "feature", *(["--strict"] if strict else [])], + capture_output=True, text=True, encoding=encoding, + env={**os.environ, "PYTHONIOENCODING": encoding + ":strict"}) + self.assertEqual(result.returncode, 1 if conflict or strict else 0, result.stderr) + self.assertIn("merge: CONFLICT" if conflict else "merge: clean", result.stdout) + self.assertIn(f" {shown}\n", result.stdout.replace("\r", "")) + self.assertIn("merged pull requests that touched them: #9", result.stdout) + self.assertNotIn("Traceback", result.stderr) + + def test_clean_unicode_report_preserves_exit_status_and_output_encoding(self): + self.check_unicode_output(False) + + def test_conflicting_unicode_report_preserves_exit_status_and_output_encoding(self): + self.check_unicode_output(True) + def test_missing_base_is_an_error_not_a_pass(self): result = subprocess.run([sys.executable, str(TOOL), "--repo", self.directory.name, "--base", "upstream/main"], capture_output=True, text=True) self.assertEqual(result.returncode, 2) From d4cce869eb12c4dc52537bf2a6cbb0b76e4f57f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Ortellado?= Date: Thu, 15 Oct 2026 10:11:54 -0300 Subject: [PATCH 2/2] test(tools): pin check_main_sync subprocess encoding --- tools/tests/test_check_main_sync.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/tests/test_check_main_sync.py b/tools/tests/test_check_main_sync.py index 26e72e7cc0..4a13a56e0a 100644 --- a/tools/tests/test_check_main_sync.py +++ b/tools/tests/test_check_main_sync.py @@ -38,7 +38,12 @@ class Repo: def run_tool(path, *args): - return subprocess.run([sys.executable, str(TOOL), "--repo", str(path), "--base", "main", *args], capture_output=True, text=True) + return subprocess.run( + [sys.executable, str(TOOL), "--repo", str(path), "--base", "main", *args], + capture_output=True, + encoding="utf-8", + env={**os.environ, "PYTHONIOENCODING": "utf-8"}, + ) class CheckMainSyncTests(unittest.TestCase):