diff --git a/src/rules/git_add.rs b/src/rules/git_add.rs index 56e2706..a5e08f6 100644 --- a/src/rules/git_add.rs +++ b/src/rules/git_add.rs @@ -1,11 +1,14 @@ use crate::{ - cli::command::CrabCommand, rules::utils::git::match_rule_with_git_support, shell::Shell, + cli::command::CrabCommand, + rules::{ + utils::git::{get_new_command_with_git_support, match_rule_with_git_support}, + Rule, + }, + shell::Shell, }; use regex::Regex; use std::path::Path; -use super::{utils::git::get_new_command_with_git_support, Rule}; - fn get_missing_file(command: &CrabCommand, path_exists: Option) -> Option { if let Some(stdout) = &command.output { let re = Regex::new(r"error: pathspec '([^']*)' did not match any file\(s\) known to git.") diff --git a/src/rules/git_commit_add.rs b/src/rules/git_commit_add.rs index 591f8d5..961c256 100644 --- a/src/rules/git_commit_add.rs +++ b/src/rules/git_commit_add.rs @@ -1,10 +1,14 @@ use crate::{ - cli::command::CrabCommand, rules::utils::git::match_rule_with_git_support, shell::Shell, + cli::command::CrabCommand, + rules::{ + utils::git::{get_new_command_with_git_support, match_rule_with_git_support}, + Rule, + }, + shell::Shell, }; -use super::{utils::git::get_new_command_with_git_support, Rule}; - use crate::utils::replace_argument; + fn auxiliary_match_rule(command: &CrabCommand) -> bool { if let Some(stdout) = &command.output { stdout.contains("no changes added to commit") diff --git a/src/rules/git_commit_amend.rs b/src/rules/git_commit_amend.rs index 8d39cb3..7f12fc8 100644 --- a/src/rules/git_commit_amend.rs +++ b/src/rules/git_commit_amend.rs @@ -1,7 +1,10 @@ -use super::{utils::git::get_new_command_with_git_support, Rule}; - use crate::{ - cli::command::CrabCommand, rules::utils::git::match_rule_with_git_support, shell::Shell, + cli::command::CrabCommand, + rules::{ + utils::git::{get_new_command_with_git_support, match_rule_with_git_support}, + Rule, + }, + shell::Shell, }; fn auxiliary_match_rule(command: &CrabCommand) -> bool { diff --git a/src/rules/git_rm_staged.rs b/src/rules/git_rm_staged.rs new file mode 100644 index 0000000..8716522 --- /dev/null +++ b/src/rules/git_rm_staged.rs @@ -0,0 +1,88 @@ +use crate::{ + cli::command::CrabCommand, + rules::{ + utils::git::{get_new_command_with_git_support, match_rule_with_git_support}, + Rule, + }, + shell::Shell, +}; + +fn auxiliary_match_rule(command: &CrabCommand) -> bool { + if let Some(output) = &command.output { + return command.script.contains(" rm ") + && output.contains("error: the following file has changes staged in the index") + && output.contains("use --cached to keep the file, or -f to force removal"); + } + false +} + +pub fn match_rule(command: &mut CrabCommand, system_shell: Option<&dyn Shell>) -> bool { + match_rule_with_git_support(auxiliary_match_rule, command) +} + +fn auxiliary_get_new_command( + command: &CrabCommand, + system_shell: Option<&dyn Shell>, +) -> Vec { + let mut command_parts = command.script_parts.clone(); + if let Some(index) = command_parts.iter().position(|r| r == "rm") { + command_parts.insert(index + 1, "--cached".to_string()); + let mut command_list = vec![command_parts.join(" ")]; + command_parts[index + 1] = "-f".to_string(); + command_list.push(command_parts.join(" ")); + return command_list; + } + vec![] +} + +pub fn get_new_command(command: &mut CrabCommand, system_shell: Option<&dyn Shell>) -> Vec { + get_new_command_with_git_support(auxiliary_get_new_command, command, system_shell) +} + +pub fn get_rule() -> Rule { + Rule::new( + "git_rm_staged".to_owned(), + None, + None, + None, + match_rule, + get_new_command, + None, + ) +} + +#[cfg(test)] +mod tests { + use super::{get_new_command, match_rule}; + use crate::cli::command::CrabCommand; + use crate::shell::Bash; + use rstest::rstest; + + fn output(target: &str) -> String { + format!("error: the following file has changes staged in the index:\n {}\n(use --cached to keep the file, or -f to force removal)", target) + } + + #[rstest] + #[case("git rm foo", &output("foo"), true)] + #[case("git rm foo bar", &output("bar"), true)] + #[case("git rm foo", "", false)] + #[case("git rm foo bar", "", false)] + #[case("git rm", "", false)] + fn test_match(#[case] command: &str, #[case] stdout: &str, #[case] is_match: bool) { + let mut command = CrabCommand::new(command.to_owned(), Some(stdout.to_owned()), None); + assert_eq!(match_rule(&mut command, None), is_match); + } + + #[rstest] + #[case("git rm foo", &output("foo"), vec!["git rm --cached foo", "git rm -f foo"])] + #[case("git rm foo bar", &output("bar"), vec!["git rm --cached foo bar", "git rm -f foo bar"])] + fn test_get_new_command( + #[case] command: &str, + #[case] stdout: &str, + #[case] expected: Vec<&str>, + ) { + let system_shell = Bash {}; + let mut command = CrabCommand::new(command.to_owned(), Some(stdout.to_owned()), None); + assert_eq!(get_new_command(&mut command, Some(&system_shell)), expected); + } +} diff --git a/src/rules/mod.rs b/src/rules/mod.rs index de921af..ee92ce3 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -73,6 +73,7 @@ mod git_remote_delete; mod git_remote_seturl_add; mod git_rm_local_modifications; mod git_rm_recursive; +mod git_rm_staged; mod git_stash; mod git_stash_pop; mod git_two_dashes; @@ -190,6 +191,7 @@ pub fn get_rules() -> Vec { git_lfs_mistype::get_rule(), git_push_pull::get_rule(), git_push_without_commits::get_rule(), + git_rm_staged::get_rule(), git_rm_recursive::get_rule(), git_rebase_merge_dir::get_rule(), git_rebase_no_changes::get_rule(),