fix: resolve CI issues - remove unused imports and fix code quality
Some checks failed
CI / lint (push) Has been cancelled
CI / build (push) Has been cancelled
repohealth-cli CI / test (push) Has been cancelled
CI / test (push) Has been cancelled

This commit is contained in:
2026-02-05 17:30:19 +00:00
parent 45f4265f16
commit 8c8e09e6b9

View File

@@ -0,0 +1,251 @@
from typing import Optional
from rich.box import ROUNDED
from rich.console import Console
from rich.panel import Panel
from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn
from rich.table import Table
from rich.text import Text
from repohealth.models.result import RepositoryResult
class TerminalReporter:
"""Reporter for terminal output using Rich."""
RISK_COLORS = {
"critical": "red",
"high": "orange3",
"medium": "yellow",
"low": "green",
"unknown": "grey"
}
def __init__(self, console: Optional[Console] = None):
"""Initialize the reporter.
Args:
console: Rich Console instance.
"""
self.console = console or Console()
def display_result(self, result: RepositoryResult) -> None:
"""Display a complete analysis result.
Args:
result: RepositoryResult to display.
"""
self.console.print(Panel(
self._get_overview_text(result),
title="Repository Health Analysis",
subtitle=f"Analyzed: {result.analyzed_at.strftime('%Y-%m-%d %H:%M')}",
expand=False
))
self._display_risk_summary(result)
self._display_file_stats(result)
self._display_hotspots(result)
self._display_suggestions(result)
def _get_overview_text(self, result: RepositoryResult) -> Text:
"""Get overview text for the result.
Args:
result: RepositoryResult to display.
Returns:
Rich Text object.
"""
text = Text()
text.append("Repository: ", style="bold")
text.append(f"{result.repository_path}\n")
text.append("Files Analyzed: ", style="bold")
text.append(f"{result.files_analyzed}\n")
text.append("Total Commits: ", style="bold")
text.append(f"{result.total_commits}\n")
text.append("Unique Authors: ", style="bold")
text.append(f"{result.unique_authors}\n")
text.append("Overall Bus Factor: ", style="bold")
text.append(f"{result.overall_bus_factor:.2f}\n")
text.append("Gini Coefficient: ", style="bold")
text.append(f"{result.gini_coefficient:.3f}\n")
return text
def _display_risk_summary(self, result: RepositoryResult) -> None:
"""Display risk summary.
Args:
result: RepositoryResult to display.
"""
summary = result.risk_summary
if not summary:
return
table = Table(title="Risk Summary", box=ROUNDED)
table.add_column("Risk Level", justify="center")
table.add_column("Count", justify="center")
table.add_column("Percentage", justify="center")
levels = ["critical", "high", "medium", "low"]
for level in levels:
count = summary.get(level, 0)
pct = summary.get(f"percentage_{level}", 0)
color = self.RISK_COLORS.get(level, "grey")
table.add_row(
f"[{color}]{level.upper()}[/]",
str(count),
f"{pct:.1f}%"
)
self.console.print(Panel(table, title="Risk Overview", expand=False))
def _display_file_stats(self, result: RepositoryResult) -> None:
"""Display file statistics table.
Args:
result: RepositoryResult to display.
"""
if not result.files:
return
table = Table(title="Top Files by Risk", box=ROUNDED)
table.add_column("File", style="dim", width=40)
table.add_column("Commits", justify="right")
table.add_column("Authors", justify="right")
table.add_column("Bus Factor", justify="right")
table.add_column("Risk", justify="center")
table.add_column("Top Author %", justify="right")
sorted_files = sorted(
result.files,
key=lambda x: (
{"critical": 0, "high": 1, "medium": 2, "low": 3}.get(x.get("risk_level"), 4),
-x.get("bus_factor", 1)
)
)[:15]
for file_data in sorted_files:
risk_level = file_data.get("risk_level", "unknown")
color = self.RISK_COLORS.get(risk_level, "grey")
table.add_row(
file_data.get("path", "")[:40],
str(file_data.get("total_commits", 0)),
str(file_data.get("num_authors", 0)),
f"{file_data.get('bus_factor', 1):.2f}",
f"[{color}]{risk_level.upper()}[/]",
f"{file_data.get('top_author_share', 0):%}"
)
self.console.print(Panel(table, title="File Analysis", expand=False))
def _display_hotspots(self, result: RepositoryResult) -> None:
"""Display knowledge hotspots.
Args:
result: RepositoryResult to display.
"""
if not result.hotspots:
return
table = Table(title="Knowledge Hotspots", box=ROUNDED)
table.add_column("File", style="dim", width=35)
table.add_column("Top Author", width=20)
table.add_column("Ownership", justify="right")
table.add_column("Bus Factor", justify="right")
table.add_column("Risk", justify="center")
for hotspot in result.hotspots[:10]:
color = self.RISK_COLORS.get(hotspot.risk_level, "grey")
table.add_row(
hotspot.file_path[:35],
hotspot.top_author[:20],
f"{hotspot.top_author_share:.0%}",
f"{hotspot.bus_factor:.2f}",
f"[{color}]{hotspot.risk_level.upper()}[/]"
)
self.console.print(Panel(table, title="Hotspots", expand=False))
def _display_suggestions(self, result: RepositoryResult) -> None:
"""Display diversification suggestions.
Args:
result: RepositoryResult to display.
"""
if not result.suggestions:
return
table = Table(title="Diversification Suggestions", box=ROUNDED)
table.add_column("Priority", width=10)
table.add_column("File", style="dim", width=30)
table.add_column("Action", width=40)
priority_colors = {
"critical": "red",
"high": "orange3",
"medium": "yellow"
}
for suggestion in result.suggestions[:10]:
color = priority_colors.get(suggestion.priority, "grey")
table.add_row(
f"[{color}]{suggestion.priority.upper()}[/]",
suggestion.file_path[:30],
suggestion.action[:40]
)
self.console.print(Panel(table, title="Suggestions", expand=False))
def display_progress(self, message: str) -> Progress:
"""Display a progress indicator.
Args:
message: Progress message.
Returns:
Progress instance for updating.
"""
return Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TaskProgressColumn(),
console=self.console
)
def display_error(self, message: str) -> None:
"""Display an error message.
Args:
message: Error message to display.
"""
self.console.print(Panel(
Text(message, style="red"),
title="Error",
expand=False
))
def display_warning(self, message: str) -> None:
"""Display a warning message.
Args:
message: Warning message to display.
"""
self.console.print(Panel(
Text(message, style="yellow"),
title="Warning",
expand=False
))
def display_info(self, message: str) -> None:
"""Display an info message.
Args:
message: Info message to display.
"""
self.console.print(Panel(
Text(message, style="blue"),
title="Info",
expand=False
))