diff --git a/src/git.rs b/src/git.rs index 3709e79f..27913f2a 100644 --- a/src/git.rs +++ b/src/git.rs @@ -19,24 +19,47 @@ pub enum GitCommand { Worktree, } -pub fn run(cmd: GitCommand, args: &[String], max_lines: Option, verbose: u8) -> Result<()> { +/// Create a git Command with global options (e.g. -C, -c, --git-dir, --work-tree) +/// prepended before any subcommand arguments. +fn git_cmd(global_args: &[String]) -> Command { + let mut cmd = Command::new("git"); + for arg in global_args { + cmd.arg(arg); + } + cmd +} + +pub fn run( + cmd: GitCommand, + args: &[String], + max_lines: Option, + verbose: u8, + global_args: &[String], +) -> Result<()> { match cmd { - GitCommand::Diff => run_diff(args, max_lines, verbose), - GitCommand::Log => run_log(args, max_lines, verbose), - GitCommand::Status => run_status(args, verbose), - GitCommand::Show => run_show(args, max_lines, verbose), - GitCommand::Add => run_add(args, verbose), - GitCommand::Commit { messages } => run_commit(&messages, verbose), - GitCommand::Push => run_push(args, verbose), - GitCommand::Pull => run_pull(args, verbose), - GitCommand::Branch => run_branch(args, verbose), - GitCommand::Fetch => run_fetch(args, verbose), - GitCommand::Stash { subcommand } => run_stash(subcommand.as_deref(), args, verbose), - GitCommand::Worktree => run_worktree(args, verbose), + GitCommand::Diff => run_diff(args, max_lines, verbose, global_args), + GitCommand::Log => run_log(args, max_lines, verbose, global_args), + GitCommand::Status => run_status(args, verbose, global_args), + GitCommand::Show => run_show(args, max_lines, verbose, global_args), + GitCommand::Add => run_add(args, verbose, global_args), + GitCommand::Commit { messages } => run_commit(&messages, verbose, global_args), + GitCommand::Push => run_push(args, verbose, global_args), + GitCommand::Pull => run_pull(args, verbose, global_args), + GitCommand::Branch => run_branch(args, verbose, global_args), + GitCommand::Fetch => run_fetch(args, verbose, global_args), + GitCommand::Stash { subcommand } => { + run_stash(subcommand.as_deref(), args, verbose, global_args) + } + GitCommand::Worktree => run_worktree(args, verbose, global_args), } } -fn run_diff(args: &[String], max_lines: Option, verbose: u8) -> Result<()> { +fn run_diff( + args: &[String], + max_lines: Option, + verbose: u8, + global_args: &[String], +) -> Result<()> { let timer = tracking::TimedExecution::start(); // Check if user wants stat output @@ -49,7 +72,7 @@ fn run_diff(args: &[String], max_lines: Option, verbose: u8) -> Result<() if wants_stat || !wants_compact { // User wants stat or explicitly no compacting - pass through directly - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("diff"); for arg in args { cmd.arg(arg); @@ -77,7 +100,7 @@ fn run_diff(args: &[String], max_lines: Option, verbose: u8) -> Result<() } // Default RTK behavior: stat first, then compacted diff - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("diff").arg("--stat"); for arg in args { @@ -95,7 +118,7 @@ fn run_diff(args: &[String], max_lines: Option, verbose: u8) -> Result<() println!("{}", stat_stdout.trim()); // Now get actual diff but compact it - let mut diff_cmd = Command::new("git"); + let mut diff_cmd = git_cmd(global_args); diff_cmd.arg("diff"); for arg in args { diff_cmd.arg(arg); @@ -123,7 +146,12 @@ fn run_diff(args: &[String], max_lines: Option, verbose: u8) -> Result<() Ok(()) } -fn run_show(args: &[String], max_lines: Option, verbose: u8) -> Result<()> { +fn run_show( + args: &[String], + max_lines: Option, + verbose: u8, + global_args: &[String], +) -> Result<()> { let timer = tracking::TimedExecution::start(); // If user wants --stat or --format only, pass through @@ -136,7 +164,7 @@ fn run_show(args: &[String], max_lines: Option, verbose: u8) -> Result<() .any(|arg| arg.starts_with("--pretty") || arg.starts_with("--format")); if wants_stat_only || wants_format { - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("show"); for arg in args { cmd.arg(arg); @@ -161,7 +189,7 @@ fn run_show(args: &[String], max_lines: Option, verbose: u8) -> Result<() } // Get raw output for tracking - let mut raw_cmd = Command::new("git"); + let mut raw_cmd = git_cmd(global_args); raw_cmd.arg("show"); for arg in args { raw_cmd.arg(arg); @@ -172,7 +200,7 @@ fn run_show(args: &[String], max_lines: Option, verbose: u8) -> Result<() .unwrap_or_default(); // Step 1: one-line commit summary - let mut summary_cmd = Command::new("git"); + let mut summary_cmd = git_cmd(global_args); summary_cmd.args(["show", "--no-patch", "--pretty=format:%h %s (%ar) <%an>"]); for arg in args { summary_cmd.arg(arg); @@ -187,7 +215,7 @@ fn run_show(args: &[String], max_lines: Option, verbose: u8) -> Result<() println!("{}", summary.trim()); // Step 2: --stat summary - let mut stat_cmd = Command::new("git"); + let mut stat_cmd = git_cmd(global_args); stat_cmd.args(["show", "--stat", "--pretty=format:"]); for arg in args { stat_cmd.arg(arg); @@ -200,7 +228,7 @@ fn run_show(args: &[String], max_lines: Option, verbose: u8) -> Result<() } // Step 3: compacted diff - let mut diff_cmd = Command::new("git"); + let mut diff_cmd = git_cmd(global_args); diff_cmd.args(["show", "--pretty=format:"]); for arg in args { diff_cmd.arg(arg); @@ -295,10 +323,15 @@ pub(crate) fn compact_diff(diff: &str, max_lines: usize) -> String { result.join("\n") } -fn run_log(args: &[String], _max_lines: Option, verbose: u8) -> Result<()> { +fn run_log( + args: &[String], + _max_lines: Option, + verbose: u8, + global_args: &[String], +) -> Result<()> { let timer = tracking::TimedExecution::start(); - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("log"); // Check if user provided format flags @@ -523,12 +556,12 @@ fn filter_status_with_args(output: &str) -> String { } } -fn run_status(args: &[String], verbose: u8) -> Result<()> { +fn run_status(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); // If user provided flags, apply minimal filtering if !args.is_empty() { - let output = Command::new("git") + let output = git_cmd(global_args) .arg("status") .args(args) .output() @@ -557,13 +590,13 @@ fn run_status(args: &[String], verbose: u8) -> Result<()> { // Default RTK compact mode (no args provided) // Get raw git status for tracking - let raw_output = Command::new("git") + let raw_output = git_cmd(global_args) .args(["status"]) .output() .map(|o| String::from_utf8_lossy(&o.stdout).to_string()) .unwrap_or_default(); - let output = Command::new("git") + let output = git_cmd(global_args) .args(["status", "--porcelain", "-b"]) .output() .context("Failed to run git status")?; @@ -585,10 +618,10 @@ fn run_status(args: &[String], verbose: u8) -> Result<()> { Ok(()) } -fn run_add(args: &[String], verbose: u8) -> Result<()> { +fn run_add(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("add"); // Pass all arguments directly to git (flags like -A, -p, --all, etc.) @@ -614,7 +647,7 @@ fn run_add(args: &[String], verbose: u8) -> Result<()> { if output.status.success() { // Count what was added - let status_output = Command::new("git") + let status_output = git_cmd(global_args) .args(["diff", "--cached", "--stat", "--shortstat"]) .output() .context("Failed to check staged files")?; @@ -657,8 +690,8 @@ fn run_add(args: &[String], verbose: u8) -> Result<()> { Ok(()) } -fn build_commit_command(messages: &[String]) -> Command { - let mut cmd = Command::new("git"); +fn build_commit_command(messages: &[String], global_args: &[String]) -> Command { + let mut cmd = git_cmd(global_args); cmd.arg("commit"); for msg in messages { cmd.args(["-m", msg]); @@ -666,7 +699,7 @@ fn build_commit_command(messages: &[String]) -> Command { cmd } -fn run_commit(messages: &[String], verbose: u8) -> Result<()> { +fn run_commit(messages: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); let original_cmd = messages @@ -680,7 +713,7 @@ fn run_commit(messages: &[String], verbose: u8) -> Result<()> { eprintln!("{}", original_cmd); } - let output = build_commit_command(messages) + let output = build_commit_command(messages, global_args) .output() .context("Failed to run git commit")?; @@ -731,14 +764,14 @@ fn run_commit(messages: &[String], verbose: u8) -> Result<()> { Ok(()) } -fn run_push(args: &[String], verbose: u8) -> Result<()> { +fn run_push(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { eprintln!("git push"); } - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("push"); for arg in args { cmd.arg(arg); @@ -792,14 +825,14 @@ fn run_push(args: &[String], verbose: u8) -> Result<()> { Ok(()) } -fn run_pull(args: &[String], verbose: u8) -> Result<()> { +fn run_pull(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { eprintln!("git pull"); } - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("pull"); for arg in args { cmd.arg(arg); @@ -877,7 +910,7 @@ fn run_pull(args: &[String], verbose: u8) -> Result<()> { Ok(()) } -fn run_branch(args: &[String], verbose: u8) -> Result<()> { +fn run_branch(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { @@ -907,7 +940,7 @@ fn run_branch(args: &[String], verbose: u8) -> Result<()> { // Write operation: action flags, or positional args without list flags (= branch creation) if has_action_flag || (has_positional_arg && !has_list_flag) { - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("branch"); for arg in args { cmd.arg(arg); @@ -946,7 +979,7 @@ fn run_branch(args: &[String], verbose: u8) -> Result<()> { } // List mode: show compact branch list - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("branch"); if !has_list_flag { cmd.arg("-a"); @@ -1027,14 +1060,14 @@ fn filter_branch_output(output: &str) -> String { result.join("\n") } -fn run_fetch(args: &[String], verbose: u8) -> Result<()> { +fn run_fetch(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { eprintln!("git fetch"); } - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("fetch"); for arg in args { cmd.arg(arg); @@ -1071,7 +1104,12 @@ fn run_fetch(args: &[String], verbose: u8) -> Result<()> { Ok(()) } -fn run_stash(subcommand: Option<&str>, args: &[String], verbose: u8) -> Result<()> { +fn run_stash( + subcommand: Option<&str>, + args: &[String], + verbose: u8, + global_args: &[String], +) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { @@ -1080,7 +1118,7 @@ fn run_stash(subcommand: Option<&str>, args: &[String], verbose: u8) -> Result<( match subcommand { Some("list") => { - let output = Command::new("git") + let output = git_cmd(global_args) .args(["stash", "list"]) .output() .context("Failed to run git stash list")?; @@ -1099,7 +1137,7 @@ fn run_stash(subcommand: Option<&str>, args: &[String], verbose: u8) -> Result<( timer.track("git stash list", "rtk git stash list", &raw, &filtered); } Some("show") => { - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.args(["stash", "show", "-p"]); for arg in args { cmd.arg(arg); @@ -1122,7 +1160,7 @@ fn run_stash(subcommand: Option<&str>, args: &[String], verbose: u8) -> Result<( } Some("pop") | Some("apply") | Some("drop") | Some("push") => { let sub = subcommand.unwrap(); - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.args(["stash", sub]); for arg in args { cmd.arg(arg); @@ -1153,7 +1191,7 @@ fn run_stash(subcommand: Option<&str>, args: &[String], verbose: u8) -> Result<( } _ => { // Default: git stash (push) - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("stash"); for arg in args { cmd.arg(arg); @@ -1209,7 +1247,7 @@ fn filter_stash_list(output: &str) -> String { result.join("\n") } -fn run_worktree(args: &[String], verbose: u8) -> Result<()> { +fn run_worktree(args: &[String], verbose: u8, global_args: &[String]) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { @@ -1222,7 +1260,7 @@ fn run_worktree(args: &[String], verbose: u8) -> Result<()> { }); if has_action { - let mut cmd = Command::new("git"); + let mut cmd = git_cmd(global_args); cmd.arg("worktree"); for arg in args { cmd.arg(arg); @@ -1257,7 +1295,7 @@ fn run_worktree(args: &[String], verbose: u8) -> Result<()> { } // Default: list mode - let output = Command::new("git") + let output = git_cmd(global_args) .args(["worktree", "list"]) .output() .context("Failed to run git worktree list")?; @@ -1300,13 +1338,13 @@ fn filter_worktree_list(output: &str) -> String { } /// Runs an unsupported git subcommand by passing it through directly -pub fn run_passthrough(args: &[OsString], verbose: u8) -> Result<()> { +pub fn run_passthrough(args: &[OsString], global_args: &[String], verbose: u8) -> Result<()> { let timer = tracking::TimedExecution::start(); if verbose > 0 { eprintln!("git passthrough: {:?}", args); } - let status = Command::new("git") + let status = git_cmd(global_args) .args(args) .status() .context("Failed to run git")?; @@ -1327,6 +1365,56 @@ pub fn run_passthrough(args: &[OsString], verbose: u8) -> Result<()> { mod tests { use super::*; + #[test] + fn test_git_cmd_no_global_args() { + let cmd = git_cmd(&[]); + let program = cmd.get_program(); + assert_eq!(program, "git"); + let args: Vec<_> = cmd.get_args().collect(); + assert!(args.is_empty()); + } + + #[test] + fn test_git_cmd_with_directory() { + let global_args = vec!["-C".to_string(), "/tmp".to_string()]; + let cmd = git_cmd(&global_args); + let args: Vec<_> = cmd.get_args().collect(); + assert_eq!(args, vec!["-C", "/tmp"]); + } + + #[test] + fn test_git_cmd_with_multiple_global_args() { + let global_args = vec![ + "-C".to_string(), + "/tmp".to_string(), + "-c".to_string(), + "user.name=test".to_string(), + "--git-dir".to_string(), + "/foo/.git".to_string(), + ]; + let cmd = git_cmd(&global_args); + let args: Vec<_> = cmd.get_args().collect(); + assert_eq!( + args, + vec![ + "-C", + "/tmp", + "-c", + "user.name=test", + "--git-dir", + "/foo/.git" + ] + ); + } + + #[test] + fn test_git_cmd_with_boolean_flags() { + let global_args = vec!["--no-pager".to_string(), "--bare".to_string()]; + let cmd = git_cmd(&global_args); + let args: Vec<_> = cmd.get_args().collect(); + assert_eq!(args, vec!["--no-pager", "--bare"]); + } + #[test] fn test_compact_diff() { let diff = r#"diff --git a/foo.rs b/foo.rs @@ -1562,7 +1650,7 @@ no changes added to commit (use "git add" and/or "git commit -a") fn test_branch_creation_not_swallowed() { let branch = "test-rtk-create-branch-regression"; // Create branch via run_branch - run_branch(&[branch.to_string()], 0).expect("run_branch should succeed"); + run_branch(&[branch.to_string()], 0, &[]).expect("run_branch should succeed"); // Verify it exists let output = Command::new("git") .args(["branch", "--list", branch]) @@ -1583,7 +1671,7 @@ no changes added to commit (use "git add" and/or "git commit -a") #[ignore] // Integration test: requires git repo fn test_branch_creation_from_commit() { let branch = "test-rtk-create-from-commit"; - run_branch(&[branch.to_string(), "HEAD".to_string()], 0) + run_branch(&[branch.to_string(), "HEAD".to_string()], 0, &[]) .expect("run_branch with start-point should succeed"); let output = Command::new("git") .args(["branch", "--list", branch]) @@ -1601,7 +1689,7 @@ no changes added to commit (use "git add" and/or "git commit -a") #[test] fn test_commit_single_message() { let messages = vec!["fix: typo".to_string()]; - let cmd = build_commit_command(&messages); + let cmd = build_commit_command(&messages, &[]); let args: Vec<_> = cmd .get_args() .map(|a| a.to_string_lossy().to_string()) @@ -1615,7 +1703,7 @@ no changes added to commit (use "git add" and/or "git commit -a") "feat: add multi-paragraph support".to_string(), "This allows git commit -m \"title\" -m \"body\".".to_string(), ]; - let cmd = build_commit_command(&messages); + let cmd = build_commit_command(&messages, &[]); let args: Vec<_> = cmd .get_args() .map(|a| a.to_string_lossy().to_string()) @@ -1639,7 +1727,7 @@ no changes added to commit (use "git add" and/or "git commit -a") "body".to_string(), "footer: refs #202".to_string(), ]; - let cmd = build_commit_command(&messages); + let cmd = build_commit_command(&messages, &[]); let args: Vec<_> = cmd .get_args() .map(|a| a.to_string_lossy().to_string()) diff --git a/src/main.rs b/src/main.rs index fcb39303..dac2ef92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -122,6 +122,38 @@ enum Commands { /// Git commands with compact output Git { + /// Change to directory before executing (like git -C , can be repeated) + #[arg(short = 'C', action = clap::ArgAction::Append)] + directory: Vec, + + /// Git configuration override (like git -c key=value, can be repeated) + #[arg(short = 'c', action = clap::ArgAction::Append)] + config_override: Vec, + + /// Set the path to the .git directory + #[arg(long = "git-dir")] + git_dir: Option, + + /// Set the path to the working tree + #[arg(long = "work-tree")] + work_tree: Option, + + /// Disable pager (like git --no-pager) + #[arg(long = "no-pager")] + no_pager: bool, + + /// Skip optional locks (like git --no-optional-locks) + #[arg(long = "no-optional-locks")] + no_optional_locks: bool, + + /// Treat repository as bare (like git --bare) + #[arg(long)] + bare: bool, + + /// Treat pathspecs literally (like git --literal-pathspecs) + #[arg(long = "literal-pathspecs")] + literal_pathspecs: bool, + #[command(subcommand)] command: GitCommands, }, @@ -885,57 +917,150 @@ fn main() -> Result<()> { local_llm::run(&file, &model, force_download, cli.verbose)?; } - Commands::Git { command } => match command { - GitCommands::Diff { args } => { - git::run(git::GitCommand::Diff, &args, None, cli.verbose)?; - } - GitCommands::Log { args } => { - git::run(git::GitCommand::Log, &args, None, cli.verbose)?; - } - GitCommands::Status { args } => { - git::run(git::GitCommand::Status, &args, None, cli.verbose)?; + Commands::Git { + directory, + config_override, + git_dir, + work_tree, + no_pager, + no_optional_locks, + bare, + literal_pathspecs, + command, + } => { + // Build global git args (inserted between "git" and subcommand) + let mut global_args: Vec = Vec::new(); + for dir in &directory { + global_args.push("-C".to_string()); + global_args.push(dir.clone()); } - GitCommands::Show { args } => { - git::run(git::GitCommand::Show, &args, None, cli.verbose)?; + for cfg in &config_override { + global_args.push("-c".to_string()); + global_args.push(cfg.clone()); } - GitCommands::Add { args } => { - git::run(git::GitCommand::Add, &args, None, cli.verbose)?; + if let Some(ref dir) = git_dir { + global_args.push("--git-dir".to_string()); + global_args.push(dir.clone()); } - GitCommands::Commit { message } => { - git::run( - git::GitCommand::Commit { messages: message }, - &[], - None, - cli.verbose, - )?; + if let Some(ref tree) = work_tree { + global_args.push("--work-tree".to_string()); + global_args.push(tree.clone()); } - GitCommands::Push { args } => { - git::run(git::GitCommand::Push, &args, None, cli.verbose)?; + if no_pager { + global_args.push("--no-pager".to_string()); } - GitCommands::Pull { args } => { - git::run(git::GitCommand::Pull, &args, None, cli.verbose)?; + if no_optional_locks { + global_args.push("--no-optional-locks".to_string()); } - GitCommands::Branch { args } => { - git::run(git::GitCommand::Branch, &args, None, cli.verbose)?; - } - GitCommands::Fetch { args } => { - git::run(git::GitCommand::Fetch, &args, None, cli.verbose)?; - } - GitCommands::Stash { subcommand, args } => { - git::run( - git::GitCommand::Stash { subcommand }, - &args, - None, - cli.verbose, - )?; + if bare { + global_args.push("--bare".to_string()); } - GitCommands::Worktree { args } => { - git::run(git::GitCommand::Worktree, &args, None, cli.verbose)?; + if literal_pathspecs { + global_args.push("--literal-pathspecs".to_string()); } - GitCommands::Other(args) => { - git::run_passthrough(&args, cli.verbose)?; + + match command { + GitCommands::Diff { args } => { + git::run( + git::GitCommand::Diff, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Log { args } => { + git::run(git::GitCommand::Log, &args, None, cli.verbose, &global_args)?; + } + GitCommands::Status { args } => { + git::run( + git::GitCommand::Status, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Show { args } => { + git::run( + git::GitCommand::Show, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Add { args } => { + git::run(git::GitCommand::Add, &args, None, cli.verbose, &global_args)?; + } + GitCommands::Commit { message } => { + git::run( + git::GitCommand::Commit { messages: message }, + &[], + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Push { args } => { + git::run( + git::GitCommand::Push, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Pull { args } => { + git::run( + git::GitCommand::Pull, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Branch { args } => { + git::run( + git::GitCommand::Branch, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Fetch { args } => { + git::run( + git::GitCommand::Fetch, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Stash { subcommand, args } => { + git::run( + git::GitCommand::Stash { subcommand }, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Worktree { args } => { + git::run( + git::GitCommand::Worktree, + &args, + None, + cli.verbose, + &global_args, + )?; + } + GitCommands::Other(args) => { + git::run_passthrough(&args, &global_args, cli.verbose)?; + } } - }, + } Commands::Gh { subcommand, args } => { gh_cmd::run(&subcommand, &args, cli.verbose, cli.ultra_compact)?; @@ -1494,6 +1619,7 @@ mod tests { match cli.command { Commands::Git { command: GitCommands::Commit { message }, + .. } => { assert_eq!(message, vec!["fix: typo"]); } @@ -1516,6 +1642,7 @@ mod tests { match cli.command { Commands::Git { command: GitCommands::Commit { message }, + .. } => { assert_eq!(message, vec!["feat: add support", "Body paragraph here."]); } @@ -1523,6 +1650,28 @@ mod tests { } } + #[test] + fn test_git_global_options_parsing() { + let cli = + Cli::try_parse_from(["rtk", "git", "--no-pager", "--no-optional-locks", "status"]) + .unwrap(); + match cli.command { + Commands::Git { + no_pager, + no_optional_locks, + bare, + literal_pathspecs, + .. + } => { + assert!(no_pager); + assert!(no_optional_locks); + assert!(!bare); + assert!(!literal_pathspecs); + } + _ => panic!("Expected Git command"), + } + } + #[test] fn test_git_commit_long_flag_multiple() { let cli = Cli::try_parse_from([ @@ -1540,6 +1689,7 @@ mod tests { match cli.command { Commands::Git { command: GitCommands::Commit { message }, + .. } => { assert_eq!(message, vec!["title", "body", "footer"]); }