fix(780): reconcile the ruff gate with #784, merged in parallel
PR Gates / Docs update reminder (pull_request) Successful in 22s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 38s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 12s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 12s
PR Gates / decisions lifecycle (pull_request) Successful in 30s
Review verdict / Set review-verdict status (pull_request_target) Successful in 36s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 4m28s
review-verdict/h10 Review-verdict: MERGEABLE @ eda2fac (base: main)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m33s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m7s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 5m46s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 9s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 6s
PR Gates / Docs update reminder (pull_request) Successful in 22s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 38s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 12s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 12s
PR Gates / decisions lifecycle (pull_request) Successful in 30s
Review verdict / Set review-verdict status (pull_request_target) Successful in 36s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 4m28s
review-verdict/h10 Review-verdict: MERGEABLE @ eda2fac (base: main)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m33s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m7s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 5m46s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 9s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 6s
#780 and #784 were green separately and red together: the gate landed with a base that predated `scripts/check-doc-narrative.py`, so nothing ever ran ruff over it. On merged main the shipped invocation is RED, which would have surfaced as a mystery lint failure on whichever PR opened next. Two findings, both in #784's files: - `RUF100` on `# noqa: BLE001` twice — `BLE` is not in this repo's `select`, so those directives suppress nothing. Enabling `BLE` instead was measured and rejected: it fires 6 more times in `decisions_validate.py`, whose broad catches are deliberate, and that is a ruleset decision for its own PR rather than a side effect of unbreaking main. The non-enabled code is dropped; the `S110` on the first site stays (S IS selected), and both explanatory comments stay. - `scripts/tests/test_check_doc_narrative.py` was not ruff-formatted. Formatted; suite still 807 passed, 2 skipped. The general shape, for the next time two PRs touch disjoint files: a gate whose population is "everything tracked" is only as green as its base. #813's CI could not have caught this and neither could #811's. Refs: #780, #784
This commit is contained in:
@@ -38,7 +38,7 @@ import sys
|
||||
try:
|
||||
sys.stdout.reconfigure(errors="replace") # type: ignore[union-attr]
|
||||
sys.stderr.reconfigure(errors="replace") # type: ignore[union-attr]
|
||||
except Exception: # noqa: BLE001, S110 — a stdout that cannot be reconfigured is not a reason to fail
|
||||
except Exception: # noqa: S110 — a stdout that cannot be reconfigured is not a reason to fail
|
||||
pass # deliberate: this is the never-fails invariant's own setup, so it cannot itself raise
|
||||
|
||||
# `docs/decisions/**` is exempt WHOLESALE — a decision record narrating how a rule was got wrong is
|
||||
@@ -254,6 +254,7 @@ def main(argv: list[str]) -> int:
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
sys.exit(main(sys.argv))
|
||||
except Exception as exc: # noqa: BLE001 — the never-fails constraint outranks a clean traceback
|
||||
# The never-fails constraint outranks a clean traceback, so this catch is deliberately blind.
|
||||
except Exception as exc:
|
||||
print(f"doc-narrative: internal error ({exc!r}) — SCANNED NOTHING. Advisory; not a failure.")
|
||||
sys.exit(0)
|
||||
|
||||
@@ -27,9 +27,7 @@ HIT = re.compile(r"^::warning file=(?P<path>[^:]+)::(?P=path):(?P<line>\d+) ", r
|
||||
|
||||
|
||||
def run(cwd: Path, *args: str) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(
|
||||
[sys.executable, str(SCRIPT), *args], cwd=cwd, capture_output=True, text=True
|
||||
)
|
||||
return subprocess.run([sys.executable, str(SCRIPT), *args], cwd=cwd, capture_output=True, text=True)
|
||||
|
||||
|
||||
def hits(out: str) -> set[tuple[str, int]]:
|
||||
@@ -76,9 +74,9 @@ def commit(r: Path, msg: str = "c") -> None:
|
||||
[
|
||||
((), "scanned "),
|
||||
(("--all",), "scanned "),
|
||||
(("--diff",), "--diff needs a base ref"), # no base ref at all
|
||||
(("--diff", ""), "--diff needs a base ref"), # `origin/` with base_ref unset
|
||||
(("--diff", "no-such-ref-xyz"), "SCANNED NOTHING"), # an unresolvable ref
|
||||
(("--diff",), "--diff needs a base ref"), # no base ref at all
|
||||
(("--diff", ""), "--diff needs a base ref"), # `origin/` with base_ref unset
|
||||
(("--diff", "no-such-ref-xyz"), "SCANNED NOTHING"), # an unresolvable ref
|
||||
(("--diff", "origin/"), "SCANNED NOTHING"),
|
||||
(("--nonsense",), "unknown mode"),
|
||||
],
|
||||
@@ -133,14 +131,14 @@ def test_a_DELETED_doc_is_not_reported_as_added_content(repo: Path) -> None:
|
||||
# stopped pinning variants and removed the surface. The table is here so the next knob someone finds
|
||||
# gets a row instead of a round.
|
||||
FORMAT_KNOBS = [
|
||||
("core.quotePath", "true"), # quotes non-ASCII paths out of the population
|
||||
("diff.dstPrefix", "dst/"), # rewrites the header the path is read from
|
||||
("core.quotePath", "true"), # quotes non-ASCII paths out of the population
|
||||
("diff.dstPrefix", "dst/"), # rewrites the header the path is read from
|
||||
("diff.srcPrefix", "src/"),
|
||||
("diff.noprefix", "true"),
|
||||
("color.diff", "always"), # injects ANSI escapes into every line
|
||||
("color.diff", "always"), # injects ANSI escapes into every line
|
||||
("color.ui", "always"),
|
||||
("diff.renames", "false"), # turns a `git mv` into a whole-file add
|
||||
("diff.context", "9"), # a configured context must not beat the -U0 on the CLI
|
||||
("diff.renames", "false"), # turns a `git mv` into a whole-file add
|
||||
("diff.context", "9"), # a configured context must not beat the -U0 on the CLI
|
||||
("diff.external", "/bin/echo"), # replaces the output wholesale
|
||||
]
|
||||
|
||||
@@ -167,9 +165,7 @@ def test_a_NON_UTF8_stdio_does_not_break_the_never_fails_invariant(repo: Path, e
|
||||
|
||||
env = dict(os.environ, **{env_name: env_value})
|
||||
env.pop("PYTHONUTF8", None)
|
||||
p = subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "--all"], cwd=repo, capture_output=True, text=True, env=env
|
||||
)
|
||||
p = subprocess.run([sys.executable, str(SCRIPT), "--all"], cwd=repo, capture_output=True, text=True, env=env)
|
||||
assert p.returncode == 0, f"{env_name}={env_value} exited {p.returncode}: {p.stderr}"
|
||||
|
||||
|
||||
@@ -224,9 +220,9 @@ def test_a_multi_hunk_file_numbers_every_hunk_from_its_own_header(repo: Path) ->
|
||||
body = [f"l{i}" for i in range(1, 31)]
|
||||
(repo / "docs" / "m.md").write_text("\n".join(body) + "\n", encoding="utf-8")
|
||||
commit(repo)
|
||||
body[4] = NARRATIVE # replace, early hunk
|
||||
body.insert(15, NARRATIVE) # pure insert, middle hunk
|
||||
body[-1] = NARRATIVE # replace, last hunk
|
||||
body[4] = NARRATIVE # replace, early hunk
|
||||
body.insert(15, NARRATIVE) # pure insert, middle hunk
|
||||
body[-1] = NARRATIVE # replace, last hunk
|
||||
(repo / "docs" / "m.md").write_text("\n".join(body) + "\n", encoding="utf-8")
|
||||
commit(repo)
|
||||
assert hits(run(repo, "--diff", "HEAD~1").stdout) == truth(repo, "docs/m.md")
|
||||
@@ -326,7 +322,10 @@ def test_a_NON_UTF8_LOCALE_does_not_silently_empty_the_scan(repo: Path) -> None:
|
||||
env = dict(os.environ, LC_ALL="C", PYTHONUTF8="0", PYTHONIOENCODING="utf-8")
|
||||
p = subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "--diff", "HEAD~1"],
|
||||
cwd=repo, capture_output=True, text=True, env=env,
|
||||
cwd=repo,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
)
|
||||
assert p.returncode == 0, p.stderr
|
||||
assert "internal error" not in p.stdout, p.stdout
|
||||
@@ -348,13 +347,11 @@ def test_MUTATION_neutering_the_pattern_makes_a_known_hit_go_quiet(repo: Path, t
|
||||
|
||||
disarmed = tmp_path / "disarmed.py"
|
||||
src = SCRIPT.read_text(encoding="utf-8")
|
||||
marker = 'PATTERNS = re.compile('
|
||||
marker = "PATTERNS = re.compile("
|
||||
assert src.count(marker) == 1
|
||||
disarmed.write_text(
|
||||
src.replace(marker, 'PATTERNS = re.compile(r"(?!x)x" # disarmed\n or ', 1), encoding="utf-8"
|
||||
)
|
||||
p = subprocess.run(
|
||||
[sys.executable, str(disarmed), "--all"], cwd=repo, capture_output=True, text=True
|
||||
)
|
||||
p = subprocess.run([sys.executable, str(disarmed), "--all"], cwd=repo, capture_output=True, text=True)
|
||||
assert p.returncode == 0, p.stderr
|
||||
assert hits(p.stdout) == set(), "the disarmed detector still flagged something — the mutation did not take"
|
||||
|
||||
Reference in New Issue
Block a user