From 2f7e90148f001d755f83893c012dc41d3b1bfac3 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Wed, 4 Feb 2026 20:05:33 +0000 Subject: [PATCH] Add CLI modules: validate, sync, merge, history --- confsync/cli/history.py | 156 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 confsync/cli/history.py diff --git a/confsync/cli/history.py b/confsync/cli/history.py new file mode 100644 index 0000000..3c3665f --- /dev/null +++ b/confsync/cli/history.py @@ -0,0 +1,156 @@ +"""History command for tracking configuration changes.""" + +from typing import Dict, Optional +import typer +from rich.console import Console +from rich.panel import Panel +from rich.table import Table +from datetime import datetime + +from confsync.utils.git_utils import GitManager + +history_cmd = typer.Typer( + name="history", + help="View and manage configuration change history", + no_args_is_help=True, +) + +console = Console() + + +@history_cmd.command("list") +def history_list( + limit: int = typer.Option( + 20, "--limit", "-l", + help="Maximum number of entries to show" + ), + repo: Optional[str] = typer.Option( + None, "--repo", "-r", + help="Git repository to read history from" + ), + manifest: str = typer.Option( + "confsync_manifest.yaml", + "--manifest", "-m", + help="Path to manifest file" + ), +): + """List configuration change history.""" + git = GitManager(repo_path=repo) + + commits = git.get_commit_history(manifest, max_count=limit) + + if not commits: + console.print("[yellow]No history found.[/yellow]") + return + + table = Table(title="Configuration History") + table.add_column("Commit", style="cyan", no_wrap=True) + table.add_column("Date", style="magenta") + table.add_column("Author", style="green") + table.add_column("Message", style="white") + + for commit in commits: + date = datetime.fromisoformat(commit["authored_datetime"]).strftime("%Y-%m-%d %H:%M") + message = commit["message"][:60] + "..." if len(commit["message"]) > 60 else commit["message"] + table.add_row( + commit["hexsha"][:7], + date, + commit["author"].split("<")[0].strip(), + message, + ) + + console.print(table) + + +@history_cmd.command("show") +def history_show( + commit: str = typer.Argument( + ..., + help="Commit hash to show" + ), + repo: Optional[str] = typer.Option( + None, "--repo", "-r", + help="Git repository" + ), + file: Optional[str] = typer.Option( + None, "--file", "-f", + help="Show only specific file from commit" + ), +): + """Show details of a specific commit.""" + git = GitManager(repo_path=repo) + + commits = git.get_commit_history(file, max_count=100) + + target = None + for c in commits: + if c["hexsha"].startswith(commit): + target = c + break + + if not target: + console.print(f"[red]Error:[/red] Commit not found: {commit}") + return + + diff = git.get_file_diff(file or "") + + console.print(Panel.fit( + f"[bold]Commit {target['hexsha'][:7]}[/bold]", + style="blue", + subtitle=target["authored_datetime"], + )) + console.print(f"\n[bold]Author:[/bold] {target['author']}") + console.print("\n[bold]Message:[/bold]") + console.print(target['message']) + + if diff: + console.print("\n[bold]Changes:[/bold]") + console.print(diff) + + +@history_cmd.command("rollback") +def history_rollback( + commit: str = typer.Argument( + ..., + help="Commit hash to rollback to" + ), + repo: Optional[str] = typer.Option( + None, "--repo", "-r", + help="Git repository" + ), + file: Optional[str] = typer.Option( + None, "--file", "-f", + help="Rollback specific file only" + ), + dry_run: bool = typer.Option( + False, "--dry-run", "-n", + help="Preview without making changes" + ), +): + """Rollback configurations to a previous commit.""" + git = GitManager(repo_path=repo) + + if dry_run: + console.print(f"[bold]Dry Run - Would rollback to {commit[:7]}[/bold]") + if file: + console.print(f"File: {file}") + commits = git.get_commit_history(file, max_count=5) + for c in commits: + if c["hexsha"].startswith(commit): + console.print(f"Target: {c['message']}") + break + console.print("[yellow]No changes made[/yellow]") + return + + if file: + console.print(f"[bold]Rolling back {file} to {commit[:7]}[/bold]") + else: + console.print(f"[bold]Rolling back to commit {commit[:7]}[/bold]") + + if git.checkout(commit): + console.print(Panel.fit( + "[bold green]Rollback Successful![/bold green]", + style="green", + )) + else: + console.print("[red]Error: Rollback failed[/red]")