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
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ that DevRepro should already have redacted usernames/home paths/secrets.
**Environment**
- OS + version:
- Shell:
- DevRepro version:
- DevRepro version (`devrepro --version`):

**Additional context**
Anything else relevant.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ jobs:
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: Ruff lint
run: ruff check devrepro tests
run: ruff check devrepro tests scripts
- name: Format check
run: ruff format --check devrepro tests
run: ruff format --check devrepro tests scripts
- name: Type check (mypy)
run: mypy devrepro
- name: Tests + coverage
Expand Down
29 changes: 29 additions & 0 deletions devrepro/cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import typer

from devrepro import __version__
from devrepro.cli.commands import register_all

app = typer.Typer(
Expand All @@ -27,6 +28,34 @@
register_all(app)


def _version_callback(value: bool) -> None:
"""Print the installed version and exit.

Eager, so it answers before Typer demands a subcommand — the bug-report
template asks reporters for this and it has to work on its own.
"""
if value:
typer.echo(f"devrepro {__version__}")
raise typer.Exit


@app.callback()
def _root(
version: bool = typer.Option(
False,
"--version",
callback=_version_callback,
is_eager=True,
help="Show the installed devrepro version and exit.",
),
) -> None:
"""Project-aware developer-environment diagnostics and safe remediation.

This callback exists so ``--version`` has somewhere to live; Typer needs a
root callback to hang a group-level option on.
"""


def main() -> None:
try:
app()
Expand Down
47 changes: 47 additions & 0 deletions tests/test_version_is_reportable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""`devrepro --version` has to work, and report the real version.

`__version__` was already derived from installed metadata (see
`devrepro/__init__.py`), but nothing exposed it on the command line: the flag
exited 2 with "No such option". A version you cannot ask the tool for is not
much use to a bug reporter.
"""

from __future__ import annotations

import pathlib
import tomllib

from devrepro import __version__
from devrepro.cli.app import app
from typer.testing import CliRunner

runner = CliRunner()
PYPROJECT = pathlib.Path(__file__).resolve().parents[1] / "pyproject.toml"


def _declared_version() -> str:
data = tomllib.loads(PYPROJECT.read_text(encoding="utf-8"))
return str(data["project"]["version"])


def test_package_version_matches_pyproject() -> None:
assert __version__ == _declared_version()


def test_version_flag_exits_zero_and_prints_the_version() -> None:
result = runner.invoke(app, ["--version"])
assert result.exit_code == 0, result.output
assert __version__ in result.output


def test_version_flag_does_not_require_a_subcommand() -> None:
"""The app is `no_args_is_help=True`; an eager callback must still answer."""
result = runner.invoke(app, ["--version"])
assert "Usage:" not in result.output


def test_adding_the_callback_did_not_hide_the_commands() -> None:
result = runner.invoke(app, ["--help"])
assert result.exit_code == 0
for expected in ("doctor", "check", "preflight", "snapshot"):
assert expected in result.output