1use clap::Parser;
2use clap_verbosity_flag::{InfoLevel, Verbosity};
3
4#[derive(Parser, Debug)]
5#[command(version)]
6#[command(name = "Auto Commit")]
7#[command(author = "Miguel Piedrafita <soy@miguelpiedrafita.com>")]
8#[command(about = "Automagically generate commit messages.", long_about = None)]
9pub struct Cli {
10 #[clap(flatten)]
11 pub verbose: Verbosity<InfoLevel>,
12
13 #[arg(
14 long = "dry-run",
15 help = "Output the generated message, but don't create a commit."
16 )]
17 pub dry_run: bool,
18
19 #[arg(
20 short,
21 long,
22 help = "Edit the generated commit message before committing."
23 )]
24 pub review: bool,
25
26 #[arg(short, long, help = "Don't ask for confirmation before committing.")]
27 pub force: bool,
28
29 #[arg(
30 long,
31 help = "Custom message format with placeholders like {title}, {description}, {prefix}, {emoji}, {scope}"
32 )]
33 pub format: Option<String>,
34}
35
36impl Cli {
37 pub fn parse_args() -> Self {
38 Self::parse()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn test_parse_dry_run() {
48 let args = vec!["auto-commit", "--dry-run"];
49 let cli = Cli::parse_from(args);
50 assert!(cli.dry_run);
51 assert!(!cli.review);
52 assert!(!cli.force);
53 assert!(cli.format.is_none());
54 }
55
56 #[test]
57 fn test_parse_review() {
58 let args = vec!["auto-commit", "--review"];
59 let cli = Cli::parse_from(args);
60 assert!(!cli.dry_run);
61 assert!(cli.review);
62 assert!(!cli.force);
63 }
64
65 #[test]
66 fn test_parse_force() {
67 let args = vec!["auto-commit", "--force"];
68 let cli = Cli::parse_from(args);
69 assert!(!cli.dry_run);
70 assert!(!cli.review);
71 assert!(cli.force);
72 }
73
74 #[test]
75 fn test_parse_format() {
76 let args = vec!["auto-commit", "--format", "{prefix}: {title}"];
77 let cli = Cli::parse_from(args);
78 assert_eq!(cli.format, Some("{prefix}: {title}".to_string()));
79 }
80
81 #[test]
82 fn test_parse_multiple_options() {
83 let args = vec!["auto-commit", "--dry-run", "--force", "--format", "custom: {title}"];
84 let cli = Cli::parse_from(args);
85 assert!(cli.dry_run);
86 assert!(cli.force);
87 assert_eq!(cli.format, Some("custom: {title}".to_string()));
88 }
89
90 #[test]
91 fn test_parse_short_options() {
92 let args = vec!["auto-commit", "-r", "-f"];
93 let cli = Cli::parse_from(args);
94 assert!(cli.review);
95 assert!(cli.force);
96 }
97
98 #[test]
99 fn test_verbosity_levels() {
100 let args = vec!["auto-commit"];
102 let cli = Cli::parse_from(args);
103 assert_eq!(cli.verbose.log_level(), Some(log::Level::Info));
104
105 let args = vec!["auto-commit", "-q"];
107 let cli = Cli::parse_from(args);
108 assert_eq!(cli.verbose.log_level(), Some(log::Level::Warn));
109
110 let args = vec!["auto-commit", "-qq"];
112 let cli = Cli::parse_from(args);
113 assert_eq!(cli.verbose.log_level(), Some(log::Level::Error));
114
115 let args = vec!["auto-commit", "-v"];
117 let cli = Cli::parse_from(args);
118 assert_eq!(cli.verbose.log_level(), Some(log::Level::Debug));
119
120 let args = vec!["auto-commit", "-vv"];
122 let cli = Cli::parse_from(args);
123 assert_eq!(cli.verbose.log_level(), Some(log::Level::Trace));
124 }
125}