Skip to content

Commit

Permalink
test: add tests for hooky cli
Browse files Browse the repository at this point in the history
  • Loading branch information
peeeuzin committed Mar 24, 2024
1 parent 245488d commit 9c252a1
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 137 deletions.
13 changes: 13 additions & 0 deletions .hooky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env sh
# Run pre-commit hooks

cargo install --path . --quiet

# Tests
sh ./tests/init-test.sh
sh ./tests/add-test.sh
sh ./tests/uninstall-test.sh

cargo uninstall

exit 0
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ description = "Git hooks helper made in Rust"
name = "hooky"
path = "src/main.rs"

[lib]
name = "hooky"
path = "src/lib.rs"

[dependencies]
140 changes: 140 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use std::fs;
use std::io::prelude::*;
use std::path;
use std::process::Command;

#[cfg(target_family = "unix")]
use std::os::unix::prelude::OpenOptionsExt;

#[cfg(target_family = "windows")]
use std::os::windows::fs::OpenOptionsExt;

pub const ALLOWED_HOOKS: [&str; 13] = [
"applypatch-msg",
"commit-msg",
"post-update",
"pre-applypatch",
"pre-commit",
"pre-merge-commit",
"pre-push",
"pre-rebase",
"pre-receive",
"prepare-commit-msg",
"push-to-checkout",
"sendemail-validate",
"update",
];

pub fn init(no_pre_commit: bool) {
let pre_commit_dir = path::Path::new(".hooky");

if !path::Path::new(".git").exists() {
println!("[error] git cannot be found");

return;
}

if pre_commit_dir.exists() {
println!("[info] hooky is already installed");

return;
}

Command::new("git")
.arg("config")
.arg("core.hooksPath")
.arg(pre_commit_dir)
.spawn()
.expect("Failed to set hooks path");

println!("[info] Hooks path set to .hooky directory");

fs::create_dir_all(pre_commit_dir).expect("Failed to create .hooky directory");

if !no_pre_commit {
let mut file = create_file(pre_commit_dir.join("pre-commit"));

file.write_all(b"#!/usr/bin/env sh\n# Run pre-commit hooks\n\nexit 0")
.expect("Failed to write to pre-commit file");

println!("[info] Created pre-commit file");
}
}

pub fn uninstall() {
let pre_commit_dir = path::Path::new(".hooky");

if !path::Path::new(".git").exists() {
println!("[error] git cannot be found");

return;
}

if !pre_commit_dir.exists() {
println!("[info] hooky is not installed");

return;
}

Command::new("git")
.arg("config")
.arg("--unset")
.arg("core.hooksPath")
.spawn()
.expect("Failed to unset hooks path");

fs::remove_dir_all(pre_commit_dir).expect("Failed to remove .hooky directory");

println!("[info] Uninstalled hooky");
}

pub fn add_hook(hook: &str) {
if !ALLOWED_HOOKS.contains(&hook) {
println!("[error] Hook not allowed");

return;
}

let pre_commit_dir = path::Path::new(".hooky");

if !pre_commit_dir.exists() {
println!("[error] .hooky directory not found");
println!("[hint] try running `hooky init` first");

return;
}

if !path::Path::new(".git").exists() {
println!("[error] git cannot be found");

return;
}
let mut file = create_file(pre_commit_dir.join(hook));

let hook_content = format!("#!/usr/bin/env sh\n# Run {} hook\n\nexit 0", hook);
file.write_all(hook_content.as_bytes())
.expect("Failed to write to hook file");

println!("[info] Created hook file");
}

fn create_file<P>(path: P) -> fs::File
where
P: AsRef<path::Path>,
{
let mut options = fs::OpenOptions::new();

options.create(true).write(true);

#[cfg(target_family = "windows")]
{
options.access_mode(0o755);
}

#[cfg(target_family = "unix")]
{
options.mode(0o755);
}

options.open(path).expect("Failed to create file")
}
140 changes: 3 additions & 137 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,4 @@
use std::env;
use std::fs;
use std::io::prelude::*;
use std::path;
use std::process::Command;

#[cfg(target_family = "unix")]
use std::os::unix::prelude::OpenOptionsExt;

#[cfg(target_family = "windows")]
use std::os::windows::fs::OpenOptionsExt;

const ALLOWED_HOOKS: [&str; 13] = [
"applypatch-msg",
"commit-msg",
"post-update",
"pre-applypatch",
"pre-commit",
"pre-merge-commit",
"pre-push",
"pre-rebase",
"pre-receive",
"prepare-commit-msg",
"push-to-checkout",
"sendemail-validate",
"update",
];

