[PATCH 8/9] hook: teach 'hookcmd' config to alias hook scripts

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

 



To enable fine-grained options which apply to a single hook executable,
and to make it easier for a single executable to be run on multiple hook
events, teach "hookcmd.<alias>.config". These can be configured as
follows:

  [hookcmd.my-linter]
    command = ~/my-linter.sh
  [hook.pre-commit]
    command = my-linter

During the config parse, we can attempt to dereference the
'hook.pre-commit.command' string 'my-linter' and check if it matches any
hookcmd names; if so, we can run the command associated with that
hookcmd alias instead.

Signed-off-by: Emily Shaffer <emilyshaffer@xxxxxxxxxx>
---
 Documentation/config/hook.txt |  5 +++++
 Documentation/git-hook.txt    | 42 +++++++++++++++++++++++++++++++----
 hook.c                        |  9 +++++++-
 t/t1360-config-based-hooks.sh | 19 ++++++++++++++++
 4 files changed, 70 insertions(+), 5 deletions(-)

diff --git a/Documentation/config/hook.txt b/Documentation/config/hook.txt
index a97b980cca..5b35170664 100644
--- a/Documentation/config/hook.txt
+++ b/Documentation/config/hook.txt
@@ -3,6 +3,11 @@ hook.<command>.command::
 	executable on your device, a oneliner for your shell, or the name of a
 	hookcmd. See linkgit:git-hook[1].
 
+hookcmd.<name>.command::
+	A command to execute during a hook for which <name> has been specified
+	as a command. This can be an executable on your device or a oneliner for
+	your shell. See linkgit:git-hook[1].
+
 hook.jobs::
 	Specifies how many hooks can be run simultaneously during parallelized
 	hook execution. If unspecified, defaults to the number of processors on
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index 8e2ab724e8..1a4d22fd90 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -18,10 +18,44 @@ This command is an interface to git hooks (see linkgit:githooks[5]).
 Currently it only provides a convenience wrapper for running hooks for
 use by git itself. In the future it might gain other functionality.
 
-This command parses the default configuration files for sections like `hook
-"<hook name>"`. `hook` is used to describe the commands which will be run during
-a particular hook event; commands are run in the order Git encounters them
-during the configuration parse (see linkgit:git-config[1]).
+This command parses the default configuration files for sections `hook` and
+`hookcmd`. `hook` is used to describe the commands which will be run during a
+particular hook event; commands are run in the order Git encounters them during
+the configuration parse (see linkgit:git-config[1]). `hookcmd` is used to
+describe attributes of a specific command. If additional attributes don't need
+to be specified, a command to run can be specified directly in the `hook`
+section; if a `hookcmd` by that name isn't found, Git will attempt to run the
+provided value directly. For example:
+
+Global config
+----
+  [hook "post-commit"]
+    command = "linter"
+    command = "~/typocheck.sh"
+
+  [hookcmd "linter"]
+    command = "/bin/linter --c"
+----
+
+Local config
+----
+  [hook "prepare-commit-msg"]
+    command = "linter"
+  [hook "post-commit"]
+    command = "python ~/run-test-suite.py"
+----
+
+With these configs, you'd then run post-commit hooks in this order:
+
+  /bin/linter --c
+  ~/typocheck.sh
+  python ~/run-test-suite.py
+  .git/hooks/post-commit (if present)
+
+and prepare-commit-msg hooks in this order:
+
+  /bin/linter --c
+  .git/hooks/prepare-commit-msg (if present)
 
 In general, when instructions suggest adding a script to
 `.git/hooks/<something>`, you can specify it in the config instead by running
diff --git a/hook.c b/hook.c
index b08b876d5d..21904d90f6 100644
--- a/hook.c
+++ b/hook.c
@@ -184,7 +184,14 @@ static int hook_config_lookup(const char *key, const char *value, void *cb_data)
 
 		/* TODO: implement skipping hooks */
 
-		/* TODO: immplement hook aliases */
+		/*
+		 * Check if a hookcmd with that name exists. If it doesn't,
+		 * 'git_config_get_value()' is documented not to touch &command,
+		 * so we don't need to do anything.
+		 */
+		strbuf_reset(&hookcmd_name);
+		strbuf_addf(&hookcmd_name, "hookcmd.%s.command", command);
+		git_config_get_value(hookcmd_name.buf, &command);
 
 		/*
 		 * TODO: implement an option-getting callback, e.g.
diff --git a/t/t1360-config-based-hooks.sh b/t/t1360-config-based-hooks.sh
index e4a7b06ad1..50ee824f05 100755
--- a/t/t1360-config-based-hooks.sh
+++ b/t/t1360-config-based-hooks.sh
@@ -18,6 +18,11 @@ setup_hooks () {
 	test_config_global hook.pre-commit.command "/path/def" --add
 }
 
+setup_hookcmd () {
+	test_config hook.pre-commit.command "abc" --add
+	test_config_global hookcmd.abc.command "/path/abc" --add
+}
+
 setup_hookdir () {
 	mkdir .git/hooks
 	write_script .git/hooks/pre-commit <<-EOF
@@ -59,6 +64,20 @@ test_expect_success 'git hook list orders by config order' '
 	test_cmp expected actual
 '
 
+test_expect_success 'git hook list dereferences a hookcmd' '
+	setup_hooks &&
+	setup_hookcmd &&
+
+	cat >expected <<-EOF &&
+	$ROOT/path/def
+	$ROOT/path/ghi
+	$ROOT/path/abc
+	EOF
+
+	git hook list pre-commit >actual &&
+	test_cmp expected actual
+'
+
 test_expect_success 'git hook list reorders on duplicate commands' '
 	setup_hooks &&
 
-- 
2.32.0.402.g57bb445576-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