use std::path::Path;
use std::process::Command;
pub fn resolve_branch_files(root_path: &Path, branch: &str) -> Option<Vec<String>> {
let base = Command::new("git")
.args(["merge-base", "HEAD", branch])
.current_dir(root_path)
.output()
.ok()?;
if !base.status.success() {
tracing::warn!(
"branch file resolution failed for branch '{}': git merge-base exited {:?}",
branch,
base.status.code()
);
return None;
}
let base_sha = std::str::from_utf8(&base.stdout).ok()?.trim().to_owned();
if base_sha.is_empty() {
tracing::warn!(
"branch file resolution failed for branch '{}': empty merge-base",
branch
);
return None;
}
let diff = Command::new("git")
.args(["diff", "--name-only", &format!("{}..HEAD", base_sha)])
.current_dir(root_path)
.output()
.ok()?;
if !diff.status.success() {
tracing::warn!(
"branch file resolution failed for branch '{}': git diff exited {:?}",
branch,
diff.status.code()
);
return None;
}
let body = std::str::from_utf8(&diff.stdout).ok()?;
Some(
body.lines()
.filter(|l| !l.is_empty())
.map(str::to_owned)
.collect(),
)
}
pub fn normalize_path(p: &str) -> &str {
p.strip_prefix("./").unwrap_or(p)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resolve_branch_files_returns_none_when_not_a_repo() {
let tmp = tempfile::tempdir().unwrap();
let result = resolve_branch_files(tmp.path(), "nope");
assert!(result.is_none(), "expected None outside a git repo");
}
#[test]
fn test_normalize_path_strips_leading_dot_slash() {
assert_eq!(normalize_path("./src/foo.rs"), "src/foo.rs");
assert_eq!(normalize_path("src/foo.rs"), "src/foo.rs");
assert_eq!(normalize_path(""), "");
}
}