#include "environment.h"
#include "gettext.h"
#include "hook.h"
+#include "hook-list.h"
#include "parse-options.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
+ N_("git hook run [--allow-unknown-hook-name] [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
#define BUILTIN_HOOK_LIST_USAGE \
- N_("git hook list [-z] [--show-scope] <hook-name>")
+ N_("git hook list [--allow-unknown-hook-name] [-z] [--show-scope] <hook-name>")
+
+static int is_known_hook(const char *name)
+{
+ const char **p;
+ for (p = hook_name_list; *p; p++)
+ if (!strcmp(*p, name))
+ return 1;
+ return 0;
+}
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
const char *hookname = NULL;
int line_terminator = '\n';
int show_scope = 0;
+ int allow_unknown = 0;
int ret = 0;
struct option list_options[] = {
N_("use NUL as line terminator"), '\0'),
OPT_BOOL(0, "show-scope", &show_scope,
N_("show the config scope that defined each hook")),
+ OPT_BOOL(0, "allow-unknown-hook-name", &allow_unknown,
+ N_("allow running a hook with a non-native hook name")),
OPT_END(),
};
hookname = argv[0];
+ if (!allow_unknown && !is_known_hook(hookname)) {
+ error(_("unknown hook event '%s';\n"
+ "use --allow-unknown-hook-name to allow non-native hook names"),
+ hookname);
+ return 1;
+ }
+
head = list_hooks(repo, hookname, NULL);
if (!head->nr) {
int i;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
int ignore_missing = 0;
+ int allow_unknown = 0;
const char *hook_name;
struct option run_options[] = {
+ OPT_BOOL(0, "allow-unknown-hook-name", &allow_unknown,
+ N_("allow running a hook with a non-native hook name")),
OPT_BOOL(0, "ignore-missing", &ignore_missing,
N_("silently ignore missing requested <hook-name>")),
OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
repo_config(the_repository, git_default_config, NULL);
hook_name = argv[0];
+
+ if (!allow_unknown && !is_known_hook(hook_name)) {
+ error(_("unknown hook event '%s';\n"
+ "use --allow-unknown-hook-name to allow non-native hook names"),
+ hook_name);
+ return 1;
+ }
+
if (!ignore_missing)
opt.error_if_missing = 1;
ret = run_hooks_opt(the_repository, hook_name, &opt);
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
'
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
'
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
'
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
'
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
'
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
'
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
'
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' '
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
'
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
'
# 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
'
# '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
'
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
'
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
'
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
'
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)
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
'