Skip to main content

commit_wizard/cli/
args.rs

1use std::path::PathBuf;
2
3use crate::{cli::cmd, core::bootstrap::AppContextArgs};
4use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
7pub enum FormatArg {
8    Auto,
9    Text,
10    Markdown,
11    Json,
12    Jsonl,
13    Plain,
14}
15
16impl FormatArg {
17    pub fn to_output_format_string(&self, use_json: bool) -> String {
18        match (use_json, self) {
19            (_, FormatArg::Text) => "text".to_string(),
20            (_, FormatArg::Markdown) => "markdown".to_string(),
21            (_, FormatArg::Json) => "json".to_string(),
22            (_, FormatArg::Jsonl) => "jsonl".to_string(),
23            (_, FormatArg::Plain) => "plain".to_string(),
24            (true, FormatArg::Auto) => "json".to_string(),
25            (false, FormatArg::Auto) => "text".to_string(),
26        }
27    }
28}
29
30#[derive(Debug, Clone, Copy, ValueEnum)]
31pub enum ColorMode {
32    Auto,
33    Always,
34    Never,
35}
36
37impl std::fmt::Display for ColorMode {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        match self {
40            ColorMode::Auto => write!(f, "auto"),
41            ColorMode::Always => write!(f, "always"),
42            ColorMode::Never => write!(f, "never"),
43        }
44    }
45}
46
47/// 🧙📖 Commit Wizard - A Spellbook for Conventional Commits, Semantic Versioning, and Changelog Automation.
48#[derive(Parser, Debug)]
49#[command(
50    name = "cw",
51    version,
52    author,
53    about = "🧙📜🪄📖✨ Commit Wizard - A Spellbook for Conventional Commits, Semantic Versioning, and Changelog Automation.",
54    propagate_version = true,
55    arg_required_else_help = true
56)]
57pub struct Cli {
58    /// Global flags (apply to all subcommands)
59    #[command(flatten)]
60    pub global: GlobalArgs,
61    /// Subcommands
62    #[command(subcommand)]
63    pub command: Command,
64}
65
66#[derive(Debug, Clone, Subcommand)]
67pub enum Command {
68    /// Add files to staging area interactively
69    Add(cmd::add::Args),
70    /// Bump version based on Conventional Commits
71    Bump(cmd::bump::Args),
72    /// Check commits in a range for Conventional Commit compliance
73    Check(cmd::check::Args),
74    /// Guide the user through writing a Conventional Commit message
75    Commit(cmd::commit::Args),
76    /// View or edit the current project, global or selected config
77    Config(cmd::config::Args),
78    /// Diagnose and fix common issues
79    Doctor(cmd::doctor::Args),
80    /// Initialize a project config (prefers .cwizard.toml; supports cwizard.toml)
81    Init(cmd::init::Args),
82    /// Push commits to a remote repository
83    Push(cmd::push::Args),
84    /// Create a new Git tag (Semantic Versioning) based on Conventional Commits
85    Tag(cmd::tag::Args),
86}
87
88#[derive(Debug, Clone, Args)]
89pub struct GlobalArgs {
90    /// Increase verbosity (-v, -vv, -vvv); combine with -q to reduce
91    #[arg(short = 'v', long = "verbose", action = ArgAction::Count, global = true)]
92    pub verbose: u8,
93    /// Decrease verbosity (-q, -qq)
94    #[arg(short = 'q', long = "quiet", action = ArgAction::Count, global = true)]
95    pub quiet: u8,
96    /// Output Envelop as JSON instead of human-readable text
97    #[arg(long, global = true)]
98    pub json: bool,
99    /// Output Payload format (json, jsonl, markdown, text)
100    #[arg(long, global = true, default_value_t = FormatArg::Auto, value_enum, conflicts_with = "plain")]
101    pub format: FormatArg,
102    /// Output plain text (equivalent to --format plain)
103    #[arg(long, short = 'p', global = true, conflicts_with = "format")]
104    pub plain: bool,
105    /// Simulate actions without changes
106    #[arg(long, global = true)]
107    pub dry_run: bool,
108    /// Color policy for output
109    #[arg(long, value_enum, default_value_t = ColorMode::Auto, global = true)]
110    pub color: ColorMode,
111    /// Run against another directory (default: current working directory)
112    #[arg(short = 'C', long = "cwd", global = true, default_value = ".")]
113    pub cwd: PathBuf,
114    /// Strict, non-interactive mode (assume yes, no prompts, CI-friendly)
115    #[arg(long, global = true, conflicts_with = "non_interactive")]
116    pub ci: bool,
117    /// Strict, non-interactive mode (assume no, no prompts, CI-friendly)
118    #[arg(long, global = true, conflicts_with = "ci")]
119    pub non_interactive: bool,
120    /// Accept defaults automatically (assume yes, no prompts)
121    #[arg(long, short = 'y', global = true)]
122    pub yes: bool,
123    /// Force actions that would normally be prevented (e.g. pushing to protected branches)
124    #[arg(long, global = true)]
125    pub force: bool,
126    /// Use a specific cwizard config not in the default location
127    #[arg(long, global = true)]
128    pub config: Option<PathBuf>,
129    /// Use a specific registry (local file or remote URL)
130    #[arg(long, global = true)]
131    pub registry: Option<String>,
132    /// Use a specific registry reference (e.g. branch, tag, commit)
133    #[arg(long = "registry-ref", global = true)]
134    pub registry_ref: Option<String>,
135    /// Use a specific registry section (e.g. for multiple registries in one file)
136    #[arg(long = "registry-section", global = true)]
137    pub registry_section: Option<String>,
138}
139
140impl From<GlobalArgs> for AppContextArgs {
141    fn from(args: GlobalArgs) -> Self {
142        Self {
143            verbose: args.verbose,
144            quiet: args.quiet,
145            json: args.json,
146            format: if args.plain {
147                "plain".to_string()
148            } else {
149                args.format.to_output_format_string(args.json)
150            },
151            dry_run: args.dry_run,
152            output_color: args.color.to_string(),
153            cwd: args.cwd,
154            ci: args.ci,
155            non_interactive: args.non_interactive,
156            auto_yes: args.yes,
157            force: args.force,
158            config_path: args.config,
159            registry: args.registry,
160            registry_ref: args.registry_ref,
161            registry_section: args.registry_section,
162        }
163    }
164}