use super::common::{fail, hl, ok};
use crate::check::{Outcome, Severity};
use crate::finding::Finding;
fn markers() -> [String; 3] {
["<", "=", ">"].map(|c| c.repeat(7))
}
fn is_own_test(file: &str, hook_name: &str) -> bool {
file.starts_with(&format!("tests/{hook_name}.test."))
}
pub const NAME: &str = "merge-conflict";
pub fn scan(file: &str, content: &str, hook_name: &str) -> Vec<Finding> {
if is_own_test(file, hook_name) {
return Vec::new();
}
let m = markers();
if !m.iter().all(|mk| content.contains(mk.as_str())) {
return Vec::new();
}
let first = content
.lines()
.enumerate()
.find(|(_, l)| m.iter().any(|mk| l.starts_with(mk.as_str())))
.map(|(i, _)| i + 1);
let mut finding = Finding::new(
NAME,
file,
Severity::Block,
"unresolved merge conflict markers",
);
if let Some(line) = first {
finding = finding.at_line(line);
}
vec![finding]
}
pub fn run(
settings: &crate::config::Settings,
hook_name: &str,
_args: &[std::ffi::OsString],
) -> Outcome {
let findings: Vec<Finding> = super::common::staged_files(&[])
.into_iter()
.filter_map(|file| {
let content = crate::git::stdout(&["show", &format!(":{file}")])?;
Some(scan(&file, &content, hook_name))
})
.flatten()
.collect();
if !findings.is_empty() {
for f in &findings {
fail(&format!("Merge conflict detected in {}", hl(&f.location())));
}
return Outcome::Failed;
}
ok(settings, "No merge conflict detected");
Outcome::Passed
}
#[cfg(test)]
mod tests {
use super::markers;
#[test]
fn the_markers_are_the_real_seven_character_ones() {
let m = markers();
assert_eq!(m[0].len(), 7);
assert_eq!(m[0], "<".repeat(7));
assert_eq!(m[1], "=".repeat(7));
assert_eq!(m[2], ">".repeat(7));
}
#[test]
fn the_hooks_own_test_is_excluded() {
let n = "pre-commit-merge-conflict";
assert!(super::is_own_test(
"tests/pre-commit-merge-conflict.test.zsh",
n
));
assert!(!super::is_own_test(
"tests/pre-commit-ban-terms.test.zsh",
n
));
assert!(!super::is_own_test("src/main.rs", n));
}
#[test]
fn this_file_contains_no_literal_marker() {
let src = include_str!("merge_conflict.rs");
for m in markers() {
assert!(!src.contains(&m), "literal marker present in this file");
}
}
}