This commit is contained in:
129
src/depcheck/reporters/terminal.py
Normal file
129
src/depcheck/reporters/terminal.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Terminal reporter with Rich formatting."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from rich import box
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.table import Table
|
||||
from rich.text import Text
|
||||
|
||||
from depcheck.config import Config
|
||||
from depcheck.models import ScanResult, Severity
|
||||
|
||||
|
||||
class TerminalReporter:
|
||||
"""Report results in terminal-friendly format using Rich."""
|
||||
|
||||
def __init__(self, config: Optional[Config] = None):
|
||||
self.config = config or Config()
|
||||
self.console = Console()
|
||||
|
||||
def report(self, result: ScanResult) -> None:
|
||||
"""Display the scan result."""
|
||||
self._print_summary(result)
|
||||
self._print_vulnerabilities(result)
|
||||
self._print_outdated_dependencies(result)
|
||||
|
||||
def _print_summary(self, result: ScanResult) -> None:
|
||||
"""Print scan summary."""
|
||||
status = "✓ All Fresh" if result.outdated_count == 0 and result.vulnerable_count == 0 else "⚠ Issues Found"
|
||||
status_color = "green" if result.outdated_count == 0 and result.vulnerable_count == 0 else "yellow"
|
||||
|
||||
summary = Table(box=box.SIMPLE, show_header=False, padding=0)
|
||||
summary.add_column()
|
||||
summary.add_column()
|
||||
|
||||
summary.add_row("Status", Text(status, style=status_color))
|
||||
summary.add_row("Dependencies Scanned", str(len(result.dependencies)))
|
||||
summary.add_row("Outdated Packages", str(result.outdated_count))
|
||||
summary.add_row("Vulnerabilities", str(result.vulnerable_count))
|
||||
if result.source_file:
|
||||
summary.add_row("Source File", result.source_file)
|
||||
|
||||
self.console.print(Panel(summary, title="Dependency Scan Results", expand=False))
|
||||
|
||||
def _print_vulnerabilities(self, result: ScanResult) -> None:
|
||||
"""Print detected vulnerabilities."""
|
||||
if not result.vulnerabilities:
|
||||
return
|
||||
|
||||
vuln_table = Table(title="Security Vulnerabilities Detected", box=box.HEAVY_EDGE)
|
||||
vuln_table.add_column("Package", style="cyan")
|
||||
vuln_table.add_column("Current", style="red")
|
||||
vuln_table.add_column("CVE ID", style="yellow")
|
||||
vuln_table.add_column("Severity", style="bold")
|
||||
vuln_table.add_column("Description")
|
||||
|
||||
severity_colors = {
|
||||
Severity.CRITICAL: "red bold",
|
||||
Severity.HIGH: "orange1",
|
||||
Severity.MEDIUM: "yellow",
|
||||
Severity.LOW: "blue",
|
||||
Severity.INFO: "white",
|
||||
}
|
||||
|
||||
for dep, vuln in result.vulnerabilities:
|
||||
severity_style = severity_colors.get(vuln.severity, "white")
|
||||
vuln_table.add_row(
|
||||
dep.name,
|
||||
dep.current_version,
|
||||
vuln.cve_id,
|
||||
Text(vuln.severity.value.upper(), style=severity_style),
|
||||
vuln.description,
|
||||
)
|
||||
|
||||
self.console.print(Panel(vuln_table, title="⚠ Security Vulnerabilities", expand=False))
|
||||
|
||||
def _print_outdated_dependencies(self, result: ScanResult) -> None:
|
||||
"""Print outdated dependencies."""
|
||||
outdated = [d for d in result.dependencies if d.is_outdated]
|
||||
if not outdated:
|
||||
return
|
||||
|
||||
outdated_table = Table(title="Outdated Packages", box=box.HEAVY_EDGE)
|
||||
outdated_table.add_column("Package", style="cyan")
|
||||
outdated_table.add_column("Current", style="yellow")
|
||||
outdated_table.add_column("Latest", style="green")
|
||||
outdated_table.add_column("Update Type", style="magenta")
|
||||
outdated_table.add_column("Category", style="white")
|
||||
|
||||
for dep in outdated:
|
||||
update_type = ""
|
||||
if dep.latest_version:
|
||||
parts = dep.current_version.split(".")
|
||||
latest_parts = dep.latest_version.split(".")
|
||||
if latest_parts[0] > parts[0]:
|
||||
update_type = "major"
|
||||
elif len(latest_parts) > 1 and len(parts) > 1 and latest_parts[1] > parts[1]:
|
||||
update_type = "minor"
|
||||
elif len(latest_parts) > 2 and len(parts) > 2 and latest_parts[2] > parts[2]:
|
||||
update_type = "patch"
|
||||
|
||||
outdated_table.add_row(
|
||||
dep.name,
|
||||
dep.current_version,
|
||||
dep.latest_version or "unknown",
|
||||
update_type or "-",
|
||||
dep.category,
|
||||
)
|
||||
|
||||
self.console.print(Panel(outdated_table, title="Outdated Packages", expand=False))
|
||||
|
||||
def print_error(self, message: str) -> None:
|
||||
"""Print error message."""
|
||||
self.console.print(Panel(Text(message, style="red"), title="Error", expand=False))
|
||||
|
||||
def print_warning(self, message: str) -> None:
|
||||
"""Print warning message."""
|
||||
self.console.print(Panel(Text(message, style="yellow"), title="Warning", expand=False))
|
||||
|
||||
def print_info(self, message: str) -> None:
|
||||
"""Print info message."""
|
||||
self.console.print(Text(message, style="blue"))
|
||||
|
||||
def get_exit_code(self, result: ScanResult) -> int:
|
||||
"""Determine exit code based on results."""
|
||||
from depcheck.reporters.json import JSONReporter
|
||||
|
||||
return JSONReporter(self.config).get_exit_code(result)
|
||||
Reference in New Issue
Block a user