From 66810a317716342535882aedce8c1921fbd881e6 Mon Sep 17 00:00:00 2001 From: teamauresta <232735187+teamauresta@users.noreply.github.com> Date: Mon, 23 Feb 2026 13:49:04 +1100 Subject: [PATCH 1/3] feat: add --version/-v flag to CLI Implements cgr --version and cgr -v commands that display the current package version read from importlib.metadata. Acceptance criteria from issue #239: - cgr --version and cgr -v both work - Version read from package metadata (not hardcoded) - Output format: code-graph-rag version X.Y.Z Changes: - Add _version_callback using app_context.console.print (highlight=False) - Add HELP_VERSION to cli_help.py - Add CLI_MSG_VERSION to constants.py - Use ch.HELP_VERSION and cs.CLI_MSG_VERSION (no hardcoded strings) - Add test_version_flag() to test_cli_smoke.py referencing cs.CLI_MSG_VERSION --- codebase_rag/cli.py | 18 ++++++++++++++++++ codebase_rag/cli_help.py | 1 + codebase_rag/constants.py | 1 + codebase_rag/tests/test_cli_smoke.py | 26 ++++++++++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/codebase_rag/cli.py b/codebase_rag/cli.py index 87f9a5379..84ff28e17 100644 --- a/codebase_rag/cli.py +++ b/codebase_rag/cli.py @@ -1,4 +1,5 @@ import asyncio +from importlib.metadata import version as get_version from pathlib import Path import typer @@ -34,6 +35,15 @@ ) +def _version_callback(value: bool) -> None: + if value: + app_context.console.print( + cs.CLI_MSG_VERSION.format(version=get_version("code-graph-rag")), + highlight=False, + ) + raise typer.Exit() + + def validate_models_early() -> None: try: orchestrator_config = settings.active_orchestrator_config @@ -58,6 +68,14 @@ def _update_and_validate_models(orchestrator: str | None, cypher: str | None) -> @app.callback() def _global_options( + version: bool | None = typer.Option( + None, + "--version", + "-v", + help=ch.HELP_VERSION, + callback=_version_callback, + is_eager=True, + ), quiet: bool = typer.Option( False, "--quiet", diff --git a/codebase_rag/cli_help.py b/codebase_rag/cli_help.py index 96e816d9a..25a9810b7 100644 --- a/codebase_rag/cli_help.py +++ b/codebase_rag/cli_help.py @@ -50,6 +50,7 @@ class CLICommandName(StrEnum): HELP_REPO_PATH_INDEX = "Path to the target repository to index." HELP_REPO_PATH_OPTIMIZE = "Path to the repository to optimize" HELP_REPO_PATH_WATCH = "Path to the repository to watch." +HELP_VERSION = "Show the version and exit." HELP_UPDATE_GRAPH = "Update the knowledge graph by parsing the repository" HELP_CLEAN_DB = "Clean the database before updating (use when adding first repo)" diff --git a/codebase_rag/constants.py b/codebase_rag/constants.py index 37c15f23a..4c867b2c0 100644 --- a/codebase_rag/constants.py +++ b/codebase_rag/constants.py @@ -234,6 +234,7 @@ class GoogleProviderType(StrEnum): CLI_MSG_EXPORTING_DATA = "Exporting graph data..." CLI_MSG_OPTIMIZATION_TERMINATED = "\nOptimization session terminated by user." CLI_MSG_MCP_TERMINATED = "\nMCP server terminated by user." +CLI_MSG_VERSION = "code-graph-rag version {version}" CLI_MSG_HINT_TARGET_REPO = ( "\nHint: Make sure TARGET_REPO_PATH environment variable is set." ) diff --git a/codebase_rag/tests/test_cli_smoke.py b/codebase_rag/tests/test_cli_smoke.py index 88b420e07..a1a1feecf 100644 --- a/codebase_rag/tests/test_cli_smoke.py +++ b/codebase_rag/tests/test_cli_smoke.py @@ -1,9 +1,12 @@ import subprocess import sys +from importlib.metadata import version as get_version from pathlib import Path import pytest +from codebase_rag import constants as cs + def test_help_command_works() -> None: repo_root = Path(__file__).parent.parent.parent @@ -32,3 +35,26 @@ def test_import_cli_module() -> None: assert hasattr(cli, "app"), "CLI module missing app attribute" except ImportError as e: pytest.fail(f"Failed to import cli module: {e}") + + +def test_version_flag() -> None: + repo_root = Path(__file__).parent.parent.parent + + for flag in ["--version", "-v"]: + result = subprocess.run( + [sys.executable, "-m", "codebase_rag.cli", flag], + check=False, + cwd=repo_root, + capture_output=True, + text=True, + timeout=30, + ) + + assert result.returncode == 0, ( + f"{flag} exited with code {result.returncode}: {result.stderr}" + ) + expected = cs.CLI_MSG_VERSION.format(version=get_version("code-graph-rag")) + assert result.stdout.strip() == expected, ( + f"{flag} output did not match expected format: {repr(result.stdout)}" + ) + assert result.stderr == "", f"Unexpected stderr for {flag}: {result.stderr}" From 1825c31f4c0496eefd89b804bee76aa52d820263 Mon Sep 17 00:00:00 2001 From: teamauresta <232735187+teamauresta@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:20:47 +1100 Subject: [PATCH 2/3] fix: sort imports in test_cli_smoke.py (ruff I001) --- codebase_rag/tests/test_cli_smoke.py | 1 + 1 file changed, 1 insertion(+) diff --git a/codebase_rag/tests/test_cli_smoke.py b/codebase_rag/tests/test_cli_smoke.py index 23c3e7288..fdda7d438 100644 --- a/codebase_rag/tests/test_cli_smoke.py +++ b/codebase_rag/tests/test_cli_smoke.py @@ -7,6 +7,7 @@ import pytest from codebase_rag import constants as cs + _ANSI_RE = re.compile(r"\x1b\[[0-9;]*m") From 00cc69e600244821258dbc0add31896036d63091 Mon Sep 17 00:00:00 2001 From: teamauresta Date: Fri, 6 Mar 2026 22:47:37 +1100 Subject: [PATCH 3/3] refactor: extract PACKAGE_NAME constant and update CLI_MSG_VERSION format - Add PACKAGE_NAME = 'code-graph-rag' to constants.py to avoid repetition - Update CLI_MSG_VERSION format string to use {package} placeholder - Use cs.PACKAGE_NAME in cli.py (app name, get_version call, format call) - Use cs.PACKAGE_NAME in test_cli_smoke.py instead of hardcoded string Addresses review feedback from @greptile-apps --- codebase_rag/cli.py | 4 ++-- codebase_rag/constants.py | 3 ++- codebase_rag/tests/test_cli_smoke.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/codebase_rag/cli.py b/codebase_rag/cli.py index 741d249cb..38aedaf3c 100644 --- a/codebase_rag/cli.py +++ b/codebase_rag/cli.py @@ -28,7 +28,7 @@ from .tools.language import cli as language_cli app = typer.Typer( - name="code-graph-rag", + name=cs.PACKAGE_NAME, help=ch.APP_DESCRIPTION, no_args_is_help=True, add_completion=False, @@ -38,7 +38,7 @@ def _version_callback(value: bool) -> None: if value: app_context.console.print( - cs.CLI_MSG_VERSION.format(version=get_version("code-graph-rag")), + cs.CLI_MSG_VERSION.format(package=cs.PACKAGE_NAME, version=get_version(cs.PACKAGE_NAME)), highlight=False, ) raise typer.Exit() diff --git a/codebase_rag/constants.py b/codebase_rag/constants.py index a0674ff2c..aa18ce7b4 100644 --- a/codebase_rag/constants.py +++ b/codebase_rag/constants.py @@ -236,7 +236,8 @@ class GoogleProviderType(StrEnum): CLI_MSG_EXPORTING_DATA = "Exporting graph data..." CLI_MSG_OPTIMIZATION_TERMINATED = "\nOptimization session terminated by user." CLI_MSG_MCP_TERMINATED = "\nMCP server terminated by user." -CLI_MSG_VERSION = "code-graph-rag version {version}" +PACKAGE_NAME = "code-graph-rag" +CLI_MSG_VERSION = "{package} version {version}" CLI_MSG_HINT_TARGET_REPO = ( "\nHint: Make sure TARGET_REPO_PATH environment variable is set." ) diff --git a/codebase_rag/tests/test_cli_smoke.py b/codebase_rag/tests/test_cli_smoke.py index fdda7d438..aeef03dd6 100644 --- a/codebase_rag/tests/test_cli_smoke.py +++ b/codebase_rag/tests/test_cli_smoke.py @@ -56,7 +56,7 @@ def test_version_flag() -> None: assert result.returncode == 0, ( f"{flag} exited with code {result.returncode}: {result.stderr}" ) - expected = cs.CLI_MSG_VERSION.format(version=get_version("code-graph-rag")) + expected = cs.CLI_MSG_VERSION.format(package=cs.PACKAGE_NAME, version=get_version(cs.PACKAGE_NAME)) assert result.stdout.strip() == expected, ( f"{flag} output did not match expected format: {repr(result.stdout)}" )