Files
repoCat/src/repocat/cli/review.py
Max P. 68b3233fcb refactor(review): streamline repo review logic and data handling
- Replaces manual path handling with `RepoCatalogState` abstraction
- Simplifies repo status checks and removes redundant imports
- Improves clarity and maintainability of interactive review process
2025-05-11 14:38:44 +02:00

89 lines
3.2 KiB
Python

from typer import Typer
from rich.console import Console
from rich.prompt import Prompt, Confirm
from datetime import datetime
import shutil
import typer
from repocat.config import load_config
from repocat.models.catalog import RepoCatalogState
from repocat.cli.move import move_command
from repocat.cli.archive import archive_repo
app = Typer()
console = Console()
@app.command("run")
def review():
"""
Führt interaktiv durch alle Repositories im Review-Ordner.
"""
catalog = RepoCatalogState.from_config(load_config())
archive_cat = next((c for c in catalog.categories if c.config.is_archive), None)
if not archive_cat:
console.print("[red]Keine Archiv-Kategorie in der Konfiguration gefunden.[/]")
raise typer.Exit(1)
review_cat = catalog.get_category("review")
if not review_cat:
console.print("[red]Kein 'review'-Eintrag in der Konfiguration gefunden.[/]")
raise typer.Exit(1)
if not review_cat.repos:
console.print("[green]✓ Keine Repositories im Review-Ordner.[/]")
return
for repo in sorted(review_cat.repos, key=lambda r: r.name):
console.rule(f"[bold cyan]{repo.name}")
console.print(f"[bold]Alter:[/] {repo.age_days} Tage")
console.print(f"[bold]Größe:[/] {repo.size_mb:.1f} MB")
if repo.git:
status = []
if repo.git.dirty:
status.append("uncommitted")
if repo.git.unpushed:
status.append("unpushed")
if not status:
status.append("clean")
else:
status = ["kein Git"]
console.print(f"[bold]Git:[/] {', '.join(status)}")
while True:
action = Prompt.ask(
"Aktion \\[m]ove / \\[a]rchive / \\[d]elete / \\[s]kip / \\[q]uit",
choices=["m", "a", "d", "s", "q"],
show_choices=False
)
if action in ("s", "skip", ""):
break
elif action in ("q", "quit"):
console.print("[bold yellow]Abgebrochen.[/]")
raise typer.Exit()
elif action in ("d", "delete"):
if Confirm.ask(f"Bist du sicher, dass du [red]{repo.name}[/] löschen willst?"):
shutil.rmtree(repo.path)
console.print(f"[red]✓ Gelöscht:[/] {repo.name}")
break
elif action in ("m", "move"):
target_categories = [c.config.name for c in catalog.categories if c.config.name != "review" and not c.config.is_archive]
target = Prompt.ask("Zielkategorie", choices=target_categories)
move_command(source=f"review/{repo.name}", target=target)
break
elif action in ("a", "archive"):
try:
archive_file = archive_repo(repo.path, archive_cat.path, dry_run=False)
console.print(f"[green]✓ Archiviert:[/] {archive_file.name}")
break
except Exception as e:
console.print(f"[red]Fehler beim Archivieren:[/] {e}")
else:
console.print("[yellow]Ungültige Eingabe. Gültig sind: m, d, s, q[/]")
console.print("[green]✓ Review abgeschlossen.[/]")