mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
fix: make proxy upgrades version-aware
Derive source-tree versions from release history so headroom --version no longer reports stale project metadata. Restart stale idle proxies after an upgrade, but leave active sessions running to avoid interrupting ongoing conversations. Remove _version.py from version-sync ownership and make version verification catch package/plugin manifest drift.
This commit is contained in:
parent
4a88c698ad
commit
ea1f608e79
7 changed files with 399 additions and 36 deletions
|
|
@ -34,7 +34,7 @@ def temp_project(tmp_path: Path) -> dict[str, Path]:
|
|||
pyproject = root / "pyproject.toml"
|
||||
pyproject.write_text('[project]\nversion = "0.5.25"\n')
|
||||
|
||||
# headroom/_version.py
|
||||
# headroom/_version.py is runtime-derived and must not be rewritten by version-sync.
|
||||
version_py = headroom / "_version.py"
|
||||
version_py.write_text('"""Package version metadata."""\n\n__version__ = "0.5.25"\n')
|
||||
|
||||
|
|
@ -102,9 +102,9 @@ def test_version_sync_explicit_version(temp_project: dict[str, Path]) -> None:
|
|||
pyproject_content = temp_project["pyproject"].read_text()
|
||||
assert 'version = "0.7.0"' in pyproject_content
|
||||
|
||||
# Verify headroom/_version.py
|
||||
# Verify headroom/_version.py is not a synced manifest.
|
||||
version_py_content = temp_project["version_py"].read_text()
|
||||
assert '__version__ = "0.7.0"' in version_py_content
|
||||
assert '__version__ = "0.5.25"' in version_py_content
|
||||
|
||||
# Verify plugins/openclaw/package.json
|
||||
openclaw_pkg = json.loads(temp_project["openclaw_pkg"].read_text())
|
||||
|
|
@ -157,7 +157,7 @@ def test_bump_patch(temp_project: dict[str, Path]) -> None:
|
|||
assert 'version = "0.5.26"' in pyproject_content
|
||||
|
||||
version_py_content = temp_project["version_py"].read_text()
|
||||
assert '__version__ = "0.5.26"' in version_py_content
|
||||
assert '__version__ = "0.5.25"' in version_py_content
|
||||
|
||||
openclaw_pkg = json.loads(temp_project["openclaw_pkg"].read_text())
|
||||
assert openclaw_pkg["version"] == "0.5.26"
|
||||
|
|
@ -187,7 +187,7 @@ def test_bump_minor(temp_project: dict[str, Path]) -> None:
|
|||
assert 'version = "0.6.0"' in pyproject_content
|
||||
|
||||
version_py_content = temp_project["version_py"].read_text()
|
||||
assert '__version__ = "0.6.0"' in version_py_content
|
||||
assert '__version__ = "0.5.25"' in version_py_content
|
||||
|
||||
openclaw_pkg = json.loads(temp_project["openclaw_pkg"].read_text())
|
||||
assert openclaw_pkg["version"] == "0.6.0"
|
||||
|
|
@ -217,7 +217,7 @@ def test_bump_major(temp_project: dict[str, Path]) -> None:
|
|||
assert 'version = "1.0.0"' in pyproject_content
|
||||
|
||||
version_py_content = temp_project["version_py"].read_text()
|
||||
assert '__version__ = "1.0.0"' in version_py_content
|
||||
assert '__version__ = "0.5.25"' in version_py_content
|
||||
|
||||
openclaw_pkg = json.loads(temp_project["openclaw_pkg"].read_text())
|
||||
assert openclaw_pkg["version"] == "1.0.0"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Verify all package versions are in sync before publishing."""
|
||||
"""Verify all package manifest versions are in sync before publishing."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
|
@ -12,26 +12,44 @@ except ImportError: # pragma: no cover - Python 3.10 fallback
|
|||
ROOT = Path(__file__).parent.parent
|
||||
|
||||
|
||||
def main():
|
||||
def _read_json_version(path: Path) -> str:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
return str(json.load(f)["version"])
|
||||
|
||||
|
||||
def _read_marketplace_versions(path: Path) -> dict[str, str]:
|
||||
with open(path, encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
|
||||
versions: dict[str, str] = {}
|
||||
metadata = payload.get("metadata")
|
||||
if isinstance(metadata, dict):
|
||||
versions[f"{path}:metadata"] = str(metadata.get("version"))
|
||||
plugins = payload.get("plugins")
|
||||
if isinstance(plugins, list):
|
||||
for index, plugin in enumerate(plugins):
|
||||
if isinstance(plugin, dict):
|
||||
versions[f"{path}:plugins[{index}]"] = str(plugin.get("version"))
|
||||
return versions
|
||||
|
||||
|
||||
def main() -> None:
|
||||
with open(ROOT / "pyproject.toml", "rb") as f:
|
||||
py_ver = tomllib.load(f)["project"]["version"]
|
||||
|
||||
with open(ROOT / "plugins/openclaw/package.json") as f:
|
||||
npm_openclaw_ver = json.load(f)["version"]
|
||||
|
||||
with open(ROOT / "sdk/typescript/package.json") as f:
|
||||
npm_sdk_ver = json.load(f)["version"]
|
||||
|
||||
headroom_ver = (
|
||||
(ROOT / "headroom" / "_version.py").read_text().split('__version__ = "')[1].split('"')[0]
|
||||
)
|
||||
|
||||
versions = {
|
||||
"pyproject.toml": py_ver,
|
||||
"openclaw/package.json": npm_openclaw_ver,
|
||||
"typescript/package.json": npm_sdk_ver,
|
||||
"headroom/_version.py": headroom_ver,
|
||||
"plugins/openclaw/package.json": _read_json_version(ROOT / "plugins/openclaw/package.json"),
|
||||
"sdk/typescript/package.json": _read_json_version(ROOT / "sdk/typescript/package.json"),
|
||||
"plugins/headroom-agent-hooks/.claude-plugin/plugin.json": _read_json_version(
|
||||
ROOT / "plugins/headroom-agent-hooks/.claude-plugin/plugin.json"
|
||||
),
|
||||
"plugins/headroom-agent-hooks/.github/plugin/plugin.json": _read_json_version(
|
||||
ROOT / "plugins/headroom-agent-hooks/.github/plugin/plugin.json"
|
||||
),
|
||||
}
|
||||
versions.update(_read_marketplace_versions(ROOT / ".claude-plugin/marketplace.json"))
|
||||
versions.update(_read_marketplace_versions(ROOT / ".github/plugin/marketplace.json"))
|
||||
|
||||
if not all(v == py_ver for v in versions.values()):
|
||||
print("Version mismatch detected:")
|
||||
|
|
|
|||
|
|
@ -37,18 +37,6 @@ def bump_version(version: str, bump_type: str) -> str:
|
|||
return f"{major}.{minor}.{patch}"
|
||||
|
||||
|
||||
def update_version_py(root: Path, version: str) -> None:
|
||||
"""Update headroom/_version.py with new version."""
|
||||
version_py_path = root / "headroom" / "_version.py"
|
||||
content = version_py_path.read_text(encoding="utf-8")
|
||||
updated = re.sub(
|
||||
r'__version__ = "[^"]+"',
|
||||
f'__version__ = "{version}"',
|
||||
content,
|
||||
)
|
||||
version_py_path.write_text(updated, encoding="utf-8")
|
||||
|
||||
|
||||
def update_package_json(file_path: Path, version: str) -> None:
|
||||
"""Update a package.json version field."""
|
||||
with open(file_path, encoding="utf-8") as f:
|
||||
|
|
@ -178,7 +166,6 @@ def main() -> None:
|
|||
|
||||
# Update all versioned files
|
||||
update_pyproject_version(args.root, version)
|
||||
update_version_py(args.root, version)
|
||||
update_openclaw_package_json(
|
||||
args.root / "plugins" / "openclaw" / "package.json", version, version
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue