fix: Add Gitea Actions CI workflow and fix linting issues
This commit is contained in:
244
src/cli.py
Normal file
244
src/cli.py
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
"""CLI interface for local-commit-message-generator."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from . import __version__
|
||||||
|
from .config import (
|
||||||
|
DEFAULT_CONFIG,
|
||||||
|
ConfigError,
|
||||||
|
ensure_config_exists,
|
||||||
|
get_config_path,
|
||||||
|
load_config,
|
||||||
|
save_config,
|
||||||
|
)
|
||||||
|
from .generator import GenerationError, generate_commit_message
|
||||||
|
from .hooks import HookManager, handle_hook_invocation
|
||||||
|
|
||||||
|
|
||||||
|
def print_version(ctx: click.Context, param: click.Parameter, value: bool) -> None:
|
||||||
|
"""Print version information."""
|
||||||
|
if not value or ctx.resilient_parsing:
|
||||||
|
return
|
||||||
|
click.echo(f"local-commit-message-generator v{__version__}")
|
||||||
|
ctx.exit()
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
@click.option(
|
||||||
|
"--version",
|
||||||
|
is_flag=True,
|
||||||
|
callback=print_version,
|
||||||
|
expose_value=False,
|
||||||
|
help="Show version information."
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--repo",
|
||||||
|
default=None,
|
||||||
|
help="Path to git repository."
|
||||||
|
)
|
||||||
|
@click.pass_context
|
||||||
|
def main(ctx: click.Context, repo: Optional[str]) -> None:
|
||||||
|
"""Generate conventional commit messages from staged git changes."""
|
||||||
|
ctx.ensure_object(dict)
|
||||||
|
ctx.obj["repo"] = repo
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.pass_context
|
||||||
|
def generate(ctx: click.Context) -> None:
|
||||||
|
"""Generate a commit message from staged changes."""
|
||||||
|
repo = ctx.obj.get("repo")
|
||||||
|
|
||||||
|
try:
|
||||||
|
message = generate_commit_message(repo_path=repo)
|
||||||
|
click.echo(message)
|
||||||
|
except GenerationError as e:
|
||||||
|
click.echo(f"Error: {e}", err=True)
|
||||||
|
click.echo("Make sure you have staged changes with 'git add'.", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(f"Unexpected error: {e}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.pass_context
|
||||||
|
def hook(ctx: click.Context) -> None:
|
||||||
|
"""Handle prepare-commit-msg hook invocation.
|
||||||
|
|
||||||
|
This is called automatically by git when the hook is installed.
|
||||||
|
Do not call this directly.
|
||||||
|
"""
|
||||||
|
repo = ctx.obj.get("repo")
|
||||||
|
args = sys.argv[1:] if sys.argv else []
|
||||||
|
|
||||||
|
try:
|
||||||
|
message = handle_hook_invocation(args, repo)
|
||||||
|
if message:
|
||||||
|
click.echo(message)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.option(
|
||||||
|
"--path",
|
||||||
|
"config_path",
|
||||||
|
default=None,
|
||||||
|
help="Path to config file."
|
||||||
|
)
|
||||||
|
@click.pass_context
|
||||||
|
def install_hook(ctx: click.Context, config_path: Optional[str]) -> None:
|
||||||
|
"""Install prepare-commit-msg git hook."""
|
||||||
|
repo = ctx.obj.get("repo")
|
||||||
|
repo_path = Path(repo) if repo else Path.cwd()
|
||||||
|
|
||||||
|
manager = HookManager(repo_path)
|
||||||
|
result = manager.install_hook()
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
click.secho(result.message, fg="green")
|
||||||
|
click.echo("Hook is now active. Commit messages will be auto-generated.")
|
||||||
|
else:
|
||||||
|
click.secho(result.message, fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.pass_context
|
||||||
|
def uninstall_hook(ctx: click.Context) -> None:
|
||||||
|
"""Uninstall prepare-commit-msg git hook."""
|
||||||
|
repo = ctx.obj.get("repo")
|
||||||
|
repo_path = Path(repo) if repo else Path.cwd()
|
||||||
|
|
||||||
|
manager = HookManager(repo_path)
|
||||||
|
result = manager.uninstall_hook()
|
||||||
|
|
||||||
|
if result.success:
|
||||||
|
click.secho(result.message, fg="green")
|
||||||
|
else:
|
||||||
|
click.secho(result.message, fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.pass_context
|
||||||
|
def status(ctx: click.Context) -> None:
|
||||||
|
"""Check git repository and staged changes status."""
|
||||||
|
repo = ctx.obj.get("repo")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .analyzer import ChangeAnalyzer
|
||||||
|
analyzer = ChangeAnalyzer(repo)
|
||||||
|
change_set = analyzer.get_staged_changes()
|
||||||
|
|
||||||
|
if change_set.has_changes:
|
||||||
|
click.secho(f"Staged changes: {change_set.total_count}", fg="green")
|
||||||
|
for change in change_set.changes[:10]:
|
||||||
|
emoji = {
|
||||||
|
"added": "+",
|
||||||
|
"deleted": "-",
|
||||||
|
"modified": "~",
|
||||||
|
"renamed": "R",
|
||||||
|
}.get(change.change_type.value, "?")
|
||||||
|
click.echo(f" {emoji} {change.path}")
|
||||||
|
if change_set.total_count > 10:
|
||||||
|
click.echo(f" ... and {change_set.total_count - 10} more")
|
||||||
|
else:
|
||||||
|
click.secho("No staged changes", fg="yellow")
|
||||||
|
click.echo("Run 'git add' to stage changes.")
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
click.secho(str(e), fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.group()
|
||||||
|
def config() -> None:
|
||||||
|
"""Manage configuration."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@config.command("show")
|
||||||
|
@click.pass_context
|
||||||
|
def config_show(ctx: click.Context) -> None:
|
||||||
|
"""Show current configuration."""
|
||||||
|
try:
|
||||||
|
ensure_config_exists()
|
||||||
|
config = load_config()
|
||||||
|
click.echo("Current Configuration:")
|
||||||
|
click.echo("-" * 40)
|
||||||
|
for key, value in config.items():
|
||||||
|
if key == "type_rules":
|
||||||
|
click.echo("type_rules:")
|
||||||
|
for type_, patterns in value.items():
|
||||||
|
click.echo(f" {type_}: {patterns}")
|
||||||
|
else:
|
||||||
|
click.echo(f"{key}: {value}")
|
||||||
|
except ConfigError as e:
|
||||||
|
click.secho(f"Error: {e}", fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@config.command("set-template")
|
||||||
|
@click.argument("template", nargs=-1)
|
||||||
|
@click.pass_context
|
||||||
|
def config_set_template(ctx: click.Context, template: tuple) -> None:
|
||||||
|
"""Set the commit message template."""
|
||||||
|
try:
|
||||||
|
ensure_config_exists()
|
||||||
|
config = load_config()
|
||||||
|
template_str = " ".join(template) if template else ""
|
||||||
|
config["template"] = template_str
|
||||||
|
save_config(config)
|
||||||
|
click.secho(f"Template updated to: {template_str}", fg="green")
|
||||||
|
except ConfigError as e:
|
||||||
|
click.secho(f"Error: {e}", fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@config.command("reset")
|
||||||
|
@click.pass_context
|
||||||
|
def config_reset(ctx: click.Context) -> None:
|
||||||
|
"""Reset configuration to defaults."""
|
||||||
|
try:
|
||||||
|
config_path = get_config_path()
|
||||||
|
if config_path.exists():
|
||||||
|
config_path.unlink()
|
||||||
|
save_config(DEFAULT_CONFIG.copy())
|
||||||
|
click.secho("Configuration reset to defaults.", fg="green")
|
||||||
|
except ConfigError as e:
|
||||||
|
click.secho(f"Error: {e}", fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.pass_context
|
||||||
|
def preview(ctx: click.Context) -> None:
|
||||||
|
"""Preview the commit message without printing."""
|
||||||
|
repo = ctx.obj.get("repo")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .generator import get_commit_message_preview
|
||||||
|
message, has_changes = get_commit_message_preview(repo)
|
||||||
|
|
||||||
|
if has_changes:
|
||||||
|
click.secho("Preview:", fg="cyan")
|
||||||
|
click.echo("-" * 40)
|
||||||
|
click.echo(message)
|
||||||
|
click.echo("-" * 40)
|
||||||
|
else:
|
||||||
|
click.secho("No staged changes to preview.", fg="yellow")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
click.secho(f"Error: {e}", fg="red", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def cli_entrypoint() -> None:
|
||||||
|
"""Entry point for the CLI."""
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user