fn main() {
let args: Vec<String> = env::args().collect();
Expand All @@ -43,124 +17,16 @@ fn main() {

fn run_command(command: &str, args: Vec<String>) {
match command {
"init" => init(args.contains(&"--no-pre-commit".to_string())),
"uninstall" => uninstall(),
"add" => add_hook(&args[0]),
"init" => hooky::init(args.contains(&"--no-pre-commit".to_string())),
"uninstall" => hooky::uninstall(),
"add" => hooky::add_hook(&args[0]),

_ => println!("Command not found"),
}
}

fn init(no_pre_commit: bool) {
let pre_commit_dir = path::Path::new(".hooky");

if !path::Path::new(".git").exists() {
println!("[error] git cannot be found");

return;
}

Command::new("git")
.arg("config")
.arg("core.hooksPath")
.arg(pre_commit_dir)
.spawn()
.expect("Failed to set hooks path");

println!("[info] Hooks path set to .hooky directory");

fs::create_dir_all(pre_commit_dir).expect("Failed to create .hooky directory");

if !no_pre_commit {
let mut file = create_file(pre_commit_dir.join("pre-commit"));

file.write_all(b"#!/usr/bin/env sh\n# Run pre-commit hooks\n\nexit 0")
.expect("Failed to write to pre-commit file");

println!("[info] Created pre-commit file");
}
}

fn uninstall() {
let pre_commit_dir = path::Path::new(".hooky");

if !path::Path::new(".git").exists() {
println!("[error] git cannot be found");

return;
}

if !pre_commit_dir.exists() {
println!("[info] hooky is not installed");

return;
}

Command::new("git")
.arg("config")
.arg("--unset")
.arg("core.hooksPath")
.spawn()
.expect("Failed to unset hooks path");

fs::remove_dir_all(pre_commit_dir).expect("Failed to remove .hooky directory");

println!("[info] Uninstalled hooky");
}

fn add_hook(hook: &str) {
if !ALLOWED_HOOKS.contains(&hook) {
println!("[error] Hook not allowed");

return;
}

let pre_commit_dir = path::Path::new(".hooky");

if !pre_commit_dir.exists() {
println!("[error] .hooky directory not found");
println!("[hint] try running `hooky init` first");

return;
}

if !path::Path::new(".git").exists() {
println!("[error] git cannot be found");

return;
}
let mut file = create_file(pre_commit_dir.join(hook));

let hook_content = format!("#!/usr/bin/env sh\n# Run {} hook\n\nexit 0", hook);
file.write_all(hook_content.as_bytes())
.expect("Failed to write to hook file");

println!("[info] Created hook file");
}

fn help() {
println!("hooky init - Initialize hooky. Optionally pass --no-pre-commit to skip creating a pre-commit hook");
println!("hooky uninstall - Uninstall hooky");
println!("hooky add <hook> - Add a hook");
}

fn create_file<P>(path: P) -> fs::File
where
P: AsRef<path::Path>,
{
let mut options = fs::OpenOptions::new();

options.create(true).write(true);

#[cfg(target_family = "windows")]
{
options.access_mode(0o755);
}

#[cfg(target_family = "unix")]
{
options.mode(0o755);
}

options.open(path).expect("Failed to create file")
}
18 changes: 18 additions & 0 deletions tests/add-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

. tests/helper.sh
setup

# Should initalize hooky
hooky init --no-pre-commit &>/dev/null

[ ! -d .hooky ] && error "Should initialize hooky: Failed to initialize hooky"

ok "Should initialize hooky"

# Should add a commit-msg hook
hooky add commit-msg &>/dev/null

[ -f .git/hooks/commit-msg ] && error "Should add a commit-msg hook: Failed to add commit-msg hook" && exit 1

ok "Should add a commit-msg hook"
19 changes: 19 additions & 0 deletions tests/helper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
me=$(basename "$0")

setup() {
set -o errexit
set -o nounset
set -o pipefail

cd $(mktemp -d)
git init &>/dev/null
}

error() {
echo -e "$me: \e[0;31mERROR:\e[m $1"
exit 1
}

ok() {
echo -e "$me: \e[0;32mOK\e[m $1"
}
11 changes: 11 additions & 0 deletions tests/init-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

. tests/helper.sh
setup

# Should initalize hooky
hooky init &>/dev/null

[ ! -d .hooky ] && error "Failed to initialize hooky"

ok "Should initialize hooky"
18 changes: 18 additions & 0 deletions tests/uninstall-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

. tests/helper.sh
setup

# Should initalize hooky
hooky init &>/dev/null

[ ! -d .hooky ] && error "Failed to initialize hooky"

ok "Should initialize hooky"

# Should uninstall hooky
hooky uninstall &>/dev/null

[ -d .hooky ] && error "Failed to uninstall hooky"

ok "Should uninstall hooky"

0 comments on commit 9c252a1

Please sign in to comment.