diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9187edf..0a0eab1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: "3.11" - run: python scripts/check_version_linearity.py diff --git a/scripts/check_version_linearity.py b/scripts/check_version_linearity.py index 6c0c765..8b61b16 100644 --- a/scripts/check_version_linearity.py +++ b/scripts/check_version_linearity.py @@ -28,7 +28,13 @@ def check(root: Path) -> tuple[int, str]: if not changelog_path.exists(): return 1, f"CHANGELOG.md not found at {changelog_path}" - declared = tomllib.loads(pyproject_path.read_text())["project"]["version"] + try: + declared = tomllib.loads(pyproject_path.read_text())["project"]["version"] + except tomllib.TOMLDecodeError as exc: + return 1, f"invalid pyproject.toml: {exc}" + except (KeyError, TypeError): + return 1, "pyproject.toml must define [project].version" + latest = latest_changelog_version(changelog_path.read_text()) if latest is None: diff --git a/tests/scripts/test_version_linearity.py b/tests/scripts/test_version_linearity.py index d882bfc..f4c1d19 100644 --- a/tests/scripts/test_version_linearity.py +++ b/tests/scripts/test_version_linearity.py @@ -13,8 +13,8 @@ def _load_script(): """Import the script as a module (it is under scripts/, outside the package tree).""" spec = importlib.util.spec_from_file_location("check_version_linearity", SCRIPT) - module = importlib.util.module_from_spec(spec) # type: ignore[arg-type] assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module @@ -79,6 +79,22 @@ def test_version_linearity_fails_when_changelog_missing(tmp_path: Path, script) assert "CHANGELOG.md not found" in message +def test_version_linearity_fails_on_malformed_pyproject(tmp_path: Path, script) -> None: + (tmp_path / "pyproject.toml").write_text('[project\nversion = "1.0.0"\n') + (tmp_path / "CHANGELOG.md").write_text("# Changelog\n\n## [1.0.0] - 2026-04-28\n") + code, message = script.check(tmp_path) + assert code == 1 + assert "invalid pyproject.toml" in message + + +def test_version_linearity_fails_when_pyproject_lacks_version(tmp_path: Path, script) -> None: + (tmp_path / "pyproject.toml").write_text('[project]\nname = "x"\n') + (tmp_path / "CHANGELOG.md").write_text("# Changelog\n\n## [1.0.0] - 2026-04-28\n") + code, message = script.check(tmp_path) + assert code == 1 + assert "[project].version" in message + + def test_latest_changelog_version_picks_first_versioned_header(script) -> None: text = """# Changelog