diff --git a/scripts/pr_review.py b/scripts/pr_review.py index 4e3ef75d..604913c9 100755 --- a/scripts/pr_review.py +++ b/scripts/pr_review.py @@ -2876,12 +2876,23 @@ def labelled_entries(body: str, label: re.Pattern[str]) -> list[str]: return entries +LINE_SUFFIX = re.compile(r":[0-9]+(?:-[0-9]+)?$") + + def entry_paths(entry: str) -> list[str]: - """The paths one list entry names, read from its own code spans.""" + """The paths one list entry names, read from its own code spans. + + A span written as `FILE:LINE` or `FILE:START-END` names the file, so the suffix is dropped. + A thread carries the path alone, which is what the entry's path is paired against. + """ return [ named for span in CODE_SPAN.finditer(entry) - if (named := bare_path(span.group()[len(span.group(1)) : -len(span.group(1))]).strip()) + if ( + named := LINE_SUFFIX.sub( + "", bare_path(span.group()[len(span.group(1)) : -len(span.group(1))]).strip() + ) + ) ] diff --git a/tests/test_pr_review.py b/tests/test_pr_review.py index f21cc7fb..8bb0fda9 100755 --- a/tests/test_pr_review.py +++ b/tests/test_pr_review.py @@ -5664,9 +5664,12 @@ def test_an_entry_on_a_file_no_thread_is_on_is_counted_where_the_totals_balance( ) def test_every_entry_on_a_threaded_file_counts_none(self) -> None: - """A trailing part, a zero-width space after a slash, and a directory each name a file.""" + """A trailing part, a zero-width space after a slash, a directory, and a path carrying a + line or a line range each name a file. + """ for listed in ( PROSE_LISTED, + "- [P1] `lib/reader.py:340` drops an entry.\n- [P2] `writer.py:12-18` is stale.\n", "- `lib/\u200breader.py` and `lib/writer.py`: one issue each (2 votes each).\n", "- `lib/`: moderate retry issue (2 votes).\n", "- A retry issue\n in `lib/reader.py` (2 votes).\n", @@ -5863,6 +5866,10 @@ def test_entries_restating_threads_count_none(self) -> None: self.assertEqual(0, self.count(with_narrative(listed))) self.assertNotIn("FINDINGS WITH NO THREAD", self.digest(with_narrative(listed))) + def test_an_entry_naming_its_file_with_a_line_pairs_with_the_thread_on_it(self) -> None: + listed = "- `pkg/guard.py:12`: a failed read skips the check (**critical**, 1 vote).\n" + self.assertEqual(0, self.count(with_narrative(listed))) + def test_an_entry_stating_no_severity_this_reads_is_counted(self) -> None: for listed in ( "- `pkg/guard.py`: a failed read skips the check (1 vote).\n",