From 791dc63c050da578a18ea5523dec2deabd1212ff Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 4 Oct 2026 22:09:51 -0700 Subject: [PATCH] fix(code-health): CRLF blobs measure like LF on Windows Measurer.measure wrote each blob's decoded text into the temp tree with write_text's default newline translation. On Windows that turns a CRLF blob into CR CR LF, so ruff counted lines differently from the AST and comment tables: hits moved to , their `# health: allow` waivers were missed, and valid code blocked. Writing with newline="" keeps the blob's own line endings. The test forces the Windows write translation so it also runs on Linux. --- scripts/code_health/measure.py | 4 +++- tests/scripts/test_code_health.py | 37 ++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/scripts/code_health/measure.py b/scripts/code_health/measure.py index fac5a222b2..038a66543c 100644 --- a/scripts/code_health/measure.py +++ b/scripts/code_health/measure.py @@ -127,7 +127,9 @@ class Measurer: for path, text in contents.items(): dest = root / path dest.parent.mkdir(parents=True, exist_ok=True) - dest.write_text(text, encoding="utf-8") + # newline="": the blob's own line endings, so ruff's line numbers match the + # AST's (Windows text mode would turn a CRLF blob into CR CR LF). + dest.write_text(text, encoding="utf-8", newline="") return self._measure_in(root, contents) def _measure_in(self, root: Path, contents: dict[str, str]) -> dict[str, FileMeasure]: diff --git a/tests/scripts/test_code_health.py b/tests/scripts/test_code_health.py index 7cee072e16..cbb8cc4817 100644 --- a/tests/scripts/test_code_health.py +++ b/tests/scripts/test_code_health.py @@ -9,8 +9,12 @@ from pathlib import Path import pytest -from scripts.code_health import replay +from scripts.code_health import gitio, replay from scripts.code_health.cli import run +from scripts.code_health.compare import compare +from scripts.code_health.measure import Measurer +from scripts.code_health.report import apply_allows +from scripts.code_health.ruff_runner import resolve_ruff REPO = Path(__file__).resolve().parents[2] _LEGACY = "def legacy(x):\n" + "".join(f" if x == {i}:\n return {i}\n" for i in range(21)) @@ -202,3 +206,34 @@ def test_replay_reports_unmeasured_prs_and_fails(tmp_path, monkeypatch, capsys): assert "1 of 1 measured PRs had at least one blocking finding" in out, out assert "2 of 3 PRs could not be measured: #2, #3" in out, out + +# --- a blob's line endings never move a hit, its scope or its waiver --- + + +def _windows_write_text(self, data, encoding=None, errors=None, newline=None): + """``Path.write_text`` as on Windows, where ``newline=None`` turns each "\n" into "\r\n".""" + if newline is None: + data = data.replace("\n", "\r\n") + with open(self, "w", encoding=encoding, errors=errors, newline="") as fh: + return fh.write(data) + + +def test_crlf_blob_measures_like_lf(tmp_path, monkeypatch): + waived = _SWALLOW.replace("except Exception:", "except Exception: # health: allow BLE001 S110 -- boundary") + results = {} + for name, eol in (("lf", "\n"), ("crlf", "\r\n")): + repo, base = _repo(tmp_path / name) + _git(repo, "config", "core.autocrlf", "false") + (repo / "pkg/b.py").write_bytes(waived.replace("\n", eol).encode("utf-8")) + head = _commit(repo, {}) + assert (eol == "\r\n") == (b"\r\n" in subprocess.run( + ["git", "show", f"{head}:pkg/b.py"], cwd=repo, capture_output=True, timeout=60, check=True).stdout) + with monkeypatch.context() as patch: + patch.setattr(Path, "write_text", _windows_write_text) + measurer = Measurer(repo, resolve_ruff(repo), known_env=set()) + base_m, head_m = measurer.measure(base, []), measurer.measure(head, ["pkg/b.py"]) + findings = compare(base_m, head_m, gitio.changed_files(repo, base, head)) + apply_allows(findings, head_m) + results[name] = sorted((f.rule, f.scope, f.line, f.allowed_reason) for f in findings) + assert results["lf"] == [("BLE001", "other", 4, "boundary"), ("S110", "other", 4, "boundary")] + assert results["crlf"] == results["lf"]