[PATCH v2 0/6] config-based hooks restarted

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is the config-based hooks topic rebased onto v4 of Ævar's
branch[1]. There is a happy CI build of it on GitHub[2].

The topic overall adds the ability to set up hooks by modifying the
config, in addition to placing specially named hooks into the hookdir.
This enables users to specify multiple hooks for a given event, and so
this topic also fleshes out the use of the run_processes_parallel() API
which is now introduced in Ævar's reordering of prior patches.

Patches 1-4 make some minor changes to prepare Ævar's series to handle
more than one hook at a time. With the exception of patch 4, there
should be no behavior change for existing hooks.

Patch 2 is opinionated about which hooks should and shouldn't be allowed
to run in parallel; if you care about a specific hook, please take a
look there.

Patch 5 is the motivating feature - it begins to parse the config
looking for hooks.

Patch 6 takes advantage of the decoupling of hooks and GITDIR to allow
out-of-repo hook runs, which would only run hooks specified in the
system or global config. This mainly targets 'sendemail-validate', but
'git-sendemail.perl' still explicitly disallows out-of-repo hook
execution on that hook for now. (Maybe that change should be added in
this series? Or maybe patch 6 belongs with that kind of change?)

Since v1:

The largest change is that the config schema is different, following the
discussion from [3] and on. 'hookcmd' has gone away entirely, and all
config-specified hooks need a user-provided name associated with them.

I have also dropped the 'skip' config from this series (also discussed
in [3]) as users can reset their 'hook.myhook.command' to 'true' or some
other noop in a later config to effectively disable any hook. The 'skip'
feature may be added later or may not, depending on if users ask us for
it.

The 'from_hookdir' field has been removed entirely. When storing hooks
by name instead of by command, it makes sense enough to store the one
from the hookdir in a special way - NULL name - because it does not have
a name to specify. This way we can use that field as an indicator that
the hook came from the hookdir, and we also do not need to reserve a
name to use for hookdir hooks (as opposed to setting hookdir hooks to
have name = "FROM_HOOKDIR" or something).

The tests have been moved into t1800-hook.sh and simplified.

The 'struct run_hooks_opt' initializer has been moved to macros (as
opposed to functions), and .jobs=0 indicates that we should look up the
configured job count or nproc at hook run time. Ævar asked me to change
these macros to RUN_HOOKS_OPT_INIT and RUN_HOOKS_OPT_INIT_SYNC or
something to simplify the merge, but I did not do that - I removed all
instances of RUN_HOOKS_OPT_INIT and now everybody uses
RUN_HOOKS_OPT_INIT_SYNC or RUN_HOOKS_OPT_INIT_ASYNC. I think it's
important for contributors to be able to tell at a glance whether the
hook event expects resource contention that would prevent parallelism. I
also think it makes the review easier (if longer) for folks who are
reviewing trying to decide whether the parallelism is appropriate for
each hook event. I do think that run_hooks_oneshot() also is a step
backwards in this regard, but I didn't get a chance to say so on the
commit that introduces it yet.

Thanks in advance, all.

 - Emily

1: https://lore.kernel.org/git/cover-v4-00.36-00000000000-20210803T191505Z-avarab%40gmail.com
2: https://github.com/nasamuffin/git/actions/runs/1122126800 (which
points to an earlier successul run before I messed with the commit
messages)
3: https://lore.kernel.org/git/87fswey5wd.fsf%40evledraar.gmail.com

Emily Shaffer (6):
  hook: run a list of hooks instead
  hook: allow parallel hook execution
  hook: introduce "git hook list"
  hook: allow running non-native hooks
  hook: include hooks from the config
  hook: allow out-of-repo 'git hook' invocations

 Documentation/config/hook.txt |   9 ++
 Documentation/git-hook.txt    |  48 +++++-
 builtin/am.c                  |   4 +-
 builtin/checkout.c            |   2 +-
 builtin/clone.c               |   2 +-
 builtin/hook.c                |  68 +++++++-
 builtin/merge.c               |   2 +-
 builtin/rebase.c              |   2 +-
 builtin/receive-pack.c        |   9 +-
 builtin/worktree.c            |   2 +-
 commit.c                      |   2 +-
 git.c                         |   2 +-
 hook.c                        | 289 +++++++++++++++++++++++++++++-----
 hook.h                        |  61 +++++--
 read-cache.c                  |   2 +-
 refs.c                        |   2 +-
 reset.c                       |   3 +-
 sequencer.c                   |   4 +-
 t/t1800-hook.sh               | 161 ++++++++++++++++++-
 transport.c                   |   2 +-
 20 files changed, 596 insertions(+), 80 deletions(-)
 create mode 100644 Documentation/config/hook.txt

Range-diff against v1:
1:  c4b95fb08a < -:  ---------- hook: treat hookdir hook specially
-:  ---------- > 1:  5177e8ba2c hook: run a list of hooks instead
-:  ---------- > 2:  eda439cd57 hook: allow parallel hook execution
-:  ---------- > 3:  cdfe3b6e16 hook: introduce "git hook list"
2:  e6a56ac674 = 4:  eb4e03e22b hook: allow running non-native hooks
3:  32ad49ea9b ! 5:  2c8e874158 hook: include hooks from the config
    @@ Commit message
         hooks to run for a given event.
     
         Multiple commands can be specified for a given hook by providing
    -    multiple "hook.<hookname>.command = <path-to-hook>" lines. Hooks will be
    -    run in config order.
    +    multiple "hook.<friendly-name>.command = <path-to-hook>" and
    +    "hook.<friendly-name>.event = <hook-event>" lines. Hooks will be run in
    +    config order of the "hook.<name>.event" lines.
     
         For example:
     
           $ git config --list | grep ^hook
    -      hook.pre-commit.command=~/bar.sh
    +      hook.bar.command=~/bar.sh
    +      hook.bar.event=pre-commit
     
           $ git hook run
           # Runs ~/bar.sh
    @@ hook.c: const char *find_hook_gently(const char *name)
     -		struct hook *to_add = xmalloc(sizeof(*to_add));
     -		to_add->hook_path = hook_path;
     -		to_add->feed_pipe_cb_data = NULL;
    --		to_add->from_hookdir = 1;
     -		list_add_tail(&to_add->list, hook_head);
     -	}
     +	/* Add the hook from the hookdir. The placeholder makes it easier to
    @@ hook.c: static int pick_next_hook(struct child_process *cp,
     +	cp->use_shell = !!run_me->name;
     +
      	/* add command */
    --	if (run_me->from_hookdir && hook_cb->options->absolute_path)
    +-	if (hook_cb->options->absolute_path)
     -		strvec_push(&cp->args, absolute_path(run_me->hook_path));
     -	else
     -		strvec_push(&cp->args, run_me->hook_path);
    @@ hook.h: int hook_exists(const char *hookname);
      	struct list_head list;
     -	/* The path to the hook */
     -	const char *hook_path;
    --
    --	unsigned from_hookdir : 1;
     +	/*
     +	 * The friendly name of the hook. NULL indicates the hook is from the
     +	 * hookdir.
4:  91e54185b3 = 6:  3216e51b6b hook: allow out-of-repo 'git hook' invocations
-- 
2.32.0.605.g8dce9f2422-goog





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux