Skip to content

Commit

Permalink
FEAT: Add rule: git flag after filename (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
luizvbo authored Apr 29, 2024
1 parent bc18409 commit 81e9d4f
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 2 deletions.
3 changes: 1 addition & 2 deletions src/rules/git_commit_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ use crate::{
Rule,
},
shell::Shell,
utils::replace_argument,
};

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")
Expand Down
136 changes: 136 additions & 0 deletions src/rules/git_flag_after_filename.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use crate::{
cli::command::CrabCommand,
rules::{
utils::git::{get_new_command_with_git_support, match_rule_with_git_support},
Rule,
},
shell::Shell,
};
use regex::Regex;

fn auxiliary_match_rule(command: &CrabCommand) -> bool {
if let Some(output) = &command.output {
let error_pattern = Regex::new(r"fatal: bad flag '(.*?)' used after filename").unwrap();
let error_pattern2 =
Regex::new(r"fatal: option '(.*?)' must come before non-option arguments").unwrap();
error_pattern.is_match(output) || error_pattern2.is_match(output)
} else {
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<String> {
if let Some(output) = &command.output {
let error_pattern = Regex::new(r"fatal: bad flag '(.*?)' used after filename").unwrap();
let error_pattern2 =
Regex::new(r"fatal: option '(.*?)' must come before non-option arguments").unwrap();
let mut command_parts = command.script_parts.clone();

if let Some(caps) = error_pattern
.captures(output)
.or_else(|| error_pattern2.captures(output))
{
if let Some(bad_flag) = caps.get(1) {
let bad_flag = bad_flag.as_str();
if let Some(bad_flag_index) = command_parts.iter().position(|r| r == bad_flag) {
for index in (0..bad_flag_index).rev() {
if !command_parts[index].starts_with('-') {
command_parts.swap(bad_flag_index, index);
break;
}
}
}
}
}

vec![command_parts.join(" ")]
} else {
vec![]
}
}

pub fn get_new_command(command: &mut CrabCommand, system_shell: Option<&dyn Shell>) -> Vec<String> {
get_new_command_with_git_support(auxiliary_get_new_command, command, system_shell)
}

pub fn get_rule() -> Rule {
Rule::new(
"git_flag_after_filename".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;

#[rstest]
#[case(
"git log README.md -p",
"fatal: bad flag '-p' used after filename",
true
)]
#[case(
"git log README.md -p CONTRIBUTING.md",
"fatal: bad flag '-p' used after filename",
true
)]
#[case(
"git log -p README.md --name-only",
"fatal: bad flag '--name-only' used after filename",
true
)]
#[case(
"git log README.md -p",
"fatal: option '-p' must come before non-option arguments",
true
)]
#[case(
"git log README.md -p CONTRIBUTING.md",
"fatal: option '-p' must come before non-option arguments",
true
)]
#[case(
"git log -p README.md --name-only",
"fatal: option '--name-only' must come before non-option arguments",
true
)]
#[case("git log README.md", "", false)]
#[case("git log -p README.md", "", 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 log README.md -p", "fatal: bad flag '-p' used after filename", vec!["git log -p README.md"])]
#[case("git log README.md -p CONTRIBUTING.md", "fatal: bad flag '-p' used after filename", vec!["git log -p README.md CONTRIBUTING.md"])]
#[case("git log -p README.md --name-only", "fatal: bad flag '--name-only' used after filename", vec!["git log -p --name-only README.md"])]
#[case("git log README.md -p", "fatal: option '-p' must come before non-option arguments", vec!["git log -p README.md"])]
#[case("git log README.md -p CONTRIBUTING.md", "fatal: option '-p' must come before non-option arguments", vec!["git log -p README.md CONTRIBUTING.md"])]
#[case("git log -p README.md --name-only", "fatal: option '--name-only' must come before non-option arguments", vec!["git log -p --name-only README.md"])]
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);
}
}
2 changes: 2 additions & 0 deletions src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ mod git_commit_reset;
mod git_diff_no_index;
mod git_diff_staged;
mod git_fix_stash;
mod git_flag_after_filename;
mod git_help_aliased;
mod git_hook_bypass;
mod git_lfs_mistype;
Expand Down Expand Up @@ -176,6 +177,7 @@ pub fn get_rules() -> Vec<Rule> {
git_commit_amend::get_rule(),
git_commit_reset::get_rule(),
git_diff_no_index::get_rule(),
git_flag_after_filename::get_rule(),
git_diff_staged::get_rule(),
git_fix_stash::get_rule(),
git_help_aliased::get_rule(),
Expand Down

0 comments on commit 81e9d4f

Please sign in to comment.