Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions java_codebase_rag/_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Version string for the CLI ``--version`` flag.

The single source of truth is the installed distribution metadata
(``java-codebase-rag`` in pyproject.toml), read via :mod:`importlib.metadata`
so a pyproject bump propagates with no second hardcoded copy.
:func:`version_string` appends the CPython version for the
``<prog> <version> (python <x.y.z>)`` format chosen for the ``--version`` flag.

Stdlib-only on purpose: this is imported at module load by both CLIs, and
``jrag`` keeps ``build_parser()`` free of torch / sentence_transformers / mcp_v2.
"""
from __future__ import annotations

import platform
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as _dist_version

_PACKAGE = "java-codebase-rag"


def package_version() -> str:
"""Installed distribution version, or ``"unknown"`` if metadata is absent.

Absent only when run from a raw checkout without ``pip install -e``; the
test suite (``conftest.py``) enforces editable install, so this is defensive.
"""
try:
return _dist_version(_PACKAGE)
except PackageNotFoundError: # pragma: no cover - defensive
return "unknown"


def version_string(prog: str) -> str:
"""Formatted ``--version`` output: ``<prog> <version> (python <x.y.z>)``."""
return f"{prog} {package_version()} (python {platform.python_version()})"
6 changes: 6 additions & 0 deletions java_codebase_rag/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
write_config_source_pointer,
)
from java_codebase_rag._fdlimit import raise_fd_limit
from java_codebase_rag._version import version_string
from java_codebase_rag.pipeline import (
clip,
is_cocoindex_preflight_blocker,
Expand Down Expand Up @@ -919,6 +920,11 @@ def build_parser() -> argparse.ArgumentParser:
formatter_class=argparse.RawDescriptionHelpFormatter,
exit_on_error=False,
)
parser.add_argument(
"--version",
action="version",
version=version_string(parser.prog),
)
subparsers = parser.add_subparsers(dest="subcommand")

init = subparsers.add_parser(
Expand Down
6 changes: 6 additions & 0 deletions java_codebase_rag/jrag.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from java_codebase_rag._fdlimit import raise_fd_limit
from java_codebase_rag._stdio import force_utf8_stdio
from java_codebase_rag._version import version_string

__all__ = ["build_parser", "main", "_console_script_main"]

Expand Down Expand Up @@ -334,6 +335,11 @@ def build_parser() -> argparse.ArgumentParser:
formatter_class=argparse.RawDescriptionHelpFormatter,
exit_on_error=False,
)
parser.add_argument(
"--version",
action="version",
version=version_string(parser.prog),
)
subparsers = parser.add_subparsers(dest="command", parser_class=_EnvelopeArgumentParser)

# Common flags applied per command via parents=[_common_parser()]. NOT
Expand Down
39 changes: 39 additions & 0 deletions tests/test_version_flag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""``--version`` flag for the ``java-codebase-rag`` and ``jrag`` CLIs.

Format contract: ``<prog> <version> (python <x.y.z>)``, exit 0. The version is
read from installed metadata, so assertions match :func:`version_string` rather
than a hardcoded literal (it bumps every release).
"""
from __future__ import annotations

import re

from java_codebase_rag import cli, jrag
from java_codebase_rag._version import version_string

_PY_VER_RE = re.compile(r"\(python \d+\.\d+\.\d+\)")


def test_java_codebase_rag_version_flag(capsys):
rc = cli.main(["--version"])

assert rc == 0
out = capsys.readouterr().out.strip()
assert out == version_string("java-codebase-rag")
assert _PY_VER_RE.search(out)


def test_jrag_version_flag(capsys):
rc = jrag.main(["--version"])

assert rc == 0
out = capsys.readouterr().out.strip()
assert out == version_string("jrag")
assert _PY_VER_RE.search(out)


def test_version_flag_rejected_after_subcommand():
"""Top-level only: ``jrag <cmd> --version`` is a usage error, not a version print."""
rc = jrag.main(["status", "--version"])

assert rc != 0
Loading