import argparse import sys from pathlib import Path from typing import List, Optional from reviewllama.git_diff import analyze_git_repository from .configs import ReviewConfig, create_config_from_vars 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 """, ) 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( "--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] return create_config_from_vars( paths=paths, model=namespace.model, server_url=normalize_server_url(namespace.server_url), # TODO: Update this system prompt. Either allow the user to provide it or engineer our own for this. "You are a helpful AI assistant", 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) for path in config.paths: analysis = analyze_git_repository(path, config.base_branch) log_git_analysis_start(path, config.base_branch) log_git_analysis_result(analysis) print(analysis.diffs) 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)