From 564c31a138c76f711b386599444e7450cd8a80ff Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 17:43:04 +0000 Subject: [PATCH] Keep reuse self-test notices out of CI logs The fallback tests for ci-reuse-merge-group.py and ci-reuse-pr-head.py let the scripts print their real "::notice::Could not verify merge-queue CI (...)" lines to stdout. lint-ecosystems runs those tests in a GitHub job, so every run on PRs, the merge queue and main gained ten fake annotations claiming the reuse check had failed. They fill the step's ten-notice cap and send anyone debugging a reuse decision down the wrong path. Capture stdout in those cases and assert that the notice is printed. The fallback path is now checked, not just silenced. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01SeHhBxEvePf8ERTaTTenMK --- scripts/tests/test_ci_reuse_merge_group.py | 13 +++++++++++-- scripts/tests/test_ci_reuse_pr_head.py | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/scripts/tests/test_ci_reuse_merge_group.py b/scripts/tests/test_ci_reuse_merge_group.py index ffa058a77..24273e548 100644 --- a/scripts/tests/test_ci_reuse_merge_group.py +++ b/scripts/tests/test_ci_reuse_merge_group.py @@ -1,6 +1,8 @@ """A reused CI verdict must belong to this workflow, repository and exact SHA.""" +import contextlib import importlib.util +import io import json import subprocess import unittest @@ -60,15 +62,22 @@ def test_non_main_pushes_and_other_events_never_query_or_skip(self): self.assertIsNone(reuse.reusable_run(dict(self.env, **change))) call.assert_not_called() + def assert_falls_back(self, env): + # Capture the fallback notice: printed to the job log it becomes a + # real (misleading) annotation on every lint-ecosystems run. + with contextlib.redirect_stdout(io.StringIO()) as out: + self.assertIsNone(reuse.reusable_run(env)) + self.assertTrue(out.getvalue().startswith("::notice::"), out.getvalue()) + def test_api_failure_timeout_and_bad_payload_keep_all_checks(self): for error in (FileNotFoundError(), subprocess.CalledProcessError(1, "gh"), subprocess.TimeoutExpired("gh", 15)): with self.subTest(error=error), patch.object(reuse.subprocess, "run", side_effect=error): - self.assertIsNone(reuse.reusable_run(self.env)) + self.assert_falls_back(self.env) for text in ("not json", "{}", '{"workflow_runs": null}', '{"workflow_runs": [null]}'): with self.subTest(text=text), patch.object(reuse.subprocess, "run", return_value= subprocess.CompletedProcess([], 0, stdout=text)): - self.assertIsNone(reuse.reusable_run(self.env)) + self.assert_falls_back(self.env) if __name__ == "__main__": diff --git a/scripts/tests/test_ci_reuse_pr_head.py b/scripts/tests/test_ci_reuse_pr_head.py index da22bd47a..468a99e8f 100644 --- a/scripts/tests/test_ci_reuse_pr_head.py +++ b/scripts/tests/test_ci_reuse_pr_head.py @@ -1,6 +1,8 @@ """Only a clean base-branch merge onto a head that passed CI may skip tests.""" +import contextlib import importlib.util +import io import json import subprocess import tempfile @@ -118,18 +120,24 @@ def test_other_events_and_bases_never_query_or_skip(self): self.assertIsNone(reuse.reusable_run(dict(self.env, **change))) call.assert_not_called() + def assert_falls_back(self, env): + # Capture the fallback notice: printed to the job log it becomes a + # real (misleading) annotation on every lint-ecosystems run. + with contextlib.redirect_stdout(io.StringIO()) as out: + self.assertIsNone(reuse.reusable_run(env)) + self.assertTrue(out.getvalue().startswith("::notice::"), out.getvalue()) + def test_api_failure_timeout_and_bad_payload_run_everything(self): for error in (FileNotFoundError(), subprocess.CalledProcessError(1, "gh"), subprocess.TimeoutExpired("gh", 15)): with self.subTest(error=error), patch.object(reuse.subprocess, "run", side_effect=error): - self.assertIsNone(reuse.reusable_run(self.env)) + self.assert_falls_back(self.env) for text in ("not json", "{}", '{"parents": null}', '{"parents": [null, null]}'): with self.subTest(text=text), patch.object(reuse.subprocess, "run", return_value= subprocess.CompletedProcess([], 0, stdout=text)): - self.assertIsNone(reuse.reusable_run(self.env)) + self.assert_falls_back(self.env) with self.subTest("missing env"), patch.object(reuse.subprocess, "run") as call: - self.assertIsNone(reuse.reusable_run({"GITHUB_EVENT_NAME": "pull_request", - "PR_BASE_REF": "main"})) + self.assert_falls_back({"GITHUB_EVENT_NAME": "pull_request", "PR_BASE_REF": "main"}) call.assert_not_called() def test_main_writes_the_output(self):