From 691c9911c76926cca5c631c11215c5d32baecb0d Mon Sep 17 00:00:00 2001 From: HanWenbo <124024253+hwb96@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:11:23 +0800 Subject: [PATCH] fix(ci): make pyrefly diff comments focus on diagnostics (#32778) --- .github/workflows/pyrefly-diff.yml | 10 +++- api/libs/pyrefly_diagnostics.py | 48 +++++++++++++++++ .../libs/test_pyrefly_diagnostics.py | 51 +++++++++++++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 api/libs/pyrefly_diagnostics.py create mode 100644 api/tests/unit_tests/libs/test_pyrefly_diagnostics.py diff --git a/.github/workflows/pyrefly-diff.yml b/.github/workflows/pyrefly-diff.yml index 2d22231144..1900232dce 100644 --- a/.github/workflows/pyrefly-diff.yml +++ b/.github/workflows/pyrefly-diff.yml @@ -29,16 +29,22 @@ jobs: - name: Install dependencies run: uv sync --project api --dev + - name: Prepare diagnostics extractor + run: | + git show ${{ github.event.pull_request.head.sha }}:api/libs/pyrefly_diagnostics.py > /tmp/pyrefly_diagnostics.py + - name: Run pyrefly on PR branch run: | - uv run --directory api pyrefly check > /tmp/pyrefly_pr.txt 2>&1 || true + uv run --directory api --dev pyrefly check 2>&1 \ + | uv run --directory api python /tmp/pyrefly_diagnostics.py > /tmp/pyrefly_pr.txt || true - name: Checkout base branch run: git checkout ${{ github.base_ref }} - name: Run pyrefly on base branch run: | - uv run --directory api pyrefly check > /tmp/pyrefly_base.txt 2>&1 || true + uv run --directory api --dev pyrefly check 2>&1 \ + | uv run --directory api python /tmp/pyrefly_diagnostics.py > /tmp/pyrefly_base.txt || true - name: Compute diff run: | diff --git a/api/libs/pyrefly_diagnostics.py b/api/libs/pyrefly_diagnostics.py new file mode 100644 index 0000000000..4d9df65099 --- /dev/null +++ b/api/libs/pyrefly_diagnostics.py @@ -0,0 +1,48 @@ +"""Helpers for producing concise pyrefly diagnostics for CI diff output.""" + +from __future__ import annotations + +import sys + +_DIAGNOSTIC_PREFIXES = ("ERROR ", "WARNING ") +_LOCATION_PREFIX = "-->" + + +def extract_diagnostics(raw_output: str) -> str: + """Extract stable diagnostic lines from pyrefly output. + + The full pyrefly output includes code excerpts and carets, which create noisy + diffs. This helper keeps only: + - diagnostic headline lines (``ERROR ...`` / ``WARNING ...``) + - the following location line (``--> path:line:column``), when present + """ + + lines = raw_output.splitlines() + diagnostics: list[str] = [] + + for index, line in enumerate(lines): + if line.startswith(_DIAGNOSTIC_PREFIXES): + diagnostics.append(line.rstrip()) + + next_index = index + 1 + if next_index < len(lines): + next_line = lines[next_index] + if next_line.lstrip().startswith(_LOCATION_PREFIX): + diagnostics.append(next_line.rstrip()) + + if not diagnostics: + return "" + + return "\n".join(diagnostics) + "\n" + + +def main() -> int: + """Read pyrefly output from stdin and print normalized diagnostics.""" + + raw_output = sys.stdin.read() + sys.stdout.write(extract_diagnostics(raw_output)) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/api/tests/unit_tests/libs/test_pyrefly_diagnostics.py b/api/tests/unit_tests/libs/test_pyrefly_diagnostics.py new file mode 100644 index 0000000000..704daa8fb4 --- /dev/null +++ b/api/tests/unit_tests/libs/test_pyrefly_diagnostics.py @@ -0,0 +1,51 @@ +from libs.pyrefly_diagnostics import extract_diagnostics + + +def test_extract_diagnostics_keeps_only_summary_and_location_lines() -> None: + # Arrange + raw_output = """INFO Checking project configured at `/tmp/project/pyrefly.toml` +ERROR `result` may be uninitialized [unbound-name] + --> controllers/console/app/annotation.py:126:16 + | +126 | return result, 200 + | ^^^^^^ + | +ERROR Object of class `App` has no attribute `access_mode` [missing-attribute] + --> controllers/console/app/app.py:574:13 + | +574 | app_model.access_mode = app_setting.access_mode + | ^^^^^^^^^^^^^^^^^^^^^ +""" + + # Act + diagnostics = extract_diagnostics(raw_output) + + # Assert + assert diagnostics == ( + "ERROR `result` may be uninitialized [unbound-name]\n" + " --> controllers/console/app/annotation.py:126:16\n" + "ERROR Object of class `App` has no attribute `access_mode` [missing-attribute]\n" + " --> controllers/console/app/app.py:574:13\n" + ) + + +def test_extract_diagnostics_handles_error_without_location_line() -> None: + # Arrange + raw_output = "ERROR unexpected pyrefly output format [bad-format]\n" + + # Act + diagnostics = extract_diagnostics(raw_output) + + # Assert + assert diagnostics == "ERROR unexpected pyrefly output format [bad-format]\n" + + +def test_extract_diagnostics_returns_empty_for_non_error_output() -> None: + # Arrange + raw_output = "INFO Checking project configured at `/tmp/project/pyrefly.toml`\n" + + # Act + diagnostics = extract_diagnostics(raw_output) + + # Assert + assert diagnostics == ""