use crate::error::Result;
use crate::templates;
use crate::utils::{create_dir, make_executable, write_file};
use std::path::Path;
pub fn apply(project_path: &Path, force: bool) -> Result<()> {
println!("🪝 Applying Hooks Pack...");
let githooks_dir = project_path.join(".githooks");
create_dir(&githooks_dir)?;
let pre_push_path = githooks_dir.join("pre-push");
write_file(&pre_push_path, templates::PRE_PUSH_HOOK, force)?;
make_executable(&pre_push_path)?;
let setup_sh_path = githooks_dir.join("setup.sh");
write_file(&setup_sh_path, templates::SETUP_HOOKS_SH, force)?;
make_executable(&setup_sh_path)?;
let readme_path = githooks_dir.join("README.md");
write_file(&readme_path, templates::GITHOOKS_README, force)?;
configure_git_hooks(project_path)?;
println!();
Ok(())
}
fn configure_git_hooks(project_path: &Path) -> Result<()> {
use std::process::Command;
let output = Command::new("git")
.current_dir(project_path)
.args(["config", "core.hooksPath", ".githooks"])
.output();
match output {
Ok(output) if output.status.success() => {
println!("⚙️ Configured git to use .githooks directory");
Ok(())
}
Ok(output) => {
let stderr = String::from_utf8_lossy(&output.stderr);
println!("⚠️ Warning: Could not configure git hooks: {}", stderr);
Ok(())
}
Err(e) => {
println!("⚠️ Warning: Git not found or not initialized: {}", e);
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_hooks_pack_creates_files() {
let temp_dir = tempdir().unwrap();
let project_path = temp_dir.path();
apply(project_path, false).unwrap();
assert!(project_path.join(".githooks").exists());
assert!(project_path.join(".githooks/pre-push").exists());
assert!(project_path.join(".githooks/setup.sh").exists());
assert!(project_path.join(".githooks/README.md").exists());
}
#[test]
#[cfg(unix)]
fn test_hooks_are_executable() {
use std::os::unix::fs::PermissionsExt;
let temp_dir = tempdir().unwrap();
let project_path = temp_dir.path();
apply(project_path, false).unwrap();
let pre_push_perms = std::fs::metadata(project_path.join(".githooks/pre-push"))
.unwrap()
.permissions();
let setup_sh_perms = std::fs::metadata(project_path.join(".githooks/setup.sh"))
.unwrap()
.permissions();
assert_eq!(pre_push_perms.mode() & 0o111, 0o111);
assert_eq!(setup_sh_perms.mode() & 0o111, 0o111);
}
}