use crate::commands::doctor::types::{CheckResult, DoctorReport};
use crate::config;
use crate::git;
use crate::runutil::{ManagedCommand, TimeoutClass, execute_managed_command};
use std::process::Command;
pub(crate) fn check_git(report: &mut DoctorReport, resolved: &config::Resolved) {
if let Err(e) = check_command("git", &["--version"]) {
report.add(CheckResult::error(
"git",
"git_binary",
&format!("git binary not found or not executable: {}", e),
false,
Some("Install git and ensure it's in your PATH"),
));
} else {
report.add(CheckResult::success(
"git",
"git_binary",
"git binary found",
));
}
match git::status_porcelain(&resolved.repo_root) {
Ok(_) => {
report.add(CheckResult::success(
"git",
"git_repo",
&format!("valid git repo at {}", resolved.repo_root.display()),
));
}
Err(e) => {
report.add(CheckResult::error(
"git",
"git_repo",
&format!("invalid git repo: {}", e),
false,
Some("Run 'git init' to initialize a git repository"),
));
}
}
match git::upstream_ref(&resolved.repo_root) {
Ok(u) => {
report.add(CheckResult::success(
"git",
"upstream_config",
&format!("upstream configured: {}", u),
));
}
Err(e) => {
report.add(CheckResult::warning(
"git",
"upstream_config",
&format!("no upstream configured: {}", e),
false,
Some("Set up a remote upstream with 'git remote add origin <url>'"),
));
}
}
match git::has_lfs(&resolved.repo_root) {
Ok(true) => {
report.add(CheckResult::success("git", "git_lfs", "Git LFS detected"));
match git::list_lfs_files(&resolved.repo_root) {
Ok(files) => {
if files.is_empty() {
log::info!("LFS initialized but no files tracked");
} else {
report.add(CheckResult::success(
"git",
"lfs_files",
&format!("LFS tracking {} file(s)", files.len()),
));
}
}
Err(e) => {
report.add(CheckResult::warning(
"git",
"lfs_files",
&format!("Failed to list LFS files: {}", e),
false,
None,
));
}
}
}
Ok(false) => {
log::info!("Git LFS not detected");
}
Err(e) => {
report.add(CheckResult::warning(
"git",
"git_lfs",
&format!("LFS check failed: {}", e),
false,
None,
));
}
}
}
fn check_command(bin: &str, args: &[&str]) -> anyhow::Result<()> {
let mut command = Command::new(bin);
command
.args(args)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::piped());
let output = execute_managed_command(ManagedCommand::new(
command,
format!("doctor git probe: {} {}", bin, args.join(" ")),
TimeoutClass::Probe,
))?
.into_output();
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
let stderr_msg = if stderr.trim().is_empty() {
format!(
"command '{}' {:?} failed with exit status: {}",
bin, args, output.status
)
} else {
format!(
"command '{}' {:?} failed with exit status {}: {}",
bin,
args,
output.status,
stderr.trim()
)
};
Err(anyhow::anyhow!(stderr_msg))
}
}