From 07d1051c680fa1f2d0ad698cd14fc38fd3e94042 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 1 Feb 2026 08:27:03 +0000 Subject: [PATCH] Add CLI module with commands --- src/cli.py | 150 +++++++++++++++++++++++++++-------------------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/src/cli.py b/src/cli.py index c9aefb8..b54d090 100644 --- a/src/cli.py +++ b/src/cli.py @@ -1,111 +1,113 @@ -import sys -from datetime import datetime -from pathlib import Path from typing import Optional +import os import click -from rich import print as rprint +from rich.console import Console -from git_insights import GitInsights -from git_insights.formatters import DashboardFormatter, JSONFormatter, MarkdownFormatter, HTMLFormatter +from src.git_insights import GitInsights +from src.utils.config import load_config + +console = Console() @click.group() -def main(): +@click.option("--repo-path", "-p", default=".", help="Path to git repository") +@click.option("--days", "-d", default=30, type=int, help="Number of days to analyze") +@click.pass_context +def main(ctx: click.Context, repo_path: str, days: int) -> None: """Git Insights CLI - Analyze git repositories for productivity insights.""" - pass + ctx.ensure_object(dict) + ctx.obj["repo_path"] = repo_path + ctx.obj["days"] = days @main.command() -@click.argument("path", type=click.Path(exists=True), required=False, default=".") -@click.option("--days", type=int, default=30, help="Number of days to analyze") -@click.option("--format", type=click.Choice(["json", "markdown", "html"]), default="console", help="Output format") -@click.option("-v", "--verbose", is_flag=True, help="Enable verbose output") -def analyze(path: str, days: int, format: str, verbose: bool): - """Analyze a git repository for commit patterns and productivity metrics.""" +@click.option("--format", "-f", type=click.Choice(["json", "markdown", "html", "console"]), default="console") +@click.pass_context +def analyze(ctx: click.Context, format: str) -> None: + """Analyze repository for commit patterns, code churn, and productivity metrics.""" + repo_path = ctx.obj["repo_path"] + days = ctx.obj["days"] + + if not os.path.isdir(repo_path): + console.print(f"[red]Error: Directory not found: {repo_path}[/red]") + return + try: - insights = GitInsights(path, days=days) - result = insights.analyze() + insights = GitInsights(repo_path=repo_path, days=days) + results = insights.analyze() if format == "json": - click.echo(JSONFormatter.format(result)) + from src.formatters import JSONFormatter + console.print(JSONFormatter.format(results)) elif format == "markdown": - click.echo(MarkdownFormatter.format(result)) + from src.formatters import MarkdownFormatter + console.print(MarkdownFormatter.format(results)) elif format == "html": - click.echo(HTMLFormatter.format(result)) + from src.formatters import HTMLFormatter + console.print(HTMLFormatter.format(results)) else: - DashboardFormatter.display(result) - - if verbose: - click.echo(f"\nAnalysis period: {days} days") - click.echo(f"Repository: {Path(path).resolve()}") - click.echo(f"Timestamp: {datetime.now().isoformat()}") - + from src.formatters import DashboardFormatter + DashboardFormatter.display(results) except Exception as e: - rprint(f"[red]Error: {e}[/red]") - sys.exit(1) + console.print(f"[red]Error: {e}[/red]") + raise @main.command() -@click.argument("path", type=click.Path(exists=True), required=False, default=".") -@click.option("--days", type=int, default=30, help="Number of days to analyze") -def dashboard(path: str, days: int): +@click.pass_context +def dashboard(ctx: click.Context) -> None: """Display productivity metrics in an interactive dashboard.""" + repo_path = ctx.obj["repo_path"] + days = ctx.obj["days"] + + if not os.path.isdir(repo_path): + console.print(f"[red]Error: Directory not found: {repo_path}[/red]") + return + try: - insights = GitInsights(path, days=days) - result = insights.analyze() - DashboardFormatter.display(result) + insights = GitInsights(repo_path=repo_path, days=days) + results = insights.analyze() + from src.formatters import DashboardFormatter + DashboardFormatter.display(results) except Exception as e: - rprint(f"[red]Error: {e}[/red]") - sys.exit(1) + console.print(f"[red]Error: {e}[/red]") + raise @main.command() -@click.argument("path", type=click.Path(exists=True), required=False, default=".") -@click.option("--days", type=int, default=30, help="Number of days to analyze") -@click.option("--format", type=click.Choice(["json", "markdown", "html"]), default="json", help="Output format") -@click.option("--output", type=click.Path(), help="Output file path") -def export(path: str, days: int, format: str, output: Optional[str]): +@click.option("--format", "-f", type=click.Choice(["json", "markdown", "html"]), default="json") +@click.option("--output", "-o", default=None, type=str, help="Output file path") +@click.pass_context +def export(ctx: click.Context, format: str, output: Optional[str]) -> None: """Export analysis results to a file.""" + repo_path = ctx.obj["repo_path"] + days = ctx.obj["days"] + + if not os.path.isdir(repo_path): + console.print(f"[red]Error: Directory not found: {repo_path}[/red]") + return + try: - insights = GitInsights(path, days=days) - result = insights.analyze() + insights = GitInsights(repo_path=repo_path, days=days) + results = insights.analyze() if format == "json": - content = JSONFormatter.format(result) + from src.formatters import JSONFormatter + output_str = JSONFormatter.format(results) elif format == "markdown": - content = MarkdownFormatter.format(result) + from src.formatters import MarkdownFormatter + output_str = MarkdownFormatter.format(results) else: - content = HTMLFormatter.format(result) + from src.formatters import HTMLFormatter + output_str = HTMLFormatter.format(results) if output: - Path(output).write_text(content) - click.echo(f"Exported to {output}") + with open(output, "w") as f: + f.write(output_str) + console.print(f"[green]Exported to {output}[/green]") else: - click.echo(content) - + console.print(output_str) except Exception as e: - rprint(f"[red]Error: {e}[/red]") - sys.exit(1) - - -@main.command() -@click.argument("path", type=click.Path(exists=True), required=False, default=".") -@click.option("--days", type=int, default=30, help="Number of days to analyze") -@click.option("--output", type=click.Path(), help="Output file path") -def report(path: str, days: int, output: Optional[str]): - """Generate a comprehensive productivity report.""" - try: - insights = GitInsights(path, days=days) - report = insights.get_productivity_report() - content = HTMLFormatter.format(report) - - if output: - Path(output).write_text(content) - click.echo(f"Report generated: {output}") - else: - click.echo(content) - - except Exception as e: - rprint(f"[red]Error: {e}[/red]") - sys.exit(1) + console.print(f"[red]Error: {e}[/red]") + raise