diff options
| author | Adrian Ratiu <adrian.ratiu@collabora.com> | 2026-03-25 21:55:03 +0200 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-25 14:00:48 -0700 |
| commit | 5c58dbc887a1f3530cb29c995f63675beebb22e9 (patch) | |
| tree | 1db89b9b9a4ef3f852b228f62c11c813174c2336 /t | |
| parent | e17bd99281ae01a758d717bdfaa759bbeefb6149 (diff) | |
| download | git-5c58dbc887a1f3530cb29c995f63675beebb22e9.tar.xz | |
hook: reject unknown hook names in git-hook(1)
Teach "git hook run" and "git hook list" to reject hook event names
that are not recognized by Git. This helps catch typos such as
"prereceive" when "pre-receive" was intended, since in 99% of the
cases users want known (already-existing) hook names.
The list of known hooks is derived from the generated hook-list.h
(built from Documentation/githooks.adoc). This is why the Makefile
is updated, so builtin/hook.c depends on hook-list.h. In meson the
header is already a dependency for all builtins, no change required.
The "--allow-unknown-hook-name" flag can be used to bypass this check.
Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 't')
| -rwxr-xr-x | t/t1800-hook.sh | 82 |
1 files changed, 56 insertions, 26 deletions
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh index 8c5237449d..96749fc06d 100755 --- a/t/t1800-hook.sh +++ b/t/t1800-hook.sh @@ -31,11 +31,41 @@ test_expect_success 'git hook usage' ' grep "unknown option" err ' +test_expect_success 'git hook list: unknown hook name is rejected' ' + test_must_fail git hook list prereceive 2>err && + test_grep "unknown hook event" err +' + +test_expect_success 'git hook run: unknown hook name is rejected' ' + test_must_fail git hook run prereceive 2>err && + test_grep "unknown hook event" err +' + +test_expect_success 'git hook list: known hook name is accepted' ' + test_must_fail git hook list pre-receive 2>err && + test_grep ! "unknown hook event" err +' + +test_expect_success 'git hook run: known hook name is accepted' ' + git hook run --ignore-missing pre-receive 2>err && + test_grep ! "unknown hook event" err +' + +test_expect_success 'git hook run: --allow-unknown-hook-name overrides rejection' ' + git hook run --allow-unknown-hook-name --ignore-missing custom-hook 2>err && + test_grep ! "unknown hook event" err +' + +test_expect_success 'git hook list: --allow-unknown-hook-name overrides rejection' ' + test_must_fail git hook list --allow-unknown-hook-name custom-hook 2>err && + test_grep ! "unknown hook event" err +' + test_expect_success 'git hook list: nonexistent hook' ' cat >stderr.expect <<-\EOF && warning: no hooks found for event '\''test-hook'\'' EOF - test_expect_code 1 git hook list test-hook 2>stderr.actual && + test_expect_code 1 git hook list --allow-unknown-hook-name test-hook 2>stderr.actual && test_cmp stderr.expect stderr.actual ' @@ -47,7 +77,7 @@ test_expect_success 'git hook list: traditional hook from hookdir' ' cat >expect <<-\EOF && hook from hookdir EOF - git hook list test-hook >actual && + git hook list --allow-unknown-hook-name test-hook >actual && test_cmp expect actual ' @@ -56,7 +86,7 @@ test_expect_success 'git hook list: configured hook' ' test_config hook.myhook.event test-hook --add && echo "myhook" >expect && - git hook list test-hook >actual && + git hook list --allow-unknown-hook-name test-hook >actual && test_cmp expect actual ' @@ -68,7 +98,7 @@ test_expect_success 'git hook list: -z shows NUL-terminated output' ' test_config hook.myhook.event test-hook --add && printf "myhookQhook from hookdirQ" >expect && - git hook list -z test-hook >actual.raw && + git hook list --allow-unknown-hook-name -z test-hook >actual.raw && nul_to_q <actual.raw >actual && test_cmp expect actual ' @@ -77,12 +107,12 @@ test_expect_success 'git hook run: nonexistent hook' ' cat >stderr.expect <<-\EOF && error: cannot find a hook named test-hook EOF - test_expect_code 1 git hook run test-hook 2>stderr.actual && + test_expect_code 1 git hook run --allow-unknown-hook-name test-hook 2>stderr.actual && test_cmp stderr.expect stderr.actual ' test_expect_success 'git hook run: nonexistent hook with --ignore-missing' ' - git hook run --ignore-missing does-not-exist 2>stderr.actual && + git hook run --allow-unknown-hook-name --ignore-missing does-not-exist 2>stderr.actual && test_must_be_empty stderr.actual ' @@ -94,7 +124,7 @@ test_expect_success 'git hook run: basic' ' cat >expect <<-\EOF && Test hook EOF - git hook run test-hook 2>actual && + git hook run --allow-unknown-hook-name test-hook 2>actual && test_cmp expect actual ' @@ -108,7 +138,7 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' ' Will end up on stderr Will end up on stderr EOF - git hook run test-hook >stdout.actual 2>stderr.actual && + git hook run --allow-unknown-hook-name test-hook >stdout.actual 2>stderr.actual && test_cmp stderr.expect stderr.actual && test_must_be_empty stdout.actual ' @@ -120,12 +150,12 @@ do exit $code EOF - test_expect_code $code git hook run test-hook + test_expect_code $code git hook run --allow-unknown-hook-name test-hook ' done test_expect_success 'git hook run arg u ments without -- is not allowed' ' - test_expect_code 129 git hook run test-hook arg u ments + test_expect_code 129 git hook run --allow-unknown-hook-name test-hook arg u ments ' test_expect_success 'git hook run -- pass arguments' ' @@ -139,7 +169,7 @@ test_expect_success 'git hook run -- pass arguments' ' u ments EOF - git hook run test-hook -- arg "u ments" 2>actual && + git hook run --allow-unknown-hook-name test-hook -- arg "u ments" 2>actual && test_cmp expect actual ' @@ -148,12 +178,12 @@ test_expect_success 'git hook run: out-of-repo runs execute global hooks' ' test_config_global hook.global-hook.command "echo no repo no problems" --add && echo "global-hook" >expect && - nongit git hook list test-hook >actual && + nongit git hook list --allow-unknown-hook-name test-hook >actual && test_cmp expect actual && echo "no repo no problems" >expect && - nongit git hook run test-hook 2>actual && + nongit git hook run --allow-unknown-hook-name test-hook 2>actual && test_cmp expect actual ' @@ -178,11 +208,11 @@ test_expect_success 'git -c core.hooksPath=<PATH> hook run' ' # Test various ways of specifying the path. See also # t1350-config-hooks-path.sh >actual && - git hook run test-hook -- ignored 2>>actual && - git -c core.hooksPath=my-hooks hook run test-hook -- one 2>>actual && - git -c core.hooksPath=my-hooks/ hook run test-hook -- two 2>>actual && - git -c core.hooksPath="$PWD/my-hooks" hook run test-hook -- three 2>>actual && - git -c core.hooksPath="$PWD/my-hooks/" hook run test-hook -- four 2>>actual && + git hook run --allow-unknown-hook-name test-hook -- ignored 2>>actual && + git -c core.hooksPath=my-hooks hook run --allow-unknown-hook-name test-hook -- one 2>>actual && + git -c core.hooksPath=my-hooks/ hook run --allow-unknown-hook-name test-hook -- two 2>>actual && + git -c core.hooksPath="$PWD/my-hooks" hook run --allow-unknown-hook-name test-hook -- three 2>>actual && + git -c core.hooksPath="$PWD/my-hooks/" hook run --allow-unknown-hook-name test-hook -- four 2>>actual && test_cmp expect actual ' @@ -262,7 +292,7 @@ test_expect_success 'hook can be configured for multiple events' ' # 'ghi' should be included in both 'pre-commit' and 'test-hook' git hook list pre-commit >actual && grep "ghi" actual && - git hook list test-hook >actual && + git hook list --allow-unknown-hook-name test-hook >actual && grep "ghi" actual ' @@ -336,15 +366,15 @@ test_expect_success 'stdin to multiple hooks' ' b3 EOF - git hook run --to-stdin=input test-hook 2>actual && + git hook run --allow-unknown-hook-name --to-stdin=input test-hook 2>actual && test_cmp expected actual ' test_expect_success 'rejects hooks with no commands configured' ' test_config hook.broken.event "test-hook" && - test_must_fail git hook list test-hook 2>actual && + test_must_fail git hook list --allow-unknown-hook-name test-hook 2>actual && test_grep "hook.broken.command" actual && - test_must_fail git hook run test-hook 2>actual && + test_must_fail git hook run --allow-unknown-hook-name test-hook 2>actual && test_grep "hook.broken.command" actual ' @@ -353,7 +383,7 @@ test_expect_success 'disabled hook is not run' ' test_config hook.skipped.command "echo \"Should not run\"" && test_config hook.skipped.enabled false && - git hook run --ignore-missing test-hook 2>actual && + git hook run --allow-unknown-hook-name --ignore-missing test-hook 2>actual && test_must_be_empty actual ' @@ -403,7 +433,7 @@ test_expect_success 'globally disabled hook can be re-enabled locally' ' test_config hook.global-hook.enabled true && echo "global-hook ran" >expected && - git hook run test-hook 2>actual && + git hook run --allow-unknown-hook-name test-hook 2>actual && test_cmp expected actual ' @@ -463,7 +493,7 @@ test_expect_success 'git hook run a hook with a bad shebang' ' test_expect_code 1 git \ -c core.hooksPath=bad-hooks \ - hook run test-hook >out 2>err && + hook run --allow-unknown-hook-name test-hook >out 2>err && test_must_be_empty out && # TODO: We should emit the same (or at least a more similar) @@ -487,7 +517,7 @@ test_expect_success 'stdin to hooks' ' EOF echo hello >input && - git hook run --to-stdin=input test-hook 2>actual && + git hook run --allow-unknown-hook-name --to-stdin=input test-hook 2>actual && test_cmp expect actual ' |
