Skip to content

Commit 4116184

Browse files
sunjin12claude
andcommitted
fix(version): resolve __version__ from importlib.metadata, not literal
Both cli/ossmate and mcp/ossmate_mcp had `__version__ = "0.0.1"` literals in their __init__.py — bump_version.py never touched these so `ossmate version` printed "0.0.1" while pip showed 0.1.0. Now both read from importlib.metadata.version() and agree with the installed wheel. Adds invariant test test_init_modules_dont_hardcode_versions to forbid the hardcoded form. Caught one day after v0.1.0 shipped — will roll into the next release rather than burning a 0.1.1 cycle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f8fba38 commit 4116184

4 files changed

Lines changed: 37 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
1010
## [Unreleased]
1111

12+
### Fixed
13+
- `ossmate version` and `ossmate_mcp.__version__` resolved to the hardcoded literal `"0.0.1"` instead of the installed package version. Both `__init__.py` modules now read from `importlib.metadata.version()` so they always agree with what `pip show` reports. New invariant test [tests/test_versioning.py](tests/test_versioning.py)::`test_init_modules_dont_hardcode_versions` forbids the hardcoded form going forward — caught the day after v0.1.0 shipped to PyPI
14+
1215
## [0.1.0] - 2026-04-19
1316

1417
First public release. Reference implementation of every Claude Code extension surface, packaged as both a plugin and a standalone CLI.
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
"""Ossmate — Claude-powered co-maintainer CLI."""
22

3-
__version__ = "0.0.1"
3+
from importlib.metadata import PackageNotFoundError, version as _pkg_version
4+
5+
try:
6+
__version__ = _pkg_version("ossmate")
7+
except PackageNotFoundError:
8+
__version__ = "0.0.0+source"
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
"""Ossmate MCP server — OSS maintainer tools exposed via Model Context Protocol."""
22

3-
__version__ = "0.0.1"
3+
from importlib.metadata import PackageNotFoundError, version as _pkg_version
4+
5+
try:
6+
__version__ = _pkg_version("ossmate-mcp")
7+
except PackageNotFoundError:
8+
__version__ = "0.0.0+source"

tests/test_versioning.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,28 @@ def test_marketplace_manifest_has_two_version_locations(self):
115115
assert "metadata" in data and "version" in data["metadata"]
116116
assert data["plugins"] and "version" in data["plugins"][0]
117117

118+
def test_init_modules_dont_hardcode_versions(self):
119+
"""`__init__.py` files MUST resolve __version__ from importlib.metadata
120+
rather than hardcoding the literal — otherwise `bump_version.py`
121+
misses them and `ossmate version` lies to users (regression caught
122+
in v0.1.0 post-release)."""
123+
for init in (
124+
REPO_ROOT / "cli" / "ossmate" / "src" / "ossmate" / "__init__.py",
125+
REPO_ROOT / "mcp" / "ossmate_mcp" / "src" / "ossmate_mcp" / "__init__.py",
126+
):
127+
text = init.read_text(encoding="utf-8")
128+
assert "importlib.metadata" in text, (
129+
f"{init.relative_to(REPO_ROOT)} must read __version__ from "
130+
f"importlib.metadata — hardcoding drifts on every release"
131+
)
132+
# Belt-and-suspenders: forbid the literal `__version__ = "X.Y.Z"` form.
133+
import re as _re
134+
135+
assert not _re.search(r'^__version__\s*=\s*"\d', text, _re.MULTILINE), (
136+
f"{init.relative_to(REPO_ROOT)} hardcodes __version__ — use "
137+
f"importlib.metadata.version() instead"
138+
)
139+
118140
def test_cli_dep_pin_matches_mcp_version(self, bump):
119141
"""The CLI declares `ossmate-mcp>=X` — X must equal the MCP package
120142
version, otherwise users get an unsolvable resolver state on first

0 commit comments

Comments
 (0)