diff --git a/scripts/check-issue-links.py b/scripts/check-issue-links.py index 3045e3c6..1e68a768 100644 --- a/scripts/check-issue-links.py +++ b/scripts/check-issue-links.py @@ -1399,15 +1399,29 @@ def _mention_detail(refs: Refs, number: int) -> str: return "; ".join(clauses) -#: A release version an issue's own text names, e.g. `Release v0.3.46`. It is read +#: A release version an issue's own **title** names, e.g. `Release v0.3.46`. It is read #: because it is the one fact an open issue carries about what finishes *it*: a PR's own #: title never reaches `judge_issues`, so "was the declaring PR a bump?" cannot be answered #: here at all, while "does this issue's completion name a published artifact?" can. +#: +#: The title and not the body, because the two say different things: a title says what an +#: issue **is**, while a body says what it was **seen in**. An ordinary issue cites the +#: release it observed its defect on, and reading that as the artifact that finishes it +#: hands the reader a published version for work that has nothing to do with one - the +#: reading then exits 0 and invites a close over work that is not done. Measured over the +#: repository's last 200 issues: 34 name a version, 26 of them in the title and 8 only in +#: the body, and three of those 8 driven through `judge_issues` each took the artifact +#: remedy for a merge about something else. An issue naming its version only in the body +#: therefore keeps the remedy it had. _RELEASE_VERSION = re.compile(r"\bv\d+\.\d+\.\d+\b") def release_version(*texts: str | None) -> str | None: - """The release version this issue's own text names, or `None` when it names none.""" + """The release version the given text names, or `None` when it names none. + + Which text is the caller's decision, not this function's: `judge_issues` passes the + issue's title alone, and the reason is stated on `_RELEASE_VERSION`. + """ for text in texts: if not text: continue @@ -1521,9 +1535,7 @@ def judge_issues( ) continue if refs.declared_merged or refs.declared_abandoned: - detail = _declined_detail( - refs, number, release_version(issue.get("title"), issue.get("body")) - ) + detail = _declined_detail(refs, number, release_version(issue.get("title"))) elif refs.mentioned_landed or refs.mentioned_abandoned or refs.mentioned_open: detail = _mention_detail(refs, number) else: diff --git a/tests/test_check_issue_links.py b/tests/test_check_issue_links.py index cdd775d7..5f79851b 100644 --- a/tests/test_check_issue_links.py +++ b/tests/test_check_issue_links.py @@ -2854,3 +2854,45 @@ def test_judge_issues_reads_the_version_off_the_issue_it_is_judging(mod) -> None rows = {row.number: row for row in mod.judge_issues(issues, refs, {})} assert "check-release-published.py v0.3.46" in rows[2781].detail assert "check-release-published" not in rows[2778].detail + + +# --- the title declares the version, the body only mentions one -------------------- +# +# The artifact remedy belongs where an issue **declares** the release it is about, and is +# wrong where its body merely cites the release it was **seen in**: that version is already +# published, so the printed reading exits 0 and invites a close over work it never +# described. Measured over the repository's last 200 issues, 34 name a version and 8 of +# them name it only in the body - each of those took the artifact sentence before this +# gate, for a merge that had done something else. + + +def test_a_version_in_the_body_does_not_make_an_issue_a_release_issue(mod) -> None: + issues = [ + { + "number": 2760, + "title": "The actionlint step's download has no retry, so one upstream 504 reddens master for hours", + "body": "master has failed its Test workflow since a85b1ddd; v0.3.41 stepped on the download.", + "created_at": "2026-11-08T10:00:00Z", + } + ] + refs = {2760: mod.Refs(declared_merged={2759})} + rows = {row.number: row for row in mod.judge_issues(issues, refs, {})} + assert "check-release-published" not in rows[2760].detail + assert "either close this issue with the reading that says the work is done" in rows[2760].detail + + +def test_the_title_is_what_declares_the_version_and_the_body_is_not(mod) -> None: + body = "master has failed its Test workflow since a85b1ddd; v0.3.41 stepped on the download." + issues = [ + {"number": 2781, "title": "Release v0.3.46", "body": body, "created_at": "2026-11-09T17:35:22Z"}, + { + "number": 2760, + "title": "The actionlint step's download has no retry, so one upstream 504 reddens master for hours", + "body": body, + "created_at": "2026-11-08T10:00:00Z", + }, + ] + refs = {2781: mod.Refs(declared_merged={2782}), 2760: mod.Refs(declared_merged={2759})} + rows = {row.number: row for row in mod.judge_issues(issues, refs, {})} + assert "check-release-published.py v0.3.46" in rows[2781].detail + assert "check-release-published" not in rows[2760].detail