hermes plugins install <repo>#gateway-plugin ships ONLY the gateway-plugin/ subdirectory into ~/.hermes/plugins/iris, so the repo-root VERSION file is not present there and plugin_version() fell back to 'unknown' — the app then showed a false 'App and gateway versions differ' warning. - version.py: resolution chain repo-root VERSION (dev/symlink install) -> plugin.yaml version field (production install) -> 'unknown'; stdlib-only parse, base= param for tests - plugin.yaml: bump stale version 0.1.0 -> 0.1.2 (matches VERSION) - scripts/check_version_sync.sh + pre-commit hook: fail commits where plugin.yaml drifts from the repo-root VERSION - tests: regression test simulating the production layout
68 lines
2.2 KiB
Python
68 lines
2.2 KiB
Python
"""Version discovery.
|
|
|
|
The repo-root ``VERSION`` file is the single source of truth for the release
|
|
version ("everything from here on out is vX.Y.Z" = bump ``VERSION`` and
|
|
commit). It is advertised to the app in ``hello.ack``
|
|
(``server_caps.app_version``) so the app can show which gateway version it is
|
|
talking to.
|
|
|
|
Resolution order (first hit wins):
|
|
|
|
1. ``<repo>/VERSION`` — dev checkout / symlink install: the plugin lives at
|
|
``<repo>/gateway-plugin``, so the ``VERSION`` file is one directory up.
|
|
2. ``version:`` in the plugin's own ``plugin.yaml`` — production install:
|
|
``hermes plugins install <repo>#gateway-plugin`` moves ONLY the
|
|
``gateway-plugin/`` subdirectory into ``~/.hermes/plugins/iris``, so the
|
|
repo-root ``VERSION`` is not present there. ``plugin.yaml`` ships with the
|
|
plugin dir; a pre-commit hook (``scripts/check_version_sync.sh``) keeps its
|
|
``version:`` field in sync with the repo-root ``VERSION``.
|
|
3. ``"unknown"``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
_FALLBACK = "unknown"
|
|
|
|
_VERSION_RE = re.compile(r"^version:\s*[\"']?([^\"'\s]+)")
|
|
|
|
|
|
def _read_version_file(path: Path) -> str:
|
|
try:
|
|
return path.read_text().strip()
|
|
except OSError:
|
|
return ""
|
|
|
|
|
|
def _plugin_yaml_version(plugin_dir: Path) -> str:
|
|
"""The top-level ``version:`` field of ``plugin.yaml`` (stdlib-only parse)."""
|
|
try:
|
|
text = (plugin_dir / "plugin.yaml").read_text()
|
|
except OSError:
|
|
return ""
|
|
for line in text.splitlines():
|
|
m = _VERSION_RE.match(line)
|
|
if m:
|
|
return m.group(1)
|
|
return ""
|
|
|
|
|
|
def plugin_version(base: Path | None = None) -> str:
|
|
"""The release version, or ``"unknown"`` if it cannot be found.
|
|
|
|
``base`` overrides the plugin directory (tests); by default it is the
|
|
directory containing this file.
|
|
"""
|
|
plugin_dir = base if base is not None else Path(__file__).resolve().parent
|
|
# 1. Repo-root VERSION (dev checkout / symlink install).
|
|
version = _read_version_file(plugin_dir.parent / "VERSION")
|
|
if version:
|
|
return version
|
|
# 2. plugin.yaml (production install ships only the plugin dir).
|
|
version = _plugin_yaml_version(plugin_dir)
|
|
if version:
|
|
return version
|
|
return _FALLBACK
|