diff --git a/repeater/companion/bridge.py b/repeater/companion/bridge.py index 0b1751d..8e32440 100644 --- a/repeater/companion/bridge.py +++ b/repeater/companion/bridge.py @@ -16,6 +16,8 @@ from typing import Any, Callable, Optional from openhop_core.companion import CompanionBridge +from repeater import __version__ as repeater_version + logger = logging.getLogger("RepeaterCompanionBridge") @@ -93,6 +95,11 @@ class RepeaterCompanionBridge(CompanionBridge): radio_settings_getter=radio_settings_getter, max_tx_power_getter=max_tx_power_getter, ) + # The companion CLI's `ver` names the openHop software; add the repeater + # ahead of the core. An older core has no companion CLI to tell. + add_version = getattr(getattr(self, "cli", None), "add_software_version", None) + if callable(add_version): + add_version("repeater", repeater_version) def _save_prefs(self) -> None: """Persist full NodePrefs as JSON to SQLite.""" diff --git a/repeater/handler_helpers/mesh_cli.py b/repeater/handler_helpers/mesh_cli.py index 2eaa5f8..ab878f1 100644 --- a/repeater/handler_helpers/mesh_cli.py +++ b/repeater/handler_helpers/mesh_cli.py @@ -4,6 +4,10 @@ import re from pathlib import Path from typing import Any, Callable, Dict, Optional +from openhop_core import __version__ as core_version + +from repeater import __version__ as repeater_version + logger = logging.getLogger(__name__) @@ -493,10 +497,13 @@ class MeshCLI: return "Error: Not yet implemented" def _cmd_version(self) -> str: - """Get version information.""" + """Report the installed openHop repeater and core versions. + + Nothing sets ``config["version"]``, so reading it answered the stale + fallback "v13" in every real deployment. + """ role = "room_server" if self.identity_type == "room_server" else "repeater" - version = self.config.get("version", "13") - return f"openHop_{role} v{version}" + return f"openHop_{role} v{repeater_version} (core v{core_version})" # ==================== Get Commands ==================== diff --git a/tests/test_companion_bridge_prefs.py b/tests/test_companion_bridge_prefs.py index aad2d8a..bd95fa0 100644 --- a/tests/test_companion_bridge_prefs.py +++ b/tests/test_companion_bridge_prefs.py @@ -84,3 +84,23 @@ def test_bridge_accepts_host_radio_callbacks(identity): "airtime_factor": 1.0, } assert bridge.get_max_tx_power_dbm() == 20 + + +def test_companion_ver_names_the_repeater_and_core_versions(): + """The virtual companion's CLI `ver` (CMD_RUN_CLI_COMMAND / remote CLI) + reports the openHop software running it, repeater first.""" + import openhop_core + from openhop_core.protocol import LocalIdentity + + import repeater + from repeater.companion.bridge import RepeaterCompanionBridge + + async def _inject(pkt, wait_for_ack=False, expected_crc=None): + return True + + bridge = RepeaterCompanionBridge(LocalIdentity(), _inject, node_name="Comp") + if not hasattr(bridge, "cli"): + pytest.skip("installed openhop_core predates the companion CLI") + assert bridge.cli.handle("ver") == ( + f"openHop repeater v{repeater.__version__}, core v{openhop_core.__version__}" + ) diff --git a/tests/test_handler_helpers_mesh_cli.py b/tests/test_handler_helpers_mesh_cli.py index 4beb338..99be37f 100644 --- a/tests/test_handler_helpers_mesh_cli.py +++ b/tests/test_handler_helpers_mesh_cli.py @@ -885,3 +885,17 @@ def test_neighbor_remove_takes_the_cached_scopes_with_it(tmp_path): assert cli.handle_command(b"\x00" * 32, "neighbor.remove all", True) == "OK" assert set(handler.get_neighbor_scopes()) == {companion} +@pytest.mark.parametrize( + ("identity_type", "role"), [("repeater", "repeater"), ("room_server", "room_server")] +) +def test_ver_reports_the_installed_repeater_and_core_versions(identity_type, role): + """Nothing sets config["version"], so it must not be the source: it answered + the stale fallback "v13" on every real node.""" + import openhop_core + + import repeater + + cli = MeshCLI("/tmp/cfg.yaml", _base_config(), _cfg_mgr(), identity_type=identity_type) + assert cli.handle_command(b"\x00" * 32, "ver", True) == ( + f"openHop_{role} v{repeater.__version__} (core v{openhop_core.__version__})" + )