ReviewLlama/src/reviewllama/cli.py

122 lines
3.5 KiB
Python
Raw Normal View History

import argparse
import sys
from pathlib import Path
from typing import List, Optional
2025-06-09 21:54:37 -04:00
from reviewllama.git_diff import analyze_git_repository
2025-06-08 06:31:34 -04:00
from .configs import OllamaConfig, ReviewConfig, create_config_from_vars
2025-06-09 21:54:37 -04:00
from .logger import (log_git_analysis_result, log_git_analysis_start,
log_paths, log_review_start)
def normalize_server_url(url: str) -> str:
"""Normalize Ollama server URL to ensure proper format."""
if not url.startswith(("http://", "https://")):
return f"http://{url}"
return url.rstrip("/")
def create_argument_parser() -> argparse.ArgumentParser:
"""Create and configure the argument parser."""
parser = argparse.ArgumentParser(
prog="reviewllama",
description="AI-powered code review assistant",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
reviewllama . --model gemma3:27b --server localhost:11434
reviewllama src/ tests/ --model llama3.2:7b --timeout 60
""",
)
parser.add_argument(
"paths",
nargs="+",
metavar="PATH",
help="One or more file paths or git directories to review",
)
parser.add_argument(
"--model",
default="llama3.2:3b",
help="Ollama model to use for code review (default: %(default)s)",
)
parser.add_argument(
"--server",
dest="server_url",
default="localhost:11434",
help="Ollama server URL (default: %(default)s)",
)
parser.add_argument(
"--timeout",
type=int,
default=30,
help="Request timeout in seconds (default: %(default)s)",
)
parser.add_argument(
"--max-retries",
dest="max_retries",
type=int,
default=3,
help="Maximum number of retry attempts (default: %(default)s)",
)
2025-06-09 21:54:37 -04:00
parser.add_argument(
"--base-branch",
dest="base_branch",
default="master",
help="Base branch to compare against (default: %(default)s)",
)
return parser
def parse_raw_arguments(args: Optional[List[str]] = None) -> argparse.Namespace:
"""Parse command line arguments into raw namespace."""
parser = create_argument_parser()
return parser.parse_args(args)
def transform_namespace_to_config(namespace: argparse.Namespace) -> ReviewConfig:
"""Transform argparse namespace into ReviewConfig."""
paths = [Path(path_str) for path_str in namespace.paths]
2025-06-08 06:31:34 -04:00
return create_config_from_vars(
paths=paths,
model=namespace.model,
2025-06-08 06:31:34 -04:00
server_url=normalize_server_url(namespace.server_url),
timeout=namespace.timeout,
max_retries=namespace.max_retries,
2025-06-09 21:54:37 -04:00
base_branch=namespace.base_branch,
)
def parse_arguments(args: Optional[List[str]] = None) -> ReviewConfig:
"""Parse command line arguments and return validated configuration."""
raw_namespace = parse_raw_arguments(args)
return transform_namespace_to_config(raw_namespace)
def cli() -> None:
"""Main entry point for the CLI."""
try:
config = parse_arguments()
# TODO: Pass config to review engine
log_review_start(config)
log_paths(config.paths)
2025-06-09 21:54:37 -04:00
for path in Paths:
analysis = analyze_git_repository(path, config.base_branch)
log_git_analysis_start(path, config.base_branch)
log_git_analysis_result(analysis)
except SystemExit:
# argparse calls sys.exit on error, let it propagate
raise
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)