Skip to main content

heddle_cli_args/cli/cli_args/
commands_hook.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Hook command definitions.
3
4use std::path::PathBuf;
5
6use clap::{Args, Subcommand};
7
8#[derive(Subcommand, Clone)]
9pub enum HookCommands {
10    /// List installed hooks.
11    List,
12
13    /// Install a hook.
14    Install {
15        /// Hook name (e.g., pre-snapshot, post-push).
16        name: String,
17        #[command(flatten)]
18        source: HookInstallSource,
19    },
20
21    /// Uninstall a hook.
22    Uninstall {
23        /// Hook name.
24        name: String,
25    },
26
27    /// Show the hook event catalog (W2/A15).
28    ///
29    /// Prints the JSON-Schema for each registered event's payload and
30    /// response. Use this to scaffold a hook without reading source.
31    Events {
32        /// When set, returns the schema for one event only.
33        #[arg(long)]
34        event: Option<String>,
35    },
36}
37
38#[derive(Args, Clone)]
39#[group(required = false, multiple = false)]
40pub struct HookInstallSource {
41    /// Read the hook script from a file path.
42    #[arg(long = "from-file", value_name = "PATH")]
43    pub from_file: Option<PathBuf>,
44
45    /// Read the hook script from standard input.
46    #[arg(long = "from-stdin")]
47    pub from_stdin: bool,
48}
49
50#[cfg(test)]
51mod tests {
52    use clap::Parser;
53
54    use crate::cli::{Cli, Commands, HookCommands};
55
56    #[test]
57    fn parses_hook_install_from_file_without_positional_script_body() {
58        let cli = Cli::try_parse_from([
59            "heddle",
60            "hook",
61            "install",
62            "pre-snapshot",
63            "--from-file",
64            "hooks/pre-snapshot.sh",
65        ])
66        .expect("parse hook install command");
67
68        match cli.command {
69            Commands::Hook {
70                command: HookCommands::Install { name, source },
71            } => {
72                assert_eq!(name, "pre-snapshot");
73                assert_eq!(
74                    source.from_file.as_deref(),
75                    Some(std::path::Path::new("hooks/pre-snapshot.sh"))
76                );
77                assert!(!source.from_stdin);
78            }
79            _ => panic!("unexpected command"),
80        }
81    }
82}