Coverage for src / repo_sync_kitty / cli.py: 77%
35 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-23 09:31 -0500
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-23 09:31 -0500
1"""Main CLI application using Typer."""
3import os
4from pathlib import Path
5from typing import Annotated
7import typer
8from rich.console import Console
10from repo_sync_kitty import __version__
11from repo_sync_kitty.commands import add, check, init, scan, status, sync
13# Initialize Sentry if DSN is provided
14if dsn := os.getenv("SENTRY_DSN"): 14 ↛ 15line 14 didn't jump to line 15 because the condition on line 14 was never true
15 try:
16 import sentry_sdk
18 sentry_sdk.init(dsn=dsn, release=f"repo-sync-kitty@{__version__}")
19 except ImportError:
20 pass # sentry-sdk not installed, skip
22console = Console()
24app = typer.Typer(
25 name="repo-sync-kitty",
26 help="Git repository synchronization tool for teams.",
27 add_completion=False,
28 no_args_is_help=True,
29)
32def version_callback(value: bool) -> None:
33 """Print version and exit."""
34 if value:
35 console.print(f"repo-sync-kitty {__version__}")
36 raise typer.Exit()
39@app.callback()
40def main(
41 ctx: typer.Context,
42 version: Annotated[ # noqa: ARG001
43 bool,
44 typer.Option(
45 "--version",
46 "-V",
47 callback=version_callback,
48 is_eager=True,
49 help="Show version and exit.",
50 ),
51 ] = False,
52 manifest: Annotated[
53 Path | None,
54 typer.Option(
55 "--manifest",
56 "-m",
57 help="Path to manifest.toml file.",
58 envvar="REPO_SYNC_KITTY_MANIFEST",
59 ),
60 ] = None,
61 root: Annotated[
62 Path | None,
63 typer.Option(
64 "--root",
65 "-r",
66 help="Root directory for repositories.",
67 envvar="REPO_SYNC_KITTY_ROOT",
68 ),
69 ] = None,
70 no_color: Annotated[
71 bool,
72 typer.Option("--no-color", help="Disable colored output."),
73 ] = False,
74 verbose: Annotated[
75 bool,
76 typer.Option("--verbose", "-v", help="Enable verbose output."),
77 ] = False,
78) -> None:
79 """Git repository synchronization tool for teams."""
80 # Store global options in context for subcommands to access
81 ctx.ensure_object(dict)
82 ctx.obj["manifest"] = manifest
83 ctx.obj["root"] = root
84 ctx.obj["verbose"] = verbose
85 if no_color: 85 ↛ 86line 85 didn't jump to line 86 because the condition on line 85 was never true
86 console.no_color = True
89# Register commands
90app.command(name="sync")(sync.sync)
91app.command(name="status")(status.status)
92app.command(name="init")(init.init)
93app.command(name="add")(add.add)
94app.command(name="check")(check.check)
95app.command(name="scan")(scan.scan)
98if __name__ == "__main__": 98 ↛ 99line 98 didn't jump to line 99 because the condition on line 98 was never true
99 app()