fix: add CLI and main module files
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled

This commit is contained in:
2026-02-01 08:19:10 +00:00
parent c9b31fb9b6
commit beb98d85fc

View File

@@ -1,226 +1,111 @@
import os
import sys
from datetime import datetime
from pathlib import Path
from typing import Optional
import click
from rich.console import Console
from rich import print as rprint
from src.git_insights import GitInsights
from src.utils.config import load_config
console = Console()
from git_insights import GitInsights
from git_insights.formatters import DashboardFormatter, JSONFormatter, MarkdownFormatter, HTMLFormatter
@click.group()
@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.option(
"--config",
"-c",
default=None,
type=str,
help="Path to config file",
)
@click.pass_context
def main(
ctx: click.Context,
repo_path: str,
days: int,
config: Optional[str],
) -> None:
def main():
"""Git Insights CLI - Analyze git repositories for productivity insights."""
ctx.ensure_object(dict)
ctx.obj["repo_path"] = repo_path
ctx.obj["days"] = days
ctx.obj["config"] = config
pass
@main.command()
@click.option(
"--format",
"-f",
type=click.Choice(["json", "markdown", "html", "console"]),
default="console",
help="Output format",
)
@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"]
config_path = ctx.obj["config"]
config = load_config(config_path) if config_path else None
if not os.path.isdir(repo_path):
console.print(f"[red]Error: Directory not found: {repo_path}[/red]")
return
@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."""
try:
insights = GitInsights(
repo_path=repo_path,
days=days,
config=config,
)
results = insights.analyze()
insights = GitInsights(path, days=days)
result = insights.analyze()
if format == "json":
from src.formatters import JSONFormatter
console.print(JSONFormatter.format(results))
click.echo(JSONFormatter.format(result))
elif format == "markdown":
from src.formatters import MarkdownFormatter
console.print(MarkdownFormatter.format(results))
click.echo(MarkdownFormatter.format(result))
elif format == "html":
from src.formatters import HTMLFormatter
console.print(HTMLFormatter.format(results))
click.echo(HTMLFormatter.format(result))
else:
from src.formatters import DashboardFormatter
DashboardFormatter.display(results)
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()}")
except Exception as e:
console.print(f"[red]Error: {e}[/red]")
raise
rprint(f"[red]Error: {e}[/red]")
sys.exit(1)
@main.command()
@click.pass_context
def dashboard(ctx: click.Context) -> None:
@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):
"""Display productivity metrics in an interactive dashboard."""
repo_path = ctx.obj["repo_path"]
days = ctx.obj["days"]
config_path = ctx.obj["config"]
config = load_config(config_path) if config_path else None
if not os.path.isdir(repo_path):
console.print(f"[red]Error: Directory not found: {repo_path}[/red]")
return
try:
insights = GitInsights(
repo_path=repo_path,
days=days,
config=config,
)
results = insights.analyze()
from src.formatters import DashboardFormatter
DashboardFormatter.display(results)
insights = GitInsights(path, days=days)
result = insights.analyze()
DashboardFormatter.display(result)
except Exception as e:
console.print(f"[red]Error: {e}[/red]")
raise
rprint(f"[red]Error: {e}[/red]")
sys.exit(1)
@main.command()
@click.option(
"--format",
"-f",
type=click.Choice(["json", "markdown", "html"]),
default="json",
help="Output format",
)
@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:
@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]):
"""Export analysis results to a file."""
repo_path = ctx.obj["repo_path"]
days = ctx.obj["days"]
config_path = ctx.obj["config"]
config = load_config(config_path) if config_path else None
if not os.path.isdir(repo_path):
console.print(f"[red]Error: Directory not found: {repo_path}[/red]")
return
try:
insights = GitInsights(
repo_path=repo_path,
days=days,
config=config,
)
results = insights.analyze()
insights = GitInsights(path, days=days)
result = insights.analyze()
if format == "json":
from src.formatters import JSONFormatter
output_str = JSONFormatter.format(results)
content = JSONFormatter.format(result)
elif format == "markdown":
from src.formatters import MarkdownFormatter
output_str = MarkdownFormatter.format(results)
content = MarkdownFormatter.format(result)
else:
from src.formatters import HTMLFormatter
output_str = HTMLFormatter.format(results)
content = HTMLFormatter.format(result)
if output:
with open(output, "w") as f:
f.write(output_str)
console.print(f"[green]Exported to {output}[/green]")
Path(output).write_text(content)
click.echo(f"Exported to {output}")
else:
console.print(output_str)
click.echo(content)
except Exception as e:
console.print(f"[red]Error: {e}[/red]")
raise
rprint(f"[red]Error: {e}[/red]")
sys.exit(1)
@main.command()
@click.option(
"--output",
"-o",
default=None,
type=str,
help="Output file path",
)
@click.pass_context
def report(ctx: click.Context, output: Optional[str]) -> None:
@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."""
repo_path = ctx.obj["repo_path"]
days = ctx.obj["days"]
config_path = ctx.obj["config"]
config = load_config(config_path) if config_path else None
if not os.path.isdir(repo_path):
console.print(f"[red]Error: Directory not found: {repo_path}[/red]")
return
try:
insights = GitInsights(
repo_path=repo_path,
days=days,
config=config,
)
results = insights.analyze()
from src.formatters import HTMLFormatter
report_str = HTMLFormatter.format(results)
insights = GitInsights(path, days=days)
report = insights.get_productivity_report()
content = HTMLFormatter.format(report)
if output:
with open(output, "w") as f:
f.write(report_str)
console.print(f"[green]Report generated: {output}[/green]")
Path(output).write_text(content)
click.echo(f"Report generated: {output}")
else:
console.print(report_str)
click.echo(content)
except Exception as e:
console.print(f"[red]Error: {e}[/red]")
raise
rprint(f"[red]Error: {e}[/red]")
sys.exit(1)