Add CLI modules: validate, sync, merge, history
This commit is contained in:
156
confsync/cli/history.py
Normal file
156
confsync/cli/history.py
Normal file
@@ -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]")
|
||||
Reference in New Issue
Block a user