Skip to content

Commit 86a3074

Browse files
10ne1gitster
authored andcommitted
hook: show disabled hooks in "git hook list"
Disabled hooks were filtered out of the cache entirely, making them invisible to "git hook list". Keep them in the cache with a new "disabled" flag which is propagated to the respective struct hook. "git hook list" now shows disabled hooks annotated with "(disabled)" in the config order. With --show-scope, it looks like: $ git hook list --show-scope pre-commit linter (global) no-leaks (local, disabled) hook from hookdir A disabled hook without a command issues a warning instead of the fatal "hook.X.command must be configured" error. We could also throw an error, however it seemd a bit excessive to me in this case. 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>
1 parent dcd7ab7 commit 86a3074

4 files changed

Lines changed: 79 additions & 27 deletions

File tree

builtin/hook.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,20 @@ static int list(int argc, const char **argv, const char *prefix,
7272
case HOOK_TRADITIONAL:
7373
printf("%s%c", _("hook from hookdir"), line_terminator);
7474
break;
75-
case HOOK_CONFIGURED:
76-
if (show_scope)
77-
printf("%s (%s)%c",
78-
h->u.configured.friendly_name,
79-
config_scope_name(h->u.configured.scope),
75+
case HOOK_CONFIGURED: {
76+
const char *name = h->u.configured.friendly_name;
77+
const char *scope = show_scope ?
78+
config_scope_name(h->u.configured.scope) : NULL;
79+
if (scope)
80+
printf("%s (%s%s)%c", name, scope,
81+
h->u.configured.disabled ? ", disabled" : "",
8082
line_terminator);
83+
else if (h->u.configured.disabled)
84+
printf("%s (disabled)%c", name, line_terminator);
8185
else
82-
printf("%s%c", h->u.configured.friendly_name,
83-
line_terminator);
86+
printf("%s%c", name, line_terminator);
8487
break;
88+
}
8589
default:
8690
BUG("unknown hook kind");
8791
}

hook.c

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ static void list_hooks_add_default(struct repository *r, const char *hookname,
119119
struct hook_config_cache_entry {
120120
char *command;
121121
enum config_scope scope;
122+
int disabled;
122123
};
123124

124125
/*
@@ -217,8 +218,10 @@ static int hook_config_lookup_all(const char *key, const char *value,
217218
* every item's string is the hook's friendly-name and its util pointer is
218219
* a hook_config_cache_entry. All strings are owned by the map.
219220
*
220-
* Disabled hooks and hooks missing a command are already filtered out at
221-
* parse time, so callers can iterate the list directly.
221+
* Disabled hooks are kept in the cache with entry->disabled set, so that
222+
* "git hook list" can display them. Hooks missing a command are filtered
223+
* out at build time; if a disabled hook has no command it is silently
224+
* skipped rather than triggering a fatal error.
222225
*/
223226
void hook_cache_clear(struct hook_config_cache *cache)
224227
{
@@ -268,21 +271,26 @@ static void build_hook_config_map(struct repository *r,
268271
struct hook_config_cache_entry *entry;
269272
char *command;
270273

271-
/* filter out disabled hooks */
272-
if (unsorted_string_list_lookup(&cb_data.disabled_hooks,
273-
hname))
274-
continue;
274+
int is_disabled =
275+
!!unsorted_string_list_lookup(
276+
&cb_data.disabled_hooks, hname);
275277

276278
command = strmap_get(&cb_data.commands, hname);
277-
if (!command)
278-
die(_("'hook.%s.command' must be configured or "
279-
"'hook.%s.event' must be removed;"
280-
" aborting."), hname, hname);
279+
if (!command) {
280+
if (is_disabled)
281+
warning(_("disabled hook '%s' has no "
282+
"command configured"), hname);
283+
else
284+
die(_("'hook.%s.command' must be configured or "
285+
"'hook.%s.event' must be removed;"
286+
" aborting."), hname, hname);
287+
}
281288

282289
/* util stores a cache entry; owned by the cache. */
283290
CALLOC_ARRAY(entry, 1);
284-
entry->command = xstrdup(command);
291+
entry->command = command ? xstrdup(command) : NULL;
285292
entry->scope = scope;
293+
entry->disabled = is_disabled;
286294
string_list_append(hooks, hname)->util = entry;
287295
}
288296

@@ -362,8 +370,10 @@ static void list_hooks_add_configured(struct repository *r,
362370

363371
hook->kind = HOOK_CONFIGURED;
364372
hook->u.configured.friendly_name = xstrdup(friendly_name);
365-
hook->u.configured.command = xstrdup(entry->command);
373+
hook->u.configured.command =
374+
entry->command ? xstrdup(entry->command) : NULL;
366375
hook->u.configured.scope = entry->scope;
376+
hook->u.configured.disabled = entry->disabled;
367377

368378
string_list_append(list, friendly_name)->util = hook;
369379
}
@@ -401,7 +411,16 @@ struct string_list *list_hooks(struct repository *r, const char *hookname,
401411
int hook_exists(struct repository *r, const char *name)
402412
{
403413
struct string_list *hooks = list_hooks(r, name, NULL);
404-
int exists = hooks->nr > 0;
414+
int exists = 0;
415+
416+
for (size_t i = 0; i < hooks->nr; i++) {
417+
struct hook *h = hooks->items[i].util;
418+
if (h->kind == HOOK_TRADITIONAL ||
419+
!h->u.configured.disabled) {
420+
exists = 1;
421+
break;
422+
}
423+
}
405424
string_list_clear_func(hooks, hook_free);
406425
free(hooks);
407426
return exists;
@@ -416,10 +435,11 @@ static int pick_next_hook(struct child_process *cp,
416435
struct string_list *hook_list = hook_cb->hook_command_list;
417436
struct hook *h;
418437

419-
if (hook_cb->hook_to_run_index >= hook_list->nr)
420-
return 0;
421-
422-
h = hook_list->items[hook_cb->hook_to_run_index++].util;
438+
do {
439+
if (hook_cb->hook_to_run_index >= hook_list->nr)
440+
return 0;
441+
h = hook_list->items[hook_cb->hook_to_run_index++].util;
442+
} while (h->kind == HOOK_CONFIGURED && h->u.configured.disabled);
423443

424444
cp->no_stdin = 1;
425445
strvec_pushv(&cp->env, hook_cb->options->env.v);

hook.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct hook {
3131
const char *friendly_name;
3232
const char *command;
3333
enum config_scope scope;
34+
int disabled;
3435
} configured;
3536
} u;
3637

t/t1800-hook.sh

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,16 +357,43 @@ test_expect_success 'disabled hook is not run' '
357357
test_must_be_empty actual
358358
'
359359

360-
test_expect_success 'disabled hook does not appear in git hook list' '
360+
test_expect_success 'disabled hook with no command warns' '
361+
test_config hook.nocommand.event "pre-commit" &&
362+
test_config hook.nocommand.enabled false &&
363+
364+
git hook list pre-commit 2>actual &&
365+
test_grep "disabled hook.*nocommand.*no command configured" actual
366+
'
367+
368+
test_expect_success 'disabled hook appears as disabled in git hook list' '
361369
test_config hook.active.event "pre-commit" &&
362370
test_config hook.active.command "echo active" &&
363371
test_config hook.inactive.event "pre-commit" &&
364372
test_config hook.inactive.command "echo inactive" &&
365373
test_config hook.inactive.enabled false &&
366374
367375
git hook list pre-commit >actual &&
368-
test_grep "active" actual &&
369-
test_grep ! "inactive" actual
376+
test_grep "^active$" actual &&
377+
test_grep "^inactive (disabled)$" actual
378+
'
379+
380+
test_expect_success 'disabled hook shows scope with --show-scope' '
381+
test_config hook.myhook.event "pre-commit" &&
382+
test_config hook.myhook.command "echo hi" &&
383+
test_config hook.myhook.enabled false &&
384+
385+
git hook list --show-scope pre-commit >actual &&
386+
test_grep "myhook (local, disabled)" actual
387+
'
388+
389+
test_expect_success 'disabled configured hook is not reported as existing by hook_exists' '
390+
test_when_finished "rm -f git-bugreport-hook-exists-test.txt" &&
391+
test_config hook.linter.event "pre-commit" &&
392+
test_config hook.linter.command "echo lint" &&
393+
test_config hook.linter.enabled false &&
394+
395+
git bugreport -s hook-exists-test &&
396+
test_grep ! "pre-commit" git-bugreport-hook-exists-test.txt
370397
'
371398

372399
test_expect_success 'globally disabled hook can be re-enabled locally' '

0 commit comments

Comments
 (0)