diff --git a/tools/release-management/src/release_management/prepare/category_x.py b/tools/release-management/src/release_management/prepare/category_x.py index 7ca445a89..8325c201c 100755 --- a/tools/release-management/src/release_management/prepare/category_x.py +++ b/tools/release-management/src/release_management/prepare/category_x.py @@ -47,7 +47,9 @@ def pattern_for(term: str) -> re.Pattern[str]: pieces = re.split(SEPARATORS, term) body = SEPARATORS.join(re.escape(p) for p in pieces) - return re.compile(rf"(? list[str]: diff --git a/tools/release-management/tests/test_prepare.py b/tools/release-management/tests/test_prepare.py index 1e6012277..b9cf4fbc1 100644 --- a/tools/release-management/tests/test_prepare.py +++ b/tools/release-management/tests/test_prepare.py @@ -427,6 +427,27 @@ def test_category_x_cli_names_the_hard_stop_file(tmp_path: Path, capsys: pytest. assert out["read"] == ["classifications/category-x-hit.md"] +@pytest.mark.parametrize("deny", ["org.example:blocked-lib", "blocked-lib"]) +def test_category_x_cli_reports_versioned_coordinate( + tmp_path: Path, capsys: pytest.CaptureFixture[str], deny: str +) -> None: + manifest = tmp_path / "build.gradle.kts" + manifest.write_text('\nimplementation("org.example:blocked-lib:1.2.3")\n' * 2, encoding="utf-8") + shown = "app/build.gradle.kts" + assert main(["prepare", "category-x", "--deny", deny, f"{shown}={manifest}"]) == 0 + out = json.loads(capsys.readouterr().out) + if deny == "blocked-lib": + assert out == {"category_x_hit": False, "category_x_violations": [], "files_scanned": [shown]} + else: + assert out == { + "category_x_hit": True, + "category_x_violations": [{"identifier": deny, "found_in": shown}], + "handoff_reason": category_x.HANDOFF, + "first_match_lines": [{"identifier": deny, "found_in": shown, "line": 2}], + "read": ["classifications/category-x-hit.md"], + } + + def test_versions_per_manifest(tmp_path: Path) -> None: files = { "pyproject.toml": '[project]\nname = "foo"\nversion = "1.0.0.dev0"\n', diff --git a/tools/release-management/tests/test_prepare_scripts.py b/tools/release-management/tests/test_prepare_scripts.py index fdaf6877d..79286cef2 100644 --- a/tools/release-management/tests/test_prepare_scripts.py +++ b/tools/release-management/tests/test_prepare_scripts.py @@ -101,6 +101,72 @@ def test_no_partial_token_match(self) -> None: self.assertFalse(out["category_x_hit"]) self.assertEqual(out["files_scanned"], ["pyproject.toml"]) + def test_versioned_coordinates_match(self) -> None: + identifier = "org.example:blocked-lib" + manifests = { + "build.gradle": "dependencies {\n implementation 'org.example:blocked-lib:1.2.3'\n}\n", + "build.gradle.kts": 'dependencies {\n implementation("org.example:blocked-lib:1.2.3")\n}\n', + "gradle.lockfile": "# dependency locks\norg.example:blocked-lib:1.2.3=compileClasspath\n", + "dependency-tree.txt": "[INFO] dependency tree\n[INFO] +- org.example:blocked-lib:jar:1.2.3:compile\n", + } + for shown, text in manifests.items(): + with self.subTest(manifest=shown): + out = category_x.scan([identifier], [(shown, self.file(text))]) + self.assertEqual( + out, + { + "category_x_hit": True, + "category_x_violations": [{"identifier": identifier, "found_in": shown}], + "handoff_reason": category_x.HANDOFF, + "first_match_lines": [{"identifier": identifier, "found_in": shown, "line": 2}], + }, + ) + + def test_versioned_coordinate_normalisation(self) -> None: + identifier = "ORG.EXAMPLE:BLOCKED-LIB" + local = self.file('implementation("org_example:blocked.lib:1.2.3")\n') + out = category_x.scan([identifier], [("build.gradle.kts", local)]) + self.assertTrue(out["category_x_hit"]) + self.assertEqual( + out["first_match_lines"], [{"identifier": identifier, "found_in": "build.gradle.kts", "line": 1}] + ) + + def test_coordinate_manifest_controls(self) -> None: + manifests = { + "pom.xml": "org.exampleblocked-lib\n", + "libs.versions.toml": 'blocked = { module = "org.example:blocked-lib", version = "1.2.3" }\n', + "build.gradle": "implementation group: 'org.example', name: 'blocked-lib', version: '1.2.3'\n", + "setup.cfg": "install_requires = blocked-lib>=1.2.3\n", + } + for shown, text in manifests.items(): + with self.subTest(manifest=shown): + out = category_x.scan(["org.example:blocked-lib"], [(shown, self.file(text))]) + self.assertTrue(out["category_x_hit"]) + + def test_versioned_coordinates_respect_token_boundaries(self) -> None: + coordinates = ( + "other.example:blocked-lib:1.2.3", + "prefixorg.example:blocked-lib:1.2.3", + "org.example:prefixblocked-lib:1.2.3", + "org.example:blocked-lib-extras:1.2.3", + "org.example:blocked-lib.extra:1.2.3", + "org.example:blocked-lib0:1.2.3", + "path/org.example:blocked-lib:1.2.3", + "another:org.example:blocked-lib:1.2.3", + ) + for coordinate in coordinates: + with self.subTest(coordinate=coordinate): + local = self.file(f'implementation("{coordinate}")\n') + self.assertFalse( + category_x.scan(["org.example:blocked-lib"], [("build.gradle.kts", local)])[ + "category_x_hit" + ] + ) + + def test_bare_artifact_does_not_match_inside_a_coordinate(self) -> None: + local = self.file('implementation("org.example:blocked-lib:1.2.3")\n') + self.assertFalse(category_x.scan(["blocked-lib"], [("build.gradle.kts", local)])["category_x_hit"]) + class NextDevVersionTest(unittest.TestCase): CONFIGURED: ClassVar[list[str]] = [