diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 963f127..5272881 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -20,4 +20,7 @@ jobs: - name: Run ShellCheck on all shell scripts run: | - shellcheck pre-commit commit-msg pre-push post-checkout post-commit post-merge install.sh uninstall.sh + shellcheck pre-commit commit-msg pre-push post-checkout post-commit post-merge install.sh uninstall.sh test/install_test.sh + + - name: Run install script regression tests + run: bash test/install_test.sh diff --git a/README.md b/README.md index 7fe71b3..9ae4cd2 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ See what's currently configured without changing anything: cd ~/.git-hooks && ./install.sh --check ``` +`--check` can be combined with other flags like `--template` to inspect what would be used without changing your git config. + ### Uninstall ```bash diff --git a/install.sh b/install.sh index df2ab95..5c9f2c6 100755 --- a/install.sh +++ b/install.sh @@ -7,8 +7,41 @@ set -euo pipefail hook_dir="$(cd "$(dirname "$0")" && pwd)" +use_template=false +check_only=false -if [ "${1:-}" = "--check" ]; then +usage() { + cat <&2 + usage >&2 + exit 1 + ;; + esac +done + +if [ "$check_only" = true ]; then hooks_path=$(git config --global --get core.hooksPath 2>/dev/null || true) template_dir=$(git config --global --get init.templateDir 2>/dev/null || true) if [ -n "$hooks_path" ]; then @@ -33,7 +66,7 @@ if [ "${1:-}" = "--check" ]; then exit 0 fi -if [ "${1:-}" = "--template" ]; then +if [ "$use_template" = true ]; then git config --global init.templateDir "$hook_dir" echo "Installed: init.templateDir set to $hook_dir" echo "New repos created with git init/clone will copy these hooks." diff --git a/test/install_test.sh b/test/install_test.sh new file mode 100644 index 0000000..500de72 --- /dev/null +++ b/test/install_test.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +install_script="$repo_root/install.sh" +tmpdir="$(mktemp -d)" +trap 'rm -rf "$tmpdir"' EXIT + +export HOME="$tmpdir/home" +mkdir -p "$HOME" + +global_config="$HOME/.gitconfig" + +run() { + local expected_status="$1" + shift + set +e + output=$(GIT_CONFIG_GLOBAL="$global_config" "$@" 2>&1) + status=$? + set -e + if [ "$status" -ne "$expected_status" ]; then + echo "expected exit $expected_status, got $status" >&2 + echo "$output" >&2 + exit 1 + fi + printf '%s' "$output" +} + +assert_contains() { + local haystack="$1" + local needle="$2" + if ! printf '%s' "$haystack" | grep -Fq "$needle"; then + echo "expected output to contain: $needle" >&2 + echo "$haystack" >&2 + exit 1 + fi +} + +assert_unset() { + local key="$1" + if GIT_CONFIG_GLOBAL="$global_config" git config --global --get "$key" >/dev/null 2>&1; then + echo "expected $key to be unset" >&2 + exit 1 + fi +} + +output=$(run 0 bash "$install_script" --check) +assert_contains "$output" "No global hooks configuration found." + +output=$(run 0 bash "$install_script" --template --check) +assert_contains "$output" "No global hooks configuration found." +assert_unset core.hooksPath +assert_unset init.templateDir + +output=$(run 0 bash "$install_script" --template) +assert_contains "$output" "Installed: init.templateDir set to $repo_root" +template_dir=$(GIT_CONFIG_GLOBAL="$global_config" git config --global --get init.templateDir) +[ "$template_dir" = "$repo_root" ] + +output=$(run 1 bash "$install_script" --bogus) +assert_contains "$output" "Unknown option: --bogus" + +output=$(run 0 bash "$install_script" --help) +assert_contains "$output" "Usage: ./install.sh" + +echo "install.sh regression tests passed"