guardy 0.2.4

Fast, secure git hooks in Rust with secret scanning and protected file synchronization
Documentation
use anyhow::Result;
use clap::{Args, Subcommand};

#[derive(Args, Clone)]
pub struct HooksArgs {
    /// Skip all hooks
    #[arg(long, global = true)]
    pub skip_all: Option<bool>,

    /// Run hooks in parallel
    #[arg(long, global = true)]
    pub parallel: Option<bool>,

    #[command(subcommand)]
    pub command: Option<HooksCommands>,
}

#[derive(Subcommand, Clone)]
pub enum HooksCommands {
    /// Install git hooks into the current repository
    Install {
        /// Specify which hooks to install (default: all)
        #[arg(long, value_delimiter = ',')]
        hooks: Option<Vec<String>>,

        /// Overwrite existing hooks
        #[arg(long)]
        force: bool,
    },
    /// Uninstall git hooks from the current repository
    Uninstall {
        /// Specify which hooks to uninstall (default: all guardy hooks)
        #[arg(long, value_delimiter = ',')]
        hooks: Option<Vec<String>>,

        /// Skip confirmation prompt
        #[arg(short, long)]
        yes: bool,
    },
    /// Run a specific hook manually for testing
    Run {
        /// Hook name to run
        hook: String,

        /// Additional arguments for the hook
        args: Vec<String>,
    },
    /// Show hooks installation and configuration status
    Status,
    /// Dump hooks configuration in various formats
    Dump {
        /// Output format (json, yaml, toml)
        #[arg(long, value_enum)]
        format: Option<String>,

        /// Output lefthook-compatible configuration
        #[arg(long)]
        lefthook: bool,
    },
    /// Validate hooks configuration
    Validate,
}

pub async fn execute(args: HooksArgs) -> Result<()> {
    match args.command {
        Some(HooksCommands::Install { hooks, force }) => {
            crate::hooks::install::install_hooks(force, hooks).await
        }
        Some(HooksCommands::Uninstall { hooks, yes }) => {
            crate::hooks::uninstall::uninstall_hooks(hooks, yes).await
        }
        Some(HooksCommands::Run { hook, args }) => {
            use crate::hooks::HookExecutor;
            let executor = HookExecutor::new();
            match executor.execute(&hook, &args).await {
                Ok(()) => Ok(()),
                Err(_) => {
                    // Hook already printed error details, just exit with error code
                    std::process::exit(1);
                }
            }
        }
        Some(HooksCommands::Status) => crate::hooks::status::hooks_status().await,
        Some(HooksCommands::Dump { format, lefthook }) => {
            if lefthook {
                crate::hooks::dump::dump_lefthook_config().await
            } else {
                crate::hooks::dump::dump_hooks_config(format).await
            }
        }
        Some(HooksCommands::Validate) => {
            // TODO: Implement hooks validate functionality
            crate::hooks::validate::validate_hooks_config().await
        }
        None => {
            // Default to hooks status if no subcommand provided
            crate::hooks::status::hooks_status().await
        }
    }
}