{"thread":{"id":"57496","subject":"[PATCH 00/10] tests: add and use a \"test_hook\" wrapper + hook fixes","startedAt":"2022-03-02T13:22:40Z","lastAt":"2022-03-17T21:40:24Z","messageCount":51,"participants":["Ævar Arnfjörð Bjarmason","Junio C Hamano","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":10},"messages":[{"id":"450089","messageId":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":null,"subject":"[PATCH 00/10] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:19Z","receivedAt":"2022-03-02T13:22:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is a test-only improvement series split up and adapted\nfrom a previous series of mine to add a \"git init --no-template\":\nhttps://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/\n\nAs the range-diff to that shows (with --creation-factor=50) all but\none commit changed too much for \"range-diff\" to show it by default.\n\nAt the end of this series we have a \"test_hook\" that behaves like the\nexisting \"test_config\", i.e. cleans up after itself (by default). See\n08/10.\n\nAs also explained in 08/10 this means that it'll be much easier to\nthoroughly test the \"config-based hooks\" series, as everything that\nnow writes hooks will go through this wrapper, and can be made to use\nthe config-based hooks.\n\nAlong the way I found various issues in existing tests that tested our\nhooks, and fixed those issues.there were variou\n\nÆvar Arnfjörð Bjarmason (10):\n  hook tests: turn exit code assertions into a loop\n  t5540: don't rely on \"hook/post-update.sample\"\n  tests: assume the hooks are disabled by default\n  bugreport tests: tighten up \"git bugreport -s hooks\" test\n  tests: indent and add hook setup to \"test_expect_success\"\n  hook tests: get rid of unnecessary sub-shells\n  fetch+push tests: have tests clean up their own mess\n  test-lib-functions: add and use a \"test_hook\" wrapper\n  tests: change \"mkdir -p && write_script\" to use \"test_hook\"\n  tests: change \"cat && chmod +x\" to use \"test_hook\"\n\n t/t0029-core-unsetenvvars.sh        |   3 +-\n t/t0091-bugreport.sh                |  20 +--\n t/t1350-config-hooks-path.sh        |   4 +-\n t/t1416-ref-transaction-hooks.sh    |  27 ++--\n t/t1800-hook.sh                     |  45 +++----\n t/t3404-rebase-interactive.sh       |  10 +-\n t/t3412-rebase-root.sh              |  18 +--\n t/t3413-rebase-hook.sh              |  18 +--\n t/t3430-rebase-merges.sh            |   6 +-\n t/t4150-am.sh                       |  24 +---\n t/t5401-update-hooks.sh             |  62 ++++-----\n t/t5402-post-merge-hook.sh          |  16 ++-\n t/t5403-post-checkout-hook.sh       |   3 +-\n t/t5406-remote-rejects.sh           |   2 +-\n t/t5407-post-rewrite-hook.sh        |  14 +-\n t/t5409-colorize-remote-messages.sh |   2 +-\n t/t5411-proc-receive-hook.sh        |   4 +-\n t/t5510-fetch.sh                    |   6 +-\n t/t5516-fetch-push.sh               | 192 +++++++++++++---------------\n t/t5521-pull-options.sh             |   4 +-\n t/t5534-push-signed.sh              |  26 ++--\n t/t5540-http-push-webdav.sh         |   4 +-\n t/t5541-http-push-smart.sh          |  22 ++--\n t/t5547-push-quarantine.sh          |   4 +-\n t/t5548-push-porcelain.sh           |   2 +-\n t/t5601-clone.sh                    |   4 +-\n t/t6500-gc.sh                       |  18 +--\n t/t7113-post-index-change-hook.sh   |   7 +-\n t/t7519-status-fsmonitor.sh         |  20 ++-\n t/t9001-send-email.sh               |   4 +-\n t/t9800-git-p4-basic.sh             |  23 ++--\n t/test-lib-functions.sh             |  52 ++++++++\n 32 files changed, 320 insertions(+), 346 deletions(-)\n\nRange-diff:\n 1:  5526d3dc838 <  -:  ----------- t0001: fix gaps in \"TEMPLATE DIRECTORY\" coverage\n 2:  ef2b67768cf <  -:  ----------- init: split out template population from create_default_files()\n 3:  784b7947512 <  -:  ----------- init: unconditionally create the \"info\" directory\n 4:  3d4ea5c5d30 <  -:  ----------- t0008: don't rely on default \".git/info/exclude\"\n 5:  6bbb39f13fc <  -:  ----------- init & clone: add a --no-template option\n 6:  2f478f7ba4a <  -:  ----------- init & clone: add init.templateDir=[bool]\n 7:  9402fb23b40 <  -:  ----------- test-lib: create test data with \"git init --no-template\" (almost)\n 8:  0c9b953dd43 <  -:  ----------- tests: don't depend on template-created .git/branches\n -:  ----------- >  1:  706460d10b9 hook tests: turn exit code assertions into a loop\n 9:  d97122f5fd8 !  2:  4bee939a894 t5540: don't rely on \"hook/post-update.sample\"\n    @@ t/t5540-http-push-webdav.sh: test_expect_success 'setup remote repository' '\n      \tcd test_repo.git &&\n      \tgit --bare update-server-info &&\n     -\tmv hooks/post-update.sample hooks/post-update &&\n    -+\twrite_script \"hooks/post-update\" <<-\\EOF &&\n    ++\twrite_script hooks/post-update <<-\\EOF &&\n     +\texec git update-server-info\n     +\tEOF\n      \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n10:  ca55471d134 <  -:  ----------- test-lib-functions: add and use a \"write_hook\" wrapper\n11:  6f805f7ebac <  -:  ----------- tests: change \"cat && chmod +x\" to use \"write_hook\"\n12:  2acbaa77f8d <  -:  ----------- tests: migrate miscellaneous \"write_script\" to \"write_hooks\"\n13:  d021a5981a1 <  -:  ----------- tests: don't depend on template-created .git/hooks\n -:  ----------- >  3:  0519102edeb tests: assume the hooks are disabled by default\n -:  ----------- >  4:  1da2efc9886 bugreport tests: tighten up \"git bugreport -s hooks\" test\n -:  ----------- >  5:  8dc478460ee tests: indent and add hook setup to \"test_expect_success\"\n -:  ----------- >  6:  d86ee06b46e hook tests: get rid of unnecessary sub-shells\n -:  ----------- >  7:  7ce22dbe738 fetch+push tests: have tests clean up their own mess\n -:  ----------- >  8:  d4102e9b929 test-lib-functions: add and use a \"test_hook\" wrapper\n -:  ----------- >  9:  1802158b14d tests: change \"mkdir -p && write_script\" to use \"test_hook\"\n -:  ----------- > 10:  7fef92872f3 tests: change \"cat && chmod +x\" to use \"test_hook\"\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450090","messageId":"patch-02.10-4bee939a894-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 02/10] t5540: don't rely on \"hook/post-update.sample\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:21Z","receivedAt":"2022-03-02T13:22:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code added in a87679339c0 (test: rename http fetch and push\ntest files, 2014-02-06) to stop relying on the \"exec git\nupdate-server-info\" in \"templates/hooks--post-update.sample\", let's\ninstead inline the expected hook in the test itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5540-http-push-webdav.sh | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh\nindex b0dbacf0b9b..380e97c1762 100755\n--- a/t/t5540-http-push-webdav.sh\n+++ b/t/t5540-http-push-webdav.sh\n@@ -42,7 +42,9 @@ test_expect_success 'setup remote repository' '\n \tgit clone --bare test_repo test_repo.git &&\n \tcd test_repo.git &&\n \tgit --bare update-server-info &&\n-\tmv hooks/post-update.sample hooks/post-update &&\n+\twrite_script hooks/post-update <<-\\EOF &&\n+\texec git update-server-info\n+\tEOF\n \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n \tcd - &&\n \tmv test_repo.git \"$HTTPD_DOCUMENT_ROOT_PATH\"\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450091","messageId":"patch-01.10-706460d10b9-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 01/10] hook tests: turn exit code assertions into a loop","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:20Z","receivedAt":"2022-03-02T13:22:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend a test added in 96e7225b310 (hook: add 'run' subcommand,\n2021-12-22) to use a for-loop instead of a copy/pasting the same test\nfor the four exit codes we test.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1800-hook.sh | 35 ++++++++++-------------------------\n 1 file changed, 10 insertions(+), 25 deletions(-)\n\ndiff --git a/t/t1800-hook.sh b/t/t1800-hook.sh\nindex 29718aa9913..ff64597e959 100755\n--- a/t/t1800-hook.sh\n+++ b/t/t1800-hook.sh\n@@ -53,31 +53,16 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n \ttest_must_be_empty stdout.actual\n '\n \n-test_expect_success 'git hook run: exit codes are passed along' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 1\n-\tEOF\n-\n-\ttest_expect_code 1 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 2\n-\tEOF\n-\n-\ttest_expect_code 2 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 128\n-\tEOF\n-\n-\ttest_expect_code 128 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 129\n-\tEOF\n-\n-\ttest_expect_code 129 git hook run test-hook\n-'\n+for code in 1 2 128 129\n+do\n+\ttest_expect_success \"git hook run: exit code $code is passed along\" '\n+\t\twrite_script .git/hooks/test-hook <<-EOF &&\n+\t\texit $code\n+\t\tEOF\n+\n+\t\ttest_expect_code $code git hook run test-hook\n+\t'\n+done\n \n test_expect_success 'git hook run arg u ments without -- is not allowed' '\n \ttest_expect_code 129 git hook run test-hook arg u ments\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450092","messageId":"patch-03.10-0519102edeb-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 03/10] tests: assume the hooks are disabled by default","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:22Z","receivedAt":"2022-03-02T13:22:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Stop moving the .git/hooks directory out of the way, or creating it\nduring test setup. Instead assume that it will contain\nharmless *.sample files.\n\nThat we can assume that is discussed in point #4 of\nf0d4d398e28 (test-lib: split up and deprecate test_create_repo(),\n2021-05-10).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1416-ref-transaction-hooks.sh | 1 -\n t/t5516-fetch-push.sh            | 3 +--\n t/t7519-status-fsmonitor.sh      | 2 --\n 3 files changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\nindex 4e1e84a91f3..d21dd5e5df0 100755\n--- a/t/t1416-ref-transaction-hooks.sh\n+++ b/t/t1416-ref-transaction-hooks.sh\n@@ -8,7 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n \n test_expect_success setup '\n-\tmkdir -p .git/hooks &&\n \ttest_commit PRE &&\n \tPRE_OID=$(git rev-parse PRE) &&\n \ttest_commit POST &&\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 3137eb8d4d2..1a20e54adc1 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -28,8 +28,7 @@ mk_empty () {\n \t(\n \t\tcd \"$repo_name\" &&\n \t\tgit init &&\n-\t\tgit config receive.denyCurrentBranch warn &&\n-\t\tmv .git/hooks .git/hooks-disabled\n+\t\tgit config receive.denyCurrentBranch warn\n \t)\n }\n \ndiff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\nindex a6308acf006..63a0f609866 100755\n--- a/t/t7519-status-fsmonitor.sh\n+++ b/t/t7519-status-fsmonitor.sh\n@@ -56,7 +56,6 @@ test_lazy_prereq UNTRACKED_CACHE '\n '\n \n test_expect_success 'setup' '\n-\tmkdir -p .git/hooks &&\n \t: >tracked &&\n \t: >modified &&\n \tmkdir dir1 &&\n@@ -322,7 +321,6 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'\n \ttest_create_repo dot-git &&\n \t(\n \t\tcd dot-git &&\n-\t\tmkdir -p .git/hooks &&\n \t\t: >tracked &&\n \t\t: >modified &&\n \t\tmkdir dir1 &&\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450093","messageId":"patch-04.10-1da2efc9886-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 04/10] bugreport tests: tighten up \"git bugreport -s hooks\" test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:23Z","receivedAt":"2022-03-02T13:22:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend a test added in 788a776069b (bugreport: collect list of\npopulated hooks, 2020-05-07) to make more sense. As noted in a\npreceding commit our .git/hooks directory already contains *.sample\nhooks, so we have no need to clobber the prepare-commit-msg.sample\nhook in particular.\n\nInstead we should assert that those *.sample hooks are not included in\nthe output, and for good measure let's add a new \"unknown-hook\", to\ncheck that we only look through our own known hooks. See\ncfe853e66be (hook-list.h: add a generated list of hooks, like\nconfig-list.h, 2021-09-26) for how we generate that data.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0091-bugreport.sh | 20 ++++++++++----------\n 1 file changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex eeedbfa9193..3025e685aaa 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -60,18 +60,18 @@ test_expect_success 'can create leading directories outside of a git dir' '\n \n test_expect_success 'indicates populated hooks' '\n \ttest_when_finished rm git-bugreport-hooks.txt &&\n-\ttest_when_finished rm -fr .git/hooks &&\n-\trm -fr .git/hooks &&\n-\tmkdir .git/hooks &&\n-\tfor hook in applypatch-msg prepare-commit-msg.sample\n-\tdo\n-\t\twrite_script \".git/hooks/$hook\" <<-EOF || return 1\n-\t\techo \"hook $hook exists\"\n-\t\tEOF\n-\tdone &&\n+\n+\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttrue\n+\tEOF\n+\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n+\ttrue\n+\tEOF\n \tgit bugreport -s hooks &&\n+\n \tgrep applypatch-msg git-bugreport-hooks.txt &&\n-\t! grep prepare-commit-msg git-bugreport-hooks.txt\n+\t! grep unknown-hook git-bugreport-hooks.txt &&\n+\t! grep -F .sample git-bugreport-hooks.txt\n '\n \n test_done\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450094","messageId":"patch-05.10-8dc478460ee-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 05/10] tests: indent and add hook setup to \"test_expect_success\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:24Z","receivedAt":"2022-03-02T13:22:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Indent various hook setup code in the test suite that's using a manual\n\"cat && chmod\" pattern.\n\nThese should also consistently use \"#!$SHELL_PATH\" instead of\n\"#!/bin/sh\", i.e. \"test_script\". Let's fix that in a subsequent\ncommit, which will be easier to review after this smaller change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3412-rebase-root.sh       | 16 ++++----\n t/t3413-rebase-hook.sh       | 16 ++++----\n t/t5401-update-hooks.sh      | 76 ++++++++++++++++++------------------\n t/t5407-post-rewrite-hook.sh | 16 ++++----\n t/t5541-http-push-smart.sh   | 24 ++++++------\n 5 files changed, 75 insertions(+), 73 deletions(-)\n\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 1e9f7833dd6..239a9343d34 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -32,10 +32,10 @@ test_expect_success 'rebase --root fails with too many args' '\n \n test_expect_success 'setup pre-rebase hook' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n cat > expect <<EOF\n@@ -142,10 +142,10 @@ EOF\n \n test_expect_success 'setup pre-rebase hook that fails' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-false\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\tfalse\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n \ndiff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh\nindex b4acb3be5cf..bb241b26b2e 100755\n--- a/t/t3413-rebase-hook.sh\n+++ b/t/t3413-rebase-hook.sh\n@@ -42,10 +42,10 @@ test_expect_success 'rebase -i' '\n \n test_expect_success 'setup pre-rebase hook' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n \n@@ -103,10 +103,10 @@ test_expect_success 'pre-rebase hook gets correct input (6)' '\n \n test_expect_success 'setup pre-rebase hook that fails' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-false\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\tfalse\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n \ndiff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh\nindex 6012cc8172a..6392f71795d 100755\n--- a/t/t5401-update-hooks.sh\n+++ b/t/t5401-update-hooks.sh\n@@ -20,46 +20,46 @@ test_expect_success setup '\n \tgit clone --bare ./. victim.git &&\n \tGIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&\n \tgit update-ref refs/heads/main $commit1 &&\n-\tgit update-ref refs/heads/tofail $commit0\n+\tgit update-ref refs/heads/tofail $commit0 &&\n+\n+\tcat >victim.git/hooks/pre-receive <<-\\EOF &&\n+\t#!/bin/sh\n+\tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n+\tcat - >$GIT_DIR/pre-receive.stdin\n+\techo STDOUT pre-receive\n+\techo STDERR pre-receive >&2\n+\tEOF\n+\tchmod u+x victim.git/hooks/pre-receive &&\n+\n+\tcat >victim.git/hooks/update <<-\\EOF &&\n+\t#!/bin/sh\n+\techo \"$@\" >>$GIT_DIR/update.args\n+\tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n+\techo STDOUT update $1\n+\techo STDERR update $1 >&2\n+\ttest \"$1\" = refs/heads/main || exit\n+\tEOF\n+\tchmod u+x victim.git/hooks/update &&\n+\n+\tcat >victim.git/hooks/post-receive <<-\\EOF &&\n+\t#!/bin/sh\n+\tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n+\tcat - >$GIT_DIR/post-receive.stdin\n+\techo STDOUT post-receive\n+\techo STDERR post-receive >&2\n+\tEOF\n+\tchmod u+x victim.git/hooks/post-receive &&\n+\n+\tcat >victim.git/hooks/post-update <<-\\EOF &&\n+\t#!/bin/sh\n+\techo \"$@\" >>$GIT_DIR/post-update.args\n+\tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n+\techo STDOUT post-update\n+\techo STDERR post-update >&2\n+\tEOF\n+\tchmod u+x victim.git/hooks/post-update\n '\n \n-cat >victim.git/hooks/pre-receive <<'EOF'\n-#!/bin/sh\n-printf %s \"$@\" >>$GIT_DIR/pre-receive.args\n-cat - >$GIT_DIR/pre-receive.stdin\n-echo STDOUT pre-receive\n-echo STDERR pre-receive >&2\n-EOF\n-chmod u+x victim.git/hooks/pre-receive\n-\n-cat >victim.git/hooks/update <<'EOF'\n-#!/bin/sh\n-echo \"$@\" >>$GIT_DIR/update.args\n-read x; printf %s \"$x\" >$GIT_DIR/update.stdin\n-echo STDOUT update $1\n-echo STDERR update $1 >&2\n-test \"$1\" = refs/heads/main || exit\n-EOF\n-chmod u+x victim.git/hooks/update\n-\n-cat >victim.git/hooks/post-receive <<'EOF'\n-#!/bin/sh\n-printf %s \"$@\" >>$GIT_DIR/post-receive.args\n-cat - >$GIT_DIR/post-receive.stdin\n-echo STDOUT post-receive\n-echo STDERR post-receive >&2\n-EOF\n-chmod u+x victim.git/hooks/post-receive\n-\n-cat >victim.git/hooks/post-update <<'EOF'\n-#!/bin/sh\n-echo \"$@\" >>$GIT_DIR/post-update.args\n-read x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n-echo STDOUT post-update\n-echo STDERR post-update >&2\n-EOF\n-chmod u+x victim.git/hooks/post-update\n-\n test_expect_success push '\n \ttest_must_fail git send-pack --force ./victim.git \\\n \t\tmain tofail >send.out 2>send.err\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 6da8d760e28..64f40ff7776 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -17,15 +17,15 @@ test_expect_success 'setup' '\n \tgit checkout A^0 &&\n \ttest_commit E bar E &&\n \ttest_commit F foo F &&\n-\tgit checkout main\n-'\n+\tgit checkout main &&\n \n-cat >.git/hooks/post-rewrite <<EOF\n-#!/bin/sh\n-echo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n-cat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n-EOF\n-chmod u+x .git/hooks/post-rewrite\n+\tcat >.git/hooks/post-rewrite <<-EOF &&\n+\t#!/bin/sh\n+\techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n+\tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n+\tEOF\n+\tchmod u+x .git/hooks/post-rewrite\n+'\n \n clear_hook_input () {\n \trm -f post-rewrite.args post-rewrite.data\ndiff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh\nindex 8ca50f8b18c..0043b718f08 100755\n--- a/t/t5541-http-push-smart.sh\n+++ b/t/t5541-http-push-smart.sh\n@@ -96,18 +96,20 @@ test_expect_success 'create and delete remote branch' '\n \ttest_must_fail git show-ref --verify refs/remotes/origin/dev\n '\n \n-cat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<EOF\n-#!/bin/sh\n-exit 1\n-EOF\n-chmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\"\n+test_expect_success 'setup rejected update hook' '\n+\tcat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<-EOF &&\n+\t#!/bin/sh\n+\texit 1\n+\tEOF\n+\tchmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" &&\n \n-cat >exp <<EOF\n-remote: error: hook declined to update refs/heads/dev2\n-To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git\n- ! [remote rejected] dev2 -> dev2 (hook declined)\n-error: failed to push some refs to 'http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\n-EOF\n+\tcat >exp <<-EOF\n+\tremote: error: hook declined to update refs/heads/dev2\n+\tTo http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git\n+\t ! [remote rejected] dev2 -> dev2 (hook declined)\n+\terror: failed to push some refs to '\\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\\''\n+\tEOF\n+'\n \n test_expect_success 'rejected update prints status' '\n \tcd \"$ROOT_PATH\"/test_repo_clone &&\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450095","messageId":"patch-06.10-d86ee06b46e-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 06/10] hook tests: get rid of unnecessary sub-shells","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:25Z","receivedAt":"2022-03-02T13:22:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the repository setup code for tests that test hooks the use\nof sub-shells when setting up the test repository and hooks.\n\nA subsequent commit will change the hook setup to use a helper that\nmakes use of \"test_when_finished\", which cannot be used in\nsub-shells. Let's change that setup code, and the adjacent and similar\n\"mk_empty\" code.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5516-fetch-push.sh   | 150 ++++++++++++++++++----------------------\n t/t6500-gc.sh           |  18 ++---\n t/t9800-git-p4-basic.sh |  24 ++++---\n 3 files changed, 94 insertions(+), 98 deletions(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 1a20e54adc1..e4bb7581568 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -24,12 +24,8 @@ D=$(pwd)\n mk_empty () {\n \trepo_name=\"$1\"\n \trm -fr \"$repo_name\" &&\n-\tmkdir \"$repo_name\" &&\n-\t(\n-\t\tcd \"$repo_name\" &&\n-\t\tgit init &&\n-\t\tgit config receive.denyCurrentBranch warn\n-\t)\n+\tgit init \"$repo_name\" &&\n+\tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n }\n \n mk_test () {\n@@ -58,36 +54,35 @@ mk_test () {\n mk_test_with_hooks() {\n \trepo_name=$1\n \tmk_test \"$@\" &&\n-\t(\n-\t\tcd \"$repo_name\" &&\n-\t\tmkdir .git/hooks &&\n-\t\tcd .git/hooks &&\n-\n-\t\tcat >pre-receive <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tcat - >>pre-receive.actual\n-\t\tEOF\n \n-\t\tcat >update <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n-\t\tEOF\n-\n-\t\tcat >post-receive <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tcat - >>post-receive.actual\n-\t\tEOF\n-\n-\t\tcat >post-update <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tfor ref in \"$@\"\n-\t\tdo\n-\t\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n-\t\tdone\n-\t\tEOF\n-\n-\t\tchmod +x pre-receive update post-receive post-update\n-\t)\n+\tcat >\"$repo_name\"/.git/hooks/pre-receive <<-'EOF' &&\n+\t#!/bin/sh\n+\tcat - >>pre-receive.actual\n+\tEOF\n+\n+\tcat >\"$repo_name\"/.git/hooks/update <<-'EOF' &&\n+\t#!/bin/sh\n+\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n+\tEOF\n+\n+\tcat >\"$repo_name\"/.git/hooks/post-receive <<-'EOF' &&\n+\t#!/bin/sh\n+\tcat - >>post-receive.actual\n+\tEOF\n+\n+\tcat >\"$repo_name\"/.git/hooks/post-update <<-'EOF' &&\n+\t#!/bin/sh\n+\tfor ref in \"$@\"\n+\tdo\n+\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n+\tdone\n+\tEOF\n+\n+\tchmod +x \\\n+\t      \"$repo_name\"/.git/hooks/pre-receive \\\n+\t      \"$repo_name\"/.git/hooks/update \\\n+\t      \"$repo_name\"/.git/hooks/post-receive \\\n+\t      \"$repo_name\"/.git/hooks/post-update\n }\n \n mk_child() {\n@@ -667,7 +662,6 @@ test_expect_success 'push does not update local refs on failure' '\n \n \tmk_test testrepo heads/main &&\n \tmk_child testrepo child &&\n-\tmkdir testrepo/.git/hooks &&\n \techo \"#!/no/frobnication/today\" >testrepo/.git/hooks/pre-receive &&\n \tchmod +x testrepo/.git/hooks/pre-receive &&\n \t(\n@@ -1679,24 +1673,21 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n test_expect_success 'updateInstead with push-to-checkout hook' '\n \trm -fr testrepo &&\n \tgit init testrepo &&\n-\t(\n-\t\tcd testrepo &&\n-\t\tgit pull .. main &&\n-\t\tgit reset --hard HEAD^^ &&\n-\t\tgit tag initial &&\n-\t\tgit config receive.denyCurrentBranch updateInstead &&\n-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n-\t\techo >&2 updating from $(git rev-parse HEAD)\n-\t\techo >&2 updating to \"$1\"\n-\n-\t\tgit update-index -q --refresh &&\n-\t\tgit read-tree -u -m HEAD \"$1\" || {\n-\t\t\tstatus=$?\n-\t\t\techo >&2 read-tree failed\n-\t\t\texit $status\n-\t\t}\n-\t\tEOF\n-\t) &&\n+\tgit -C testrepo pull .. main &&\n+\tgit -C testrepo reset --hard HEAD^^ &&\n+\tgit -C testrepo tag initial &&\n+\tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n+\twrite_script testrepo/.git/hooks/push-to-checkout <<-\\EOF &&\n+\techo >&2 updating from $(git rev-parse HEAD)\n+\techo >&2 updating to \"$1\"\n+\n+\tgit update-index -q --refresh &&\n+\tgit read-tree -u -m HEAD \"$1\" || {\n+\t\tstatus=$?\n+\t\techo >&2 read-tree failed\n+\t\texit $status\n+\t}\n+\tEOF\n \n \t# Try pushing into a pristine\n \tgit push testrepo main &&\n@@ -1741,33 +1732,30 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \t# push into void\n \trm -fr void &&\n \tgit init void &&\n-\t(\n-\t\tcd void &&\n-\t\tgit config receive.denyCurrentBranch updateInstead &&\n-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n-\t\tif git rev-parse --quiet --verify HEAD\n-\t\tthen\n-\t\t\thas_head=yes\n-\t\t\techo >&2 updating from $(git rev-parse HEAD)\n-\t\telse\n-\t\t\thas_head=no\n-\t\t\techo >&2 pushing into void\n-\t\tfi\n-\t\techo >&2 updating to \"$1\"\n-\n-\t\tgit update-index -q --refresh &&\n-\t\tcase \"$has_head\" in\n-\t\tyes)\n-\t\t\tgit read-tree -u -m HEAD \"$1\" ;;\n-\t\tno)\n-\t\t\tgit read-tree -u -m \"$1\" ;;\n-\t\tesac || {\n-\t\t\tstatus=$?\n-\t\t\techo >&2 read-tree failed\n-\t\t\texit $status\n-\t\t}\n-\t\tEOF\n-\t) &&\n+\tgit -C void config receive.denyCurrentBranch updateInstead &&\n+\twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n+\tif git rev-parse --quiet --verify HEAD\n+\tthen\n+\t\thas_head=yes\n+\t\techo >&2 updating from $(git rev-parse HEAD)\n+\telse\n+\t\thas_head=no\n+\t\techo >&2 pushing into void\n+\tfi\n+\techo >&2 updating to \"$1\"\n+\n+\tgit update-index -q --refresh &&\n+\tcase \"$has_head\" in\n+\tyes)\n+\t\tgit read-tree -u -m HEAD \"$1\" ;;\n+\tno)\n+\t\tgit read-tree -u -m \"$1\" ;;\n+\tesac || {\n+\t\tstatus=$?\n+\t\techo >&2 read-tree failed\n+\t\texit $status\n+\t}\n+\tEOF\n \n \tgit push void main &&\n \t(\ndiff --git a/t/t6500-gc.sh b/t/t6500-gc.sh\nindex c2021267f2c..a6b0db22867 100755\n--- a/t/t6500-gc.sh\n+++ b/t/t6500-gc.sh\n@@ -101,12 +101,12 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tEOF\n \n \tgit init pre-auto-gc-hook &&\n+\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\techo >&2 no gc for you &&\n+\texit 1\n+\tEOF\n \t(\n \t\tcd pre-auto-gc-hook &&\n-\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n-\t\techo >&2 no gc for you &&\n-\t\texit 1\n-\t\tEOF\n \n \t\tgit config gc.auto 3 &&\n \t\tgit config gc.autoDetach false &&\n@@ -128,12 +128,14 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tSee \"git help gc\" for manual housekeeping.\n \tEOF\n \n+\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\techo >&2 will gc for you &&\n+\texit 0\n+\tEOF\n+\n \t(\n \t\tcd pre-auto-gc-hook &&\n-\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n-\t\techo >&2 will gc for you &&\n-\t\texit 0\n-\t\tEOF\n+\n \t\tgit gc --auto >../out.actual 2>../err.actual\n \t) &&\n \ndiff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh\nindex 806005a793a..3c1534c94d6 100755\n--- a/t/t9800-git-p4-basic.sh\n+++ b/t/t9800-git-p4-basic.sh\n@@ -277,16 +277,22 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit commit -m \"add hello.txt\" &&\n \t\tgit config git-p4.skipSubmitEdit true &&\n \t\tgit p4 submit --dry-run >out &&\n-\t\tgrep \"Would apply\" out &&\n-\t\tmkdir -p .git/hooks &&\n-\t\twrite_script .git/hooks/p4-pre-submit <<-\\EOF &&\n-\t\texit 0\n-\t\tEOF\n+\t\tgrep \"Would apply\" out\n+\t) &&\n+\tmkdir -p \"$git\"/.git/hooks &&\n+\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\texit 0\n+\tEOF\n+\t(\n+\t\tcd \"$git\" &&\n \t\tgit p4 submit --dry-run >out &&\n-\t\tgrep \"Would apply\" out &&\n-\t\twrite_script .git/hooks/p4-pre-submit <<-\\EOF &&\n-\t\texit 1\n-\t\tEOF\n+\t\tgrep \"Would apply\" out\n+\t) &&\n+\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\texit 1\n+\tEOF\n+\t(\n+\t\tcd \"$git\" &&\n \t\ttest_must_fail git p4 submit --dry-run >errs 2>&1 &&\n \t\t! grep \"Would apply\" errs\n \t)\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450096","messageId":"patch-07.10-7ce22dbe738-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 07/10] fetch+push tests: have tests clean up their own mess","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:26Z","receivedAt":"2022-03-02T13:23:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"t5516-fetch-push.sh\" test code to make use of\n\"test_when_finished\" to remove data instead of having tests clean up\nleftover data from earlier tests, which may or may not be\nthere (e.g. depending on the --run=* option).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5516-fetch-push.sh | 50 +++++++++++++++++++++++++------------------\n 1 file changed, 29 insertions(+), 21 deletions(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex e4bb7581568..fbe0a72b0b2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -23,7 +23,8 @@ D=$(pwd)\n \n mk_empty () {\n \trepo_name=\"$1\"\n-\trm -fr \"$repo_name\" &&\n+\ttest_when_finished \"rm -rf \\\"$repo_name\\\"\" &&\n+\ttest_path_is_missing \"$repo_name\" &&\n \tgit init \"$repo_name\" &&\n \tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n }\n@@ -86,7 +87,7 @@ mk_test_with_hooks() {\n }\n \n mk_child() {\n-\trm -rf \"$2\" &&\n+\ttest_when_finished \"rm -rf \\\"$2\\\"\" &&\n \tgit clone \"$1\" \"$2\"\n }\n \n@@ -191,32 +192,32 @@ grep_wrote () {\n \tgrep 'write_pack_file/wrote.*\"value\":\"'$1'\"' $2\n }\n \n-test_expect_success 'push with negotiation' '\n-\t# Without negotiation\n+test_expect_success 'push without negotiation' '\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n-\techo now pushing without negotiation &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main &&\n-\tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n+\tgrep_wrote 5 event # 2 commits, 2 trees, 1 blob\n+'\n \n-\t# Same commands, but with negotiation\n-\trm event &&\n+test_expect_success 'push with negotiation' '\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main &&\n \tgrep_wrote 2 event # 1 commit, 1 tree\n '\n \n test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' '\n-\trm event &&\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT=\"$(pwd)/event\" \\\n \t\tgit -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&\n \tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n@@ -1323,7 +1324,7 @@ done\n \n test_expect_success 'fetch follows tags by default' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n \t(\n \t\tcd src &&\n@@ -1333,6 +1334,7 @@ test_expect_success 'fetch follows tags by default' '\n \t\tsed -n \"p; s|refs/heads/main$|refs/remotes/origin/main|p\" tmp1 |\n \t\tsort -k 3 >../expect\n \t) &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init dst &&\n \t(\n \t\tcd dst &&\n@@ -1358,8 +1360,9 @@ test_expect_success 'peeled advertisements are not considered ref tips' '\n \n test_expect_success 'pushing a specific ref applies remote.$name.push as refmap' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1382,8 +1385,9 @@ test_expect_success 'pushing a specific ref applies remote.$name.push as refmap'\n \n test_expect_success 'with no remote.$name.push, it is not used as refmap' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1404,8 +1408,9 @@ test_expect_success 'with no remote.$name.push, it is not used as refmap' '\n \n test_expect_success 'with no remote.$name.push, upstream mapping is used' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1433,8 +1438,9 @@ test_expect_success 'with no remote.$name.push, upstream mapping is used' '\n \n test_expect_success 'push does not follow tags by default' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1456,8 +1462,9 @@ test_expect_success 'push does not follow tags by default' '\n \n test_expect_success 'push --follow-tags only pushes relevant tags' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1495,9 +1502,9 @@ EOF\n '\n \n test_expect_success 'pushing a tag pushes the tagged object' '\n-\trm -rf dst.git &&\n \tblob=$(echo unreferenced | git hash-object -w --stdin) &&\n \tgit tag -m foo tag-of-blob $blob &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \tgit push dst.git tag-of-blob &&\n \t# the receiving index-pack should have noticed\n@@ -1508,7 +1515,7 @@ test_expect_success 'pushing a tag pushes the tagged object' '\n '\n \n test_expect_success 'push into bare respects core.logallrefupdates' '\n-\trm -rf dst.git &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \tgit -C dst.git config core.logallrefupdates true &&\n \n@@ -1526,7 +1533,7 @@ test_expect_success 'push into bare respects core.logallrefupdates' '\n '\n \n test_expect_success 'fetch into bare respects core.logallrefupdates' '\n-\trm -rf dst.git &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \t(\n \t\tcd dst.git &&\n@@ -1547,6 +1554,7 @@ test_expect_success 'fetch into bare respects core.logallrefupdates' '\n '\n \n test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n+\tmk_empty testrepo &&\n \tgit push testrepo main &&\n \t(\n \t\tcd testrepo &&\n@@ -1649,7 +1657,7 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n \t) &&\n \n \t# (5) push into void\n-\trm -fr void &&\n+\ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \t(\n \t\tcd void &&\n@@ -1671,7 +1679,7 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n '\n \n test_expect_success 'updateInstead with push-to-checkout hook' '\n-\trm -fr testrepo &&\n+\ttest_when_finished \"rm -rf testrepo\" &&\n \tgit init testrepo &&\n \tgit -C testrepo pull .. main &&\n \tgit -C testrepo reset --hard HEAD^^ &&\n@@ -1730,7 +1738,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \t) &&\n \n \t# push into void\n-\trm -fr void &&\n+\ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \tgit -C void config receive.denyCurrentBranch updateInstead &&\n \twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450098","messageId":"patch-10.10-7fef92872f3-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 10/10] tests: change \"cat && chmod +x\" to use \"test_hook\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:29Z","receivedAt":"2022-03-02T13:23:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various test code to use the \"test_hook\" helper. This change:\n\n - Fixes the long-standing issues with those tests using \"#!/bin/sh\"\n   instead of \"#!$SHELL_PATH\". Using \"#!/bin/sh\" here happened to work\n   because this code was so simply that it e.g. worked on Solaris\n   /bin/sh.\n\n - Removes the \"mkdir .git/hooks\" invocation, as explained in a\n   preceding commit we'll rely on the default templates to create that\n   directory for us.\n\nFor the test in \"t5402-post-merge-hook.sh\" it's easier and more\ncorrect to unroll the for-loop into a test_expect_success, so let's do\nthat.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3412-rebase-root.sh       | 12 +++---------\n t/t3413-rebase-hook.sh       | 12 +++---------\n t/t5401-update-hooks.sh      | 16 ++++------------\n t/t5402-post-merge-hook.sh   | 16 +++++++++-------\n t/t5407-post-rewrite-hook.sh |  4 +---\n t/t5516-fetch-push.sh        | 19 ++++---------------\n t/t5541-http-push-smart.sh   |  4 +---\n t/t5601-clone.sh             |  4 +---\n 8 files changed, 26 insertions(+), 61 deletions(-)\n\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 239a9343d34..58371d8a547 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -31,12 +31,9 @@ test_expect_success 'rebase --root fails with too many args' '\n '\n \n test_expect_success 'setup pre-rebase hook' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n-\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\ttest_hook --setup pre-rebase <<-\\EOF\n+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n cat > expect <<EOF\n 4\n@@ -141,12 +138,9 @@ commit work7~5\n EOF\n \n test_expect_success 'setup pre-rebase hook that fails' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n \tfalse\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n \n test_expect_success 'pre-rebase hook stops rebase' '\ndiff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh\nindex bb241b26b2e..9fab0d779bb 100755\n--- a/t/t3413-rebase-hook.sh\n+++ b/t/t3413-rebase-hook.sh\n@@ -41,12 +41,9 @@ test_expect_success 'rebase -i' '\n '\n \n test_expect_success 'setup pre-rebase hook' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n-\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\ttest_hook --setup pre-rebase <<-\\EOF\n+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n \n test_expect_success 'pre-rebase hook gets correct input (1)' '\n@@ -102,12 +99,9 @@ test_expect_success 'pre-rebase hook gets correct input (6)' '\n '\n \n test_expect_success 'setup pre-rebase hook that fails' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n \tfalse\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n \n test_expect_success 'pre-rebase hook stops rebase (1)' '\ndiff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh\nindex 6392f71795d..d5771b96114 100755\n--- a/t/t5401-update-hooks.sh\n+++ b/t/t5401-update-hooks.sh\n@@ -22,42 +22,34 @@ test_expect_success setup '\n \tgit update-ref refs/heads/main $commit1 &&\n \tgit update-ref refs/heads/tofail $commit0 &&\n \n-\tcat >victim.git/hooks/pre-receive <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git pre-receive <<-\\EOF &&\n \tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n \tcat - >$GIT_DIR/pre-receive.stdin\n \techo STDOUT pre-receive\n \techo STDERR pre-receive >&2\n \tEOF\n-\tchmod u+x victim.git/hooks/pre-receive &&\n \n-\tcat >victim.git/hooks/update <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git update <<-\\EOF &&\n \techo \"$@\" >>$GIT_DIR/update.args\n \tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n \techo STDOUT update $1\n \techo STDERR update $1 >&2\n \ttest \"$1\" = refs/heads/main || exit\n \tEOF\n-\tchmod u+x victim.git/hooks/update &&\n \n-\tcat >victim.git/hooks/post-receive <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git post-receive <<-\\EOF &&\n \tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n \tcat - >$GIT_DIR/post-receive.stdin\n \techo STDOUT post-receive\n \techo STDERR post-receive >&2\n \tEOF\n-\tchmod u+x victim.git/hooks/post-receive &&\n \n-\tcat >victim.git/hooks/post-update <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git post-update <<-\\EOF\n \techo \"$@\" >>$GIT_DIR/post-update.args\n \tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n \techo STDOUT post-update\n \techo STDERR post-update >&2\n \tEOF\n-\tchmod u+x victim.git/hooks/post-update\n '\n \n test_expect_success push '\ndiff --git a/t/t5402-post-merge-hook.sh b/t/t5402-post-merge-hook.sh\nindex 3e5e19c7191..915af2de95e 100755\n--- a/t/t5402-post-merge-hook.sh\n+++ b/t/t5402-post-merge-hook.sh\n@@ -25,13 +25,15 @@ test_expect_success setup '\n \tGIT_DIR=clone2/.git git update-index --add a\n '\n \n-for clone in 1 2; do\n-\tcat >clone${clone}/.git/hooks/post-merge <<'EOF'\n-#!/bin/sh\n-echo $@ >> $GIT_DIR/post-merge.args\n-EOF\n-\tchmod u+x clone${clone}/.git/hooks/post-merge\n-done\n+test_expect_success 'setup clone hooks' '\n+\ttest_when_finished \"rm -f hook\" &&\n+\tcat >hook <<-\\EOF &&\n+\techo $@ >>$GIT_DIR/post-merge.args\n+\tEOF\n+\n+\ttest_hook --setup -C clone1 post-merge <hook &&\n+\ttest_hook --setup -C clone2 post-merge <hook\n+'\n \n test_expect_success 'post-merge does not run for up-to-date ' '\n \tGIT_DIR=clone1/.git git merge $commit0 &&\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 64f40ff7776..5f3ff051ca2 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -19,12 +19,10 @@ test_expect_success 'setup' '\n \ttest_commit F foo F &&\n \tgit checkout main &&\n \n-\tcat >.git/hooks/post-rewrite <<-EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup post-rewrite <<-EOF\n \techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n \tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n \tEOF\n-\tchmod u+x .git/hooks/post-rewrite\n '\n \n clear_hook_input () {\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex b689baf01a9..4dfb080433e 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -55,35 +55,24 @@ mk_test () {\n mk_test_with_hooks() {\n \trepo_name=$1\n \tmk_test \"$@\" &&\n-\n-\tcat >\"$repo_name\"/.git/hooks/pre-receive <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" pre-receive <<-'EOF' &&\n \tcat - >>pre-receive.actual\n \tEOF\n \n-\tcat >\"$repo_name\"/.git/hooks/update <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" update <<-'EOF' &&\n \tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n \tEOF\n \n-\tcat >\"$repo_name\"/.git/hooks/post-receive <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" post-receive <<-'EOF' &&\n \tcat - >>post-receive.actual\n \tEOF\n \n-\tcat >\"$repo_name\"/.git/hooks/post-update <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" post-update <<-'EOF'\n \tfor ref in \"$@\"\n \tdo\n \t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n \tdone\n \tEOF\n-\n-\tchmod +x \\\n-\t      \"$repo_name\"/.git/hooks/pre-receive \\\n-\t      \"$repo_name\"/.git/hooks/update \\\n-\t      \"$repo_name\"/.git/hooks/post-receive \\\n-\t      \"$repo_name\"/.git/hooks/post-update\n }\n \n mk_child() {\ndiff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh\nindex 0043b718f08..ab4b5cfcd11 100755\n--- a/t/t5541-http-push-smart.sh\n+++ b/t/t5541-http-push-smart.sh\n@@ -97,11 +97,9 @@ test_expect_success 'create and delete remote branch' '\n '\n \n test_expect_success 'setup rejected update hook' '\n-\tcat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<-EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git\" update <<-\\EOF &&\n \texit 1\n \tEOF\n-\tchmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" &&\n \n \tcat >exp <<-EOF\n \tremote: error: hook declined to update refs/heads/dev2\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex 83c24fc97a7..4a61f2c901e 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -79,12 +79,10 @@ test_expect_success 'clone from hooks' '\n \tcd .. &&\n \tgit init r1 &&\n \tcd r1 &&\n-\tcat >.git/hooks/pre-commit <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook pre-commit <<-\\EOF &&\n \tgit clone ../r0 ../r2\n \texit 1\n \tEOF\n-\tchmod u+x .git/hooks/pre-commit &&\n \t: >file &&\n \tgit add file &&\n \ttest_must_fail git commit -m invoke-hook &&\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450097","messageId":"patch-08.10-d4102e9b929-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 08/10] test-lib-functions: add and use a \"test_hook\" wrapper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:27Z","receivedAt":"2022-03-02T13:23:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a \"test_hook\" wrapper similar to the existing \"test_config\"\nwrapper added in d960c47a881 (test-lib: add helper functions for\nconfig, 2011-08-17).\n\nThis wrapper:\n\n - Will clean up the hook with \"test_when_finished\", unless --setup is\n   provided.\n\n - Will error if we clobber a hook, unless --clobber is provided.\n\n - Takes a name like \"update\" instead of \".git/hooks/update\".\n\n - Accepts -C <dir>, like \"test_config\" and \"test_commit\".\n\nBy using a wrapper we'll be able to easily change all the hook-related\ncode that assumes that the template-created \".git/hooks\" directory is\ncreated by \"init\", \"clone\" etc. once another topic follows-up and\nchanges the test suite to stop creating trash directories using those\ntemplates.\n\nIn addition this will make it easy to have the hooks configured using\nthe \"configuration-based hooks\" topic, once we get around to\nintegrating that. I.e. we'll be able to run the tests in a mode where\nwe sometimes create a .git/hooks/<name>, and other times create a\nscript in another location, and point the relevant configuration\nsnippet to it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0091-bugreport.sh                |  4 +--\n t/t1416-ref-transaction-hooks.sh    | 26 +++++++--------\n t/t1800-hook.sh                     | 14 +++++---\n t/t5406-remote-rejects.sh           |  2 +-\n t/t5409-colorize-remote-messages.sh |  2 +-\n t/t5411-proc-receive-hook.sh        |  4 +--\n t/t5510-fetch.sh                    |  6 ++--\n t/t5516-fetch-push.sh               |  4 +--\n t/t5521-pull-options.sh             |  4 +--\n t/t5540-http-push-webdav.sh         |  2 +-\n t/t5547-push-quarantine.sh          |  4 +--\n t/t5548-push-porcelain.sh           |  2 +-\n t/t6500-gc.sh                       |  4 +--\n t/t7519-status-fsmonitor.sh         | 18 +++++-----\n t/test-lib-functions.sh             | 52 +++++++++++++++++++++++++++++\n 15 files changed, 101 insertions(+), 47 deletions(-)\n\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex 3025e685aaa..e4701da26aa 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -61,10 +61,10 @@ test_expect_success 'can create leading directories outside of a git dir' '\n test_expect_success 'indicates populated hooks' '\n \ttest_when_finished rm git-bugreport-hooks.txt &&\n \n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \ttrue\n \tEOF\n-\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n+\ttest_hook unknown-hook <<-\\EOF &&\n \ttrue\n \tEOF\n \tgit bugreport -s hooks &&\ndiff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\nindex d21dd5e5df0..085a7a46f21 100755\n--- a/t/t1416-ref-transaction-hooks.sh\n+++ b/t/t1416-ref-transaction-hooks.sh\n@@ -15,9 +15,8 @@ test_expect_success setup '\n '\n \n test_expect_success 'hook allows updating ref if successful' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$*\" >>actual\n \tEOF\n \tcat >expect <<-EOF &&\n@@ -29,9 +28,8 @@ test_expect_success 'hook allows updating ref if successful' '\n '\n \n test_expect_success 'hook aborts updating ref in prepared state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = prepared\n \t\tthen\n \t\t\texit 1\n@@ -42,9 +40,9 @@ test_expect_success 'hook aborts updating ref in prepared state' '\n '\n \n test_expect_success 'hook gets all queued updates in prepared state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = prepared\n \t\tthen\n \t\t\twhile read -r line\n@@ -65,9 +63,9 @@ test_expect_success 'hook gets all queued updates in prepared state' '\n '\n \n test_expect_success 'hook gets all queued updates in committed state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = committed\n \t\tthen\n \t\t\twhile read -r line\n@@ -85,9 +83,9 @@ test_expect_success 'hook gets all queued updates in committed state' '\n '\n \n test_expect_success 'hook gets all queued updates in aborted state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = aborted\n \t\tthen\n \t\t\twhile read -r line\n@@ -114,11 +112,11 @@ test_expect_success 'interleaving hook calls succeed' '\n \n \tgit init --bare target-repo.git &&\n \n-\twrite_script target-repo.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C target-repo.git reference-transaction <<-\\EOF &&\n \t\techo $0 \"$@\" >>actual\n \tEOF\n \n-\twrite_script target-repo.git/hooks/update <<-\\EOF &&\n+\ttest_hook -C target-repo.git update <<-\\EOF &&\n \t\techo $0 \"$@\" >>actual\n \tEOF\n \n@@ -139,7 +137,7 @@ test_expect_success 'hook does not get called on packing refs' '\n \t# Pack references first such that we are in a known state.\n \tgit pack-refs --all &&\n \n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$@\" >>actual\n \t\tcat >>actual\n \tEOF\n@@ -165,7 +163,7 @@ test_expect_success 'deleting packed ref calls hook once' '\n \tgit update-ref refs/heads/to-be-deleted $POST_OID &&\n \tgit pack-refs --all &&\n \n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$@\" >>actual\n \t\tcat >>actual\n \tEOF\ndiff --git a/t/t1800-hook.sh b/t/t1800-hook.sh\nindex ff64597e959..26ed5e11bc8 100755\n--- a/t/t1800-hook.sh\n+++ b/t/t1800-hook.sh\n@@ -27,7 +27,7 @@ test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '\n '\n \n test_expect_success 'git hook run: basic' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo Test hook\n \tEOF\n \n@@ -39,7 +39,7 @@ test_expect_success 'git hook run: basic' '\n '\n \n test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo >&1 Will end up on stderr\n \techo >&2 Will end up on stderr\n \tEOF\n@@ -56,7 +56,7 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n for code in 1 2 128 129\n do\n \ttest_expect_success \"git hook run: exit code $code is passed along\" '\n-\t\twrite_script .git/hooks/test-hook <<-EOF &&\n+\t\ttest_hook test-hook <<-EOF &&\n \t\texit $code\n \t\tEOF\n \n@@ -69,7 +69,7 @@ test_expect_success 'git hook run arg u ments without -- is not allowed' '\n '\n \n test_expect_success 'git hook run -- pass arguments' '\n-\twrite_script .git/hooks/test-hook <<-\\EOF &&\n+\ttest_hook test-hook <<-\\EOF &&\n \techo $1\n \techo $2\n \tEOF\n@@ -84,7 +84,7 @@ test_expect_success 'git hook run -- pass arguments' '\n '\n \n test_expect_success 'git hook run -- out-of-repo runs excluded' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo Test hook\n \tEOF\n \n@@ -105,6 +105,10 @@ test_expect_success 'git -c core.hooksPath=<PATH> hook run' '\n \tHook ran four\n \tEOF\n \n+\ttest_hook test-hook <<-EOF &&\n+\techo Test hook\n+\tEOF\n+\n \t# Test various ways of specifying the path. See also\n \t# t1350-config-hooks-path.sh\n \t>actual &&\ndiff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh\nindex 5c509db6fc3..dcbeb420827 100755\n--- a/t/t5406-remote-rejects.sh\n+++ b/t/t5406-remote-rejects.sh\n@@ -5,7 +5,7 @@ test_description='remote push rejects are reported by client'\n . ./test-lib.sh\n \n test_expect_success 'setup' '\n-\twrite_script .git/hooks/update <<-\\EOF &&\n+\ttest_hook update <<-\\EOF &&\n \texit 1\n \tEOF\n \techo 1 >file &&\ndiff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh\nindex 9f1a483f426..fa5de4500a4 100755\n--- a/t/t5409-colorize-remote-messages.sh\n+++ b/t/t5409-colorize-remote-messages.sh\n@@ -5,7 +5,7 @@ test_description='remote messages are colorized on the client'\n . ./test-lib.sh\n \n test_expect_success 'setup' '\n-\twrite_script .git/hooks/update <<-\\EOF &&\n+\ttest_hook --setup update <<-\\EOF &&\n \techo error: error\n \techo ERROR: also highlighted\n \techo hint: hint\ndiff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh\nindex 98b0e812082..92cf52c6d4a 100755\n--- a/t/t5411-proc-receive-hook.sh\n+++ b/t/t5411-proc-receive-hook.sh\n@@ -36,7 +36,7 @@ setup_upstream_and_workbench () {\n \t\tTAG=$(git -C workbench rev-parse v123) &&\n \n \t\t# setup pre-receive hook\n-\t\twrite_script upstream.git/hooks/pre-receive <<-\\EOF &&\n+\t\ttest_hook --setup -C upstream.git pre-receive <<-\\EOF &&\n \t\texec >&2\n \t\techo \"# pre-receive hook\"\n \t\twhile read old new ref\n@@ -46,7 +46,7 @@ setup_upstream_and_workbench () {\n \t\tEOF\n \n \t\t# setup post-receive hook\n-\t\twrite_script upstream.git/hooks/post-receive <<-\\EOF &&\n+\t\ttest_hook --setup -C upstream.git post-receive <<-\\EOF &&\n \t\texec >&2\n \t\techo \"# post-receive hook\"\n \t\twhile read old new ref\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex ef0da0a63b5..4620f0ca7fa 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -273,7 +273,7 @@ test_expect_success 'fetch --atomic executes a single reference transaction only\n \tEOF\n \n \trm -f atomic/actual &&\n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \tEOF\n \n@@ -306,7 +306,7 @@ test_expect_success 'fetch --atomic aborts all reference updates if hook aborts'\n \tEOF\n \n \trm -f atomic/actual &&\n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic/.git reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \t\texit 1\n \tEOF\n@@ -334,7 +334,7 @@ test_expect_success 'fetch --atomic --append appends to FETCH_HEAD' '\n \ttest_line_count = 2 atomic/.git/FETCH_HEAD &&\n \tcp atomic/.git/FETCH_HEAD expected &&\n \n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\texit 1\n \tEOF\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex fbe0a72b0b2..b689baf01a9 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -1685,7 +1685,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \tgit -C testrepo reset --hard HEAD^^ &&\n \tgit -C testrepo tag initial &&\n \tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n-\twrite_script testrepo/.git/hooks/push-to-checkout <<-\\EOF &&\n+\ttest_hook -C testrepo push-to-checkout <<-\\EOF &&\n \techo >&2 updating from $(git rev-parse HEAD)\n \techo >&2 updating to \"$1\"\n \n@@ -1741,7 +1741,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \tgit -C void config receive.denyCurrentBranch updateInstead &&\n-\twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n+\ttest_hook -C void push-to-checkout <<-\\EOF &&\n \tif git rev-parse --quiet --verify HEAD\n \tthen\n \t\thas_head=yes\ndiff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh\nindex 66cfcb09c55..264de29c35c 100755\n--- a/t/t5521-pull-options.sh\n+++ b/t/t5521-pull-options.sh\n@@ -233,7 +233,7 @@ test_expect_success 'git pull --no-verify flag passed to merge' '\n \tgit init src &&\n \ttest_commit -C src one &&\n \tgit clone src dst &&\n-\twrite_script dst/.git/hooks/commit-msg <<-\\EOF &&\n+\ttest_hook -C dst commit-msg <<-\\EOF &&\n \tfalse\n \tEOF\n \ttest_commit -C src two &&\n@@ -245,7 +245,7 @@ test_expect_success 'git pull --no-verify --verify passed to merge' '\n \tgit init src &&\n \ttest_commit -C src one &&\n \tgit clone src dst &&\n-\twrite_script dst/.git/hooks/commit-msg <<-\\EOF &&\n+\ttest_hook -C dst commit-msg <<-\\EOF &&\n \tfalse\n \tEOF\n \ttest_commit -C src two &&\ndiff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh\nindex 380e97c1762..37db3dec0c5 100755\n--- a/t/t5540-http-push-webdav.sh\n+++ b/t/t5540-http-push-webdav.sh\n@@ -42,7 +42,7 @@ test_expect_success 'setup remote repository' '\n \tgit clone --bare test_repo test_repo.git &&\n \tcd test_repo.git &&\n \tgit --bare update-server-info &&\n-\twrite_script hooks/post-update <<-\\EOF &&\n+\ttest_hook --setup post-update <<-\\EOF &&\n \texec git update-server-info\n \tEOF\n \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\ndiff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh\nindex faaa51ccc56..1876fb34e51 100755\n--- a/t/t5547-push-quarantine.sh\n+++ b/t/t5547-push-quarantine.sh\n@@ -5,7 +5,7 @@ test_description='check quarantine of objects during push'\n \n test_expect_success 'create picky dest repo' '\n \tgit init --bare dest.git &&\n-\twrite_script dest.git/hooks/pre-receive <<-\\EOF\n+\ttest_hook --setup -C dest.git pre-receive <<-\\EOF\n \twhile read old new ref; do\n \t\ttest \"$(git log -1 --format=%s $new)\" = reject && exit 1\n \tdone\n@@ -60,7 +60,7 @@ test_expect_success 'push to repo path with path separator (colon)' '\n \n test_expect_success 'updating a ref from quarantine is forbidden' '\n \tgit init --bare update.git &&\n-\twrite_script update.git/hooks/pre-receive <<-\\EOF &&\n+\ttest_hook -C update.git pre-receive <<-\\EOF &&\n \tread old new refname\n \tgit update-ref refs/heads/unrelated $new\n \texit 1\ndiff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh\nindex f11ff57e549..6282728eaf3 100755\n--- a/t/t5548-push-porcelain.sh\n+++ b/t/t5548-push-porcelain.sh\n@@ -168,7 +168,7 @@ run_git_push_porcelain_output_test() {\n \t'\n \n \ttest_expect_success \"prepare pre-receive hook ($PROTOCOL)\" '\n-\t\twrite_script \"$upstream/hooks/pre-receive\" <<-EOF\n+\t\ttest_hook --setup -C \"$upstream\" pre-receive <<-EOF\n \t\texit 1\n \t\tEOF\n \t'\ndiff --git a/t/t6500-gc.sh b/t/t6500-gc.sh\nindex a6b0db22867..39871b9901e 100755\n--- a/t/t6500-gc.sh\n+++ b/t/t6500-gc.sh\n@@ -101,7 +101,7 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tEOF\n \n \tgit init pre-auto-gc-hook &&\n-\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\ttest_hook -C pre-auto-gc-hook pre-auto-gc <<-\\EOF &&\n \techo >&2 no gc for you &&\n \texit 1\n \tEOF\n@@ -128,7 +128,7 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tSee \"git help gc\" for manual housekeeping.\n \tEOF\n \n-\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\ttest_hook -C pre-auto-gc-hook --clobber pre-auto-gc <<-\\EOF &&\n \techo >&2 will gc for you &&\n \texit 0\n \tEOF\ndiff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\nindex 63a0f609866..d8b0fc4681c 100755\n--- a/t/t7519-status-fsmonitor.sh\n+++ b/t/t7519-status-fsmonitor.sh\n@@ -26,7 +26,7 @@ dirty_repo () {\n }\n \n write_integration_script () {\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF\n+\ttest_hook --setup --clobber fsmonitor-test<<-\\EOF\n \tif test \"$#\" -ne 2\n \tthen\n \t\techo \"$0: exactly 2 arguments expected\"\n@@ -107,7 +107,7 @@ EOF\n \n # test that \"update-index --fsmonitor-valid\" sets the fsmonitor valid bit\n test_expect_success 'update-index --fsmonitor-valid\" sets the fsmonitor valid bit' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook fsmonitor-test<<-\\EOF &&\n \t\tprintf \"last_update_token\\0\"\n \tEOF\n \tgit update-index --fsmonitor &&\n@@ -168,7 +168,7 @@ EOF\n \n # test that newly added files are marked valid\n test_expect_success 'newly added files are marked valid' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --setup --clobber fsmonitor-test<<-\\EOF &&\n \t\tprintf \"last_update_token\\0\"\n \tEOF\n \tgit add new &&\n@@ -209,7 +209,7 @@ EOF\n \n # test that *only* files returned by the integration script get flagged as invalid\n test_expect_success '*only* files returned by the integration script get flagged as invalid' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \tprintf \"last_update_token\\0\"\n \tprintf \"dir1/modified\\0\"\n \tEOF\n@@ -230,7 +230,7 @@ test_expect_success 'refresh_index() invalidates fsmonitor cache' '\n \tdirty_repo &&\n \twrite_integration_script &&\n \tgit add . &&\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \tEOF\n \tgit commit -m \"to reset\" &&\n \tgit reset HEAD~1 &&\n@@ -279,7 +279,7 @@ do\n \t\t# Make sure it's actually skipping the check for modified and untracked\n \t\t# (if enabled) files unless it is told about them.\n \t\ttest_expect_success \"status doesn't detect unreported modifications\" '\n-\t\t\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\t\t\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\t:>marker\n \t\t\tEOF\n@@ -405,14 +405,14 @@ test_expect_success 'status succeeds with sparse index' '\n \t\tgit -C sparse sparse-checkout init --cone --sparse-index &&\n \t\tgit -C sparse sparse-checkout set dir1 dir2 &&\n \n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\tEOF\n \t\tgit -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&\n \t\tgit -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&\n \t\tcheck_sparse_index_behavior ! &&\n \n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\tprintf \"dir1/modified\\0\"\n \t\tEOF\n@@ -430,7 +430,7 @@ test_expect_success 'status succeeds with sparse index' '\n \n \t\t# This one modifies outside the sparse-checkout definition\n \t\t# and hence we expect to expand the sparse-index.\n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\tprintf \"dir1a/modified\\0\"\n \t\tEOF\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 85385d2ede7..0bef5913100 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -551,6 +551,58 @@ write_script () {\n \tchmod +x \"$1\"\n }\n \n+# Usage: test_hook [options] <hook-name> <<-\\EOF\n+#\n+#   -C <dir>:\n+#\tRun all git commands in directory <dir>\n+#   --setup\n+#\tSetup a hook for subsequent tests, i.e. don't remove it in a\n+#\t\"test_when_finished\"\n+#   --clobber\n+#\tOverwrite an existing <hook-name>, if it exists. Implies\n+#\t--setup (i.e. the \"test_when_finished\" is assumed to have been\n+#\tset up already).\n+test_hook () {\n+\tsetup= &&\n+\tclobber= &&\n+\tindir= &&\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-C)\n+\t\t\tindir=\"$2\" &&\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--setup)\n+\t\t\tsetup=t\n+\t\t\t;;\n+\t\t--clobber)\n+\t\t\tclobber=t\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tBUG \"invalid argument: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac &&\n+\t\tshift\n+\tdone &&\n+\n+\tgit_dir=$(git -C \"$indir\" rev-parse --absolute-git-dir) &&\n+\thook_dir=\"$git_dir/hooks\" &&\n+\thook_file=\"$hook_dir/$1\" &&\n+\tif test -z \"$clobber\"\n+\tthen\n+\t\ttest_path_is_missing \"$hook_file\"\n+\tfi &&\n+\tif test -z \"$setup$clobber\"\n+\tthen\n+\t\ttest_when_finished \"rm \\\"$hook_file\\\"\"\n+\tfi &&\n+\twrite_script \"$hook_file\"\n+}\n+\n # Use test_set_prereq to tell that a particular prerequisite is available.\n # The prerequisite can later be checked for in two ways:\n #\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450099","messageId":"patch-09.10-1802158b14d-20220302T131859Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH 09/10] tests: change \"mkdir -p && write_script\" to use \"test_hook\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-02T13:22:28Z","receivedAt":"2022-03-02T13:23:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change tests that used a \"mkdir -p .git/hooks && write_script\" pattern\nto use the new \"test_hook\" helper instead. The new helper does not\ncreate the .git/hooks directory, rather we assume that the default\ntemplate will do so for us.\n\nAn upcoming series[1] will extend \"test_hook\" to operate in a\n\"--template=\" mode, but for now assuming that we have a .git/hooks\nalready is a safe assumption. If that assumption becomes false in the\nfuture we'll only need to change 'test_hook\", instead of all of these\ncallsites.\n\n1. https://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0029-core-unsetenvvars.sh      |  3 +--\n t/t1350-config-hooks-path.sh      |  4 ++--\n t/t3404-rebase-interactive.sh     | 10 ++--------\n t/t3430-rebase-merges.sh          |  6 +++---\n t/t4150-am.sh                     | 24 ++++++------------------\n t/t5403-post-checkout-hook.sh     |  3 +--\n t/t5534-push-signed.sh            | 26 ++++++++------------------\n t/t7113-post-index-change-hook.sh |  7 +++----\n t/t9001-send-email.sh             |  4 +---\n t/t9800-git-p4-basic.sh           |  5 ++---\n 10 files changed, 29 insertions(+), 63 deletions(-)\n\ndiff --git a/t/t0029-core-unsetenvvars.sh b/t/t0029-core-unsetenvvars.sh\nindex b138e1d9cbc..4e8e90dd982 100755\n--- a/t/t0029-core-unsetenvvars.sh\n+++ b/t/t0029-core-unsetenvvars.sh\n@@ -12,8 +12,7 @@ then\n fi\n \n test_expect_success 'setup' '\n-\tmkdir -p \"$TRASH_DIRECTORY/.git/hooks\" &&\n-\twrite_script \"$TRASH_DIRECTORY/.git/hooks/pre-commit\" <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \techo $HOBBES >&2\n \tEOF\n '\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nindex fa9647a7c0b..f6dc83e2aab 100755\n--- a/t/t1350-config-hooks-path.sh\n+++ b/t/t1350-config-hooks-path.sh\n@@ -6,11 +6,11 @@ test_description='Test the core.hooksPath configuration variable'\n \n test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n \t>actual &&\n-\tmkdir -p .git/custom-hooks .git/hooks &&\n+\tmkdir -p .git/custom-hooks &&\n \twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n \techo CUSTOM >>actual\n \tEOF\n-\twrite_script .git/hooks/pre-commit <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \techo NORMAL >>actual\n \tEOF\n '\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex a38f2da7691..f31afd4a547 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -619,9 +619,7 @@ test_expect_success 'rebase a detached HEAD' '\n '\n \n test_expect_success 'rebase a commit violating pre-commit' '\n-\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n+\ttest_hook pre-commit <<-\\EOF &&\n \ttest -z \"$(git diff --cached --check)\"\n \tEOF\n \techo \"monde! \" >> file1 &&\n@@ -636,8 +634,6 @@ test_expect_success 'rebase a commit violating pre-commit' '\n '\n \n test_expect_success 'rebase with a file named HEAD in worktree' '\n-\n-\trm -fr .git/hooks &&\n \tgit reset --hard &&\n \tgit checkout -b branch3 A &&\n \n@@ -1688,10 +1684,8 @@ test_expect_success 'valid author header when author contains single quote' '\n '\n \n test_expect_success 'post-commit hook is called' '\n-\ttest_when_finished \"rm -f .git/hooks/post-commit\" &&\n \t>actual &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-commit <<-\\EOS &&\n+\ttest_hook post-commit <<-\\EOS &&\n \tgit rev-parse HEAD >>actual\n \tEOS\n \t(\ndiff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh\nindex 43c82d9a33b..f351701fec2 100755\n--- a/t/t3430-rebase-merges.sh\n+++ b/t/t3430-rebase-merges.sh\n@@ -292,9 +292,9 @@ test_expect_success 'post-rewrite hook and fixups work for merges' '\n \tgit commit --fixup HEAD same2.t &&\n \tfixup=\"$(git rev-parse HEAD)\" &&\n \n-\tmkdir -p .git/hooks &&\n-\ttest_when_finished \"rm .git/hooks/post-rewrite\" &&\n-\techo \"cat >actual\" | write_script .git/hooks/post-rewrite &&\n+\ttest_hook post-rewrite <<-\\EOF &&\n+\tcat >actual\n+\tEOF\n \n \ttest_tick &&\n \tgit rebase -i --autosquash -r HEAD^^^ &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 159fae8d016..cdad4b68807 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -315,12 +315,10 @@ test_expect_success 'am --patch-format=hg applies hg patch' '\n '\n \n test_expect_success 'am with applypatch-msg hook' '\n-\ttest_when_finished \"rm -f .git/hooks/applypatch-msg\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \tcat \"$1\" >actual-msg &&\n \techo hook-message >\"$1\"\n \tEOF\n@@ -335,12 +333,10 @@ test_expect_success 'am with applypatch-msg hook' '\n '\n \n test_expect_success 'am with failing applypatch-msg hook' '\n-\ttest_when_finished \"rm -f .git/hooks/applypatch-msg\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \texit 1\n \tEOF\n \ttest_must_fail git am patch1 &&\n@@ -350,12 +346,10 @@ test_expect_success 'am with failing applypatch-msg hook' '\n '\n \n test_expect_success 'am with pre-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/pre-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-applypatch <<-\\EOF &&\n+\ttest_hook pre-applypatch <<-\\EOF &&\n \tgit diff first >diff.actual\n \texit 0\n \tEOF\n@@ -368,12 +362,10 @@ test_expect_success 'am with pre-applypatch hook' '\n '\n \n test_expect_success 'am with failing pre-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/pre-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-applypatch <<-\\EOF &&\n+\ttest_hook pre-applypatch <<-\\EOF &&\n \texit 1\n \tEOF\n \ttest_must_fail git am patch1 &&\n@@ -383,12 +375,10 @@ test_expect_success 'am with failing pre-applypatch hook' '\n '\n \n test_expect_success 'am with post-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/post-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-applypatch <<-\\EOF &&\n+\ttest_hook post-applypatch <<-\\EOF &&\n \tgit rev-parse HEAD >head.actual\n \tgit diff second >diff.actual\n \texit 0\n@@ -403,12 +393,10 @@ test_expect_success 'am with post-applypatch hook' '\n '\n \n test_expect_success 'am with failing post-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/post-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-applypatch <<-\\EOF &&\n+\ttest_hook post-applypatch <<-\\EOF &&\n \tgit rev-parse HEAD >head.actual\n \texit 1\n \tEOF\ndiff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh\nindex d1181816906..978f240cdac 100755\n--- a/t/t5403-post-checkout-hook.sh\n+++ b/t/t5403-post-checkout-hook.sh\n@@ -10,8 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n \n test_expect_success setup '\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-checkout <<-\\EOF &&\n+\ttest_hook --setup post-checkout <<-\\EOF &&\n \techo \"$@\" >.git/post-checkout.args\n \tEOF\n \ttest_commit one &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 24d374adbae..7c0a148e73c 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -35,8 +35,7 @@ test_expect_success setup '\n \n test_expect_success 'unsigned push does not send push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -52,8 +51,7 @@ test_expect_success 'unsigned push does not send push certificate' '\n \n test_expect_success 'talking with a receiver without push certificate support' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -69,22 +67,19 @@ test_expect_success 'talking with a receiver without push certificate support' '\n \n test_expect_success 'push --signed fails with a receiver without push certificate support' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \ttest_must_fail git push --signed dst noop ff +noff 2>err &&\n \ttest_i18ngrep \"the receiving end does not support\" err\n '\n \n test_expect_success 'push --signed=1 is accepted' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \ttest_must_fail git push --signed=1 dst noop ff +noff 2>err &&\n \ttest_i18ngrep \"the receiving end does not support\" err\n '\n \n test_expect_success GPG 'no certificate for a signed push with no update' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \tif test -n \"${GIT_PUSH_CERT-}\"\n \tthen\n \t\tgit cat-file blob $GIT_PUSH_CERT >../push-cert\n@@ -96,9 +91,8 @@ test_expect_success GPG 'no certificate for a signed push with no update' '\n \n test_expect_success GPG 'signed push sends push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -139,10 +133,9 @@ test_expect_success GPG 'signed push sends push certificate' '\n \n test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config gpg.ssh.allowedSignersFile \"${GPGSSH_ALLOWED_SIGNERS}\" &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -223,9 +216,8 @@ test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \n test_expect_success GPG 'fail without key and heed user.signingkey' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -273,9 +265,8 @@ test_expect_success GPG 'fail without key and heed user.signingkey' '\n test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '\n \ttest_config gpg.format x509 &&\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -326,10 +317,9 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '\n test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' '\n \ttest_config gpg.format ssh &&\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config gpg.ssh.allowedSignersFile \"${GPGSSH_ALLOWED_SIGNERS}\" &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\ndiff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh\nindex a21781d68a1..58e55a7c779 100755\n--- a/t/t7113-post-index-change-hook.sh\n+++ b/t/t7113-post-index-change-hook.sh\n@@ -17,8 +17,7 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n \t\t\texit 1\n@@ -63,7 +62,7 @@ test_expect_success 'test status, add, commit, others trigger hook without flags\n '\n \n test_expect_success 'test checkout and reset trigger the hook' '\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n \t\t\texit 1\n@@ -106,7 +105,7 @@ test_expect_success 'test checkout and reset trigger the hook' '\n '\n \n test_expect_success 'test reset --mixed and update-index triggers the hook' '\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n \t\t\texit 1\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 84d0f40d76a..42694fe5841 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2288,9 +2288,7 @@ test_expect_success $PREREQ 'cmdline in-reply-to used with --no-thread' '\n '\n \n test_expect_success $PREREQ 'invoke hook' '\n-\tmkdir -p .git/hooks &&\n-\n-\twrite_script .git/hooks/sendemail-validate <<-\\EOF &&\n+\ttest_hook sendemail-validate <<-\\EOF &&\n \t# test that we have the correct environment variable, pwd, and\n \t# argument\n \tcase \"$GIT_DIR\" in\ndiff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh\nindex 3c1534c94d6..8b30062c0cf 100755\n--- a/t/t9800-git-p4-basic.sh\n+++ b/t/t9800-git-p4-basic.sh\n@@ -279,8 +279,7 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit p4 submit --dry-run >out &&\n \t\tgrep \"Would apply\" out\n \t) &&\n-\tmkdir -p \"$git\"/.git/hooks &&\n-\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\ttest_hook -C \"$git\" p4-pre-submit <<-\\EOF &&\n \texit 0\n \tEOF\n \t(\n@@ -288,7 +287,7 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit p4 submit --dry-run >out &&\n \t\tgrep \"Would apply\" out\n \t) &&\n-\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\ttest_hook -C \"$git\" --clobber p4-pre-submit <<-\\EOF &&\n \texit 1\n \tEOF\n \t(\n-- \n2.35.1.1228.g56895c6ee86\n\n"},{"id":"450170","messageId":"xmqqlexsjcrc.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-01.10-706460d10b9-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 01/10] hook tests: turn exit code assertions into a loop","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T20:55:03Z","receivedAt":"2022-03-02T20:55:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Amend a test added in 96e7225b310 (hook: add 'run' subcommand,\n> 2021-12-22) to use a for-loop instead of a copy/pasting the same test\n> for the four exit codes we test.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t1800-hook.sh | 35 ++++++++++-------------------------\n>  1 file changed, 10 insertions(+), 25 deletions(-)\n> ...\n> +for code in 1 2 128 129\n> +do\n> +\ttest_expect_success \"git hook run: exit code $code is passed along\" '\n> +\t\twrite_script .git/hooks/test-hook <<-EOF &&\n> +\t\texit $code\n> +\t\tEOF\n> +\n> +\t\ttest_expect_code $code git hook run test-hook\n> +\t'\n> +done\n\nLooks good.  Each being separate test_expect_success means we do not\nhave to worry about breaking out of the loop upon a failure, which\nis much cleaner than I would have thought ;-)\n\nIt also illustrates a good use of unquoted here document.\n"},{"id":"450172","messageId":"xmqqh78gjc81.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-02.10-4bee939a894-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 02/10] t5540: don't rely on \"hook/post-update.sample\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:06:38Z","receivedAt":"2022-03-02T21:06:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change code added in a87679339c0 (test: rename http fetch and push\n> test files, 2014-02-06) to stop relying on the \"exec git\n> update-server-info\" in \"templates/hooks--post-update.sample\", let's\n> instead inline the expected hook in the test itself.\n\nFor this particular hook, it indeed is a good change, as future\npost-update samples we ship may have something quite different.\n\nI do not know if it is a good idea in general, though.  We want\nto promise shipping certain sample scripts as part of the default\ninstall, and the default install is what our tests check.  We want\nto keep something that ensures the default install does ship the\nsample we want to include, and such tests do need to rely on the\npresence of .sample files.  But this script does not need to be\nthe one to do so.\n\n>  \tgit --bare update-server-info &&\n> -\tmv hooks/post-update.sample hooks/post-update &&\n> +\twrite_script hooks/post-update <<-\\EOF &&\n> +\texec git update-server-info\n> +\tEOF\n>  \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n>  \tcd - &&\n>  \tmv test_repo.git \"$HTTPD_DOCUMENT_ROOT_PATH\"\n\nOK.\n\nWe might want to deprecate and remove the support for dumb walkers,\nbut until then, this looks superb.\n\nThanks.\n\n"},{"id":"450174","messageId":"xmqq8rtsjbww.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-03.10-0519102edeb-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 03/10] tests: assume the hooks are disabled by default","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:13:19Z","receivedAt":"2022-03-02T21:14:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Stop moving the .git/hooks directory out of the way, or creating it\n> during test setup. Instead assume that it will contain\n> harmless *.sample files.\n\nMakes sense.  We ship sample files and no activated hooks in the\ndefault install, and we do want to assume that in most of our tests\n(except for ones that validate that asssumptions, of course).\n\n> diff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\n> index 4e1e84a91f3..d21dd5e5df0 100755\n> --- a/t/t1416-ref-transaction-hooks.sh\n> +++ b/t/t1416-ref-transaction-hooks.sh\n> @@ -8,7 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n>  . ./test-lib.sh\n>  \n>  test_expect_success setup '\n> -\tmkdir -p .git/hooks &&\n\nInteresting.  This becomes part of the tests that validate the\nassumption that we do ship the hooks/ directory with sample files\n;-)\n\n>  \ttest_commit PRE &&\n>  \tPRE_OID=$(git rev-parse PRE) &&\n>  \ttest_commit POST &&\n> diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\n> index 3137eb8d4d2..1a20e54adc1 100755\n> --- a/t/t5516-fetch-push.sh\n> +++ b/t/t5516-fetch-push.sh\n> @@ -28,8 +28,7 @@ mk_empty () {\n>  \t(\n>  \t\tcd \"$repo_name\" &&\n>  \t\tgit init &&\n> -\t\tgit config receive.denyCurrentBranch warn &&\n> -\t\tmv .git/hooks .git/hooks-disabled\n> +\t\tgit config receive.denyCurrentBranch warn\n>  \t)\n>  }\n\nGood.\n\n> diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\n> index a6308acf006..63a0f609866 100755\n> --- a/t/t7519-status-fsmonitor.sh\n> +++ b/t/t7519-status-fsmonitor.sh\n> @@ -56,7 +56,6 @@ test_lazy_prereq UNTRACKED_CACHE '\n>  '\n>  \n>  test_expect_success 'setup' '\n> -\tmkdir -p .git/hooks &&\n>  \t: >tracked &&\n>  \t: >modified &&\n>  \tmkdir dir1 &&\n> @@ -322,7 +321,6 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'\n>  \ttest_create_repo dot-git &&\n>  \t(\n>  \t\tcd dot-git &&\n> -\t\tmkdir -p .git/hooks &&\n>  \t\t: >tracked &&\n>  \t\t: >modified &&\n>  \t\tmkdir dir1 &&\n\nNice.  Presumably these should have been done when we stopped\nmucking with hooks-disabled in test_create_repo helper but we\nforgot to do so, and these are the only remaining bits?\n\nThanks for tying the loose ends.\n\n"},{"id":"450175","messageId":"xmqqzgm8hwwc.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-04.10-1da2efc9886-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 04/10] bugreport tests: tighten up \"git bugreport -s hooks\" test","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:22:59Z","receivedAt":"2022-03-02T21:23:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n> +\ttrue\n> +\tEOF\n> +\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n> +\ttrue\n> +\tEOF\n>  \tgit bugreport -s hooks &&\n> +\n>  \tgrep applypatch-msg git-bugreport-hooks.txt &&\n> -\t! grep prepare-commit-msg git-bugreport-hooks.txt\n> +\t! grep unknown-hook git-bugreport-hooks.txt &&\n> +\t! grep -F .sample git-bugreport-hooks.txt\n>  '\n\nThe above is not wrong per-se, but because we control which hooks\nare and are not visible to \"git bugreport\" we run in this test, I\nwonder if we should do\n\n\tgit bugreport -s tmp &&\n\tsed -ne '/^\\[Enabled Hooks\\]$/,/^$/p' git-bugreport-tmp.txt |\n\tsort >actual &&\n\tsort >expect <<-\\EOF &&\n\t[Enabled Hooks]\n\tapplypatch-msg\n\tEOF\n\ttest_cmp expect actual\n\ninstead.  It is not like checking the \"git help -a\" output for list\nof commands, which may grow or shrink as the system evolves.\n\n"},{"id":"450176","messageId":"xmqqv8wwhwpe.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-05.10-8dc478460ee-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 05/10] tests: indent and add hook setup to \"test_expect_success\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:27:09Z","receivedAt":"2022-03-02T21:27:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Indent various hook setup code in the test suite that's using a manual\n> \"cat && chmod\" pattern.\n>\n> These should also consistently use \"#!$SHELL_PATH\" instead of\n> \"#!/bin/sh\", i.e. \"test_script\". Let's fix that in a subsequent\n> commit, which will be easier to review after this smaller change.\n\nThese do move them in the right direction, but I am not sure if a\nstep-wise \"first we do <<- trick to kill unindented mess, and then\nanother \"use write_script\" to touch the same places, consuming twice\nthe reviewer bandwidth.  I certainly would hate to have to see these\nlines twice X-<.\n\n"},{"id":"450178","messageId":"xmqqo82ohwih.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-06.10-d86ee06b46e-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 06/10] hook tests: get rid of unnecessary sub-shells","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:31:18Z","receivedAt":"2022-03-02T21:31:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Refactor the repository setup code for tests that test hooks the use\n> of sub-shells when setting up the test repository and hooks.\n>\n> A subsequent commit will change the hook setup to use a helper that\n> makes use of \"test_when_finished\", which cannot be used in\n> sub-shells. Let's change that setup code, and the adjacent and similar\n> \"mk_empty\" code.\n\nMakes sense.\n\n> diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\n> index 1a20e54adc1..e4bb7581568 100755\n> --- a/t/t5516-fetch-push.sh\n> +++ b/t/t5516-fetch-push.sh\n> @@ -24,12 +24,8 @@ D=$(pwd)\n>  mk_empty () {\n>  \trepo_name=\"$1\"\n>  \trm -fr \"$repo_name\" &&\n> -\tmkdir \"$repo_name\" &&\n> -\t(\n> -\t\tcd \"$repo_name\" &&\n> -\t\tgit init &&\n> -\t\tgit config receive.denyCurrentBranch warn\n> -\t)\n> +\tgit init \"$repo_name\" &&\n> +\tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n>  }\n\nI thought of this exact change when I saw a change to this part in\nthis series in an earlier step.  Excellent.\n\n"},{"id":"450181","messageId":"xmqqczj4hvx4.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-07.10-7ce22dbe738-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 07/10] fetch+push tests: have tests clean up their own mess","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:44:07Z","receivedAt":"2022-03-02T21:44:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the \"t5516-fetch-push.sh\" test code to make use of\n> \"test_when_finished\" to remove data instead of having tests clean up\n> leftover data from earlier tests, which may or may not be\n> there (e.g. depending on the --run=* option).\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t5516-fetch-push.sh | 50 +++++++++++++++++++++++++------------------\n>  1 file changed, 29 insertions(+), 21 deletions(-)\n>\n> diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\n> index e4bb7581568..fbe0a72b0b2 100755\n> --- a/t/t5516-fetch-push.sh\n> +++ b/t/t5516-fetch-push.sh\n> @@ -23,7 +23,8 @@ D=$(pwd)\n>  \n>  mk_empty () {\n>  \trepo_name=\"$1\"\n> -\trm -fr \"$repo_name\" &&\n> +\ttest_when_finished \"rm -rf \\\"$repo_name\\\"\" &&\n\nAny justification to swap between fr and rf?\n\n> +\ttest_path_is_missing \"$repo_name\" &&\n\nSo, the idea is that the philosophy so far was that each test clears\nwhatever the mess the previous ones created and empties what it cares\nto be empty with \"rm -fr\", but now in the new world order, each test\nrelies on test_when_finished to clear any and all effects it leaves\nto the environment?\n\nOK.  Since the clearing the \"effects\" is to remove the whole thing,\nthere is little room for such a plan to go wrong.\n\n> @@ -191,32 +192,32 @@ grep_wrote () {\n>  \tgrep 'write_pack_file/wrote.*\"value\":\"'$1'\"' $2\n>  }\n>  \n> -test_expect_success 'push with negotiation' '\n> -\t# Without negotiation\n\n;-)\n\n> +test_expect_success 'push without negotiation' '\n>  \tmk_empty testrepo &&\n>  \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n>  \ttest_commit -C testrepo unrelated_commit &&\n>  \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n> -\techo now pushing without negotiation &&\n> +\ttest_when_finished \"rm event\" &&\n>  \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main &&\n> -\tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n> +\tgrep_wrote 5 event # 2 commits, 2 trees, 1 blob\n> +'\n>  \n> -\t# Same commands, but with negotiation\n> -\trm event &&\n\nGood to split them into two.  Presumably the later part wasn't\nrelying on the leftover side effects created by the early part?\n\nThanks.  Looking good.\n"},{"id":"450182","messageId":"xmqq1qzkhv87.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-08.10-d4102e9b929-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 08/10] test-lib-functions: add and use a \"test_hook\" wrapper","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T21:59:04Z","receivedAt":"2022-03-02T21:59:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> @@ -430,7 +430,7 @@ test_expect_success 'status succeeds with sparse index' '\n>  \n>  \t\t# This one modifies outside the sparse-checkout definition\n>  \t\t# and hence we expect to expand the sparse-index.\n> -\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n> +\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n>  \t\t\tprintf \"last_update_token\\0\"\n>  \t\t\tprintf \"dir1a/modified\\0\"\n>  \t\tEOF\n\nThese look almost trivial (the --setup part is somewhat trickier\nthan the rest), thanks to the use of write_script.\n\nIt would have been even cleaner if we jumped from \"unindented\ncat && chmod +x\" directly to \"use write_script\" in one of the\nearlier steps, which would have reduced the need for the last step\nin the series.\n\n> diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\n> index 85385d2ede7..0bef5913100 100644\n> --- a/t/test-lib-functions.sh\n> +++ b/t/test-lib-functions.sh\n> @@ -551,6 +551,58 @@ write_script () {\n>  \tchmod +x \"$1\"\n>  }\n>  \n> +# Usage: test_hook [options] <hook-name> <<-\\EOF\n> +#\n> +#   -C <dir>:\n> +#\tRun all git commands in directory <dir>\n> +#   --setup\n> +#\tSetup a hook for subsequent tests, i.e. don't remove it in a\n> +#\t\"test_when_finished\"\n> +#   --clobber\n> +#\tOverwrite an existing <hook-name>, if it exists. Implies\n> +#\t--setup (i.e. the \"test_when_finished\" is assumed to have been\n> +#\tset up already).\n\nOK.\n\nWe aspire to make everybody use test_hook, so the fact that we have\nto clobber means somebody else made the right choice to either use\nor not use --setup to create it, and we do not have to (re)arrange\nit to be removed later, hence it makes perfect sense for --clobber\nto imply --setup.\n\nLooking good.\n\n\n> +test_hook () {\n> +\tsetup= &&\n> +\tclobber= &&\n> +\tindir= &&\n> +\twhile test $# != 0\n> +\tdo\n> +\t\tcase \"$1\" in\n> +\t\t-C)\n> +\t\t\tindir=\"$2\" &&\n> +\t\t\tshift\n> +\t\t\t;;\n> +\t\t--setup)\n> +\t\t\tsetup=t\n> +\t\t\t;;\n> +\t\t--clobber)\n> +\t\t\tclobber=t\n> +\t\t\t;;\n> +\t\t-*)\n> +\t\t\tBUG \"invalid argument: $1\"\n> +\t\t\t;;\n> +\t\t*)\n> +\t\t\tbreak\n> +\t\t\t;;\n> +\t\tesac &&\n> +\t\tshift\n> +\tdone &&\n> +\n> +\tgit_dir=$(git -C \"$indir\" rev-parse --absolute-git-dir) &&\n> +\thook_dir=\"$git_dir/hooks\" &&\n> +\thook_file=\"$hook_dir/$1\" &&\n> +\tif test -z \"$clobber\"\n> +\tthen\n> +\t\ttest_path_is_missing \"$hook_file\"\n> +\tfi &&\n> +\tif test -z \"$setup$clobber\"\n> +\tthen\n> +\t\ttest_when_finished \"rm \\\"$hook_file\\\"\"\n> +\tfi &&\n> +\twrite_script \"$hook_file\"\n> +}\n> +\n>  # Use test_set_prereq to tell that a particular prerequisite is available.\n>  # The prerequisite can later be checked for in two ways:\n>  #\n"},{"id":"450183","messageId":"xmqqwnhcggbk.fsf@gitster.g","threadId":"57496","inReplyTo":"patch-09.10-1802158b14d-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 09/10] tests: change \"mkdir -p && write_script\" to use \"test_hook\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T22:06:23Z","receivedAt":"2022-03-02T22:06:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change tests that used a \"mkdir -p .git/hooks && write_script\" pattern\n\nHmph, it is a bit sad that \"mkdir -p\" weren't removed as part of\nan earlier [03/10].\n\nThe end result looked sensible.\n"},{"id":"450189","messageId":"xmqqsfs0getx.fsf@gitster.g","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 00/10] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-02T22:38:34Z","receivedAt":"2022-03-02T22:38:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> This series is a test-only improvement series split up and adapted\n> from a previous series of mine to add a \"git init --no-template\":\n> https://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/\n\nI looked at all the steps and left some comments; overall the end\nresult was a pleasant read, even though the progression felt some\nimprovements were needed.\n\nThanks.\n"},{"id":"450243","messageId":"CAPig+cRfb7AuJK-NhkdAV6P52HviSFqJXB9kvDpmtTYd=yJSUQ@mail.gmail.com","threadId":"57496","inReplyTo":"patch-10.10-7fef92872f3-20220302T131859Z-avarab@gmail.com","subject":"Re: [PATCH 10/10] tests: change \"cat && chmod +x\" to use \"test_hook\"","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2022-03-03T05:46:16Z","receivedAt":"2022-03-03T05:48:46Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Mar 2, 2022 at 8:22 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> Refactor various test code to use the \"test_hook\" helper. This change:\n>\n>  - Fixes the long-standing issues with those tests using \"#!/bin/sh\"\n>    instead of \"#!$SHELL_PATH\". Using \"#!/bin/sh\" here happened to work\n>    because this code was so simply that it e.g. worked on Solaris\n>    /bin/sh.\n\ns/simply/simple/\n\n>  - Removes the \"mkdir .git/hooks\" invocation, as explained in a\n>    preceding commit we'll rely on the default templates to create that\n>    directory for us.\n>\n> For the test in \"t5402-post-merge-hook.sh\" it's easier and more\n> correct to unroll the for-loop into a test_expect_success, so let's do\n> that.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"},{"id":"450541","messageId":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com","subject":"[PATCH v2 00/10] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:31Z","receivedAt":"2022-03-07T12:43:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is a test-only improvement series split up and adapted\nfrom a previous series of mine to add a \"git init --no-template\":\nhttps://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/;\nFor v1 see:\nhttps://lore.kernel.org/git/cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com/\n\nChanges since v1:\n\n * Fixed typo/grammer pointed out by Eric Sunshine.\n * Various commit message fixes/clarifications etc. to address Junio's\n   comments.\n * Tightened up the \"git bugreport test\" even more\n\nJunio also suggested re-arranging this to do this migration in fewer\nsteps. I started doing that but doing so would have taken a lot of\ntime solving conflicts, re-writing commits etc. I think given that\nthere's agreement on the end-state that doing so wasn't worth the time\nI'd spend on it, or for reviewers in having to review the really large\nresulting range-diff. So hopefully this version is acceptable to\nadvance...\n\nÆvar Arnfjörð Bjarmason (10):\n  hook tests: turn exit code assertions into a loop\n  t5540: don't rely on \"hook/post-update.sample\"\n  tests: assume the hooks are disabled by default\n  bugreport tests: tighten up \"git bugreport -s hooks\" test\n  tests: indent and add hook setup to \"test_expect_success\"\n  hook tests: get rid of unnecessary sub-shells\n  fetch+push tests: have tests clean up their own mess\n  test-lib-functions: add and use a \"test_hook\" wrapper\n  tests: change \"mkdir -p && write_script\" to use \"test_hook\"\n  tests: change \"cat && chmod +x\" to use \"test_hook\"\n\n t/t0029-core-unsetenvvars.sh        |   3 +-\n t/t0091-bugreport.sh                |  26 ++--\n t/t1350-config-hooks-path.sh        |   4 +-\n t/t1416-ref-transaction-hooks.sh    |  27 ++--\n t/t1800-hook.sh                     |  45 +++----\n t/t3404-rebase-interactive.sh       |  10 +-\n t/t3412-rebase-root.sh              |  18 +--\n t/t3413-rebase-hook.sh              |  18 +--\n t/t3430-rebase-merges.sh            |   6 +-\n t/t4150-am.sh                       |  24 +---\n t/t5401-update-hooks.sh             |  62 ++++-----\n t/t5402-post-merge-hook.sh          |  16 ++-\n t/t5403-post-checkout-hook.sh       |   3 +-\n t/t5406-remote-rejects.sh           |   2 +-\n t/t5407-post-rewrite-hook.sh        |  14 +-\n t/t5409-colorize-remote-messages.sh |   2 +-\n t/t5411-proc-receive-hook.sh        |   4 +-\n t/t5510-fetch.sh                    |   6 +-\n t/t5516-fetch-push.sh               | 192 +++++++++++++---------------\n t/t5521-pull-options.sh             |   4 +-\n t/t5534-push-signed.sh              |  26 ++--\n t/t5540-http-push-webdav.sh         |   4 +-\n t/t5541-http-push-smart.sh          |  22 ++--\n t/t5547-push-quarantine.sh          |   4 +-\n t/t5548-push-porcelain.sh           |   2 +-\n t/t5601-clone.sh                    |   4 +-\n t/t6500-gc.sh                       |  18 +--\n t/t7113-post-index-change-hook.sh   |   7 +-\n t/t7519-status-fsmonitor.sh         |  20 ++-\n t/t9001-send-email.sh               |   4 +-\n t/t9800-git-p4-basic.sh             |  23 ++--\n t/test-lib-functions.sh             |  52 ++++++++\n 32 files changed, 325 insertions(+), 347 deletions(-)\n\nRange-diff against v1:\n 1:  706460d10b9 =  1:  706460d10b9 hook tests: turn exit code assertions into a loop\n 2:  4bee939a894 =  2:  4bee939a894 t5540: don't rely on \"hook/post-update.sample\"\n 3:  0519102edeb !  3:  fc1a9d4d55b tests: assume the hooks are disabled by default\n    @@ Commit message\n     \n         That we can assume that is discussed in point #4 of\n         f0d4d398e28 (test-lib: split up and deprecate test_create_repo(),\n    -    2021-05-10).\n    +    2021-05-10), those parts of this could and should have been done in\n    +    that change.\n    +\n    +    Removing the \"mkdir -p\" here will then validate that our templates are\n    +    being used, since we'd subsequently fail to create a hook in that\n    +    directory if it didn't exist. Subsequent commits will have those hooks\n    +    created by a \"test_hook\" wrapper, which will then being doing that\n    +    same validation.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n 4:  1da2efc9886 !  4:  8dd7b40e510 bugreport tests: tighten up \"git bugreport -s hooks\" test\n    @@ Commit message\n         bugreport tests: tighten up \"git bugreport -s hooks\" test\n     \n         Amend a test added in 788a776069b (bugreport: collect list of\n    -    populated hooks, 2020-05-07) to make more sense. As noted in a\n    -    preceding commit our .git/hooks directory already contains *.sample\n    -    hooks, so we have no need to clobber the prepare-commit-msg.sample\n    -    hook in particular.\n    +    populated hooks, 2020-05-07) to \"test_cmp\" for the expected output,\n    +    instead of selectively using \"grep\" to check for specific things we\n    +    either expect or don't expect in the output.\n    +\n    +    As noted in a preceding commit our .git/hooks directory already\n    +    contains *.sample hooks, so we have no need to clobber the\n    +    prepare-commit-msg.sample hook in particular.\n     \n         Instead we should assert that those *.sample hooks are not included in\n         the output, and for good measure let's add a new \"unknown-hook\", to\n    @@ Commit message\n         cfe853e66be (hook-list.h: add a generated list of hooks, like\n         config-list.h, 2021-09-26) for how we generate that data.\n     \n    +    We're intentionally not piping the \"actual\" output through \"sort\" or\n    +    similar, we'd also like to check that our reported hooks are sorted.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/t0091-bugreport.sh ##\n    @@ t/t0091-bugreport.sh: test_expect_success 'can create leading directories outsid\n     +\ttrue\n     +\tEOF\n      \tgit bugreport -s hooks &&\n    -+\n    - \tgrep applypatch-msg git-bugreport-hooks.txt &&\n    +-\tgrep applypatch-msg git-bugreport-hooks.txt &&\n     -\t! grep prepare-commit-msg git-bugreport-hooks.txt\n    -+\t! grep unknown-hook git-bugreport-hooks.txt &&\n    -+\t! grep -F .sample git-bugreport-hooks.txt\n    ++\n    ++\tsort >expect <<-\\EOF &&\n    ++\t[Enabled Hooks]\n    ++\tapplypatch-msg\n    ++\tEOF\n    ++\n    ++\tsed -ne \"/^\\[Enabled Hooks\\]$/,/^$/p\" <git-bugreport-hooks.txt >actual &&\n    ++\ttest_cmp expect actual\n      '\n      \n      test_done\n 5:  8dc478460ee =  5:  19db5b2d7c2 tests: indent and add hook setup to \"test_expect_success\"\n 6:  d86ee06b46e =  6:  08bd1629d65 hook tests: get rid of unnecessary sub-shells\n 7:  7ce22dbe738 !  7:  0ac75ed062f fetch+push tests: have tests clean up their own mess\n    @@ Commit message\n         leftover data from earlier tests, which may or may not be\n         there (e.g. depending on the --run=* option).\n     \n    +    Before this each test would have been responsible for cleaning up\n    +    after a preceding test (which may or may not have run, e.g. if --run\n    +    or \"GIT_SKIP_TESTS\" was used), now each test will instead clean up\n    +    after itself.\n    +\n    +    When doing this split up the \"push with negotiation\" test, now the\n    +    middle of the test doesn't need to \"rm event\", and since it delimited\n    +    two halves that were testing two different things the end-state is\n    +    easier to read and reason about.\n    +\n    +    While changing these lines make the minor change from \"-fr\" to \"-rf\"\n    +    as the \"rm\" argument, some of them used it already, it's more common\n    +    in the test suite, and it leaves the end-state of the file with more\n    +    consistency.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/t5516-fetch-push.sh ##\n 8:  d4102e9b929 =  8:  1fce2d8855a test-lib-functions: add and use a \"test_hook\" wrapper\n 9:  1802158b14d =  9:  121ca23db37 tests: change \"mkdir -p && write_script\" to use \"test_hook\"\n10:  7fef92872f3 ! 10:  db27fa32bbd tests: change \"cat && chmod +x\" to use \"test_hook\"\n    @@ Commit message\n     \n          - Fixes the long-standing issues with those tests using \"#!/bin/sh\"\n            instead of \"#!$SHELL_PATH\". Using \"#!/bin/sh\" here happened to work\n    -       because this code was so simply that it e.g. worked on Solaris\n    +       because this code was so simple that it e.g. worked on Solaris\n            /bin/sh.\n     \n          - Removes the \"mkdir .git/hooks\" invocation, as explained in a\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450542","messageId":"patch-v2-01.10-706460d10b9-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 01/10] hook tests: turn exit code assertions into a loop","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:32Z","receivedAt":"2022-03-07T12:43:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend a test added in 96e7225b310 (hook: add 'run' subcommand,\n2021-12-22) to use a for-loop instead of a copy/pasting the same test\nfor the four exit codes we test.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1800-hook.sh | 35 ++++++++++-------------------------\n 1 file changed, 10 insertions(+), 25 deletions(-)\n\ndiff --git a/t/t1800-hook.sh b/t/t1800-hook.sh\nindex 29718aa9913..ff64597e959 100755\n--- a/t/t1800-hook.sh\n+++ b/t/t1800-hook.sh\n@@ -53,31 +53,16 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n \ttest_must_be_empty stdout.actual\n '\n \n-test_expect_success 'git hook run: exit codes are passed along' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 1\n-\tEOF\n-\n-\ttest_expect_code 1 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 2\n-\tEOF\n-\n-\ttest_expect_code 2 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 128\n-\tEOF\n-\n-\ttest_expect_code 128 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 129\n-\tEOF\n-\n-\ttest_expect_code 129 git hook run test-hook\n-'\n+for code in 1 2 128 129\n+do\n+\ttest_expect_success \"git hook run: exit code $code is passed along\" '\n+\t\twrite_script .git/hooks/test-hook <<-EOF &&\n+\t\texit $code\n+\t\tEOF\n+\n+\t\ttest_expect_code $code git hook run test-hook\n+\t'\n+done\n \n test_expect_success 'git hook run arg u ments without -- is not allowed' '\n \ttest_expect_code 129 git hook run test-hook arg u ments\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450543","messageId":"patch-v2-02.10-4bee939a894-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 02/10] t5540: don't rely on \"hook/post-update.sample\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:33Z","receivedAt":"2022-03-07T12:43:55Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code added in a87679339c0 (test: rename http fetch and push\ntest files, 2014-02-06) to stop relying on the \"exec git\nupdate-server-info\" in \"templates/hooks--post-update.sample\", let's\ninstead inline the expected hook in the test itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5540-http-push-webdav.sh | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh\nindex b0dbacf0b9b..380e97c1762 100755\n--- a/t/t5540-http-push-webdav.sh\n+++ b/t/t5540-http-push-webdav.sh\n@@ -42,7 +42,9 @@ test_expect_success 'setup remote repository' '\n \tgit clone --bare test_repo test_repo.git &&\n \tcd test_repo.git &&\n \tgit --bare update-server-info &&\n-\tmv hooks/post-update.sample hooks/post-update &&\n+\twrite_script hooks/post-update <<-\\EOF &&\n+\texec git update-server-info\n+\tEOF\n \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n \tcd - &&\n \tmv test_repo.git \"$HTTPD_DOCUMENT_ROOT_PATH\"\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450544","messageId":"patch-v2-03.10-fc1a9d4d55b-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 03/10] tests: assume the hooks are disabled by default","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:34Z","receivedAt":"2022-03-07T12:43:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Stop moving the .git/hooks directory out of the way, or creating it\nduring test setup. Instead assume that it will contain\nharmless *.sample files.\n\nThat we can assume that is discussed in point #4 of\nf0d4d398e28 (test-lib: split up and deprecate test_create_repo(),\n2021-05-10), those parts of this could and should have been done in\nthat change.\n\nRemoving the \"mkdir -p\" here will then validate that our templates are\nbeing used, since we'd subsequently fail to create a hook in that\ndirectory if it didn't exist. Subsequent commits will have those hooks\ncreated by a \"test_hook\" wrapper, which will then being doing that\nsame validation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1416-ref-transaction-hooks.sh | 1 -\n t/t5516-fetch-push.sh            | 3 +--\n t/t7519-status-fsmonitor.sh      | 2 --\n 3 files changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\nindex 4e1e84a91f3..d21dd5e5df0 100755\n--- a/t/t1416-ref-transaction-hooks.sh\n+++ b/t/t1416-ref-transaction-hooks.sh\n@@ -8,7 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n \n test_expect_success setup '\n-\tmkdir -p .git/hooks &&\n \ttest_commit PRE &&\n \tPRE_OID=$(git rev-parse PRE) &&\n \ttest_commit POST &&\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 3137eb8d4d2..1a20e54adc1 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -28,8 +28,7 @@ mk_empty () {\n \t(\n \t\tcd \"$repo_name\" &&\n \t\tgit init &&\n-\t\tgit config receive.denyCurrentBranch warn &&\n-\t\tmv .git/hooks .git/hooks-disabled\n+\t\tgit config receive.denyCurrentBranch warn\n \t)\n }\n \ndiff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\nindex a6308acf006..63a0f609866 100755\n--- a/t/t7519-status-fsmonitor.sh\n+++ b/t/t7519-status-fsmonitor.sh\n@@ -56,7 +56,6 @@ test_lazy_prereq UNTRACKED_CACHE '\n '\n \n test_expect_success 'setup' '\n-\tmkdir -p .git/hooks &&\n \t: >tracked &&\n \t: >modified &&\n \tmkdir dir1 &&\n@@ -322,7 +321,6 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'\n \ttest_create_repo dot-git &&\n \t(\n \t\tcd dot-git &&\n-\t\tmkdir -p .git/hooks &&\n \t\t: >tracked &&\n \t\t: >modified &&\n \t\tmkdir dir1 &&\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450545","messageId":"patch-v2-04.10-8dd7b40e510-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 04/10] bugreport tests: tighten up \"git bugreport -s hooks\" test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:35Z","receivedAt":"2022-03-07T12:44:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend a test added in 788a776069b (bugreport: collect list of\npopulated hooks, 2020-05-07) to \"test_cmp\" for the expected output,\ninstead of selectively using \"grep\" to check for specific things we\neither expect or don't expect in the output.\n\nAs noted in a preceding commit our .git/hooks directory already\ncontains *.sample hooks, so we have no need to clobber the\nprepare-commit-msg.sample hook in particular.\n\nInstead we should assert that those *.sample hooks are not included in\nthe output, and for good measure let's add a new \"unknown-hook\", to\ncheck that we only look through our own known hooks. See\ncfe853e66be (hook-list.h: add a generated list of hooks, like\nconfig-list.h, 2021-09-26) for how we generate that data.\n\nWe're intentionally not piping the \"actual\" output through \"sort\" or\nsimilar, we'd also like to check that our reported hooks are sorted.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0091-bugreport.sh | 26 +++++++++++++++-----------\n 1 file changed, 15 insertions(+), 11 deletions(-)\n\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex eeedbfa9193..d51e18b0bb9 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -60,18 +60,22 @@ test_expect_success 'can create leading directories outside of a git dir' '\n \n test_expect_success 'indicates populated hooks' '\n \ttest_when_finished rm git-bugreport-hooks.txt &&\n-\ttest_when_finished rm -fr .git/hooks &&\n-\trm -fr .git/hooks &&\n-\tmkdir .git/hooks &&\n-\tfor hook in applypatch-msg prepare-commit-msg.sample\n-\tdo\n-\t\twrite_script \".git/hooks/$hook\" <<-EOF || return 1\n-\t\techo \"hook $hook exists\"\n-\t\tEOF\n-\tdone &&\n+\n+\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttrue\n+\tEOF\n+\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n+\ttrue\n+\tEOF\n \tgit bugreport -s hooks &&\n-\tgrep applypatch-msg git-bugreport-hooks.txt &&\n-\t! grep prepare-commit-msg git-bugreport-hooks.txt\n+\n+\tsort >expect <<-\\EOF &&\n+\t[Enabled Hooks]\n+\tapplypatch-msg\n+\tEOF\n+\n+\tsed -ne \"/^\\[Enabled Hooks\\]$/,/^$/p\" <git-bugreport-hooks.txt >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450546","messageId":"patch-v2-05.10-19db5b2d7c2-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 05/10] tests: indent and add hook setup to \"test_expect_success\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:36Z","receivedAt":"2022-03-07T12:44:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Indent various hook setup code in the test suite that's using a manual\n\"cat && chmod\" pattern.\n\nThese should also consistently use \"#!$SHELL_PATH\" instead of\n\"#!/bin/sh\", i.e. \"test_script\". Let's fix that in a subsequent\ncommit, which will be easier to review after this smaller change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3412-rebase-root.sh       | 16 ++++----\n t/t3413-rebase-hook.sh       | 16 ++++----\n t/t5401-update-hooks.sh      | 76 ++++++++++++++++++------------------\n t/t5407-post-rewrite-hook.sh | 16 ++++----\n t/t5541-http-push-smart.sh   | 24 ++++++------\n 5 files changed, 75 insertions(+), 73 deletions(-)\n\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 1e9f7833dd6..239a9343d34 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -32,10 +32,10 @@ test_expect_success 'rebase --root fails with too many args' '\n \n test_expect_success 'setup pre-rebase hook' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n cat > expect <<EOF\n@@ -142,10 +142,10 @@ EOF\n \n test_expect_success 'setup pre-rebase hook that fails' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-false\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\tfalse\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n \ndiff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh\nindex b4acb3be5cf..bb241b26b2e 100755\n--- a/t/t3413-rebase-hook.sh\n+++ b/t/t3413-rebase-hook.sh\n@@ -42,10 +42,10 @@ test_expect_success 'rebase -i' '\n \n test_expect_success 'setup pre-rebase hook' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n \n@@ -103,10 +103,10 @@ test_expect_success 'pre-rebase hook gets correct input (6)' '\n \n test_expect_success 'setup pre-rebase hook that fails' '\n \tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-false\n-EOF\n+\tcat >.git/hooks/pre-rebase <<-EOF &&\n+\t#!$SHELL_PATH\n+\tfalse\n+\tEOF\n \tchmod +x .git/hooks/pre-rebase\n '\n \ndiff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh\nindex 6012cc8172a..6392f71795d 100755\n--- a/t/t5401-update-hooks.sh\n+++ b/t/t5401-update-hooks.sh\n@@ -20,46 +20,46 @@ test_expect_success setup '\n \tgit clone --bare ./. victim.git &&\n \tGIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&\n \tgit update-ref refs/heads/main $commit1 &&\n-\tgit update-ref refs/heads/tofail $commit0\n+\tgit update-ref refs/heads/tofail $commit0 &&\n+\n+\tcat >victim.git/hooks/pre-receive <<-\\EOF &&\n+\t#!/bin/sh\n+\tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n+\tcat - >$GIT_DIR/pre-receive.stdin\n+\techo STDOUT pre-receive\n+\techo STDERR pre-receive >&2\n+\tEOF\n+\tchmod u+x victim.git/hooks/pre-receive &&\n+\n+\tcat >victim.git/hooks/update <<-\\EOF &&\n+\t#!/bin/sh\n+\techo \"$@\" >>$GIT_DIR/update.args\n+\tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n+\techo STDOUT update $1\n+\techo STDERR update $1 >&2\n+\ttest \"$1\" = refs/heads/main || exit\n+\tEOF\n+\tchmod u+x victim.git/hooks/update &&\n+\n+\tcat >victim.git/hooks/post-receive <<-\\EOF &&\n+\t#!/bin/sh\n+\tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n+\tcat - >$GIT_DIR/post-receive.stdin\n+\techo STDOUT post-receive\n+\techo STDERR post-receive >&2\n+\tEOF\n+\tchmod u+x victim.git/hooks/post-receive &&\n+\n+\tcat >victim.git/hooks/post-update <<-\\EOF &&\n+\t#!/bin/sh\n+\techo \"$@\" >>$GIT_DIR/post-update.args\n+\tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n+\techo STDOUT post-update\n+\techo STDERR post-update >&2\n+\tEOF\n+\tchmod u+x victim.git/hooks/post-update\n '\n \n-cat >victim.git/hooks/pre-receive <<'EOF'\n-#!/bin/sh\n-printf %s \"$@\" >>$GIT_DIR/pre-receive.args\n-cat - >$GIT_DIR/pre-receive.stdin\n-echo STDOUT pre-receive\n-echo STDERR pre-receive >&2\n-EOF\n-chmod u+x victim.git/hooks/pre-receive\n-\n-cat >victim.git/hooks/update <<'EOF'\n-#!/bin/sh\n-echo \"$@\" >>$GIT_DIR/update.args\n-read x; printf %s \"$x\" >$GIT_DIR/update.stdin\n-echo STDOUT update $1\n-echo STDERR update $1 >&2\n-test \"$1\" = refs/heads/main || exit\n-EOF\n-chmod u+x victim.git/hooks/update\n-\n-cat >victim.git/hooks/post-receive <<'EOF'\n-#!/bin/sh\n-printf %s \"$@\" >>$GIT_DIR/post-receive.args\n-cat - >$GIT_DIR/post-receive.stdin\n-echo STDOUT post-receive\n-echo STDERR post-receive >&2\n-EOF\n-chmod u+x victim.git/hooks/post-receive\n-\n-cat >victim.git/hooks/post-update <<'EOF'\n-#!/bin/sh\n-echo \"$@\" >>$GIT_DIR/post-update.args\n-read x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n-echo STDOUT post-update\n-echo STDERR post-update >&2\n-EOF\n-chmod u+x victim.git/hooks/post-update\n-\n test_expect_success push '\n \ttest_must_fail git send-pack --force ./victim.git \\\n \t\tmain tofail >send.out 2>send.err\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 6da8d760e28..64f40ff7776 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -17,15 +17,15 @@ test_expect_success 'setup' '\n \tgit checkout A^0 &&\n \ttest_commit E bar E &&\n \ttest_commit F foo F &&\n-\tgit checkout main\n-'\n+\tgit checkout main &&\n \n-cat >.git/hooks/post-rewrite <<EOF\n-#!/bin/sh\n-echo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n-cat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n-EOF\n-chmod u+x .git/hooks/post-rewrite\n+\tcat >.git/hooks/post-rewrite <<-EOF &&\n+\t#!/bin/sh\n+\techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n+\tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n+\tEOF\n+\tchmod u+x .git/hooks/post-rewrite\n+'\n \n clear_hook_input () {\n \trm -f post-rewrite.args post-rewrite.data\ndiff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh\nindex 8ca50f8b18c..0043b718f08 100755\n--- a/t/t5541-http-push-smart.sh\n+++ b/t/t5541-http-push-smart.sh\n@@ -96,18 +96,20 @@ test_expect_success 'create and delete remote branch' '\n \ttest_must_fail git show-ref --verify refs/remotes/origin/dev\n '\n \n-cat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<EOF\n-#!/bin/sh\n-exit 1\n-EOF\n-chmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\"\n+test_expect_success 'setup rejected update hook' '\n+\tcat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<-EOF &&\n+\t#!/bin/sh\n+\texit 1\n+\tEOF\n+\tchmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" &&\n \n-cat >exp <<EOF\n-remote: error: hook declined to update refs/heads/dev2\n-To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git\n- ! [remote rejected] dev2 -> dev2 (hook declined)\n-error: failed to push some refs to 'http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\n-EOF\n+\tcat >exp <<-EOF\n+\tremote: error: hook declined to update refs/heads/dev2\n+\tTo http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git\n+\t ! [remote rejected] dev2 -> dev2 (hook declined)\n+\terror: failed to push some refs to '\\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\\''\n+\tEOF\n+'\n \n test_expect_success 'rejected update prints status' '\n \tcd \"$ROOT_PATH\"/test_repo_clone &&\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450547","messageId":"patch-v2-06.10-08bd1629d65-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 06/10] hook tests: get rid of unnecessary sub-shells","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:37Z","receivedAt":"2022-03-07T12:44:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the repository setup code for tests that test hooks the use\nof sub-shells when setting up the test repository and hooks.\n\nA subsequent commit will change the hook setup to use a helper that\nmakes use of \"test_when_finished\", which cannot be used in\nsub-shells. Let's change that setup code, and the adjacent and similar\n\"mk_empty\" code.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5516-fetch-push.sh   | 150 ++++++++++++++++++----------------------\n t/t6500-gc.sh           |  18 ++---\n t/t9800-git-p4-basic.sh |  24 ++++---\n 3 files changed, 94 insertions(+), 98 deletions(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 1a20e54adc1..e4bb7581568 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -24,12 +24,8 @@ D=$(pwd)\n mk_empty () {\n \trepo_name=\"$1\"\n \trm -fr \"$repo_name\" &&\n-\tmkdir \"$repo_name\" &&\n-\t(\n-\t\tcd \"$repo_name\" &&\n-\t\tgit init &&\n-\t\tgit config receive.denyCurrentBranch warn\n-\t)\n+\tgit init \"$repo_name\" &&\n+\tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n }\n \n mk_test () {\n@@ -58,36 +54,35 @@ mk_test () {\n mk_test_with_hooks() {\n \trepo_name=$1\n \tmk_test \"$@\" &&\n-\t(\n-\t\tcd \"$repo_name\" &&\n-\t\tmkdir .git/hooks &&\n-\t\tcd .git/hooks &&\n-\n-\t\tcat >pre-receive <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tcat - >>pre-receive.actual\n-\t\tEOF\n \n-\t\tcat >update <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n-\t\tEOF\n-\n-\t\tcat >post-receive <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tcat - >>post-receive.actual\n-\t\tEOF\n-\n-\t\tcat >post-update <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tfor ref in \"$@\"\n-\t\tdo\n-\t\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n-\t\tdone\n-\t\tEOF\n-\n-\t\tchmod +x pre-receive update post-receive post-update\n-\t)\n+\tcat >\"$repo_name\"/.git/hooks/pre-receive <<-'EOF' &&\n+\t#!/bin/sh\n+\tcat - >>pre-receive.actual\n+\tEOF\n+\n+\tcat >\"$repo_name\"/.git/hooks/update <<-'EOF' &&\n+\t#!/bin/sh\n+\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n+\tEOF\n+\n+\tcat >\"$repo_name\"/.git/hooks/post-receive <<-'EOF' &&\n+\t#!/bin/sh\n+\tcat - >>post-receive.actual\n+\tEOF\n+\n+\tcat >\"$repo_name\"/.git/hooks/post-update <<-'EOF' &&\n+\t#!/bin/sh\n+\tfor ref in \"$@\"\n+\tdo\n+\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n+\tdone\n+\tEOF\n+\n+\tchmod +x \\\n+\t      \"$repo_name\"/.git/hooks/pre-receive \\\n+\t      \"$repo_name\"/.git/hooks/update \\\n+\t      \"$repo_name\"/.git/hooks/post-receive \\\n+\t      \"$repo_name\"/.git/hooks/post-update\n }\n \n mk_child() {\n@@ -667,7 +662,6 @@ test_expect_success 'push does not update local refs on failure' '\n \n \tmk_test testrepo heads/main &&\n \tmk_child testrepo child &&\n-\tmkdir testrepo/.git/hooks &&\n \techo \"#!/no/frobnication/today\" >testrepo/.git/hooks/pre-receive &&\n \tchmod +x testrepo/.git/hooks/pre-receive &&\n \t(\n@@ -1679,24 +1673,21 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n test_expect_success 'updateInstead with push-to-checkout hook' '\n \trm -fr testrepo &&\n \tgit init testrepo &&\n-\t(\n-\t\tcd testrepo &&\n-\t\tgit pull .. main &&\n-\t\tgit reset --hard HEAD^^ &&\n-\t\tgit tag initial &&\n-\t\tgit config receive.denyCurrentBranch updateInstead &&\n-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n-\t\techo >&2 updating from $(git rev-parse HEAD)\n-\t\techo >&2 updating to \"$1\"\n-\n-\t\tgit update-index -q --refresh &&\n-\t\tgit read-tree -u -m HEAD \"$1\" || {\n-\t\t\tstatus=$?\n-\t\t\techo >&2 read-tree failed\n-\t\t\texit $status\n-\t\t}\n-\t\tEOF\n-\t) &&\n+\tgit -C testrepo pull .. main &&\n+\tgit -C testrepo reset --hard HEAD^^ &&\n+\tgit -C testrepo tag initial &&\n+\tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n+\twrite_script testrepo/.git/hooks/push-to-checkout <<-\\EOF &&\n+\techo >&2 updating from $(git rev-parse HEAD)\n+\techo >&2 updating to \"$1\"\n+\n+\tgit update-index -q --refresh &&\n+\tgit read-tree -u -m HEAD \"$1\" || {\n+\t\tstatus=$?\n+\t\techo >&2 read-tree failed\n+\t\texit $status\n+\t}\n+\tEOF\n \n \t# Try pushing into a pristine\n \tgit push testrepo main &&\n@@ -1741,33 +1732,30 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \t# push into void\n \trm -fr void &&\n \tgit init void &&\n-\t(\n-\t\tcd void &&\n-\t\tgit config receive.denyCurrentBranch updateInstead &&\n-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n-\t\tif git rev-parse --quiet --verify HEAD\n-\t\tthen\n-\t\t\thas_head=yes\n-\t\t\techo >&2 updating from $(git rev-parse HEAD)\n-\t\telse\n-\t\t\thas_head=no\n-\t\t\techo >&2 pushing into void\n-\t\tfi\n-\t\techo >&2 updating to \"$1\"\n-\n-\t\tgit update-index -q --refresh &&\n-\t\tcase \"$has_head\" in\n-\t\tyes)\n-\t\t\tgit read-tree -u -m HEAD \"$1\" ;;\n-\t\tno)\n-\t\t\tgit read-tree -u -m \"$1\" ;;\n-\t\tesac || {\n-\t\t\tstatus=$?\n-\t\t\techo >&2 read-tree failed\n-\t\t\texit $status\n-\t\t}\n-\t\tEOF\n-\t) &&\n+\tgit -C void config receive.denyCurrentBranch updateInstead &&\n+\twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n+\tif git rev-parse --quiet --verify HEAD\n+\tthen\n+\t\thas_head=yes\n+\t\techo >&2 updating from $(git rev-parse HEAD)\n+\telse\n+\t\thas_head=no\n+\t\techo >&2 pushing into void\n+\tfi\n+\techo >&2 updating to \"$1\"\n+\n+\tgit update-index -q --refresh &&\n+\tcase \"$has_head\" in\n+\tyes)\n+\t\tgit read-tree -u -m HEAD \"$1\" ;;\n+\tno)\n+\t\tgit read-tree -u -m \"$1\" ;;\n+\tesac || {\n+\t\tstatus=$?\n+\t\techo >&2 read-tree failed\n+\t\texit $status\n+\t}\n+\tEOF\n \n \tgit push void main &&\n \t(\ndiff --git a/t/t6500-gc.sh b/t/t6500-gc.sh\nindex c2021267f2c..a6b0db22867 100755\n--- a/t/t6500-gc.sh\n+++ b/t/t6500-gc.sh\n@@ -101,12 +101,12 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tEOF\n \n \tgit init pre-auto-gc-hook &&\n+\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\techo >&2 no gc for you &&\n+\texit 1\n+\tEOF\n \t(\n \t\tcd pre-auto-gc-hook &&\n-\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n-\t\techo >&2 no gc for you &&\n-\t\texit 1\n-\t\tEOF\n \n \t\tgit config gc.auto 3 &&\n \t\tgit config gc.autoDetach false &&\n@@ -128,12 +128,14 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tSee \"git help gc\" for manual housekeeping.\n \tEOF\n \n+\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\techo >&2 will gc for you &&\n+\texit 0\n+\tEOF\n+\n \t(\n \t\tcd pre-auto-gc-hook &&\n-\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n-\t\techo >&2 will gc for you &&\n-\t\texit 0\n-\t\tEOF\n+\n \t\tgit gc --auto >../out.actual 2>../err.actual\n \t) &&\n \ndiff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh\nindex 806005a793a..3c1534c94d6 100755\n--- a/t/t9800-git-p4-basic.sh\n+++ b/t/t9800-git-p4-basic.sh\n@@ -277,16 +277,22 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit commit -m \"add hello.txt\" &&\n \t\tgit config git-p4.skipSubmitEdit true &&\n \t\tgit p4 submit --dry-run >out &&\n-\t\tgrep \"Would apply\" out &&\n-\t\tmkdir -p .git/hooks &&\n-\t\twrite_script .git/hooks/p4-pre-submit <<-\\EOF &&\n-\t\texit 0\n-\t\tEOF\n+\t\tgrep \"Would apply\" out\n+\t) &&\n+\tmkdir -p \"$git\"/.git/hooks &&\n+\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\texit 0\n+\tEOF\n+\t(\n+\t\tcd \"$git\" &&\n \t\tgit p4 submit --dry-run >out &&\n-\t\tgrep \"Would apply\" out &&\n-\t\twrite_script .git/hooks/p4-pre-submit <<-\\EOF &&\n-\t\texit 1\n-\t\tEOF\n+\t\tgrep \"Would apply\" out\n+\t) &&\n+\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\texit 1\n+\tEOF\n+\t(\n+\t\tcd \"$git\" &&\n \t\ttest_must_fail git p4 submit --dry-run >errs 2>&1 &&\n \t\t! grep \"Would apply\" errs\n \t)\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450548","messageId":"patch-v2-08.10-1fce2d8855a-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 08/10] test-lib-functions: add and use a \"test_hook\" wrapper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:39Z","receivedAt":"2022-03-07T12:44:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a \"test_hook\" wrapper similar to the existing \"test_config\"\nwrapper added in d960c47a881 (test-lib: add helper functions for\nconfig, 2011-08-17).\n\nThis wrapper:\n\n - Will clean up the hook with \"test_when_finished\", unless --setup is\n   provided.\n\n - Will error if we clobber a hook, unless --clobber is provided.\n\n - Takes a name like \"update\" instead of \".git/hooks/update\".\n\n - Accepts -C <dir>, like \"test_config\" and \"test_commit\".\n\nBy using a wrapper we'll be able to easily change all the hook-related\ncode that assumes that the template-created \".git/hooks\" directory is\ncreated by \"init\", \"clone\" etc. once another topic follows-up and\nchanges the test suite to stop creating trash directories using those\ntemplates.\n\nIn addition this will make it easy to have the hooks configured using\nthe \"configuration-based hooks\" topic, once we get around to\nintegrating that. I.e. we'll be able to run the tests in a mode where\nwe sometimes create a .git/hooks/<name>, and other times create a\nscript in another location, and point the relevant configuration\nsnippet to it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0091-bugreport.sh                |  4 +--\n t/t1416-ref-transaction-hooks.sh    | 26 +++++++--------\n t/t1800-hook.sh                     | 14 +++++---\n t/t5406-remote-rejects.sh           |  2 +-\n t/t5409-colorize-remote-messages.sh |  2 +-\n t/t5411-proc-receive-hook.sh        |  4 +--\n t/t5510-fetch.sh                    |  6 ++--\n t/t5516-fetch-push.sh               |  4 +--\n t/t5521-pull-options.sh             |  4 +--\n t/t5540-http-push-webdav.sh         |  2 +-\n t/t5547-push-quarantine.sh          |  4 +--\n t/t5548-push-porcelain.sh           |  2 +-\n t/t6500-gc.sh                       |  4 +--\n t/t7519-status-fsmonitor.sh         | 18 +++++-----\n t/test-lib-functions.sh             | 52 +++++++++++++++++++++++++++++\n 15 files changed, 101 insertions(+), 47 deletions(-)\n\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex d51e18b0bb9..08f5fe9caef 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -61,10 +61,10 @@ test_expect_success 'can create leading directories outside of a git dir' '\n test_expect_success 'indicates populated hooks' '\n \ttest_when_finished rm git-bugreport-hooks.txt &&\n \n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \ttrue\n \tEOF\n-\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n+\ttest_hook unknown-hook <<-\\EOF &&\n \ttrue\n \tEOF\n \tgit bugreport -s hooks &&\ndiff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\nindex d21dd5e5df0..085a7a46f21 100755\n--- a/t/t1416-ref-transaction-hooks.sh\n+++ b/t/t1416-ref-transaction-hooks.sh\n@@ -15,9 +15,8 @@ test_expect_success setup '\n '\n \n test_expect_success 'hook allows updating ref if successful' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$*\" >>actual\n \tEOF\n \tcat >expect <<-EOF &&\n@@ -29,9 +28,8 @@ test_expect_success 'hook allows updating ref if successful' '\n '\n \n test_expect_success 'hook aborts updating ref in prepared state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = prepared\n \t\tthen\n \t\t\texit 1\n@@ -42,9 +40,9 @@ test_expect_success 'hook aborts updating ref in prepared state' '\n '\n \n test_expect_success 'hook gets all queued updates in prepared state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = prepared\n \t\tthen\n \t\t\twhile read -r line\n@@ -65,9 +63,9 @@ test_expect_success 'hook gets all queued updates in prepared state' '\n '\n \n test_expect_success 'hook gets all queued updates in committed state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = committed\n \t\tthen\n \t\t\twhile read -r line\n@@ -85,9 +83,9 @@ test_expect_success 'hook gets all queued updates in committed state' '\n '\n \n test_expect_success 'hook gets all queued updates in aborted state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = aborted\n \t\tthen\n \t\t\twhile read -r line\n@@ -114,11 +112,11 @@ test_expect_success 'interleaving hook calls succeed' '\n \n \tgit init --bare target-repo.git &&\n \n-\twrite_script target-repo.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C target-repo.git reference-transaction <<-\\EOF &&\n \t\techo $0 \"$@\" >>actual\n \tEOF\n \n-\twrite_script target-repo.git/hooks/update <<-\\EOF &&\n+\ttest_hook -C target-repo.git update <<-\\EOF &&\n \t\techo $0 \"$@\" >>actual\n \tEOF\n \n@@ -139,7 +137,7 @@ test_expect_success 'hook does not get called on packing refs' '\n \t# Pack references first such that we are in a known state.\n \tgit pack-refs --all &&\n \n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$@\" >>actual\n \t\tcat >>actual\n \tEOF\n@@ -165,7 +163,7 @@ test_expect_success 'deleting packed ref calls hook once' '\n \tgit update-ref refs/heads/to-be-deleted $POST_OID &&\n \tgit pack-refs --all &&\n \n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$@\" >>actual\n \t\tcat >>actual\n \tEOF\ndiff --git a/t/t1800-hook.sh b/t/t1800-hook.sh\nindex ff64597e959..26ed5e11bc8 100755\n--- a/t/t1800-hook.sh\n+++ b/t/t1800-hook.sh\n@@ -27,7 +27,7 @@ test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '\n '\n \n test_expect_success 'git hook run: basic' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo Test hook\n \tEOF\n \n@@ -39,7 +39,7 @@ test_expect_success 'git hook run: basic' '\n '\n \n test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo >&1 Will end up on stderr\n \techo >&2 Will end up on stderr\n \tEOF\n@@ -56,7 +56,7 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n for code in 1 2 128 129\n do\n \ttest_expect_success \"git hook run: exit code $code is passed along\" '\n-\t\twrite_script .git/hooks/test-hook <<-EOF &&\n+\t\ttest_hook test-hook <<-EOF &&\n \t\texit $code\n \t\tEOF\n \n@@ -69,7 +69,7 @@ test_expect_success 'git hook run arg u ments without -- is not allowed' '\n '\n \n test_expect_success 'git hook run -- pass arguments' '\n-\twrite_script .git/hooks/test-hook <<-\\EOF &&\n+\ttest_hook test-hook <<-\\EOF &&\n \techo $1\n \techo $2\n \tEOF\n@@ -84,7 +84,7 @@ test_expect_success 'git hook run -- pass arguments' '\n '\n \n test_expect_success 'git hook run -- out-of-repo runs excluded' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo Test hook\n \tEOF\n \n@@ -105,6 +105,10 @@ test_expect_success 'git -c core.hooksPath=<PATH> hook run' '\n \tHook ran four\n \tEOF\n \n+\ttest_hook test-hook <<-EOF &&\n+\techo Test hook\n+\tEOF\n+\n \t# Test various ways of specifying the path. See also\n \t# t1350-config-hooks-path.sh\n \t>actual &&\ndiff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh\nindex 5c509db6fc3..dcbeb420827 100755\n--- a/t/t5406-remote-rejects.sh\n+++ b/t/t5406-remote-rejects.sh\n@@ -5,7 +5,7 @@ test_description='remote push rejects are reported by client'\n . ./test-lib.sh\n \n test_expect_success 'setup' '\n-\twrite_script .git/hooks/update <<-\\EOF &&\n+\ttest_hook update <<-\\EOF &&\n \texit 1\n \tEOF\n \techo 1 >file &&\ndiff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh\nindex 9f1a483f426..fa5de4500a4 100755\n--- a/t/t5409-colorize-remote-messages.sh\n+++ b/t/t5409-colorize-remote-messages.sh\n@@ -5,7 +5,7 @@ test_description='remote messages are colorized on the client'\n . ./test-lib.sh\n \n test_expect_success 'setup' '\n-\twrite_script .git/hooks/update <<-\\EOF &&\n+\ttest_hook --setup update <<-\\EOF &&\n \techo error: error\n \techo ERROR: also highlighted\n \techo hint: hint\ndiff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh\nindex 98b0e812082..92cf52c6d4a 100755\n--- a/t/t5411-proc-receive-hook.sh\n+++ b/t/t5411-proc-receive-hook.sh\n@@ -36,7 +36,7 @@ setup_upstream_and_workbench () {\n \t\tTAG=$(git -C workbench rev-parse v123) &&\n \n \t\t# setup pre-receive hook\n-\t\twrite_script upstream.git/hooks/pre-receive <<-\\EOF &&\n+\t\ttest_hook --setup -C upstream.git pre-receive <<-\\EOF &&\n \t\texec >&2\n \t\techo \"# pre-receive hook\"\n \t\twhile read old new ref\n@@ -46,7 +46,7 @@ setup_upstream_and_workbench () {\n \t\tEOF\n \n \t\t# setup post-receive hook\n-\t\twrite_script upstream.git/hooks/post-receive <<-\\EOF &&\n+\t\ttest_hook --setup -C upstream.git post-receive <<-\\EOF &&\n \t\texec >&2\n \t\techo \"# post-receive hook\"\n \t\twhile read old new ref\ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex ef0da0a63b5..4620f0ca7fa 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -273,7 +273,7 @@ test_expect_success 'fetch --atomic executes a single reference transaction only\n \tEOF\n \n \trm -f atomic/actual &&\n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \tEOF\n \n@@ -306,7 +306,7 @@ test_expect_success 'fetch --atomic aborts all reference updates if hook aborts'\n \tEOF\n \n \trm -f atomic/actual &&\n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic/.git reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \t\texit 1\n \tEOF\n@@ -334,7 +334,7 @@ test_expect_success 'fetch --atomic --append appends to FETCH_HEAD' '\n \ttest_line_count = 2 atomic/.git/FETCH_HEAD &&\n \tcp atomic/.git/FETCH_HEAD expected &&\n \n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\texit 1\n \tEOF\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex fbe0a72b0b2..b689baf01a9 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -1685,7 +1685,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \tgit -C testrepo reset --hard HEAD^^ &&\n \tgit -C testrepo tag initial &&\n \tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n-\twrite_script testrepo/.git/hooks/push-to-checkout <<-\\EOF &&\n+\ttest_hook -C testrepo push-to-checkout <<-\\EOF &&\n \techo >&2 updating from $(git rev-parse HEAD)\n \techo >&2 updating to \"$1\"\n \n@@ -1741,7 +1741,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \tgit -C void config receive.denyCurrentBranch updateInstead &&\n-\twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n+\ttest_hook -C void push-to-checkout <<-\\EOF &&\n \tif git rev-parse --quiet --verify HEAD\n \tthen\n \t\thas_head=yes\ndiff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh\nindex 66cfcb09c55..264de29c35c 100755\n--- a/t/t5521-pull-options.sh\n+++ b/t/t5521-pull-options.sh\n@@ -233,7 +233,7 @@ test_expect_success 'git pull --no-verify flag passed to merge' '\n \tgit init src &&\n \ttest_commit -C src one &&\n \tgit clone src dst &&\n-\twrite_script dst/.git/hooks/commit-msg <<-\\EOF &&\n+\ttest_hook -C dst commit-msg <<-\\EOF &&\n \tfalse\n \tEOF\n \ttest_commit -C src two &&\n@@ -245,7 +245,7 @@ test_expect_success 'git pull --no-verify --verify passed to merge' '\n \tgit init src &&\n \ttest_commit -C src one &&\n \tgit clone src dst &&\n-\twrite_script dst/.git/hooks/commit-msg <<-\\EOF &&\n+\ttest_hook -C dst commit-msg <<-\\EOF &&\n \tfalse\n \tEOF\n \ttest_commit -C src two &&\ndiff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh\nindex 380e97c1762..37db3dec0c5 100755\n--- a/t/t5540-http-push-webdav.sh\n+++ b/t/t5540-http-push-webdav.sh\n@@ -42,7 +42,7 @@ test_expect_success 'setup remote repository' '\n \tgit clone --bare test_repo test_repo.git &&\n \tcd test_repo.git &&\n \tgit --bare update-server-info &&\n-\twrite_script hooks/post-update <<-\\EOF &&\n+\ttest_hook --setup post-update <<-\\EOF &&\n \texec git update-server-info\n \tEOF\n \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\ndiff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh\nindex faaa51ccc56..1876fb34e51 100755\n--- a/t/t5547-push-quarantine.sh\n+++ b/t/t5547-push-quarantine.sh\n@@ -5,7 +5,7 @@ test_description='check quarantine of objects during push'\n \n test_expect_success 'create picky dest repo' '\n \tgit init --bare dest.git &&\n-\twrite_script dest.git/hooks/pre-receive <<-\\EOF\n+\ttest_hook --setup -C dest.git pre-receive <<-\\EOF\n \twhile read old new ref; do\n \t\ttest \"$(git log -1 --format=%s $new)\" = reject && exit 1\n \tdone\n@@ -60,7 +60,7 @@ test_expect_success 'push to repo path with path separator (colon)' '\n \n test_expect_success 'updating a ref from quarantine is forbidden' '\n \tgit init --bare update.git &&\n-\twrite_script update.git/hooks/pre-receive <<-\\EOF &&\n+\ttest_hook -C update.git pre-receive <<-\\EOF &&\n \tread old new refname\n \tgit update-ref refs/heads/unrelated $new\n \texit 1\ndiff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh\nindex f11ff57e549..6282728eaf3 100755\n--- a/t/t5548-push-porcelain.sh\n+++ b/t/t5548-push-porcelain.sh\n@@ -168,7 +168,7 @@ run_git_push_porcelain_output_test() {\n \t'\n \n \ttest_expect_success \"prepare pre-receive hook ($PROTOCOL)\" '\n-\t\twrite_script \"$upstream/hooks/pre-receive\" <<-EOF\n+\t\ttest_hook --setup -C \"$upstream\" pre-receive <<-EOF\n \t\texit 1\n \t\tEOF\n \t'\ndiff --git a/t/t6500-gc.sh b/t/t6500-gc.sh\nindex a6b0db22867..39871b9901e 100755\n--- a/t/t6500-gc.sh\n+++ b/t/t6500-gc.sh\n@@ -101,7 +101,7 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tEOF\n \n \tgit init pre-auto-gc-hook &&\n-\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\ttest_hook -C pre-auto-gc-hook pre-auto-gc <<-\\EOF &&\n \techo >&2 no gc for you &&\n \texit 1\n \tEOF\n@@ -128,7 +128,7 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tSee \"git help gc\" for manual housekeeping.\n \tEOF\n \n-\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n+\ttest_hook -C pre-auto-gc-hook --clobber pre-auto-gc <<-\\EOF &&\n \techo >&2 will gc for you &&\n \texit 0\n \tEOF\ndiff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\nindex 63a0f609866..d8b0fc4681c 100755\n--- a/t/t7519-status-fsmonitor.sh\n+++ b/t/t7519-status-fsmonitor.sh\n@@ -26,7 +26,7 @@ dirty_repo () {\n }\n \n write_integration_script () {\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF\n+\ttest_hook --setup --clobber fsmonitor-test<<-\\EOF\n \tif test \"$#\" -ne 2\n \tthen\n \t\techo \"$0: exactly 2 arguments expected\"\n@@ -107,7 +107,7 @@ EOF\n \n # test that \"update-index --fsmonitor-valid\" sets the fsmonitor valid bit\n test_expect_success 'update-index --fsmonitor-valid\" sets the fsmonitor valid bit' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook fsmonitor-test<<-\\EOF &&\n \t\tprintf \"last_update_token\\0\"\n \tEOF\n \tgit update-index --fsmonitor &&\n@@ -168,7 +168,7 @@ EOF\n \n # test that newly added files are marked valid\n test_expect_success 'newly added files are marked valid' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --setup --clobber fsmonitor-test<<-\\EOF &&\n \t\tprintf \"last_update_token\\0\"\n \tEOF\n \tgit add new &&\n@@ -209,7 +209,7 @@ EOF\n \n # test that *only* files returned by the integration script get flagged as invalid\n test_expect_success '*only* files returned by the integration script get flagged as invalid' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \tprintf \"last_update_token\\0\"\n \tprintf \"dir1/modified\\0\"\n \tEOF\n@@ -230,7 +230,7 @@ test_expect_success 'refresh_index() invalidates fsmonitor cache' '\n \tdirty_repo &&\n \twrite_integration_script &&\n \tgit add . &&\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \tEOF\n \tgit commit -m \"to reset\" &&\n \tgit reset HEAD~1 &&\n@@ -279,7 +279,7 @@ do\n \t\t# Make sure it's actually skipping the check for modified and untracked\n \t\t# (if enabled) files unless it is told about them.\n \t\ttest_expect_success \"status doesn't detect unreported modifications\" '\n-\t\t\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\t\t\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\t:>marker\n \t\t\tEOF\n@@ -405,14 +405,14 @@ test_expect_success 'status succeeds with sparse index' '\n \t\tgit -C sparse sparse-checkout init --cone --sparse-index &&\n \t\tgit -C sparse sparse-checkout set dir1 dir2 &&\n \n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\tEOF\n \t\tgit -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&\n \t\tgit -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&\n \t\tcheck_sparse_index_behavior ! &&\n \n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\tprintf \"dir1/modified\\0\"\n \t\tEOF\n@@ -430,7 +430,7 @@ test_expect_success 'status succeeds with sparse index' '\n \n \t\t# This one modifies outside the sparse-checkout definition\n \t\t# and hence we expect to expand the sparse-index.\n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\tprintf \"dir1a/modified\\0\"\n \t\tEOF\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 85385d2ede7..0bef5913100 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -551,6 +551,58 @@ write_script () {\n \tchmod +x \"$1\"\n }\n \n+# Usage: test_hook [options] <hook-name> <<-\\EOF\n+#\n+#   -C <dir>:\n+#\tRun all git commands in directory <dir>\n+#   --setup\n+#\tSetup a hook for subsequent tests, i.e. don't remove it in a\n+#\t\"test_when_finished\"\n+#   --clobber\n+#\tOverwrite an existing <hook-name>, if it exists. Implies\n+#\t--setup (i.e. the \"test_when_finished\" is assumed to have been\n+#\tset up already).\n+test_hook () {\n+\tsetup= &&\n+\tclobber= &&\n+\tindir= &&\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-C)\n+\t\t\tindir=\"$2\" &&\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--setup)\n+\t\t\tsetup=t\n+\t\t\t;;\n+\t\t--clobber)\n+\t\t\tclobber=t\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tBUG \"invalid argument: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac &&\n+\t\tshift\n+\tdone &&\n+\n+\tgit_dir=$(git -C \"$indir\" rev-parse --absolute-git-dir) &&\n+\thook_dir=\"$git_dir/hooks\" &&\n+\thook_file=\"$hook_dir/$1\" &&\n+\tif test -z \"$clobber\"\n+\tthen\n+\t\ttest_path_is_missing \"$hook_file\"\n+\tfi &&\n+\tif test -z \"$setup$clobber\"\n+\tthen\n+\t\ttest_when_finished \"rm \\\"$hook_file\\\"\"\n+\tfi &&\n+\twrite_script \"$hook_file\"\n+}\n+\n # Use test_set_prereq to tell that a particular prerequisite is available.\n # The prerequisite can later be checked for in two ways:\n #\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450549","messageId":"patch-v2-07.10-0ac75ed062f-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 07/10] fetch+push tests: have tests clean up their own mess","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:38Z","receivedAt":"2022-03-07T12:44:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"t5516-fetch-push.sh\" test code to make use of\n\"test_when_finished\" to remove data instead of having tests clean up\nleftover data from earlier tests, which may or may not be\nthere (e.g. depending on the --run=* option).\n\nBefore this each test would have been responsible for cleaning up\nafter a preceding test (which may or may not have run, e.g. if --run\nor \"GIT_SKIP_TESTS\" was used), now each test will instead clean up\nafter itself.\n\nWhen doing this split up the \"push with negotiation\" test, now the\nmiddle of the test doesn't need to \"rm event\", and since it delimited\ntwo halves that were testing two different things the end-state is\neasier to read and reason about.\n\nWhile changing these lines make the minor change from \"-fr\" to \"-rf\"\nas the \"rm\" argument, some of them used it already, it's more common\nin the test suite, and it leaves the end-state of the file with more\nconsistency.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5516-fetch-push.sh | 50 +++++++++++++++++++++++++------------------\n 1 file changed, 29 insertions(+), 21 deletions(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex e4bb7581568..fbe0a72b0b2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -23,7 +23,8 @@ D=$(pwd)\n \n mk_empty () {\n \trepo_name=\"$1\"\n-\trm -fr \"$repo_name\" &&\n+\ttest_when_finished \"rm -rf \\\"$repo_name\\\"\" &&\n+\ttest_path_is_missing \"$repo_name\" &&\n \tgit init \"$repo_name\" &&\n \tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n }\n@@ -86,7 +87,7 @@ mk_test_with_hooks() {\n }\n \n mk_child() {\n-\trm -rf \"$2\" &&\n+\ttest_when_finished \"rm -rf \\\"$2\\\"\" &&\n \tgit clone \"$1\" \"$2\"\n }\n \n@@ -191,32 +192,32 @@ grep_wrote () {\n \tgrep 'write_pack_file/wrote.*\"value\":\"'$1'\"' $2\n }\n \n-test_expect_success 'push with negotiation' '\n-\t# Without negotiation\n+test_expect_success 'push without negotiation' '\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n-\techo now pushing without negotiation &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main &&\n-\tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n+\tgrep_wrote 5 event # 2 commits, 2 trees, 1 blob\n+'\n \n-\t# Same commands, but with negotiation\n-\trm event &&\n+test_expect_success 'push with negotiation' '\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main &&\n \tgrep_wrote 2 event # 1 commit, 1 tree\n '\n \n test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' '\n-\trm event &&\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT=\"$(pwd)/event\" \\\n \t\tgit -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&\n \tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n@@ -1323,7 +1324,7 @@ done\n \n test_expect_success 'fetch follows tags by default' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n \t(\n \t\tcd src &&\n@@ -1333,6 +1334,7 @@ test_expect_success 'fetch follows tags by default' '\n \t\tsed -n \"p; s|refs/heads/main$|refs/remotes/origin/main|p\" tmp1 |\n \t\tsort -k 3 >../expect\n \t) &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init dst &&\n \t(\n \t\tcd dst &&\n@@ -1358,8 +1360,9 @@ test_expect_success 'peeled advertisements are not considered ref tips' '\n \n test_expect_success 'pushing a specific ref applies remote.$name.push as refmap' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1382,8 +1385,9 @@ test_expect_success 'pushing a specific ref applies remote.$name.push as refmap'\n \n test_expect_success 'with no remote.$name.push, it is not used as refmap' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1404,8 +1408,9 @@ test_expect_success 'with no remote.$name.push, it is not used as refmap' '\n \n test_expect_success 'with no remote.$name.push, upstream mapping is used' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1433,8 +1438,9 @@ test_expect_success 'with no remote.$name.push, upstream mapping is used' '\n \n test_expect_success 'push does not follow tags by default' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1456,8 +1462,9 @@ test_expect_success 'push does not follow tags by default' '\n \n test_expect_success 'push --follow-tags only pushes relevant tags' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1495,9 +1502,9 @@ EOF\n '\n \n test_expect_success 'pushing a tag pushes the tagged object' '\n-\trm -rf dst.git &&\n \tblob=$(echo unreferenced | git hash-object -w --stdin) &&\n \tgit tag -m foo tag-of-blob $blob &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \tgit push dst.git tag-of-blob &&\n \t# the receiving index-pack should have noticed\n@@ -1508,7 +1515,7 @@ test_expect_success 'pushing a tag pushes the tagged object' '\n '\n \n test_expect_success 'push into bare respects core.logallrefupdates' '\n-\trm -rf dst.git &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \tgit -C dst.git config core.logallrefupdates true &&\n \n@@ -1526,7 +1533,7 @@ test_expect_success 'push into bare respects core.logallrefupdates' '\n '\n \n test_expect_success 'fetch into bare respects core.logallrefupdates' '\n-\trm -rf dst.git &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \t(\n \t\tcd dst.git &&\n@@ -1547,6 +1554,7 @@ test_expect_success 'fetch into bare respects core.logallrefupdates' '\n '\n \n test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n+\tmk_empty testrepo &&\n \tgit push testrepo main &&\n \t(\n \t\tcd testrepo &&\n@@ -1649,7 +1657,7 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n \t) &&\n \n \t# (5) push into void\n-\trm -fr void &&\n+\ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \t(\n \t\tcd void &&\n@@ -1671,7 +1679,7 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n '\n \n test_expect_success 'updateInstead with push-to-checkout hook' '\n-\trm -fr testrepo &&\n+\ttest_when_finished \"rm -rf testrepo\" &&\n \tgit init testrepo &&\n \tgit -C testrepo pull .. main &&\n \tgit -C testrepo reset --hard HEAD^^ &&\n@@ -1730,7 +1738,7 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \t) &&\n \n \t# push into void\n-\trm -fr void &&\n+\ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \tgit -C void config receive.denyCurrentBranch updateInstead &&\n \twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450550","messageId":"patch-v2-10.10-db27fa32bbd-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 10/10] tests: change \"cat && chmod +x\" to use \"test_hook\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:41Z","receivedAt":"2022-03-07T12:44:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various test code to use the \"test_hook\" helper. This change:\n\n - Fixes the long-standing issues with those tests using \"#!/bin/sh\"\n   instead of \"#!$SHELL_PATH\". Using \"#!/bin/sh\" here happened to work\n   because this code was so simple that it e.g. worked on Solaris\n   /bin/sh.\n\n - Removes the \"mkdir .git/hooks\" invocation, as explained in a\n   preceding commit we'll rely on the default templates to create that\n   directory for us.\n\nFor the test in \"t5402-post-merge-hook.sh\" it's easier and more\ncorrect to unroll the for-loop into a test_expect_success, so let's do\nthat.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3412-rebase-root.sh       | 12 +++---------\n t/t3413-rebase-hook.sh       | 12 +++---------\n t/t5401-update-hooks.sh      | 16 ++++------------\n t/t5402-post-merge-hook.sh   | 16 +++++++++-------\n t/t5407-post-rewrite-hook.sh |  4 +---\n t/t5516-fetch-push.sh        | 19 ++++---------------\n t/t5541-http-push-smart.sh   |  4 +---\n t/t5601-clone.sh             |  4 +---\n 8 files changed, 26 insertions(+), 61 deletions(-)\n\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 239a9343d34..58371d8a547 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -31,12 +31,9 @@ test_expect_success 'rebase --root fails with too many args' '\n '\n \n test_expect_success 'setup pre-rebase hook' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n-\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\ttest_hook --setup pre-rebase <<-\\EOF\n+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n cat > expect <<EOF\n 4\n@@ -141,12 +138,9 @@ commit work7~5\n EOF\n \n test_expect_success 'setup pre-rebase hook that fails' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n \tfalse\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n \n test_expect_success 'pre-rebase hook stops rebase' '\ndiff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh\nindex bb241b26b2e..9fab0d779bb 100755\n--- a/t/t3413-rebase-hook.sh\n+++ b/t/t3413-rebase-hook.sh\n@@ -41,12 +41,9 @@ test_expect_success 'rebase -i' '\n '\n \n test_expect_success 'setup pre-rebase hook' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n-\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+\ttest_hook --setup pre-rebase <<-\\EOF\n+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n \n test_expect_success 'pre-rebase hook gets correct input (1)' '\n@@ -102,12 +99,9 @@ test_expect_success 'pre-rebase hook gets correct input (6)' '\n '\n \n test_expect_success 'setup pre-rebase hook that fails' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<-EOF &&\n-\t#!$SHELL_PATH\n+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n \tfalse\n \tEOF\n-\tchmod +x .git/hooks/pre-rebase\n '\n \n test_expect_success 'pre-rebase hook stops rebase (1)' '\ndiff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh\nindex 6392f71795d..d5771b96114 100755\n--- a/t/t5401-update-hooks.sh\n+++ b/t/t5401-update-hooks.sh\n@@ -22,42 +22,34 @@ test_expect_success setup '\n \tgit update-ref refs/heads/main $commit1 &&\n \tgit update-ref refs/heads/tofail $commit0 &&\n \n-\tcat >victim.git/hooks/pre-receive <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git pre-receive <<-\\EOF &&\n \tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n \tcat - >$GIT_DIR/pre-receive.stdin\n \techo STDOUT pre-receive\n \techo STDERR pre-receive >&2\n \tEOF\n-\tchmod u+x victim.git/hooks/pre-receive &&\n \n-\tcat >victim.git/hooks/update <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git update <<-\\EOF &&\n \techo \"$@\" >>$GIT_DIR/update.args\n \tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n \techo STDOUT update $1\n \techo STDERR update $1 >&2\n \ttest \"$1\" = refs/heads/main || exit\n \tEOF\n-\tchmod u+x victim.git/hooks/update &&\n \n-\tcat >victim.git/hooks/post-receive <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git post-receive <<-\\EOF &&\n \tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n \tcat - >$GIT_DIR/post-receive.stdin\n \techo STDOUT post-receive\n \techo STDERR post-receive >&2\n \tEOF\n-\tchmod u+x victim.git/hooks/post-receive &&\n \n-\tcat >victim.git/hooks/post-update <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C victim.git post-update <<-\\EOF\n \techo \"$@\" >>$GIT_DIR/post-update.args\n \tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n \techo STDOUT post-update\n \techo STDERR post-update >&2\n \tEOF\n-\tchmod u+x victim.git/hooks/post-update\n '\n \n test_expect_success push '\ndiff --git a/t/t5402-post-merge-hook.sh b/t/t5402-post-merge-hook.sh\nindex 3e5e19c7191..915af2de95e 100755\n--- a/t/t5402-post-merge-hook.sh\n+++ b/t/t5402-post-merge-hook.sh\n@@ -25,13 +25,15 @@ test_expect_success setup '\n \tGIT_DIR=clone2/.git git update-index --add a\n '\n \n-for clone in 1 2; do\n-\tcat >clone${clone}/.git/hooks/post-merge <<'EOF'\n-#!/bin/sh\n-echo $@ >> $GIT_DIR/post-merge.args\n-EOF\n-\tchmod u+x clone${clone}/.git/hooks/post-merge\n-done\n+test_expect_success 'setup clone hooks' '\n+\ttest_when_finished \"rm -f hook\" &&\n+\tcat >hook <<-\\EOF &&\n+\techo $@ >>$GIT_DIR/post-merge.args\n+\tEOF\n+\n+\ttest_hook --setup -C clone1 post-merge <hook &&\n+\ttest_hook --setup -C clone2 post-merge <hook\n+'\n \n test_expect_success 'post-merge does not run for up-to-date ' '\n \tGIT_DIR=clone1/.git git merge $commit0 &&\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 64f40ff7776..5f3ff051ca2 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -19,12 +19,10 @@ test_expect_success 'setup' '\n \ttest_commit F foo F &&\n \tgit checkout main &&\n \n-\tcat >.git/hooks/post-rewrite <<-EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup post-rewrite <<-EOF\n \techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n \tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n \tEOF\n-\tchmod u+x .git/hooks/post-rewrite\n '\n \n clear_hook_input () {\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex b689baf01a9..4dfb080433e 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -55,35 +55,24 @@ mk_test () {\n mk_test_with_hooks() {\n \trepo_name=$1\n \tmk_test \"$@\" &&\n-\n-\tcat >\"$repo_name\"/.git/hooks/pre-receive <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" pre-receive <<-'EOF' &&\n \tcat - >>pre-receive.actual\n \tEOF\n \n-\tcat >\"$repo_name\"/.git/hooks/update <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" update <<-'EOF' &&\n \tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n \tEOF\n \n-\tcat >\"$repo_name\"/.git/hooks/post-receive <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" post-receive <<-'EOF' &&\n \tcat - >>post-receive.actual\n \tEOF\n \n-\tcat >\"$repo_name\"/.git/hooks/post-update <<-'EOF' &&\n-\t#!/bin/sh\n+\ttest_hook -C \"$repo_name\" post-update <<-'EOF'\n \tfor ref in \"$@\"\n \tdo\n \t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n \tdone\n \tEOF\n-\n-\tchmod +x \\\n-\t      \"$repo_name\"/.git/hooks/pre-receive \\\n-\t      \"$repo_name\"/.git/hooks/update \\\n-\t      \"$repo_name\"/.git/hooks/post-receive \\\n-\t      \"$repo_name\"/.git/hooks/post-update\n }\n \n mk_child() {\ndiff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh\nindex 0043b718f08..ab4b5cfcd11 100755\n--- a/t/t5541-http-push-smart.sh\n+++ b/t/t5541-http-push-smart.sh\n@@ -97,11 +97,9 @@ test_expect_success 'create and delete remote branch' '\n '\n \n test_expect_success 'setup rejected update hook' '\n-\tcat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<-EOF &&\n-\t#!/bin/sh\n+\ttest_hook --setup -C \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git\" update <<-\\EOF &&\n \texit 1\n \tEOF\n-\tchmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" &&\n \n \tcat >exp <<-EOF\n \tremote: error: hook declined to update refs/heads/dev2\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex 83c24fc97a7..4a61f2c901e 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -79,12 +79,10 @@ test_expect_success 'clone from hooks' '\n \tcd .. &&\n \tgit init r1 &&\n \tcd r1 &&\n-\tcat >.git/hooks/pre-commit <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook pre-commit <<-\\EOF &&\n \tgit clone ../r0 ../r2\n \texit 1\n \tEOF\n-\tchmod u+x .git/hooks/pre-commit &&\n \t: >file &&\n \tgit add file &&\n \ttest_must_fail git commit -m invoke-hook &&\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450551","messageId":"patch-v2-09.10-121ca23db37-20220307T123909Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v2 09/10] tests: change \"mkdir -p && write_script\" to use \"test_hook\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-07T12:43:40Z","receivedAt":"2022-03-07T12:44:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change tests that used a \"mkdir -p .git/hooks && write_script\" pattern\nto use the new \"test_hook\" helper instead. The new helper does not\ncreate the .git/hooks directory, rather we assume that the default\ntemplate will do so for us.\n\nAn upcoming series[1] will extend \"test_hook\" to operate in a\n\"--template=\" mode, but for now assuming that we have a .git/hooks\nalready is a safe assumption. If that assumption becomes false in the\nfuture we'll only need to change 'test_hook\", instead of all of these\ncallsites.\n\n1. https://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0029-core-unsetenvvars.sh      |  3 +--\n t/t1350-config-hooks-path.sh      |  4 ++--\n t/t3404-rebase-interactive.sh     | 10 ++--------\n t/t3430-rebase-merges.sh          |  6 +++---\n t/t4150-am.sh                     | 24 ++++++------------------\n t/t5403-post-checkout-hook.sh     |  3 +--\n t/t5534-push-signed.sh            | 26 ++++++++------------------\n t/t7113-post-index-change-hook.sh |  7 +++----\n t/t9001-send-email.sh             |  4 +---\n t/t9800-git-p4-basic.sh           |  5 ++---\n 10 files changed, 29 insertions(+), 63 deletions(-)\n\ndiff --git a/t/t0029-core-unsetenvvars.sh b/t/t0029-core-unsetenvvars.sh\nindex b138e1d9cbc..4e8e90dd982 100755\n--- a/t/t0029-core-unsetenvvars.sh\n+++ b/t/t0029-core-unsetenvvars.sh\n@@ -12,8 +12,7 @@ then\n fi\n \n test_expect_success 'setup' '\n-\tmkdir -p \"$TRASH_DIRECTORY/.git/hooks\" &&\n-\twrite_script \"$TRASH_DIRECTORY/.git/hooks/pre-commit\" <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \techo $HOBBES >&2\n \tEOF\n '\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nindex fa9647a7c0b..f6dc83e2aab 100755\n--- a/t/t1350-config-hooks-path.sh\n+++ b/t/t1350-config-hooks-path.sh\n@@ -6,11 +6,11 @@ test_description='Test the core.hooksPath configuration variable'\n \n test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n \t>actual &&\n-\tmkdir -p .git/custom-hooks .git/hooks &&\n+\tmkdir -p .git/custom-hooks &&\n \twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n \techo CUSTOM >>actual\n \tEOF\n-\twrite_script .git/hooks/pre-commit <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \techo NORMAL >>actual\n \tEOF\n '\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex a38f2da7691..f31afd4a547 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -619,9 +619,7 @@ test_expect_success 'rebase a detached HEAD' '\n '\n \n test_expect_success 'rebase a commit violating pre-commit' '\n-\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n+\ttest_hook pre-commit <<-\\EOF &&\n \ttest -z \"$(git diff --cached --check)\"\n \tEOF\n \techo \"monde! \" >> file1 &&\n@@ -636,8 +634,6 @@ test_expect_success 'rebase a commit violating pre-commit' '\n '\n \n test_expect_success 'rebase with a file named HEAD in worktree' '\n-\n-\trm -fr .git/hooks &&\n \tgit reset --hard &&\n \tgit checkout -b branch3 A &&\n \n@@ -1688,10 +1684,8 @@ test_expect_success 'valid author header when author contains single quote' '\n '\n \n test_expect_success 'post-commit hook is called' '\n-\ttest_when_finished \"rm -f .git/hooks/post-commit\" &&\n \t>actual &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-commit <<-\\EOS &&\n+\ttest_hook post-commit <<-\\EOS &&\n \tgit rev-parse HEAD >>actual\n \tEOS\n \t(\ndiff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh\nindex 43c82d9a33b..f351701fec2 100755\n--- a/t/t3430-rebase-merges.sh\n+++ b/t/t3430-rebase-merges.sh\n@@ -292,9 +292,9 @@ test_expect_success 'post-rewrite hook and fixups work for merges' '\n \tgit commit --fixup HEAD same2.t &&\n \tfixup=\"$(git rev-parse HEAD)\" &&\n \n-\tmkdir -p .git/hooks &&\n-\ttest_when_finished \"rm .git/hooks/post-rewrite\" &&\n-\techo \"cat >actual\" | write_script .git/hooks/post-rewrite &&\n+\ttest_hook post-rewrite <<-\\EOF &&\n+\tcat >actual\n+\tEOF\n \n \ttest_tick &&\n \tgit rebase -i --autosquash -r HEAD^^^ &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 159fae8d016..cdad4b68807 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -315,12 +315,10 @@ test_expect_success 'am --patch-format=hg applies hg patch' '\n '\n \n test_expect_success 'am with applypatch-msg hook' '\n-\ttest_when_finished \"rm -f .git/hooks/applypatch-msg\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \tcat \"$1\" >actual-msg &&\n \techo hook-message >\"$1\"\n \tEOF\n@@ -335,12 +333,10 @@ test_expect_success 'am with applypatch-msg hook' '\n '\n \n test_expect_success 'am with failing applypatch-msg hook' '\n-\ttest_when_finished \"rm -f .git/hooks/applypatch-msg\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \texit 1\n \tEOF\n \ttest_must_fail git am patch1 &&\n@@ -350,12 +346,10 @@ test_expect_success 'am with failing applypatch-msg hook' '\n '\n \n test_expect_success 'am with pre-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/pre-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-applypatch <<-\\EOF &&\n+\ttest_hook pre-applypatch <<-\\EOF &&\n \tgit diff first >diff.actual\n \texit 0\n \tEOF\n@@ -368,12 +362,10 @@ test_expect_success 'am with pre-applypatch hook' '\n '\n \n test_expect_success 'am with failing pre-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/pre-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-applypatch <<-\\EOF &&\n+\ttest_hook pre-applypatch <<-\\EOF &&\n \texit 1\n \tEOF\n \ttest_must_fail git am patch1 &&\n@@ -383,12 +375,10 @@ test_expect_success 'am with failing pre-applypatch hook' '\n '\n \n test_expect_success 'am with post-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/post-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-applypatch <<-\\EOF &&\n+\ttest_hook post-applypatch <<-\\EOF &&\n \tgit rev-parse HEAD >head.actual\n \tgit diff second >diff.actual\n \texit 0\n@@ -403,12 +393,10 @@ test_expect_success 'am with post-applypatch hook' '\n '\n \n test_expect_success 'am with failing post-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/post-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-applypatch <<-\\EOF &&\n+\ttest_hook post-applypatch <<-\\EOF &&\n \tgit rev-parse HEAD >head.actual\n \texit 1\n \tEOF\ndiff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh\nindex d1181816906..978f240cdac 100755\n--- a/t/t5403-post-checkout-hook.sh\n+++ b/t/t5403-post-checkout-hook.sh\n@@ -10,8 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n \n test_expect_success setup '\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-checkout <<-\\EOF &&\n+\ttest_hook --setup post-checkout <<-\\EOF &&\n \techo \"$@\" >.git/post-checkout.args\n \tEOF\n \ttest_commit one &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 24d374adbae..7c0a148e73c 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -35,8 +35,7 @@ test_expect_success setup '\n \n test_expect_success 'unsigned push does not send push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -52,8 +51,7 @@ test_expect_success 'unsigned push does not send push certificate' '\n \n test_expect_success 'talking with a receiver without push certificate support' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -69,22 +67,19 @@ test_expect_success 'talking with a receiver without push certificate support' '\n \n test_expect_success 'push --signed fails with a receiver without push certificate support' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \ttest_must_fail git push --signed dst noop ff +noff 2>err &&\n \ttest_i18ngrep \"the receiving end does not support\" err\n '\n \n test_expect_success 'push --signed=1 is accepted' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \ttest_must_fail git push --signed=1 dst noop ff +noff 2>err &&\n \ttest_i18ngrep \"the receiving end does not support\" err\n '\n \n test_expect_success GPG 'no certificate for a signed push with no update' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \tif test -n \"${GIT_PUSH_CERT-}\"\n \tthen\n \t\tgit cat-file blob $GIT_PUSH_CERT >../push-cert\n@@ -96,9 +91,8 @@ test_expect_success GPG 'no certificate for a signed push with no update' '\n \n test_expect_success GPG 'signed push sends push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -139,10 +133,9 @@ test_expect_success GPG 'signed push sends push certificate' '\n \n test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config gpg.ssh.allowedSignersFile \"${GPGSSH_ALLOWED_SIGNERS}\" &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -223,9 +216,8 @@ test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \n test_expect_success GPG 'fail without key and heed user.signingkey' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -273,9 +265,8 @@ test_expect_success GPG 'fail without key and heed user.signingkey' '\n test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '\n \ttest_config gpg.format x509 &&\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -326,10 +317,9 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '\n test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' '\n \ttest_config gpg.format ssh &&\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config gpg.ssh.allowedSignersFile \"${GPGSSH_ALLOWED_SIGNERS}\" &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\ndiff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh\nindex a21781d68a1..58e55a7c779 100755\n--- a/t/t7113-post-index-change-hook.sh\n+++ b/t/t7113-post-index-change-hook.sh\n@@ -17,8 +17,7 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n \t\t\texit 1\n@@ -63,7 +62,7 @@ test_expect_success 'test status, add, commit, others trigger hook without flags\n '\n \n test_expect_success 'test checkout and reset trigger the hook' '\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n \t\t\texit 1\n@@ -106,7 +105,7 @@ test_expect_success 'test checkout and reset trigger the hook' '\n '\n \n test_expect_success 'test reset --mixed and update-index triggers the hook' '\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n \t\t\texit 1\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 84d0f40d76a..42694fe5841 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2288,9 +2288,7 @@ test_expect_success $PREREQ 'cmdline in-reply-to used with --no-thread' '\n '\n \n test_expect_success $PREREQ 'invoke hook' '\n-\tmkdir -p .git/hooks &&\n-\n-\twrite_script .git/hooks/sendemail-validate <<-\\EOF &&\n+\ttest_hook sendemail-validate <<-\\EOF &&\n \t# test that we have the correct environment variable, pwd, and\n \t# argument\n \tcase \"$GIT_DIR\" in\ndiff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh\nindex 3c1534c94d6..8b30062c0cf 100755\n--- a/t/t9800-git-p4-basic.sh\n+++ b/t/t9800-git-p4-basic.sh\n@@ -279,8 +279,7 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit p4 submit --dry-run >out &&\n \t\tgrep \"Would apply\" out\n \t) &&\n-\tmkdir -p \"$git\"/.git/hooks &&\n-\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\ttest_hook -C \"$git\" p4-pre-submit <<-\\EOF &&\n \texit 0\n \tEOF\n \t(\n@@ -288,7 +287,7 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit p4 submit --dry-run >out &&\n \t\tgrep \"Would apply\" out\n \t) &&\n-\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n+\ttest_hook -C \"$git\" --clobber p4-pre-submit <<-\\EOF &&\n \texit 1\n \tEOF\n \t(\n-- \n2.35.1.1242.gfeba0eae32b\n\n"},{"id":"450649","messageId":"xmqqtuc9qwrj.fsf@gitster.g","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"Re: [PATCH v2 00/10] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-07T21:26:56Z","receivedAt":"2022-03-07T21:27:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Junio also suggested re-arranging this to do this migration in fewer\n> steps. I started doing that but doing so would have taken a lot of\n> time solving conflicts, re-writing commits etc. I think given that\n\nGiven how much reviewer bandwidth you consume, it may be a good\nthing to slow you down, I would have to say ;-)\n\n> there's agreement on the end-state that doing so wasn't worth the time\n\n\nSomebody needs to take another look at the end-state, as I do not\nrecall if there was any firm agreement, but in any case the series\nmust bisect well.\n\nIn any case, the new \"test_hook\" helper, together with many places\nconverted to use it by this patch, look quite nicely done.\n\nWill replace.\n\nThanks.\n\n"},{"id":"451540","messageId":"patch-v3-01.13-7761d777e9c-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 01/13] test-lib-functions: add and use a \"test_hook\" wrapper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:06Z","receivedAt":"2022-03-17T10:13:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a \"test_hook\" wrapper similar to the existing \"test_config\"\nwrapper added in d960c47a881 (test-lib: add helper functions for\nconfig, 2011-08-17).\n\nThis wrapper:\n\n - Will clean up the hook with \"test_when_finished\", unless --setup is\n   provided.\n\n - Will error if we clobber a hook, unless --clobber is provided.\n\n - Takes a name like \"update\" instead of \".git/hooks/update\".\n\n - Accepts -C <dir>, like \"test_config\" and \"test_commit\".\n\nBy using a wrapper we'll be able to easily change all the hook-related\ncode that assumes that the template-created \".git/hooks\" directory is\ncreated by \"init\", \"clone\" etc. once another topic follows-up and\nchanges the test suite to stop creating trash directories using those\ntemplates.\n\nIn addition this will make it easy to have the hooks configured using\nthe \"configuration-based hooks\" topic, once we get around to\nintegrating that. I.e. we'll be able to run the tests in a mode where\nwe sometimes create a .git/hooks/<name>, and other times create a\nscript in another location, and point the relevant configuration\nsnippet to it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1416-ref-transaction-hooks.sh    | 26 +++++++--------\n t/t1800-hook.sh                     | 12 ++++---\n t/t5401-update-hooks.sh             |  2 +-\n t/t5406-remote-rejects.sh           |  2 +-\n t/t5409-colorize-remote-messages.sh |  2 +-\n t/t5411-proc-receive-hook.sh        |  4 +--\n t/t5503-tagfollow.sh                |  4 +--\n t/t5510-fetch.sh                    |  8 ++---\n t/t5521-pull-options.sh             |  4 +--\n t/t5547-push-quarantine.sh          |  4 +--\n t/t5548-push-porcelain.sh           |  2 +-\n t/t7519-status-fsmonitor.sh         | 18 +++++-----\n t/test-lib-functions.sh             | 52 +++++++++++++++++++++++++++++\n 13 files changed, 97 insertions(+), 43 deletions(-)\n\ndiff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\nindex 4e1e84a91f3..6fca1f08d9a 100755\n--- a/t/t1416-ref-transaction-hooks.sh\n+++ b/t/t1416-ref-transaction-hooks.sh\n@@ -16,9 +16,8 @@ test_expect_success setup '\n '\n \n test_expect_success 'hook allows updating ref if successful' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$*\" >>actual\n \tEOF\n \tcat >expect <<-EOF &&\n@@ -30,9 +29,8 @@ test_expect_success 'hook allows updating ref if successful' '\n '\n \n test_expect_success 'hook aborts updating ref in prepared state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = prepared\n \t\tthen\n \t\t\texit 1\n@@ -43,9 +41,9 @@ test_expect_success 'hook aborts updating ref in prepared state' '\n '\n \n test_expect_success 'hook gets all queued updates in prepared state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = prepared\n \t\tthen\n \t\t\twhile read -r line\n@@ -66,9 +64,9 @@ test_expect_success 'hook gets all queued updates in prepared state' '\n '\n \n test_expect_success 'hook gets all queued updates in committed state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = committed\n \t\tthen\n \t\t\twhile read -r line\n@@ -86,9 +84,9 @@ test_expect_success 'hook gets all queued updates in committed state' '\n '\n \n test_expect_success 'hook gets all queued updates in aborted state' '\n-\ttest_when_finished \"rm .git/hooks/reference-transaction actual\" &&\n+\ttest_when_finished \"rm actual\" &&\n \tgit reset --hard PRE &&\n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\tif test \"$1\" = aborted\n \t\tthen\n \t\t\twhile read -r line\n@@ -115,11 +113,11 @@ test_expect_success 'interleaving hook calls succeed' '\n \n \tgit init --bare target-repo.git &&\n \n-\twrite_script target-repo.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C target-repo.git reference-transaction <<-\\EOF &&\n \t\techo $0 \"$@\" >>actual\n \tEOF\n \n-\twrite_script target-repo.git/hooks/update <<-\\EOF &&\n+\ttest_hook -C target-repo.git update <<-\\EOF &&\n \t\techo $0 \"$@\" >>actual\n \tEOF\n \n@@ -140,7 +138,7 @@ test_expect_success 'hook does not get called on packing refs' '\n \t# Pack references first such that we are in a known state.\n \tgit pack-refs --all &&\n \n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$@\" >>actual\n \t\tcat >>actual\n \tEOF\n@@ -166,7 +164,7 @@ test_expect_success 'deleting packed ref calls hook once' '\n \tgit update-ref refs/heads/to-be-deleted $POST_OID &&\n \tgit pack-refs --all &&\n \n-\twrite_script .git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook reference-transaction <<-\\EOF &&\n \t\techo \"$@\" >>actual\n \t\tcat >>actual\n \tEOF\ndiff --git a/t/t1800-hook.sh b/t/t1800-hook.sh\nindex 29718aa9913..93540b1fa12 100755\n--- a/t/t1800-hook.sh\n+++ b/t/t1800-hook.sh\n@@ -27,7 +27,7 @@ test_expect_success 'git hook run: nonexistent hook with --ignore-missing' '\n '\n \n test_expect_success 'git hook run: basic' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo Test hook\n \tEOF\n \n@@ -39,7 +39,7 @@ test_expect_success 'git hook run: basic' '\n '\n \n test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo >&1 Will end up on stderr\n \techo >&2 Will end up on stderr\n \tEOF\n@@ -84,7 +84,7 @@ test_expect_success 'git hook run arg u ments without -- is not allowed' '\n '\n \n test_expect_success 'git hook run -- pass arguments' '\n-\twrite_script .git/hooks/test-hook <<-\\EOF &&\n+\ttest_hook test-hook <<-\\EOF &&\n \techo $1\n \techo $2\n \tEOF\n@@ -99,7 +99,7 @@ test_expect_success 'git hook run -- pass arguments' '\n '\n \n test_expect_success 'git hook run -- out-of-repo runs excluded' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n+\ttest_hook test-hook <<-EOF &&\n \techo Test hook\n \tEOF\n \n@@ -120,6 +120,10 @@ test_expect_success 'git -c core.hooksPath=<PATH> hook run' '\n \tHook ran four\n \tEOF\n \n+\ttest_hook test-hook <<-EOF &&\n+\techo Test hook\n+\tEOF\n+\n \t# Test various ways of specifying the path. See also\n \t# t1350-config-hooks-path.sh\n \t>actual &&\ndiff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh\nindex 6012cc8172a..799349a416c 100755\n--- a/t/t5401-update-hooks.sh\n+++ b/t/t5401-update-hooks.sh\n@@ -136,7 +136,7 @@ test_expect_success 'send-pack stderr contains hook messages' '\n '\n \n test_expect_success 'pre-receive hook that forgets to read its input' '\n-\twrite_script victim.git/hooks/pre-receive <<-\\EOF &&\n+\ttest_hook --clobber -C victim.git pre-receive <<-\\EOF &&\n \texit 0\n \tEOF\n \trm -f victim.git/hooks/update victim.git/hooks/post-update &&\ndiff --git a/t/t5406-remote-rejects.sh b/t/t5406-remote-rejects.sh\nindex 5c509db6fc3..dcbeb420827 100755\n--- a/t/t5406-remote-rejects.sh\n+++ b/t/t5406-remote-rejects.sh\n@@ -5,7 +5,7 @@ test_description='remote push rejects are reported by client'\n . ./test-lib.sh\n \n test_expect_success 'setup' '\n-\twrite_script .git/hooks/update <<-\\EOF &&\n+\ttest_hook update <<-\\EOF &&\n \texit 1\n \tEOF\n \techo 1 >file &&\ndiff --git a/t/t5409-colorize-remote-messages.sh b/t/t5409-colorize-remote-messages.sh\nindex 9f1a483f426..fa5de4500a4 100755\n--- a/t/t5409-colorize-remote-messages.sh\n+++ b/t/t5409-colorize-remote-messages.sh\n@@ -5,7 +5,7 @@ test_description='remote messages are colorized on the client'\n . ./test-lib.sh\n \n test_expect_success 'setup' '\n-\twrite_script .git/hooks/update <<-\\EOF &&\n+\ttest_hook --setup update <<-\\EOF &&\n \techo error: error\n \techo ERROR: also highlighted\n \techo hint: hint\ndiff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh\nindex 98b0e812082..92cf52c6d4a 100755\n--- a/t/t5411-proc-receive-hook.sh\n+++ b/t/t5411-proc-receive-hook.sh\n@@ -36,7 +36,7 @@ setup_upstream_and_workbench () {\n \t\tTAG=$(git -C workbench rev-parse v123) &&\n \n \t\t# setup pre-receive hook\n-\t\twrite_script upstream.git/hooks/pre-receive <<-\\EOF &&\n+\t\ttest_hook --setup -C upstream.git pre-receive <<-\\EOF &&\n \t\texec >&2\n \t\techo \"# pre-receive hook\"\n \t\twhile read old new ref\n@@ -46,7 +46,7 @@ setup_upstream_and_workbench () {\n \t\tEOF\n \n \t\t# setup post-receive hook\n-\t\twrite_script upstream.git/hooks/post-receive <<-\\EOF &&\n+\t\ttest_hook --setup -C upstream.git post-receive <<-\\EOF &&\n \t\texec >&2\n \t\techo \"# post-receive hook\"\n \t\twhile read old new ref\ndiff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh\nindex a3c01014b7e..acdb731edfe 100755\n--- a/t/t5503-tagfollow.sh\n+++ b/t/t5503-tagfollow.sh\n@@ -169,7 +169,7 @@ test_expect_success 'atomic fetch with failing backfill' '\n \t# one of both fails to update correctly.\n \t#\n \t# To trigger failure we simply abort when backfilling a tag.\n-\twrite_script clone3/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C clone3 reference-transaction <<-\\EOF &&\n \t\twhile read oldrev newrev reference\n \t\tdo\n \t\t\tif test \"$reference\" = refs/tags/tag1\n@@ -201,7 +201,7 @@ test_expect_success 'atomic fetch with backfill should use single transaction' '\n \t\t$ZERO_OID $T refs/tags/tag1\n \tEOF\n \n-\twrite_script clone4/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C clone4 reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \tEOF\n \ndiff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh\nindex 48e14e2dab1..6f38a69fbb2 100755\n--- a/t/t5510-fetch.sh\n+++ b/t/t5510-fetch.sh\n@@ -273,7 +273,7 @@ test_expect_success 'fetch --atomic executes a single reference transaction only\n \tEOF\n \n \trm -f atomic/actual &&\n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \tEOF\n \n@@ -306,7 +306,7 @@ test_expect_success 'fetch --atomic aborts all reference updates if hook aborts'\n \tEOF\n \n \trm -f atomic/actual &&\n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic/.git reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \t\texit 1\n \tEOF\n@@ -334,7 +334,7 @@ test_expect_success 'fetch --atomic --append appends to FETCH_HEAD' '\n \ttest_line_count = 2 atomic/.git/FETCH_HEAD &&\n \tcp atomic/.git/FETCH_HEAD expected &&\n \n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\texit 1\n \tEOF\n \n@@ -364,7 +364,7 @@ test_expect_success 'fetch --atomic --prune executes a single reference transact\n \t\t$ZERO_OID $head_oid refs/remotes/origin/new-branch\n \tEOF\n \n-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n+\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n \t\t( echo \"$*\" && cat ) >>actual\n \tEOF\n \ndiff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh\nindex 66cfcb09c55..264de29c35c 100755\n--- a/t/t5521-pull-options.sh\n+++ b/t/t5521-pull-options.sh\n@@ -233,7 +233,7 @@ test_expect_success 'git pull --no-verify flag passed to merge' '\n \tgit init src &&\n \ttest_commit -C src one &&\n \tgit clone src dst &&\n-\twrite_script dst/.git/hooks/commit-msg <<-\\EOF &&\n+\ttest_hook -C dst commit-msg <<-\\EOF &&\n \tfalse\n \tEOF\n \ttest_commit -C src two &&\n@@ -245,7 +245,7 @@ test_expect_success 'git pull --no-verify --verify passed to merge' '\n \tgit init src &&\n \ttest_commit -C src one &&\n \tgit clone src dst &&\n-\twrite_script dst/.git/hooks/commit-msg <<-\\EOF &&\n+\ttest_hook -C dst commit-msg <<-\\EOF &&\n \tfalse\n \tEOF\n \ttest_commit -C src two &&\ndiff --git a/t/t5547-push-quarantine.sh b/t/t5547-push-quarantine.sh\nindex faaa51ccc56..1876fb34e51 100755\n--- a/t/t5547-push-quarantine.sh\n+++ b/t/t5547-push-quarantine.sh\n@@ -5,7 +5,7 @@ test_description='check quarantine of objects during push'\n \n test_expect_success 'create picky dest repo' '\n \tgit init --bare dest.git &&\n-\twrite_script dest.git/hooks/pre-receive <<-\\EOF\n+\ttest_hook --setup -C dest.git pre-receive <<-\\EOF\n \twhile read old new ref; do\n \t\ttest \"$(git log -1 --format=%s $new)\" = reject && exit 1\n \tdone\n@@ -60,7 +60,7 @@ test_expect_success 'push to repo path with path separator (colon)' '\n \n test_expect_success 'updating a ref from quarantine is forbidden' '\n \tgit init --bare update.git &&\n-\twrite_script update.git/hooks/pre-receive <<-\\EOF &&\n+\ttest_hook -C update.git pre-receive <<-\\EOF &&\n \tread old new refname\n \tgit update-ref refs/heads/unrelated $new\n \texit 1\ndiff --git a/t/t5548-push-porcelain.sh b/t/t5548-push-porcelain.sh\nindex f11ff57e549..6282728eaf3 100755\n--- a/t/t5548-push-porcelain.sh\n+++ b/t/t5548-push-porcelain.sh\n@@ -168,7 +168,7 @@ run_git_push_porcelain_output_test() {\n \t'\n \n \ttest_expect_success \"prepare pre-receive hook ($PROTOCOL)\" '\n-\t\twrite_script \"$upstream/hooks/pre-receive\" <<-EOF\n+\t\ttest_hook --setup -C \"$upstream\" pre-receive <<-EOF\n \t\texit 1\n \t\tEOF\n \t'\ndiff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\nindex fffc57120d6..4c7c00c94f1 100755\n--- a/t/t7519-status-fsmonitor.sh\n+++ b/t/t7519-status-fsmonitor.sh\n@@ -26,7 +26,7 @@ dirty_repo () {\n }\n \n write_integration_script () {\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF\n+\ttest_hook --setup --clobber fsmonitor-test<<-\\EOF\n \tif test \"$#\" -ne 2\n \tthen\n \t\techo \"$0: exactly 2 arguments expected\"\n@@ -108,7 +108,7 @@ EOF\n \n # test that \"update-index --fsmonitor-valid\" sets the fsmonitor valid bit\n test_expect_success 'update-index --fsmonitor-valid\" sets the fsmonitor valid bit' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook fsmonitor-test<<-\\EOF &&\n \t\tprintf \"last_update_token\\0\"\n \tEOF\n \tgit update-index --fsmonitor &&\n@@ -169,7 +169,7 @@ EOF\n \n # test that newly added files are marked valid\n test_expect_success 'newly added files are marked valid' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --setup --clobber fsmonitor-test<<-\\EOF &&\n \t\tprintf \"last_update_token\\0\"\n \tEOF\n \tgit add new &&\n@@ -210,7 +210,7 @@ EOF\n \n # test that *only* files returned by the integration script get flagged as invalid\n test_expect_success '*only* files returned by the integration script get flagged as invalid' '\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \tprintf \"last_update_token\\0\"\n \tprintf \"dir1/modified\\0\"\n \tEOF\n@@ -231,7 +231,7 @@ test_expect_success 'refresh_index() invalidates fsmonitor cache' '\n \tdirty_repo &&\n \twrite_integration_script &&\n \tgit add . &&\n-\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \tEOF\n \tgit commit -m \"to reset\" &&\n \tgit reset HEAD~1 &&\n@@ -280,7 +280,7 @@ do\n \t\t# Make sure it's actually skipping the check for modified and untracked\n \t\t# (if enabled) files unless it is told about them.\n \t\ttest_expect_success \"status doesn't detect unreported modifications\" '\n-\t\t\twrite_script .git/hooks/fsmonitor-test<<-\\EOF &&\n+\t\t\ttest_hook --clobber fsmonitor-test<<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\t:>marker\n \t\t\tEOF\n@@ -414,14 +414,14 @@ test_expect_success 'status succeeds with sparse index' '\n \t\tgit -C sparse sparse-checkout init --cone --sparse-index &&\n \t\tgit -C sparse sparse-checkout set dir1 dir2 &&\n \n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\tEOF\n \t\tgit -C full config core.fsmonitor ../.git/hooks/fsmonitor-test &&\n \t\tgit -C sparse config core.fsmonitor ../.git/hooks/fsmonitor-test &&\n \t\tcheck_sparse_index_behavior ! &&\n \n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\tprintf \"dir1/modified\\0\"\n \t\tEOF\n@@ -439,7 +439,7 @@ test_expect_success 'status succeeds with sparse index' '\n \n \t\t# This one modifies outside the sparse-checkout definition\n \t\t# and hence we expect to expand the sparse-index.\n-\t\twrite_script .git/hooks/fsmonitor-test <<-\\EOF &&\n+\t\ttest_hook --clobber fsmonitor-test <<-\\EOF &&\n \t\t\tprintf \"last_update_token\\0\"\n \t\t\tprintf \"dir1a/modified\\0\"\n \t\tEOF\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 0f439c99d61..6c9c61c79c2 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -551,6 +551,58 @@ write_script () {\n \tchmod +x \"$1\"\n }\n \n+# Usage: test_hook [options] <hook-name> <<-\\EOF\n+#\n+#   -C <dir>:\n+#\tRun all git commands in directory <dir>\n+#   --setup\n+#\tSetup a hook for subsequent tests, i.e. don't remove it in a\n+#\t\"test_when_finished\"\n+#   --clobber\n+#\tOverwrite an existing <hook-name>, if it exists. Implies\n+#\t--setup (i.e. the \"test_when_finished\" is assumed to have been\n+#\tset up already).\n+test_hook () {\n+\tsetup= &&\n+\tclobber= &&\n+\tindir= &&\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-C)\n+\t\t\tindir=\"$2\" &&\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--setup)\n+\t\t\tsetup=t\n+\t\t\t;;\n+\t\t--clobber)\n+\t\t\tclobber=t\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tBUG \"invalid argument: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac &&\n+\t\tshift\n+\tdone &&\n+\n+\tgit_dir=$(git -C \"$indir\" rev-parse --absolute-git-dir) &&\n+\thook_dir=\"$git_dir/hooks\" &&\n+\thook_file=\"$hook_dir/$1\" &&\n+\tif test -z \"$clobber\"\n+\tthen\n+\t\ttest_path_is_missing \"$hook_file\"\n+\tfi &&\n+\tif test -z \"$setup$clobber\"\n+\tthen\n+\t\ttest_when_finished \"rm \\\"$hook_file\\\"\"\n+\tfi &&\n+\twrite_script \"$hook_file\"\n+}\n+\n # Use test_set_prereq to tell that a particular prerequisite is available.\n # The prerequisite can later be checked for in two ways:\n #\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451541","messageId":"patch-v3-03.13-8451c31911d-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 03/13] http tests: don't rely on \"hook/post-update.sample\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:08Z","receivedAt":"2022-03-17T10:13:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change code added in a87679339c0 (test: rename http fetch and push\ntest files, 2014-02-06) to stop relying on the \"exec git\nupdate-server-info\" in \"templates/hooks--post-update.sample\", let's\ninstead inline the expected hook in the test itself.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5540-http-push-webdav.sh | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t5540-http-push-webdav.sh b/t/t5540-http-push-webdav.sh\nindex b0dbacf0b9b..37db3dec0c5 100755\n--- a/t/t5540-http-push-webdav.sh\n+++ b/t/t5540-http-push-webdav.sh\n@@ -42,7 +42,9 @@ test_expect_success 'setup remote repository' '\n \tgit clone --bare test_repo test_repo.git &&\n \tcd test_repo.git &&\n \tgit --bare update-server-info &&\n-\tmv hooks/post-update.sample hooks/post-update &&\n+\ttest_hook --setup post-update <<-\\EOF &&\n+\texec git update-server-info\n+\tEOF\n \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n \tcd - &&\n \tmv test_repo.git \"$HTTPD_DOCUMENT_ROOT_PATH\"\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451542","messageId":"patch-v3-02.13-aa4ee4da289-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 02/13] hook tests: turn exit code assertions into a loop","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:07Z","receivedAt":"2022-03-17T10:13:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend a test added in 96e7225b310 (hook: add 'run' subcommand,\n2021-12-22) to use a for-loop instead of a copy/pasting the same test\nfor the four exit codes we test.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1800-hook.sh | 35 ++++++++++-------------------------\n 1 file changed, 10 insertions(+), 25 deletions(-)\n\ndiff --git a/t/t1800-hook.sh b/t/t1800-hook.sh\nindex 93540b1fa12..26ed5e11bc8 100755\n--- a/t/t1800-hook.sh\n+++ b/t/t1800-hook.sh\n@@ -53,31 +53,16 @@ test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n \ttest_must_be_empty stdout.actual\n '\n \n-test_expect_success 'git hook run: exit codes are passed along' '\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 1\n-\tEOF\n-\n-\ttest_expect_code 1 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 2\n-\tEOF\n-\n-\ttest_expect_code 2 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 128\n-\tEOF\n-\n-\ttest_expect_code 128 git hook run test-hook &&\n-\n-\twrite_script .git/hooks/test-hook <<-EOF &&\n-\texit 129\n-\tEOF\n-\n-\ttest_expect_code 129 git hook run test-hook\n-'\n+for code in 1 2 128 129\n+do\n+\ttest_expect_success \"git hook run: exit code $code is passed along\" '\n+\t\ttest_hook test-hook <<-EOF &&\n+\t\texit $code\n+\t\tEOF\n+\n+\t\ttest_expect_code $code git hook run test-hook\n+\t'\n+done\n \n test_expect_success 'git hook run arg u ments without -- is not allowed' '\n \ttest_expect_code 129 git hook run test-hook arg u ments\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451544","messageId":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com","subject":"[PATCH v3 00/13] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:05Z","receivedAt":"2022-03-17T10:13:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This series is a test-only improvement series split up and adapted\nfrom a previous series of mine to add a \"git init --no-template\":\nhttps://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/;\nFor v1 and v2 see:\nhttps://lore.kernel.org/git/cover-00.10-00000000000-20220302T131859Z-avarab@gmail.com/\nand\nhttps://lore.kernel.org/git/cover-v2-00.10-00000000000-20220307T123909Z-avarab@gmail.com/\n\nChanges since v2:\n\n * A large rewrite to hopefully make Junio happy. I.e. I rewrote &\n   rebased the churn of changing certain tests in several\n   commit. Before it was first indentation changes, then getting rid\n   of sub-shells etc.\n\n   Now the first commit introduces the test_hook wrapper, and all\n   subsequent commits use it directly.\n\n * I added new commits to convert the test of the test suite, e.g. the\n   proc-receive tests.\n\n   Before (v2):  32 files changed, 325 insertions(+), 347 deletions(-)\n   After  (v3): 67 files changed, 572 insertions(+), 600 deletions(-)\n\nÆvar Arnfjörð Bjarmason (13):\n  test-lib-functions: add and use a \"test_hook\" wrapper\n  hook tests: turn exit code assertions into a loop\n  http tests: don't rely on \"hook/post-update.sample\"\n  tests: assume the hooks are disabled by default\n  bugreport tests: tighten up \"git bugreport -s hooks\" test\n  fetch+push tests: use \"test_hook\" and \"test_when_finished\" pattern\n  gc + p4 tests: use \"test_hook\", remove sub-shells\n  tests: change \"cat && chmod +x\" to use \"test_hook\"\n  tests: change \"mkdir -p && write_script\" to use \"test_hook\"\n  tests: use \"test_hook\" for misc \"mkdir -p\" and \"chmod\" cases\n  tests: extend \"test_hook\" for \"rm\" and \"chmod -x\", convert \"$HOOK\"\n  proc-receive hook tests: use \"test_hook\" instead of \"write_script\"\n  http tests: use \"test_hook\" for \"smart\" and \"dumb\" http tests\n\n t/t0029-core-unsetenvvars.sh                  |   3 +-\n t/t0091-bugreport.sh                          |  26 ++-\n t/t1350-config-hooks-path.sh                  |   4 +-\n t/t1416-ref-transaction-hooks.sh              |  27 ++-\n t/t1800-hook.sh                               |  45 ++--\n t/t2400-worktree-add.sh                       |   5 +-\n t/t3404-rebase-interactive.sh                 |  10 +-\n t/t3412-rebase-root.sh                        |  18 +-\n t/t3413-rebase-hook.sh                        |  18 +-\n t/t3430-rebase-merges.sh                      |   6 +-\n t/t4150-am.sh                                 |  24 +--\n t/t5401-update-hooks.sh                       |  64 +++---\n t/t5402-post-merge-hook.sh                    |  16 +-\n t/t5403-post-checkout-hook.sh                 |   3 +-\n t/t5406-remote-rejects.sh                     |   2 +-\n t/t5407-post-rewrite-hook.sh                  |  14 +-\n t/t5409-colorize-remote-messages.sh           |   2 +-\n t/t5411-proc-receive-hook.sh                  |   4 +-\n t/t5411/once-0010-report-status-v1.sh         |   2 +-\n t/t5411/test-0002-pre-receive-declined.sh     |   4 +-\n ...st-0003-pre-receive-declined--porcelain.sh |   2 +-\n t/t5411/test-0013-bad-protocol.sh             |  20 +-\n t/t5411/test-0014-bad-protocol--porcelain.sh  |  18 +-\n t/t5411/test-0020-report-ng.sh                |   4 +-\n t/t5411/test-0021-report-ng--porcelain.sh     |   4 +-\n t/t5411/test-0022-report-unexpect-ref.sh      |   2 +-\n ...est-0023-report-unexpect-ref--porcelain.sh |   2 +-\n t/t5411/test-0024-report-unknown-ref.sh       |   2 +-\n ...test-0025-report-unknown-ref--porcelain.sh |   2 +-\n t/t5411/test-0026-push-options.sh             |   6 +-\n t/t5411/test-0027-push-options--porcelain.sh  |   6 +-\n t/t5411/test-0030-report-ok.sh                |   2 +-\n t/t5411/test-0031-report-ok--porcelain.sh     |   2 +-\n t/t5411/test-0032-report-with-options.sh      |  14 +-\n ...est-0033-report-with-options--porcelain.sh |  14 +-\n t/t5411/test-0034-report-ft.sh                |   2 +-\n t/t5411/test-0035-report-ft--porcelain.sh     |   2 +-\n ...t-0036-report-multi-rewrite-for-one-ref.sh |   6 +-\n ...rt-multi-rewrite-for-one-ref--porcelain.sh |   6 +-\n t/t5411/test-0038-report-mixed-refs.sh        |   2 +-\n .../test-0039-report-mixed-refs--porcelain.sh |   2 +-\n t/t5411/test-0040-process-all-refs.sh         |   2 +-\n .../test-0041-process-all-refs--porcelain.sh  |   2 +-\n ...t-0050-proc-receive-refs-with-modifiers.sh |   4 +-\n t/t5503-tagfollow.sh                          |   4 +-\n t/t5510-fetch.sh                              |   8 +-\n t/t5516-fetch-push.sh                         | 192 ++++++++----------\n t/t5521-pull-options.sh                       |   4 +-\n t/t5534-push-signed.sh                        |  26 +--\n t/t5540-http-push-webdav.sh                   |   4 +-\n t/t5541-http-push-smart.sh                    |  32 ++-\n t/t5543-atomic-push.sh                        |   5 +-\n t/t5547-push-quarantine.sh                    |   4 +-\n t/t5548-push-porcelain.sh                     |   2 +-\n t/t5550-http-fetch-dumb.sh                    |  25 +--\n t/t5571-pre-push-hook.sh                      |  38 ++--\n t/t5601-clone.sh                              |   4 +-\n t/t6500-gc.sh                                 |  22 +-\n t/t7113-post-index-change-hook.sh             |   7 +-\n ...3-pre-commit-and-pre-merge-commit-hooks.sh | 150 +++++++-------\n t/t7504-commit-msg-hook.sh                    |  43 ++--\n t/t7505-prepare-commit-msg-hook.sh            |  43 ++--\n t/t7519-status-fsmonitor.sh                   |  20 +-\n t/t7520-ignored-hook-warning.sh               |  11 +-\n t/t9001-send-email.sh                         |   4 +-\n t/t9800-git-p4-basic.sh                       |  23 ++-\n t/test-lib-functions.sh                       |  76 +++++++\n 67 files changed, 572 insertions(+), 600 deletions(-)\n\nRange-diff against v2:\n 8:  1fce2d8855a !  1:  7761d777e9c test-lib-functions: add and use a \"test_hook\" wrapper\n    @@ Commit message\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## t/t0091-bugreport.sh ##\n    -@@ t/t0091-bugreport.sh: test_expect_success 'can create leading directories outside of a git dir' '\n    - test_expect_success 'indicates populated hooks' '\n    - \ttest_when_finished rm git-bugreport-hooks.txt &&\n    - \n    --\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n    -+\ttest_hook applypatch-msg <<-\\EOF &&\n    - \ttrue\n    - \tEOF\n    --\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n    -+\ttest_hook unknown-hook <<-\\EOF &&\n    - \ttrue\n    - \tEOF\n    - \tgit bugreport -s hooks &&\n    -\n      ## t/t1416-ref-transaction-hooks.sh ##\n     @@ t/t1416-ref-transaction-hooks.sh: test_expect_success setup '\n      '\n    @@ t/t1800-hook.sh: test_expect_success 'git hook run: basic' '\n      \techo >&1 Will end up on stderr\n      \techo >&2 Will end up on stderr\n      \tEOF\n    -@@ t/t1800-hook.sh: test_expect_success 'git hook run: stdout and stderr both write to our stderr' '\n    - for code in 1 2 128 129\n    - do\n    - \ttest_expect_success \"git hook run: exit code $code is passed along\" '\n    --\t\twrite_script .git/hooks/test-hook <<-EOF &&\n    -+\t\ttest_hook test-hook <<-EOF &&\n    - \t\texit $code\n    - \t\tEOF\n    - \n     @@ t/t1800-hook.sh: test_expect_success 'git hook run arg u ments without -- is not allowed' '\n      '\n      \n    @@ t/t1800-hook.sh: test_expect_success 'git -c core.hooksPath=<PATH> hook run' '\n      \t# t1350-config-hooks-path.sh\n      \t>actual &&\n     \n    + ## t/t5401-update-hooks.sh ##\n    +@@ t/t5401-update-hooks.sh: test_expect_success 'send-pack stderr contains hook messages' '\n    + '\n    + \n    + test_expect_success 'pre-receive hook that forgets to read its input' '\n    +-\twrite_script victim.git/hooks/pre-receive <<-\\EOF &&\n    ++\ttest_hook --clobber -C victim.git pre-receive <<-\\EOF &&\n    + \texit 0\n    + \tEOF\n    + \trm -f victim.git/hooks/update victim.git/hooks/post-update &&\n    +\n      ## t/t5406-remote-rejects.sh ##\n     @@ t/t5406-remote-rejects.sh: test_description='remote push rejects are reported by client'\n      . ./test-lib.sh\n    @@ t/t5411-proc-receive-hook.sh: setup_upstream_and_workbench () {\n      \t\techo \"# post-receive hook\"\n      \t\twhile read old new ref\n     \n    + ## t/t5503-tagfollow.sh ##\n    +@@ t/t5503-tagfollow.sh: test_expect_success 'atomic fetch with failing backfill' '\n    + \t# one of both fails to update correctly.\n    + \t#\n    + \t# To trigger failure we simply abort when backfilling a tag.\n    +-\twrite_script clone3/.git/hooks/reference-transaction <<-\\EOF &&\n    ++\ttest_hook -C clone3 reference-transaction <<-\\EOF &&\n    + \t\twhile read oldrev newrev reference\n    + \t\tdo\n    + \t\t\tif test \"$reference\" = refs/tags/tag1\n    +@@ t/t5503-tagfollow.sh: test_expect_success 'atomic fetch with backfill should use single transaction' '\n    + \t\t$ZERO_OID $T refs/tags/tag1\n    + \tEOF\n    + \n    +-\twrite_script clone4/.git/hooks/reference-transaction <<-\\EOF &&\n    ++\ttest_hook -C clone4 reference-transaction <<-\\EOF &&\n    + \t\t( echo \"$*\" && cat ) >>actual\n    + \tEOF\n    + \n    +\n      ## t/t5510-fetch.sh ##\n     @@ t/t5510-fetch.sh: test_expect_success 'fetch --atomic executes a single reference transaction only\n      \tEOF\n    @@ t/t5510-fetch.sh: test_expect_success 'fetch --atomic --append appends to FETCH_\n      \t\texit 1\n      \tEOF\n      \n    -\n    - ## t/t5516-fetch-push.sh ##\n    -@@ t/t5516-fetch-push.sh: test_expect_success 'updateInstead with push-to-checkout hook' '\n    - \tgit -C testrepo reset --hard HEAD^^ &&\n    - \tgit -C testrepo tag initial &&\n    - \tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n    --\twrite_script testrepo/.git/hooks/push-to-checkout <<-\\EOF &&\n    -+\ttest_hook -C testrepo push-to-checkout <<-\\EOF &&\n    - \techo >&2 updating from $(git rev-parse HEAD)\n    - \techo >&2 updating to \"$1\"\n    - \n    -@@ t/t5516-fetch-push.sh: test_expect_success 'updateInstead with push-to-checkout hook' '\n    - \ttest_when_finished \"rm -rf void\" &&\n    - \tgit init void &&\n    - \tgit -C void config receive.denyCurrentBranch updateInstead &&\n    --\twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n    -+\ttest_hook -C void push-to-checkout <<-\\EOF &&\n    - \tif git rev-parse --quiet --verify HEAD\n    - \tthen\n    - \t\thas_head=yes\n    +@@ t/t5510-fetch.sh: test_expect_success 'fetch --atomic --prune executes a single reference transact\n    + \t\t$ZERO_OID $head_oid refs/remotes/origin/new-branch\n    + \tEOF\n    + \n    +-\twrite_script atomic/.git/hooks/reference-transaction <<-\\EOF &&\n    ++\ttest_hook -C atomic reference-transaction <<-\\EOF &&\n    + \t\t( echo \"$*\" && cat ) >>actual\n    + \tEOF\n    + \n     \n      ## t/t5521-pull-options.sh ##\n     @@ t/t5521-pull-options.sh: test_expect_success 'git pull --no-verify flag passed to merge' '\n    @@ t/t5521-pull-options.sh: test_expect_success 'git pull --no-verify --verify pass\n      \tEOF\n      \ttest_commit -C src two &&\n     \n    - ## t/t5540-http-push-webdav.sh ##\n    -@@ t/t5540-http-push-webdav.sh: test_expect_success 'setup remote repository' '\n    - \tgit clone --bare test_repo test_repo.git &&\n    - \tcd test_repo.git &&\n    - \tgit --bare update-server-info &&\n    --\twrite_script hooks/post-update <<-\\EOF &&\n    -+\ttest_hook --setup post-update <<-\\EOF &&\n    - \texec git update-server-info\n    - \tEOF\n    - \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n    -\n      ## t/t5547-push-quarantine.sh ##\n     @@ t/t5547-push-quarantine.sh: test_description='check quarantine of objects during push'\n      \n    @@ t/t5548-push-porcelain.sh: run_git_push_porcelain_output_test() {\n      \t\tEOF\n      \t'\n     \n    - ## t/t6500-gc.sh ##\n    -@@ t/t6500-gc.sh: test_expect_success 'pre-auto-gc hook can stop auto gc' '\n    - \tEOF\n    - \n    - \tgit init pre-auto-gc-hook &&\n    --\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n    -+\ttest_hook -C pre-auto-gc-hook pre-auto-gc <<-\\EOF &&\n    - \techo >&2 no gc for you &&\n    - \texit 1\n    - \tEOF\n    -@@ t/t6500-gc.sh: test_expect_success 'pre-auto-gc hook can stop auto gc' '\n    - \tSee \"git help gc\" for manual housekeeping.\n    - \tEOF\n    - \n    --\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n    -+\ttest_hook -C pre-auto-gc-hook --clobber pre-auto-gc <<-\\EOF &&\n    - \techo >&2 will gc for you &&\n    - \texit 0\n    - \tEOF\n    -\n      ## t/t7519-status-fsmonitor.sh ##\n     @@ t/t7519-status-fsmonitor.sh: dirty_repo () {\n      }\n 1:  706460d10b9 !  2:  aa4ee4da289 hook tests: turn exit code assertions into a loop\n    @@ t/t1800-hook.sh: test_expect_success 'git hook run: stdout and stderr both write\n     +for code in 1 2 128 129\n     +do\n     +\ttest_expect_success \"git hook run: exit code $code is passed along\" '\n    -+\t\twrite_script .git/hooks/test-hook <<-EOF &&\n    ++\t\ttest_hook test-hook <<-EOF &&\n     +\t\texit $code\n     +\t\tEOF\n     +\n 2:  4bee939a894 !  3:  8451c31911d t5540: don't rely on \"hook/post-update.sample\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    t5540: don't rely on \"hook/post-update.sample\"\n    +    http tests: don't rely on \"hook/post-update.sample\"\n     \n         Change code added in a87679339c0 (test: rename http fetch and push\n         test files, 2014-02-06) to stop relying on the \"exec git\n    @@ t/t5540-http-push-webdav.sh: test_expect_success 'setup remote repository' '\n      \tcd test_repo.git &&\n      \tgit --bare update-server-info &&\n     -\tmv hooks/post-update.sample hooks/post-update &&\n    -+\twrite_script hooks/post-update <<-\\EOF &&\n    ++\ttest_hook --setup post-update <<-\\EOF &&\n     +\texec git update-server-info\n     +\tEOF\n      \tORIG_HEAD=$(git rev-parse --verify HEAD) &&\n 3:  fc1a9d4d55b !  4:  3a3289afd80 tests: assume the hooks are disabled by default\n    @@ t/t7519-status-fsmonitor.sh: test_expect_success UNTRACKED_CACHE 'ignore .git ch\n      \t\tcd dot-git &&\n     -\t\tmkdir -p .git/hooks &&\n      \t\t: >tracked &&\n    + \t\ttest-tool chmtime =-60 tracked &&\n      \t\t: >modified &&\n    - \t\tmkdir dir1 &&\n 4:  8dd7b40e510 !  5:  c21e3e43a55 bugreport tests: tighten up \"git bugreport -s hooks\" test\n    @@ t/t0091-bugreport.sh: test_expect_success 'can create leading directories outsid\n     -\t\tEOF\n     -\tdone &&\n     +\n    -+\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n    ++\ttest_hook applypatch-msg <<-\\EOF &&\n     +\ttrue\n     +\tEOF\n    -+\twrite_script .git/hooks/unknown-hook <<-\\EOF &&\n    ++\ttest_hook unknown-hook <<-\\EOF &&\n     +\ttrue\n     +\tEOF\n      \tgit bugreport -s hooks &&\n 7:  0ac75ed062f !  6:  0cf152dfca7 fetch+push tests: have tests clean up their own mess\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    fetch+push tests: have tests clean up their own mess\n    +    fetch+push tests: use \"test_hook\" and \"test_when_finished\" pattern\n     \n    -    Change the \"t5516-fetch-push.sh\" test code to make use of\n    -    \"test_when_finished\" to remove data instead of having tests clean up\n    -    leftover data from earlier tests, which may or may not be\n    -    there (e.g. depending on the --run=* option).\n    +    Change the \"t5516-fetch-push.sh\" test code to make use of the new\n    +    \"test_hook\" helper, and to use \"test_when_finished\" to have tests\n    +    clean up their own state, instead of relying on subsequent tests to\n    +    clean the trash directory.\n     \n         Before this each test would have been responsible for cleaning up\n         after a preceding test (which may or may not have run, e.g. if --run\n         or \"GIT_SKIP_TESTS\" was used), now each test will instead clean up\n         after itself.\n     \n    -    When doing this split up the \"push with negotiation\" test, now the\n    +    In order to use both \"test_hook\" and \"test_when_finished\" we need to\n    +    move them out of sub-shells, which requires some refactoring.\n    +\n    +    While we're at it split up the \"push with negotiation\" test, now the\n         middle of the test doesn't need to \"rm event\", and since it delimited\n         two halves that were testing two different things the end-state is\n         easier to read and reason about.\n    @@ t/t5516-fetch-push.sh: D=$(pwd)\n      mk_empty () {\n      \trepo_name=\"$1\"\n     -\trm -fr \"$repo_name\" &&\n    +-\tmkdir \"$repo_name\" &&\n    +-\t(\n    +-\t\tcd \"$repo_name\" &&\n    +-\t\tgit init &&\n    +-\t\tgit config receive.denyCurrentBranch warn\n    +-\t)\n     +\ttest_when_finished \"rm -rf \\\"$repo_name\\\"\" &&\n     +\ttest_path_is_missing \"$repo_name\" &&\n    - \tgit init \"$repo_name\" &&\n    - \tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n    ++\tgit init \"$repo_name\" &&\n    ++\tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n      }\n    -@@ t/t5516-fetch-push.sh: mk_test_with_hooks() {\n    + \n    + mk_test () {\n    +@@ t/t5516-fetch-push.sh: mk_test () {\n    + mk_test_with_hooks() {\n    + \trepo_name=$1\n    + \tmk_test \"$@\" &&\n    +-\t(\n    +-\t\tcd \"$repo_name\" &&\n    +-\t\tmkdir .git/hooks &&\n    +-\t\tcd .git/hooks &&\n    +-\n    +-\t\tcat >pre-receive <<-'EOF' &&\n    +-\t\t#!/bin/sh\n    +-\t\tcat - >>pre-receive.actual\n    +-\t\tEOF\n    +-\n    +-\t\tcat >update <<-'EOF' &&\n    +-\t\t#!/bin/sh\n    +-\t\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n    +-\t\tEOF\n    +-\n    +-\t\tcat >post-receive <<-'EOF' &&\n    +-\t\t#!/bin/sh\n    +-\t\tcat - >>post-receive.actual\n    +-\t\tEOF\n    +-\n    +-\t\tcat >post-update <<-'EOF' &&\n    +-\t\t#!/bin/sh\n    +-\t\tfor ref in \"$@\"\n    +-\t\tdo\n    +-\t\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n    +-\t\tdone\n    +-\t\tEOF\n    +-\n    +-\t\tchmod +x pre-receive update post-receive post-update\n    +-\t)\n    ++\ttest_hook -C \"$repo_name\" pre-receive <<-'EOF' &&\n    ++\tcat - >>pre-receive.actual\n    ++\tEOF\n    ++\n    ++\ttest_hook -C \"$repo_name\" update <<-'EOF' &&\n    ++\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n    ++\tEOF\n    ++\n    ++\ttest_hook -C \"$repo_name\" post-receive <<-'EOF' &&\n    ++\tcat - >>post-receive.actual\n    ++\tEOF\n    ++\n    ++\ttest_hook -C \"$repo_name\" post-update <<-'EOF'\n    ++\tfor ref in \"$@\"\n    ++\tdo\n    ++\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n    ++\tdone\n    ++\tEOF\n      }\n      \n      mk_child() {\n    @@ t/t5516-fetch-push.sh: grep_wrote () {\n      \tGIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT=\"$(pwd)/event\" \\\n      \t\tgit -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&\n      \tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n    +@@ t/t5516-fetch-push.sh: test_expect_success 'push does not update local refs on failure' '\n    + \n    + \tmk_test testrepo heads/main &&\n    + \tmk_child testrepo child &&\n    +-\tmkdir testrepo/.git/hooks &&\n    + \techo \"#!/no/frobnication/today\" >testrepo/.git/hooks/pre-receive &&\n    + \tchmod +x testrepo/.git/hooks/pre-receive &&\n    + \t(\n     @@ t/t5516-fetch-push.sh: done\n      \n      test_expect_success 'fetch follows tags by default' '\n    @@ t/t5516-fetch-push.sh: test_expect_success 'receive.denyCurrentBranch = updateIn\n     -\trm -fr testrepo &&\n     +\ttest_when_finished \"rm -rf testrepo\" &&\n      \tgit init testrepo &&\n    - \tgit -C testrepo pull .. main &&\n    - \tgit -C testrepo reset --hard HEAD^^ &&\n    +-\t(\n    +-\t\tcd testrepo &&\n    +-\t\tgit pull .. main &&\n    +-\t\tgit reset --hard HEAD^^ &&\n    +-\t\tgit tag initial &&\n    +-\t\tgit config receive.denyCurrentBranch updateInstead &&\n    +-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n    +-\t\techo >&2 updating from $(git rev-parse HEAD)\n    +-\t\techo >&2 updating to \"$1\"\n    +-\n    +-\t\tgit update-index -q --refresh &&\n    +-\t\tgit read-tree -u -m HEAD \"$1\" || {\n    +-\t\t\tstatus=$?\n    +-\t\t\techo >&2 read-tree failed\n    +-\t\t\texit $status\n    +-\t\t}\n    +-\t\tEOF\n    +-\t) &&\n    ++\tgit -C testrepo pull .. main &&\n    ++\tgit -C testrepo reset --hard HEAD^^ &&\n    ++\tgit -C testrepo tag initial &&\n    ++\tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n    ++\ttest_hook -C testrepo push-to-checkout <<-\\EOF &&\n    ++\techo >&2 updating from $(git rev-parse HEAD)\n    ++\techo >&2 updating to \"$1\"\n    ++\n    ++\tgit update-index -q --refresh &&\n    ++\tgit read-tree -u -m HEAD \"$1\" || {\n    ++\t\tstatus=$?\n    ++\t\techo >&2 read-tree failed\n    ++\t\texit $status\n    ++\t}\n    ++\tEOF\n    + \n    + \t# Try pushing into a pristine\n    + \tgit push testrepo main &&\n     @@ t/t5516-fetch-push.sh: test_expect_success 'updateInstead with push-to-checkout hook' '\n      \t) &&\n      \n    @@ t/t5516-fetch-push.sh: test_expect_success 'updateInstead with push-to-checkout\n     -\trm -fr void &&\n     +\ttest_when_finished \"rm -rf void\" &&\n      \tgit init void &&\n    - \tgit -C void config receive.denyCurrentBranch updateInstead &&\n    - \twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n    +-\t(\n    +-\t\tcd void &&\n    +-\t\tgit config receive.denyCurrentBranch updateInstead &&\n    +-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n    +-\t\tif git rev-parse --quiet --verify HEAD\n    +-\t\tthen\n    +-\t\t\thas_head=yes\n    +-\t\t\techo >&2 updating from $(git rev-parse HEAD)\n    +-\t\telse\n    +-\t\t\thas_head=no\n    +-\t\t\techo >&2 pushing into void\n    +-\t\tfi\n    +-\t\techo >&2 updating to \"$1\"\n    +-\n    +-\t\tgit update-index -q --refresh &&\n    +-\t\tcase \"$has_head\" in\n    +-\t\tyes)\n    +-\t\t\tgit read-tree -u -m HEAD \"$1\" ;;\n    +-\t\tno)\n    +-\t\t\tgit read-tree -u -m \"$1\" ;;\n    +-\t\tesac || {\n    +-\t\t\tstatus=$?\n    +-\t\t\techo >&2 read-tree failed\n    +-\t\t\texit $status\n    +-\t\t}\n    +-\t\tEOF\n    +-\t) &&\n    ++\tgit -C void config receive.denyCurrentBranch updateInstead &&\n    ++\ttest_hook -C void push-to-checkout <<-\\EOF &&\n    ++\tif git rev-parse --quiet --verify HEAD\n    ++\tthen\n    ++\t\thas_head=yes\n    ++\t\techo >&2 updating from $(git rev-parse HEAD)\n    ++\telse\n    ++\t\thas_head=no\n    ++\t\techo >&2 pushing into void\n    ++\tfi\n    ++\techo >&2 updating to \"$1\"\n    ++\n    ++\tgit update-index -q --refresh &&\n    ++\tcase \"$has_head\" in\n    ++\tyes)\n    ++\t\tgit read-tree -u -m HEAD \"$1\" ;;\n    ++\tno)\n    ++\t\tgit read-tree -u -m \"$1\" ;;\n    ++\tesac || {\n    ++\t\tstatus=$?\n    ++\t\techo >&2 read-tree failed\n    ++\t\texit $status\n    ++\t}\n    ++\tEOF\n    + \n    + \tgit push void main &&\n    + \t(\n 6:  08bd1629d65 !  7:  bb57b298598 hook tests: get rid of unnecessary sub-shells\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    hook tests: get rid of unnecessary sub-shells\n    +    gc + p4 tests: use \"test_hook\", remove sub-shells\n     \n         Refactor the repository setup code for tests that test hooks the use\n    -    of sub-shells when setting up the test repository and hooks.\n    -\n    -    A subsequent commit will change the hook setup to use a helper that\n    -    makes use of \"test_when_finished\", which cannot be used in\n    -    sub-shells. Let's change that setup code, and the adjacent and similar\n    -    \"mk_empty\" code.\n    +    of sub-shells when setting up the test repository and hooks, and use\n    +    the \"test_hook\" wrapper instead of \"write_scripts\".\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## t/t5516-fetch-push.sh ##\n    -@@ t/t5516-fetch-push.sh: D=$(pwd)\n    - mk_empty () {\n    - \trepo_name=\"$1\"\n    - \trm -fr \"$repo_name\" &&\n    --\tmkdir \"$repo_name\" &&\n    --\t(\n    --\t\tcd \"$repo_name\" &&\n    --\t\tgit init &&\n    --\t\tgit config receive.denyCurrentBranch warn\n    --\t)\n    -+\tgit init \"$repo_name\" &&\n    -+\tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n    - }\n    - \n    - mk_test () {\n    -@@ t/t5516-fetch-push.sh: mk_test () {\n    - mk_test_with_hooks() {\n    - \trepo_name=$1\n    - \tmk_test \"$@\" &&\n    --\t(\n    --\t\tcd \"$repo_name\" &&\n    --\t\tmkdir .git/hooks &&\n    --\t\tcd .git/hooks &&\n    --\n    --\t\tcat >pre-receive <<-'EOF' &&\n    --\t\t#!/bin/sh\n    --\t\tcat - >>pre-receive.actual\n    --\t\tEOF\n    - \n    --\t\tcat >update <<-'EOF' &&\n    --\t\t#!/bin/sh\n    --\t\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n    --\t\tEOF\n    --\n    --\t\tcat >post-receive <<-'EOF' &&\n    --\t\t#!/bin/sh\n    --\t\tcat - >>post-receive.actual\n    --\t\tEOF\n    --\n    --\t\tcat >post-update <<-'EOF' &&\n    --\t\t#!/bin/sh\n    --\t\tfor ref in \"$@\"\n    --\t\tdo\n    --\t\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n    --\t\tdone\n    --\t\tEOF\n    --\n    --\t\tchmod +x pre-receive update post-receive post-update\n    --\t)\n    -+\tcat >\"$repo_name\"/.git/hooks/pre-receive <<-'EOF' &&\n    -+\t#!/bin/sh\n    -+\tcat - >>pre-receive.actual\n    -+\tEOF\n    -+\n    -+\tcat >\"$repo_name\"/.git/hooks/update <<-'EOF' &&\n    -+\t#!/bin/sh\n    -+\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n    -+\tEOF\n    -+\n    -+\tcat >\"$repo_name\"/.git/hooks/post-receive <<-'EOF' &&\n    -+\t#!/bin/sh\n    -+\tcat - >>post-receive.actual\n    -+\tEOF\n    -+\n    -+\tcat >\"$repo_name\"/.git/hooks/post-update <<-'EOF' &&\n    -+\t#!/bin/sh\n    -+\tfor ref in \"$@\"\n    -+\tdo\n    -+\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n    -+\tdone\n    -+\tEOF\n    -+\n    -+\tchmod +x \\\n    -+\t      \"$repo_name\"/.git/hooks/pre-receive \\\n    -+\t      \"$repo_name\"/.git/hooks/update \\\n    -+\t      \"$repo_name\"/.git/hooks/post-receive \\\n    -+\t      \"$repo_name\"/.git/hooks/post-update\n    - }\n    - \n    - mk_child() {\n    -@@ t/t5516-fetch-push.sh: test_expect_success 'push does not update local refs on failure' '\n    - \n    - \tmk_test testrepo heads/main &&\n    - \tmk_child testrepo child &&\n    --\tmkdir testrepo/.git/hooks &&\n    - \techo \"#!/no/frobnication/today\" >testrepo/.git/hooks/pre-receive &&\n    - \tchmod +x testrepo/.git/hooks/pre-receive &&\n    - \t(\n    -@@ t/t5516-fetch-push.sh: test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n    - test_expect_success 'updateInstead with push-to-checkout hook' '\n    - \trm -fr testrepo &&\n    - \tgit init testrepo &&\n    --\t(\n    --\t\tcd testrepo &&\n    --\t\tgit pull .. main &&\n    --\t\tgit reset --hard HEAD^^ &&\n    --\t\tgit tag initial &&\n    --\t\tgit config receive.denyCurrentBranch updateInstead &&\n    --\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n    --\t\techo >&2 updating from $(git rev-parse HEAD)\n    --\t\techo >&2 updating to \"$1\"\n    --\n    --\t\tgit update-index -q --refresh &&\n    --\t\tgit read-tree -u -m HEAD \"$1\" || {\n    --\t\t\tstatus=$?\n    --\t\t\techo >&2 read-tree failed\n    --\t\t\texit $status\n    --\t\t}\n    --\t\tEOF\n    --\t) &&\n    -+\tgit -C testrepo pull .. main &&\n    -+\tgit -C testrepo reset --hard HEAD^^ &&\n    -+\tgit -C testrepo tag initial &&\n    -+\tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n    -+\twrite_script testrepo/.git/hooks/push-to-checkout <<-\\EOF &&\n    -+\techo >&2 updating from $(git rev-parse HEAD)\n    -+\techo >&2 updating to \"$1\"\n    -+\n    -+\tgit update-index -q --refresh &&\n    -+\tgit read-tree -u -m HEAD \"$1\" || {\n    -+\t\tstatus=$?\n    -+\t\techo >&2 read-tree failed\n    -+\t\texit $status\n    -+\t}\n    -+\tEOF\n    - \n    - \t# Try pushing into a pristine\n    - \tgit push testrepo main &&\n    -@@ t/t5516-fetch-push.sh: test_expect_success 'updateInstead with push-to-checkout hook' '\n    - \t# push into void\n    - \trm -fr void &&\n    - \tgit init void &&\n    --\t(\n    --\t\tcd void &&\n    --\t\tgit config receive.denyCurrentBranch updateInstead &&\n    --\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n    --\t\tif git rev-parse --quiet --verify HEAD\n    --\t\tthen\n    --\t\t\thas_head=yes\n    --\t\t\techo >&2 updating from $(git rev-parse HEAD)\n    --\t\telse\n    --\t\t\thas_head=no\n    --\t\t\techo >&2 pushing into void\n    --\t\tfi\n    --\t\techo >&2 updating to \"$1\"\n    --\n    --\t\tgit update-index -q --refresh &&\n    --\t\tcase \"$has_head\" in\n    --\t\tyes)\n    --\t\t\tgit read-tree -u -m HEAD \"$1\" ;;\n    --\t\tno)\n    --\t\t\tgit read-tree -u -m \"$1\" ;;\n    --\t\tesac || {\n    --\t\t\tstatus=$?\n    --\t\t\techo >&2 read-tree failed\n    --\t\t\texit $status\n    --\t\t}\n    --\t\tEOF\n    --\t) &&\n    -+\tgit -C void config receive.denyCurrentBranch updateInstead &&\n    -+\twrite_script void/.git/hooks/push-to-checkout <<-\\EOF &&\n    -+\tif git rev-parse --quiet --verify HEAD\n    -+\tthen\n    -+\t\thas_head=yes\n    -+\t\techo >&2 updating from $(git rev-parse HEAD)\n    -+\telse\n    -+\t\thas_head=no\n    -+\t\techo >&2 pushing into void\n    -+\tfi\n    -+\techo >&2 updating to \"$1\"\n    -+\n    -+\tgit update-index -q --refresh &&\n    -+\tcase \"$has_head\" in\n    -+\tyes)\n    -+\t\tgit read-tree -u -m HEAD \"$1\" ;;\n    -+\tno)\n    -+\t\tgit read-tree -u -m \"$1\" ;;\n    -+\tesac || {\n    -+\t\tstatus=$?\n    -+\t\techo >&2 read-tree failed\n    -+\t\texit $status\n    -+\t}\n    -+\tEOF\n    - \n    - \tgit push void main &&\n    - \t(\n    -\n      ## t/t6500-gc.sh ##\n     @@ t/t6500-gc.sh: test_expect_success 'pre-auto-gc hook can stop auto gc' '\n      \tEOF\n      \n      \tgit init pre-auto-gc-hook &&\n    -+\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n    ++\ttest_hook -C pre-auto-gc-hook pre-auto-gc <<-\\EOF &&\n     +\techo >&2 no gc for you &&\n     +\texit 1\n     +\tEOF\n    @@ t/t6500-gc.sh: test_expect_success 'pre-auto-gc hook can stop auto gc' '\n      \tSee \"git help gc\" for manual housekeeping.\n      \tEOF\n      \n    -+\twrite_script \"pre-auto-gc-hook/.git/hooks/pre-auto-gc\" <<-\\EOF &&\n    -+\techo >&2 will gc for you &&\n    -+\texit 0\n    -+\tEOF\n    -+\n    - \t(\n    - \t\tcd pre-auto-gc-hook &&\n    +-\t(\n    +-\t\tcd pre-auto-gc-hook &&\n     -\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n     -\t\techo >&2 will gc for you &&\n     -\t\texit 0\n     -\t\tEOF\n    +-\t\tgit gc --auto >../out.actual 2>../err.actual\n    +-\t) &&\n    ++\ttest_hook -C pre-auto-gc-hook --clobber pre-auto-gc <<-\\EOF &&\n    ++\techo >&2 will gc for you &&\n    ++\texit 0\n    ++\tEOF\n     +\n    - \t\tgit gc --auto >../out.actual 2>../err.actual\n    - \t) &&\n    ++\tgit -C pre-auto-gc-hook gc --auto >out.actual 2>err.actual &&\n      \n    + \ttest_must_be_empty out.actual &&\n    + \ttest_cmp err.expect err.actual\n     \n      ## t/t9800-git-p4-basic.sh ##\n     @@ t/t9800-git-p4-basic.sh: test_expect_success 'run hook p4-pre-submit before submit' '\n    @@ t/t9800-git-p4-basic.sh: test_expect_success 'run hook p4-pre-submit before subm\n     -\t\tEOF\n     +\t\tgrep \"Would apply\" out\n     +\t) &&\n    -+\tmkdir -p \"$git\"/.git/hooks &&\n    -+\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n    ++\ttest_hook -C \"$git\" p4-pre-submit <<-\\EOF &&\n     +\texit 0\n     +\tEOF\n     +\t(\n    @@ t/t9800-git-p4-basic.sh: test_expect_success 'run hook p4-pre-submit before subm\n     -\t\tEOF\n     +\t\tgrep \"Would apply\" out\n     +\t) &&\n    -+\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n    ++\ttest_hook -C \"$git\" --clobber p4-pre-submit <<-\\EOF &&\n     +\texit 1\n     +\tEOF\n     +\t(\n10:  db27fa32bbd !  8:  bb25560d432 tests: change \"cat && chmod +x\" to use \"test_hook\"\n    @@ Commit message\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## t/t3412-rebase-root.sh ##\n    -@@ t/t3412-rebase-root.sh: test_expect_success 'rebase --root fails with too many args' '\n    - '\n    - \n    - test_expect_success 'setup pre-rebase hook' '\n    --\tmkdir -p .git/hooks &&\n    --\tcat >.git/hooks/pre-rebase <<-EOF &&\n    --\t#!$SHELL_PATH\n    --\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n    -+\ttest_hook --setup pre-rebase <<-\\EOF\n    -+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n    - \tEOF\n    --\tchmod +x .git/hooks/pre-rebase\n    - '\n    - cat > expect <<EOF\n    - 4\n    -@@ t/t3412-rebase-root.sh: commit work7~5\n    - EOF\n    - \n    - test_expect_success 'setup pre-rebase hook that fails' '\n    --\tmkdir -p .git/hooks &&\n    --\tcat >.git/hooks/pre-rebase <<-EOF &&\n    --\t#!$SHELL_PATH\n    -+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n    - \tfalse\n    - \tEOF\n    --\tchmod +x .git/hooks/pre-rebase\n    - '\n    - \n    - test_expect_success 'pre-rebase hook stops rebase' '\n    -\n    - ## t/t3413-rebase-hook.sh ##\n    -@@ t/t3413-rebase-hook.sh: test_expect_success 'rebase -i' '\n    - '\n    - \n    - test_expect_success 'setup pre-rebase hook' '\n    --\tmkdir -p .git/hooks &&\n    --\tcat >.git/hooks/pre-rebase <<-EOF &&\n    --\t#!$SHELL_PATH\n    --\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n    -+\ttest_hook --setup pre-rebase <<-\\EOF\n    -+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n    - \tEOF\n    --\tchmod +x .git/hooks/pre-rebase\n    - '\n    - \n    - test_expect_success 'pre-rebase hook gets correct input (1)' '\n    -@@ t/t3413-rebase-hook.sh: test_expect_success 'pre-rebase hook gets correct input (6)' '\n    - '\n    - \n    - test_expect_success 'setup pre-rebase hook that fails' '\n    --\tmkdir -p .git/hooks &&\n    --\tcat >.git/hooks/pre-rebase <<-EOF &&\n    --\t#!$SHELL_PATH\n    -+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n    - \tfalse\n    - \tEOF\n    --\tchmod +x .git/hooks/pre-rebase\n    - '\n    - \n    - test_expect_success 'pre-rebase hook stops rebase (1)' '\n    -\n    - ## t/t5401-update-hooks.sh ##\n    -@@ t/t5401-update-hooks.sh: test_expect_success setup '\n    - \tgit update-ref refs/heads/main $commit1 &&\n    - \tgit update-ref refs/heads/tofail $commit0 &&\n    - \n    --\tcat >victim.git/hooks/pre-receive <<-\\EOF &&\n    --\t#!/bin/sh\n    -+\ttest_hook --setup -C victim.git pre-receive <<-\\EOF &&\n    - \tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n    - \tcat - >$GIT_DIR/pre-receive.stdin\n    - \techo STDOUT pre-receive\n    - \techo STDERR pre-receive >&2\n    - \tEOF\n    --\tchmod u+x victim.git/hooks/pre-receive &&\n    - \n    --\tcat >victim.git/hooks/update <<-\\EOF &&\n    --\t#!/bin/sh\n    -+\ttest_hook --setup -C victim.git update <<-\\EOF &&\n    - \techo \"$@\" >>$GIT_DIR/update.args\n    - \tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n    - \techo STDOUT update $1\n    - \techo STDERR update $1 >&2\n    - \ttest \"$1\" = refs/heads/main || exit\n    - \tEOF\n    --\tchmod u+x victim.git/hooks/update &&\n    - \n    --\tcat >victim.git/hooks/post-receive <<-\\EOF &&\n    --\t#!/bin/sh\n    -+\ttest_hook --setup -C victim.git post-receive <<-\\EOF &&\n    - \tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n    - \tcat - >$GIT_DIR/post-receive.stdin\n    - \techo STDOUT post-receive\n    - \techo STDERR post-receive >&2\n    - \tEOF\n    --\tchmod u+x victim.git/hooks/post-receive &&\n    - \n    --\tcat >victim.git/hooks/post-update <<-\\EOF &&\n    --\t#!/bin/sh\n    -+\ttest_hook --setup -C victim.git post-update <<-\\EOF\n    - \techo \"$@\" >>$GIT_DIR/post-update.args\n    - \tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n    - \techo STDOUT post-update\n    - \techo STDERR post-update >&2\n    - \tEOF\n    --\tchmod u+x victim.git/hooks/post-update\n    - '\n    - \n    - test_expect_success push '\n    -\n      ## t/t5402-post-merge-hook.sh ##\n     @@ t/t5402-post-merge-hook.sh: test_expect_success setup '\n      \tGIT_DIR=clone2/.git git update-index --add a\n    @@ t/t5402-post-merge-hook.sh: test_expect_success setup '\n      test_expect_success 'post-merge does not run for up-to-date ' '\n      \tGIT_DIR=clone1/.git git merge $commit0 &&\n     \n    - ## t/t5407-post-rewrite-hook.sh ##\n    -@@ t/t5407-post-rewrite-hook.sh: test_expect_success 'setup' '\n    - \ttest_commit F foo F &&\n    - \tgit checkout main &&\n    - \n    --\tcat >.git/hooks/post-rewrite <<-EOF &&\n    --\t#!/bin/sh\n    -+\ttest_hook --setup post-rewrite <<-EOF\n    - \techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n    - \tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n    - \tEOF\n    --\tchmod u+x .git/hooks/post-rewrite\n    - '\n    - \n    - clear_hook_input () {\n    -\n    - ## t/t5516-fetch-push.sh ##\n    -@@ t/t5516-fetch-push.sh: mk_test () {\n    - mk_test_with_hooks() {\n    - \trepo_name=$1\n    - \tmk_test \"$@\" &&\n    --\n    --\tcat >\"$repo_name\"/.git/hooks/pre-receive <<-'EOF' &&\n    --\t#!/bin/sh\n    -+\ttest_hook -C \"$repo_name\" pre-receive <<-'EOF' &&\n    - \tcat - >>pre-receive.actual\n    - \tEOF\n    - \n    --\tcat >\"$repo_name\"/.git/hooks/update <<-'EOF' &&\n    --\t#!/bin/sh\n    -+\ttest_hook -C \"$repo_name\" update <<-'EOF' &&\n    - \tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n    - \tEOF\n    - \n    --\tcat >\"$repo_name\"/.git/hooks/post-receive <<-'EOF' &&\n    --\t#!/bin/sh\n    -+\ttest_hook -C \"$repo_name\" post-receive <<-'EOF' &&\n    - \tcat - >>post-receive.actual\n    - \tEOF\n    - \n    --\tcat >\"$repo_name\"/.git/hooks/post-update <<-'EOF' &&\n    --\t#!/bin/sh\n    -+\ttest_hook -C \"$repo_name\" post-update <<-'EOF'\n    - \tfor ref in \"$@\"\n    - \tdo\n    - \t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n    - \tdone\n    - \tEOF\n    --\n    --\tchmod +x \\\n    --\t      \"$repo_name\"/.git/hooks/pre-receive \\\n    --\t      \"$repo_name\"/.git/hooks/update \\\n    --\t      \"$repo_name\"/.git/hooks/post-receive \\\n    --\t      \"$repo_name\"/.git/hooks/post-update\n    - }\n    - \n    - mk_child() {\n    -\n    - ## t/t5541-http-push-smart.sh ##\n    -@@ t/t5541-http-push-smart.sh: test_expect_success 'create and delete remote branch' '\n    - '\n    - \n    - test_expect_success 'setup rejected update hook' '\n    --\tcat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<-EOF &&\n    --\t#!/bin/sh\n    -+\ttest_hook --setup -C \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git\" update <<-\\EOF &&\n    - \texit 1\n    - \tEOF\n    --\tchmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" &&\n    - \n    - \tcat >exp <<-EOF\n    - \tremote: error: hook declined to update refs/heads/dev2\n    -\n      ## t/t5601-clone.sh ##\n     @@ t/t5601-clone.sh: test_expect_success 'clone from hooks' '\n      \tcd .. &&\n 9:  121ca23db37 !  9:  f908e27da82 tests: change \"mkdir -p && write_script\" to use \"test_hook\"\n    @@ t/t9001-send-email.sh: test_expect_success $PREREQ 'cmdline in-reply-to used wit\n      \t# test that we have the correct environment variable, pwd, and\n      \t# argument\n      \tcase \"$GIT_DIR\" in\n    -\n    - ## t/t9800-git-p4-basic.sh ##\n    -@@ t/t9800-git-p4-basic.sh: test_expect_success 'run hook p4-pre-submit before submit' '\n    - \t\tgit p4 submit --dry-run >out &&\n    - \t\tgrep \"Would apply\" out\n    - \t) &&\n    --\tmkdir -p \"$git\"/.git/hooks &&\n    --\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n    -+\ttest_hook -C \"$git\" p4-pre-submit <<-\\EOF &&\n    - \texit 0\n    - \tEOF\n    - \t(\n    -@@ t/t9800-git-p4-basic.sh: test_expect_success 'run hook p4-pre-submit before submit' '\n    - \t\tgit p4 submit --dry-run >out &&\n    - \t\tgrep \"Would apply\" out\n    - \t) &&\n    --\twrite_script \"$git\"/.git/hooks/p4-pre-submit <<-\\EOF &&\n    -+\ttest_hook -C \"$git\" --clobber p4-pre-submit <<-\\EOF &&\n    - \texit 1\n    - \tEOF\n    - \t(\n 5:  19db5b2d7c2 ! 10:  dab99b8359d tests: indent and add hook setup to \"test_expect_success\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    tests: indent and add hook setup to \"test_expect_success\"\n    +    tests: use \"test_hook\" for misc \"mkdir -p\" and \"chmod\" cases\n     \n    -    Indent various hook setup code in the test suite that's using a manual\n    -    \"cat && chmod\" pattern.\n    -\n    -    These should also consistently use \"#!$SHELL_PATH\" instead of\n    -    \"#!/bin/sh\", i.e. \"test_script\". Let's fix that in a subsequent\n    -    commit, which will be easier to review after this smaller change.\n    +    Make use of \"test_hook\" in various cases that didn't fit neatly into\n    +    preceding commits. Here we need to indent blocks in addition to\n    +    changing the test code, or to make other small cosmetic changes.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## t/t3412-rebase-root.sh ##\n     @@ t/t3412-rebase-root.sh: test_expect_success 'rebase --root fails with too many args' '\n    + '\n      \n      test_expect_success 'setup pre-rebase hook' '\n    - \tmkdir -p .git/hooks &&\n    +-\tmkdir -p .git/hooks &&\n     -\tcat >.git/hooks/pre-rebase <<EOF &&\n     -#!$SHELL_PATH\n     -echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n     -EOF\n    -+\tcat >.git/hooks/pre-rebase <<-EOF &&\n    -+\t#!$SHELL_PATH\n    -+\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n    +-\tchmod +x .git/hooks/pre-rebase\n    ++\ttest_hook --setup pre-rebase <<-\\EOF\n    ++\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n     +\tEOF\n    - \tchmod +x .git/hooks/pre-rebase\n      '\n      cat > expect <<EOF\n    -@@ t/t3412-rebase-root.sh: EOF\n    + 4\n    +@@ t/t3412-rebase-root.sh: commit work7~5\n    + EOF\n      \n      test_expect_success 'setup pre-rebase hook that fails' '\n    - \tmkdir -p .git/hooks &&\n    +-\tmkdir -p .git/hooks &&\n     -\tcat >.git/hooks/pre-rebase <<EOF &&\n     -#!$SHELL_PATH\n     -false\n     -EOF\n    -+\tcat >.git/hooks/pre-rebase <<-EOF &&\n    -+\t#!$SHELL_PATH\n    +-\tchmod +x .git/hooks/pre-rebase\n    ++\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n     +\tfalse\n     +\tEOF\n    - \tchmod +x .git/hooks/pre-rebase\n      '\n      \n    + test_expect_success 'pre-rebase hook stops rebase' '\n     \n      ## t/t3413-rebase-hook.sh ##\n     @@ t/t3413-rebase-hook.sh: test_expect_success 'rebase -i' '\n    + '\n      \n      test_expect_success 'setup pre-rebase hook' '\n    - \tmkdir -p .git/hooks &&\n    +-\tmkdir -p .git/hooks &&\n     -\tcat >.git/hooks/pre-rebase <<EOF &&\n     -#!$SHELL_PATH\n     -echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n     -EOF\n    -+\tcat >.git/hooks/pre-rebase <<-EOF &&\n    -+\t#!$SHELL_PATH\n    -+\techo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n    +-\tchmod +x .git/hooks/pre-rebase\n    ++\ttest_hook --setup pre-rebase <<-\\EOF\n    ++\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n     +\tEOF\n    - \tchmod +x .git/hooks/pre-rebase\n      '\n      \n    + test_expect_success 'pre-rebase hook gets correct input (1)' '\n     @@ t/t3413-rebase-hook.sh: test_expect_success 'pre-rebase hook gets correct input (6)' '\n    + '\n      \n      test_expect_success 'setup pre-rebase hook that fails' '\n    - \tmkdir -p .git/hooks &&\n    +-\tmkdir -p .git/hooks &&\n     -\tcat >.git/hooks/pre-rebase <<EOF &&\n     -#!$SHELL_PATH\n     -false\n     -EOF\n    -+\tcat >.git/hooks/pre-rebase <<-EOF &&\n    -+\t#!$SHELL_PATH\n    +-\tchmod +x .git/hooks/pre-rebase\n    ++\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n     +\tfalse\n     +\tEOF\n    - \tchmod +x .git/hooks/pre-rebase\n      '\n      \n    + test_expect_success 'pre-rebase hook stops rebase (1)' '\n     \n      ## t/t5401-update-hooks.sh ##\n     @@ t/t5401-update-hooks.sh: test_expect_success setup '\n    @@ t/t5401-update-hooks.sh: test_expect_success setup '\n      \tGIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&\n      \tgit update-ref refs/heads/main $commit1 &&\n     -\tgit update-ref refs/heads/tofail $commit0\n    +-'\n     +\tgit update-ref refs/heads/tofail $commit0 &&\n    -+\n    -+\tcat >victim.git/hooks/pre-receive <<-\\EOF &&\n    -+\t#!/bin/sh\n    -+\tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n    -+\tcat - >$GIT_DIR/pre-receive.stdin\n    -+\techo STDOUT pre-receive\n    -+\techo STDERR pre-receive >&2\n    -+\tEOF\n    -+\tchmod u+x victim.git/hooks/pre-receive &&\n    -+\n    -+\tcat >victim.git/hooks/update <<-\\EOF &&\n    -+\t#!/bin/sh\n    -+\techo \"$@\" >>$GIT_DIR/update.args\n    -+\tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n    -+\techo STDOUT update $1\n    -+\techo STDERR update $1 >&2\n    -+\ttest \"$1\" = refs/heads/main || exit\n    -+\tEOF\n    -+\tchmod u+x victim.git/hooks/update &&\n    -+\n    -+\tcat >victim.git/hooks/post-receive <<-\\EOF &&\n    -+\t#!/bin/sh\n    -+\tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n    -+\tcat - >$GIT_DIR/post-receive.stdin\n    -+\techo STDOUT post-receive\n    -+\techo STDERR post-receive >&2\n    -+\tEOF\n    -+\tchmod u+x victim.git/hooks/post-receive &&\n    -+\n    -+\tcat >victim.git/hooks/post-update <<-\\EOF &&\n    -+\t#!/bin/sh\n    -+\techo \"$@\" >>$GIT_DIR/post-update.args\n    -+\tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n    -+\techo STDOUT post-update\n    -+\techo STDERR post-update >&2\n    -+\tEOF\n    -+\tchmod u+x victim.git/hooks/post-update\n    - '\n      \n     -cat >victim.git/hooks/pre-receive <<'EOF'\n     -#!/bin/sh\n    @@ t/t5401-update-hooks.sh: test_expect_success setup '\n     -echo STDERR pre-receive >&2\n     -EOF\n     -chmod u+x victim.git/hooks/pre-receive\n    --\n    ++\ttest_hook --setup -C victim.git pre-receive <<-\\EOF &&\n    ++\tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n    ++\tcat - >$GIT_DIR/pre-receive.stdin\n    ++\techo STDOUT pre-receive\n    ++\techo STDERR pre-receive >&2\n    ++\tEOF\n    + \n     -cat >victim.git/hooks/update <<'EOF'\n     -#!/bin/sh\n     -echo \"$@\" >>$GIT_DIR/update.args\n    @@ t/t5401-update-hooks.sh: test_expect_success setup '\n     -test \"$1\" = refs/heads/main || exit\n     -EOF\n     -chmod u+x victim.git/hooks/update\n    --\n    ++\ttest_hook --setup -C victim.git update <<-\\EOF &&\n    ++\techo \"$@\" >>$GIT_DIR/update.args\n    ++\tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n    ++\techo STDOUT update $1\n    ++\techo STDERR update $1 >&2\n    ++\ttest \"$1\" = refs/heads/main || exit\n    ++\tEOF\n    + \n     -cat >victim.git/hooks/post-receive <<'EOF'\n     -#!/bin/sh\n     -printf %s \"$@\" >>$GIT_DIR/post-receive.args\n    @@ t/t5401-update-hooks.sh: test_expect_success setup '\n     -echo STDERR post-receive >&2\n     -EOF\n     -chmod u+x victim.git/hooks/post-receive\n    --\n    ++\ttest_hook --setup -C victim.git post-receive <<-\\EOF &&\n    ++\tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n    ++\tcat - >$GIT_DIR/post-receive.stdin\n    ++\techo STDOUT post-receive\n    ++\techo STDERR post-receive >&2\n    ++\tEOF\n    + \n     -cat >victim.git/hooks/post-update <<'EOF'\n     -#!/bin/sh\n     -echo \"$@\" >>$GIT_DIR/post-update.args\n    @@ t/t5401-update-hooks.sh: test_expect_success setup '\n     -echo STDERR post-update >&2\n     -EOF\n     -chmod u+x victim.git/hooks/post-update\n    --\n    ++\ttest_hook --setup -C victim.git post-update <<-\\EOF\n    ++\techo \"$@\" >>$GIT_DIR/post-update.args\n    ++\tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n    ++\techo STDOUT post-update\n    ++\techo STDERR post-update >&2\n    ++\tEOF\n    ++'\n    + \n      test_expect_success push '\n      \ttest_must_fail git send-pack --force ./victim.git \\\n    - \t\tmain tofail >send.out 2>send.err\n     \n      ## t/t5407-post-rewrite-hook.sh ##\n     @@ t/t5407-post-rewrite-hook.sh: test_expect_success 'setup' '\n    @@ t/t5407-post-rewrite-hook.sh: test_expect_success 'setup' '\n     -cat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n     -EOF\n     -chmod u+x .git/hooks/post-rewrite\n    -+\tcat >.git/hooks/post-rewrite <<-EOF &&\n    -+\t#!/bin/sh\n    ++\ttest_hook --setup post-rewrite <<-EOF\n     +\techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n     +\tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n     +\tEOF\n    -+\tchmod u+x .git/hooks/post-rewrite\n     +'\n      \n      clear_hook_input () {\n    @@ t/t5541-http-push-smart.sh: test_expect_success 'create and delete remote branch\n     -EOF\n     -chmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\"\n     +test_expect_success 'setup rejected update hook' '\n    -+\tcat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<-EOF &&\n    -+\t#!/bin/sh\n    ++\ttest_hook --setup -C \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git\" update <<-\\EOF &&\n     +\texit 1\n     +\tEOF\n    -+\tchmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" &&\n      \n     -cat >exp <<EOF\n     -remote: error: hook declined to update refs/heads/dev2\n -:  ----------- > 11:  f541b0b2d70 tests: extend \"test_hook\" for \"rm\" and \"chmod -x\", convert \"$HOOK\"\n -:  ----------- > 12:  5b764ffc65a proc-receive hook tests: use \"test_hook\" instead of \"write_script\"\n -:  ----------- > 13:  2dffde32036 http tests: use \"test_hook\" for \"smart\" and \"dumb\" http tests\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451543","messageId":"patch-v3-04.13-3a3289afd80-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 04/13] tests: assume the hooks are disabled by default","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:09Z","receivedAt":"2022-03-17T10:13:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Stop moving the .git/hooks directory out of the way, or creating it\nduring test setup. Instead assume that it will contain\nharmless *.sample files.\n\nThat we can assume that is discussed in point #4 of\nf0d4d398e28 (test-lib: split up and deprecate test_create_repo(),\n2021-05-10), those parts of this could and should have been done in\nthat change.\n\nRemoving the \"mkdir -p\" here will then validate that our templates are\nbeing used, since we'd subsequently fail to create a hook in that\ndirectory if it didn't exist. Subsequent commits will have those hooks\ncreated by a \"test_hook\" wrapper, which will then being doing that\nsame validation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1416-ref-transaction-hooks.sh | 1 -\n t/t5516-fetch-push.sh            | 3 +--\n t/t7519-status-fsmonitor.sh      | 2 --\n 3 files changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/t/t1416-ref-transaction-hooks.sh b/t/t1416-ref-transaction-hooks.sh\nindex 6fca1f08d9a..085a7a46f21 100755\n--- a/t/t1416-ref-transaction-hooks.sh\n+++ b/t/t1416-ref-transaction-hooks.sh\n@@ -8,7 +8,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n \n test_expect_success setup '\n-\tmkdir -p .git/hooks &&\n \ttest_commit PRE &&\n \tPRE_OID=$(git rev-parse PRE) &&\n \ttest_commit POST &&\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 3137eb8d4d2..1a20e54adc1 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -28,8 +28,7 @@ mk_empty () {\n \t(\n \t\tcd \"$repo_name\" &&\n \t\tgit init &&\n-\t\tgit config receive.denyCurrentBranch warn &&\n-\t\tmv .git/hooks .git/hooks-disabled\n+\t\tgit config receive.denyCurrentBranch warn\n \t)\n }\n \ndiff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh\nindex 4c7c00c94f1..d4f9c6a837b 100755\n--- a/t/t7519-status-fsmonitor.sh\n+++ b/t/t7519-status-fsmonitor.sh\n@@ -56,7 +56,6 @@ test_lazy_prereq UNTRACKED_CACHE '\n '\n \n test_expect_success 'setup' '\n-\tmkdir -p .git/hooks &&\n \t: >tracked &&\n \t: >modified &&\n \tmkdir dir1 &&\n@@ -322,7 +321,6 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR'\n \ttest_create_repo dot-git &&\n \t(\n \t\tcd dot-git &&\n-\t\tmkdir -p .git/hooks &&\n \t\t: >tracked &&\n \t\ttest-tool chmtime =-60 tracked &&\n \t\t: >modified &&\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451545","messageId":"patch-v3-05.13-c21e3e43a55-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 05/13] bugreport tests: tighten up \"git bugreport -s hooks\" test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:10Z","receivedAt":"2022-03-17T10:13:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Amend a test added in 788a776069b (bugreport: collect list of\npopulated hooks, 2020-05-07) to \"test_cmp\" for the expected output,\ninstead of selectively using \"grep\" to check for specific things we\neither expect or don't expect in the output.\n\nAs noted in a preceding commit our .git/hooks directory already\ncontains *.sample hooks, so we have no need to clobber the\nprepare-commit-msg.sample hook in particular.\n\nInstead we should assert that those *.sample hooks are not included in\nthe output, and for good measure let's add a new \"unknown-hook\", to\ncheck that we only look through our own known hooks. See\ncfe853e66be (hook-list.h: add a generated list of hooks, like\nconfig-list.h, 2021-09-26) for how we generate that data.\n\nWe're intentionally not piping the \"actual\" output through \"sort\" or\nsimilar, we'd also like to check that our reported hooks are sorted.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0091-bugreport.sh | 26 +++++++++++++++-----------\n 1 file changed, 15 insertions(+), 11 deletions(-)\n\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nindex eeedbfa9193..08f5fe9caef 100755\n--- a/t/t0091-bugreport.sh\n+++ b/t/t0091-bugreport.sh\n@@ -60,18 +60,22 @@ test_expect_success 'can create leading directories outside of a git dir' '\n \n test_expect_success 'indicates populated hooks' '\n \ttest_when_finished rm git-bugreport-hooks.txt &&\n-\ttest_when_finished rm -fr .git/hooks &&\n-\trm -fr .git/hooks &&\n-\tmkdir .git/hooks &&\n-\tfor hook in applypatch-msg prepare-commit-msg.sample\n-\tdo\n-\t\twrite_script \".git/hooks/$hook\" <<-EOF || return 1\n-\t\techo \"hook $hook exists\"\n-\t\tEOF\n-\tdone &&\n+\n+\ttest_hook applypatch-msg <<-\\EOF &&\n+\ttrue\n+\tEOF\n+\ttest_hook unknown-hook <<-\\EOF &&\n+\ttrue\n+\tEOF\n \tgit bugreport -s hooks &&\n-\tgrep applypatch-msg git-bugreport-hooks.txt &&\n-\t! grep prepare-commit-msg git-bugreport-hooks.txt\n+\n+\tsort >expect <<-\\EOF &&\n+\t[Enabled Hooks]\n+\tapplypatch-msg\n+\tEOF\n+\n+\tsed -ne \"/^\\[Enabled Hooks\\]$/,/^$/p\" <git-bugreport-hooks.txt >actual &&\n+\ttest_cmp expect actual\n '\n \n test_done\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451546","messageId":"patch-v3-06.13-0cf152dfca7-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 06/13] fetch+push tests: use \"test_hook\" and \"test_when_finished\" pattern","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:11Z","receivedAt":"2022-03-17T10:13:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the \"t5516-fetch-push.sh\" test code to make use of the new\n\"test_hook\" helper, and to use \"test_when_finished\" to have tests\nclean up their own state, instead of relying on subsequent tests to\nclean the trash directory.\n\nBefore this each test would have been responsible for cleaning up\nafter a preceding test (which may or may not have run, e.g. if --run\nor \"GIT_SKIP_TESTS\" was used), now each test will instead clean up\nafter itself.\n\nIn order to use both \"test_hook\" and \"test_when_finished\" we need to\nmove them out of sub-shells, which requires some refactoring.\n\nWhile we're at it split up the \"push with negotiation\" test, now the\nmiddle of the test doesn't need to \"rm event\", and since it delimited\ntwo halves that were testing two different things the end-state is\neasier to read and reason about.\n\nWhile changing these lines make the minor change from \"-fr\" to \"-rf\"\nas the \"rm\" argument, some of them used it already, it's more common\nin the test suite, and it leaves the end-state of the file with more\nconsistency.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5516-fetch-push.sh | 191 +++++++++++++++++++-----------------------\n 1 file changed, 88 insertions(+), 103 deletions(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 1a20e54adc1..4dfb080433e 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -23,13 +23,10 @@ D=$(pwd)\n \n mk_empty () {\n \trepo_name=\"$1\"\n-\trm -fr \"$repo_name\" &&\n-\tmkdir \"$repo_name\" &&\n-\t(\n-\t\tcd \"$repo_name\" &&\n-\t\tgit init &&\n-\t\tgit config receive.denyCurrentBranch warn\n-\t)\n+\ttest_when_finished \"rm -rf \\\"$repo_name\\\"\" &&\n+\ttest_path_is_missing \"$repo_name\" &&\n+\tgit init \"$repo_name\" &&\n+\tgit -C \"$repo_name\" config receive.denyCurrentBranch warn\n }\n \n mk_test () {\n@@ -58,40 +55,28 @@ mk_test () {\n mk_test_with_hooks() {\n \trepo_name=$1\n \tmk_test \"$@\" &&\n-\t(\n-\t\tcd \"$repo_name\" &&\n-\t\tmkdir .git/hooks &&\n-\t\tcd .git/hooks &&\n-\n-\t\tcat >pre-receive <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tcat - >>pre-receive.actual\n-\t\tEOF\n-\n-\t\tcat >update <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n-\t\tEOF\n-\n-\t\tcat >post-receive <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tcat - >>post-receive.actual\n-\t\tEOF\n-\n-\t\tcat >post-update <<-'EOF' &&\n-\t\t#!/bin/sh\n-\t\tfor ref in \"$@\"\n-\t\tdo\n-\t\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n-\t\tdone\n-\t\tEOF\n-\n-\t\tchmod +x pre-receive update post-receive post-update\n-\t)\n+\ttest_hook -C \"$repo_name\" pre-receive <<-'EOF' &&\n+\tcat - >>pre-receive.actual\n+\tEOF\n+\n+\ttest_hook -C \"$repo_name\" update <<-'EOF' &&\n+\tprintf \"%s %s %s\\n\" \"$@\" >>update.actual\n+\tEOF\n+\n+\ttest_hook -C \"$repo_name\" post-receive <<-'EOF' &&\n+\tcat - >>post-receive.actual\n+\tEOF\n+\n+\ttest_hook -C \"$repo_name\" post-update <<-'EOF'\n+\tfor ref in \"$@\"\n+\tdo\n+\t\tprintf \"%s\\n\" \"$ref\" >>post-update.actual\n+\tdone\n+\tEOF\n }\n \n mk_child() {\n-\trm -rf \"$2\" &&\n+\ttest_when_finished \"rm -rf \\\"$2\\\"\" &&\n \tgit clone \"$1\" \"$2\"\n }\n \n@@ -196,32 +181,32 @@ grep_wrote () {\n \tgrep 'write_pack_file/wrote.*\"value\":\"'$1'\"' $2\n }\n \n-test_expect_success 'push with negotiation' '\n-\t# Without negotiation\n+test_expect_success 'push without negotiation' '\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n-\techo now pushing without negotiation &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 push testrepo refs/heads/main:refs/remotes/origin/main &&\n-\tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n+\tgrep_wrote 5 event # 2 commits, 2 trees, 1 blob\n+'\n \n-\t# Same commands, but with negotiation\n-\trm event &&\n+test_expect_success 'push with negotiation' '\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TRACE2_EVENT=\"$(pwd)/event\" git -c protocol.version=2 -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main &&\n \tgrep_wrote 2 event # 1 commit, 1 tree\n '\n \n test_expect_success 'push with negotiation proceeds anyway even if negotiation fails' '\n-\trm event &&\n \tmk_empty testrepo &&\n \tgit push testrepo $the_first_commit:refs/remotes/origin/first_commit &&\n \ttest_commit -C testrepo unrelated_commit &&\n \tgit -C testrepo config receive.hideRefs refs/remotes/origin/first_commit &&\n+\ttest_when_finished \"rm event\" &&\n \tGIT_TEST_PROTOCOL_VERSION=0 GIT_TRACE2_EVENT=\"$(pwd)/event\" \\\n \t\tgit -c push.negotiate=1 push testrepo refs/heads/main:refs/remotes/origin/main 2>err &&\n \tgrep_wrote 5 event && # 2 commits, 2 trees, 1 blob\n@@ -667,7 +652,6 @@ test_expect_success 'push does not update local refs on failure' '\n \n \tmk_test testrepo heads/main &&\n \tmk_child testrepo child &&\n-\tmkdir testrepo/.git/hooks &&\n \techo \"#!/no/frobnication/today\" >testrepo/.git/hooks/pre-receive &&\n \tchmod +x testrepo/.git/hooks/pre-receive &&\n \t(\n@@ -1329,7 +1313,7 @@ done\n \n test_expect_success 'fetch follows tags by default' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n \t(\n \t\tcd src &&\n@@ -1339,6 +1323,7 @@ test_expect_success 'fetch follows tags by default' '\n \t\tsed -n \"p; s|refs/heads/main$|refs/remotes/origin/main|p\" tmp1 |\n \t\tsort -k 3 >../expect\n \t) &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init dst &&\n \t(\n \t\tcd dst &&\n@@ -1364,8 +1349,9 @@ test_expect_success 'peeled advertisements are not considered ref tips' '\n \n test_expect_success 'pushing a specific ref applies remote.$name.push as refmap' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1388,8 +1374,9 @@ test_expect_success 'pushing a specific ref applies remote.$name.push as refmap'\n \n test_expect_success 'with no remote.$name.push, it is not used as refmap' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1410,8 +1397,9 @@ test_expect_success 'with no remote.$name.push, it is not used as refmap' '\n \n test_expect_success 'with no remote.$name.push, upstream mapping is used' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1439,8 +1427,9 @@ test_expect_success 'with no remote.$name.push, upstream mapping is used' '\n \n test_expect_success 'push does not follow tags by default' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1462,8 +1451,9 @@ test_expect_success 'push does not follow tags by default' '\n \n test_expect_success 'push --follow-tags only pushes relevant tags' '\n \tmk_test testrepo heads/main &&\n-\trm -fr src dst &&\n+\ttest_when_finished \"rm -rf src\" &&\n \tgit init src &&\n+\ttest_when_finished \"rm -rf dst\" &&\n \tgit init --bare dst &&\n \t(\n \t\tcd src &&\n@@ -1501,9 +1491,9 @@ EOF\n '\n \n test_expect_success 'pushing a tag pushes the tagged object' '\n-\trm -rf dst.git &&\n \tblob=$(echo unreferenced | git hash-object -w --stdin) &&\n \tgit tag -m foo tag-of-blob $blob &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \tgit push dst.git tag-of-blob &&\n \t# the receiving index-pack should have noticed\n@@ -1514,7 +1504,7 @@ test_expect_success 'pushing a tag pushes the tagged object' '\n '\n \n test_expect_success 'push into bare respects core.logallrefupdates' '\n-\trm -rf dst.git &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \tgit -C dst.git config core.logallrefupdates true &&\n \n@@ -1532,7 +1522,7 @@ test_expect_success 'push into bare respects core.logallrefupdates' '\n '\n \n test_expect_success 'fetch into bare respects core.logallrefupdates' '\n-\trm -rf dst.git &&\n+\ttest_when_finished \"rm -rf dst.git\" &&\n \tgit init --bare dst.git &&\n \t(\n \t\tcd dst.git &&\n@@ -1553,6 +1543,7 @@ test_expect_success 'fetch into bare respects core.logallrefupdates' '\n '\n \n test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n+\tmk_empty testrepo &&\n \tgit push testrepo main &&\n \t(\n \t\tcd testrepo &&\n@@ -1655,7 +1646,7 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n \t) &&\n \n \t# (5) push into void\n-\trm -fr void &&\n+\ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n \t(\n \t\tcd void &&\n@@ -1677,26 +1668,23 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '\n '\n \n test_expect_success 'updateInstead with push-to-checkout hook' '\n-\trm -fr testrepo &&\n+\ttest_when_finished \"rm -rf testrepo\" &&\n \tgit init testrepo &&\n-\t(\n-\t\tcd testrepo &&\n-\t\tgit pull .. main &&\n-\t\tgit reset --hard HEAD^^ &&\n-\t\tgit tag initial &&\n-\t\tgit config receive.denyCurrentBranch updateInstead &&\n-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n-\t\techo >&2 updating from $(git rev-parse HEAD)\n-\t\techo >&2 updating to \"$1\"\n-\n-\t\tgit update-index -q --refresh &&\n-\t\tgit read-tree -u -m HEAD \"$1\" || {\n-\t\t\tstatus=$?\n-\t\t\techo >&2 read-tree failed\n-\t\t\texit $status\n-\t\t}\n-\t\tEOF\n-\t) &&\n+\tgit -C testrepo pull .. main &&\n+\tgit -C testrepo reset --hard HEAD^^ &&\n+\tgit -C testrepo tag initial &&\n+\tgit -C testrepo config receive.denyCurrentBranch updateInstead &&\n+\ttest_hook -C testrepo push-to-checkout <<-\\EOF &&\n+\techo >&2 updating from $(git rev-parse HEAD)\n+\techo >&2 updating to \"$1\"\n+\n+\tgit update-index -q --refresh &&\n+\tgit read-tree -u -m HEAD \"$1\" || {\n+\t\tstatus=$?\n+\t\techo >&2 read-tree failed\n+\t\texit $status\n+\t}\n+\tEOF\n \n \t# Try pushing into a pristine\n \tgit push testrepo main &&\n@@ -1739,35 +1727,32 @@ test_expect_success 'updateInstead with push-to-checkout hook' '\n \t) &&\n \n \t# push into void\n-\trm -fr void &&\n+\ttest_when_finished \"rm -rf void\" &&\n \tgit init void &&\n-\t(\n-\t\tcd void &&\n-\t\tgit config receive.denyCurrentBranch updateInstead &&\n-\t\twrite_script .git/hooks/push-to-checkout <<-\\EOF\n-\t\tif git rev-parse --quiet --verify HEAD\n-\t\tthen\n-\t\t\thas_head=yes\n-\t\t\techo >&2 updating from $(git rev-parse HEAD)\n-\t\telse\n-\t\t\thas_head=no\n-\t\t\techo >&2 pushing into void\n-\t\tfi\n-\t\techo >&2 updating to \"$1\"\n-\n-\t\tgit update-index -q --refresh &&\n-\t\tcase \"$has_head\" in\n-\t\tyes)\n-\t\t\tgit read-tree -u -m HEAD \"$1\" ;;\n-\t\tno)\n-\t\t\tgit read-tree -u -m \"$1\" ;;\n-\t\tesac || {\n-\t\t\tstatus=$?\n-\t\t\techo >&2 read-tree failed\n-\t\t\texit $status\n-\t\t}\n-\t\tEOF\n-\t) &&\n+\tgit -C void config receive.denyCurrentBranch updateInstead &&\n+\ttest_hook -C void push-to-checkout <<-\\EOF &&\n+\tif git rev-parse --quiet --verify HEAD\n+\tthen\n+\t\thas_head=yes\n+\t\techo >&2 updating from $(git rev-parse HEAD)\n+\telse\n+\t\thas_head=no\n+\t\techo >&2 pushing into void\n+\tfi\n+\techo >&2 updating to \"$1\"\n+\n+\tgit update-index -q --refresh &&\n+\tcase \"$has_head\" in\n+\tyes)\n+\t\tgit read-tree -u -m HEAD \"$1\" ;;\n+\tno)\n+\t\tgit read-tree -u -m \"$1\" ;;\n+\tesac || {\n+\t\tstatus=$?\n+\t\techo >&2 read-tree failed\n+\t\texit $status\n+\t}\n+\tEOF\n \n \tgit push void main &&\n \t(\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451547","messageId":"patch-v3-08.13-bb25560d432-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 08/13] tests: change \"cat && chmod +x\" to use \"test_hook\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:13Z","receivedAt":"2022-03-17T10:13:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various test code to use the \"test_hook\" helper. This change:\n\n - Fixes the long-standing issues with those tests using \"#!/bin/sh\"\n   instead of \"#!$SHELL_PATH\". Using \"#!/bin/sh\" here happened to work\n   because this code was so simple that it e.g. worked on Solaris\n   /bin/sh.\n\n - Removes the \"mkdir .git/hooks\" invocation, as explained in a\n   preceding commit we'll rely on the default templates to create that\n   directory for us.\n\nFor the test in \"t5402-post-merge-hook.sh\" it's easier and more\ncorrect to unroll the for-loop into a test_expect_success, so let's do\nthat.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5402-post-merge-hook.sh | 16 +++++++++-------\n t/t5601-clone.sh           |  4 +---\n 2 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/t/t5402-post-merge-hook.sh b/t/t5402-post-merge-hook.sh\nindex 3e5e19c7191..915af2de95e 100755\n--- a/t/t5402-post-merge-hook.sh\n+++ b/t/t5402-post-merge-hook.sh\n@@ -25,13 +25,15 @@ test_expect_success setup '\n \tGIT_DIR=clone2/.git git update-index --add a\n '\n \n-for clone in 1 2; do\n-\tcat >clone${clone}/.git/hooks/post-merge <<'EOF'\n-#!/bin/sh\n-echo $@ >> $GIT_DIR/post-merge.args\n-EOF\n-\tchmod u+x clone${clone}/.git/hooks/post-merge\n-done\n+test_expect_success 'setup clone hooks' '\n+\ttest_when_finished \"rm -f hook\" &&\n+\tcat >hook <<-\\EOF &&\n+\techo $@ >>$GIT_DIR/post-merge.args\n+\tEOF\n+\n+\ttest_hook --setup -C clone1 post-merge <hook &&\n+\ttest_hook --setup -C clone2 post-merge <hook\n+'\n \n test_expect_success 'post-merge does not run for up-to-date ' '\n \tGIT_DIR=clone1/.git git merge $commit0 &&\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex 83c24fc97a7..4a61f2c901e 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -79,12 +79,10 @@ test_expect_success 'clone from hooks' '\n \tcd .. &&\n \tgit init r1 &&\n \tcd r1 &&\n-\tcat >.git/hooks/pre-commit <<-\\EOF &&\n-\t#!/bin/sh\n+\ttest_hook pre-commit <<-\\EOF &&\n \tgit clone ../r0 ../r2\n \texit 1\n \tEOF\n-\tchmod u+x .git/hooks/pre-commit &&\n \t: >file &&\n \tgit add file &&\n \ttest_must_fail git commit -m invoke-hook &&\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451548","messageId":"patch-v3-10.13-dab99b8359d-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 10/13] tests: use \"test_hook\" for misc \"mkdir -p\" and \"chmod\" cases","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:15Z","receivedAt":"2022-03-17T10:13:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make use of \"test_hook\" in various cases that didn't fit neatly into\npreceding commits. Here we need to indent blocks in addition to\nchanging the test code, or to make other small cosmetic changes.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3412-rebase-root.sh       | 18 ++++-------\n t/t3413-rebase-hook.sh       | 18 ++++-------\n t/t5401-update-hooks.sh      | 62 ++++++++++++++++--------------------\n t/t5407-post-rewrite-hook.sh | 14 ++++----\n t/t5541-http-push-smart.sh   | 22 ++++++-------\n 5 files changed, 56 insertions(+), 78 deletions(-)\n\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 1e9f7833dd6..58371d8a547 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -31,12 +31,9 @@ test_expect_success 'rebase --root fails with too many args' '\n '\n \n test_expect_success 'setup pre-rebase hook' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n-EOF\n-\tchmod +x .git/hooks/pre-rebase\n+\ttest_hook --setup pre-rebase <<-\\EOF\n+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n+\tEOF\n '\n cat > expect <<EOF\n 4\n@@ -141,12 +138,9 @@ commit work7~5\n EOF\n \n test_expect_success 'setup pre-rebase hook that fails' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-false\n-EOF\n-\tchmod +x .git/hooks/pre-rebase\n+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n+\tfalse\n+\tEOF\n '\n \n test_expect_success 'pre-rebase hook stops rebase' '\ndiff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh\nindex b4acb3be5cf..9fab0d779bb 100755\n--- a/t/t3413-rebase-hook.sh\n+++ b/t/t3413-rebase-hook.sh\n@@ -41,12 +41,9 @@ test_expect_success 'rebase -i' '\n '\n \n test_expect_success 'setup pre-rebase hook' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n-EOF\n-\tchmod +x .git/hooks/pre-rebase\n+\ttest_hook --setup pre-rebase <<-\\EOF\n+\techo \"$1,$2\" >.git/PRE-REBASE-INPUT\n+\tEOF\n '\n \n test_expect_success 'pre-rebase hook gets correct input (1)' '\n@@ -102,12 +99,9 @@ test_expect_success 'pre-rebase hook gets correct input (6)' '\n '\n \n test_expect_success 'setup pre-rebase hook that fails' '\n-\tmkdir -p .git/hooks &&\n-\tcat >.git/hooks/pre-rebase <<EOF &&\n-#!$SHELL_PATH\n-false\n-EOF\n-\tchmod +x .git/hooks/pre-rebase\n+\ttest_hook --setup --clobber pre-rebase <<-\\EOF\n+\tfalse\n+\tEOF\n '\n \n test_expect_success 'pre-rebase hook stops rebase (1)' '\ndiff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh\nindex 799349a416c..001b7a17ad2 100755\n--- a/t/t5401-update-hooks.sh\n+++ b/t/t5401-update-hooks.sh\n@@ -20,45 +20,37 @@ test_expect_success setup '\n \tgit clone --bare ./. victim.git &&\n \tGIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&\n \tgit update-ref refs/heads/main $commit1 &&\n-\tgit update-ref refs/heads/tofail $commit0\n-'\n+\tgit update-ref refs/heads/tofail $commit0 &&\n \n-cat >victim.git/hooks/pre-receive <<'EOF'\n-#!/bin/sh\n-printf %s \"$@\" >>$GIT_DIR/pre-receive.args\n-cat - >$GIT_DIR/pre-receive.stdin\n-echo STDOUT pre-receive\n-echo STDERR pre-receive >&2\n-EOF\n-chmod u+x victim.git/hooks/pre-receive\n+\ttest_hook --setup -C victim.git pre-receive <<-\\EOF &&\n+\tprintf %s \"$@\" >>$GIT_DIR/pre-receive.args\n+\tcat - >$GIT_DIR/pre-receive.stdin\n+\techo STDOUT pre-receive\n+\techo STDERR pre-receive >&2\n+\tEOF\n \n-cat >victim.git/hooks/update <<'EOF'\n-#!/bin/sh\n-echo \"$@\" >>$GIT_DIR/update.args\n-read x; printf %s \"$x\" >$GIT_DIR/update.stdin\n-echo STDOUT update $1\n-echo STDERR update $1 >&2\n-test \"$1\" = refs/heads/main || exit\n-EOF\n-chmod u+x victim.git/hooks/update\n+\ttest_hook --setup -C victim.git update <<-\\EOF &&\n+\techo \"$@\" >>$GIT_DIR/update.args\n+\tread x; printf %s \"$x\" >$GIT_DIR/update.stdin\n+\techo STDOUT update $1\n+\techo STDERR update $1 >&2\n+\ttest \"$1\" = refs/heads/main || exit\n+\tEOF\n \n-cat >victim.git/hooks/post-receive <<'EOF'\n-#!/bin/sh\n-printf %s \"$@\" >>$GIT_DIR/post-receive.args\n-cat - >$GIT_DIR/post-receive.stdin\n-echo STDOUT post-receive\n-echo STDERR post-receive >&2\n-EOF\n-chmod u+x victim.git/hooks/post-receive\n+\ttest_hook --setup -C victim.git post-receive <<-\\EOF &&\n+\tprintf %s \"$@\" >>$GIT_DIR/post-receive.args\n+\tcat - >$GIT_DIR/post-receive.stdin\n+\techo STDOUT post-receive\n+\techo STDERR post-receive >&2\n+\tEOF\n \n-cat >victim.git/hooks/post-update <<'EOF'\n-#!/bin/sh\n-echo \"$@\" >>$GIT_DIR/post-update.args\n-read x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n-echo STDOUT post-update\n-echo STDERR post-update >&2\n-EOF\n-chmod u+x victim.git/hooks/post-update\n+\ttest_hook --setup -C victim.git post-update <<-\\EOF\n+\techo \"$@\" >>$GIT_DIR/post-update.args\n+\tread x; printf %s \"$x\" >$GIT_DIR/post-update.stdin\n+\techo STDOUT post-update\n+\techo STDERR post-update >&2\n+\tEOF\n+'\n \n test_expect_success push '\n \ttest_must_fail git send-pack --force ./victim.git \\\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 6da8d760e28..5f3ff051ca2 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -17,15 +17,13 @@ test_expect_success 'setup' '\n \tgit checkout A^0 &&\n \ttest_commit E bar E &&\n \ttest_commit F foo F &&\n-\tgit checkout main\n-'\n+\tgit checkout main &&\n \n-cat >.git/hooks/post-rewrite <<EOF\n-#!/bin/sh\n-echo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n-cat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n-EOF\n-chmod u+x .git/hooks/post-rewrite\n+\ttest_hook --setup post-rewrite <<-EOF\n+\techo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n+\tcat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n+\tEOF\n+'\n \n clear_hook_input () {\n \trm -f post-rewrite.args post-rewrite.data\ndiff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh\nindex 8ca50f8b18c..ab4b5cfcd11 100755\n--- a/t/t5541-http-push-smart.sh\n+++ b/t/t5541-http-push-smart.sh\n@@ -96,18 +96,18 @@ test_expect_success 'create and delete remote branch' '\n \ttest_must_fail git show-ref --verify refs/remotes/origin/dev\n '\n \n-cat >\"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\" <<EOF\n-#!/bin/sh\n-exit 1\n-EOF\n-chmod a+x \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update\"\n+test_expect_success 'setup rejected update hook' '\n+\ttest_hook --setup -C \"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git\" update <<-\\EOF &&\n+\texit 1\n+\tEOF\n \n-cat >exp <<EOF\n-remote: error: hook declined to update refs/heads/dev2\n-To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git\n- ! [remote rejected] dev2 -> dev2 (hook declined)\n-error: failed to push some refs to 'http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\n-EOF\n+\tcat >exp <<-EOF\n+\tremote: error: hook declined to update refs/heads/dev2\n+\tTo http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git\n+\t ! [remote rejected] dev2 -> dev2 (hook declined)\n+\terror: failed to push some refs to '\\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\\''\n+\tEOF\n+'\n \n test_expect_success 'rejected update prints status' '\n \tcd \"$ROOT_PATH\"/test_repo_clone &&\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451549","messageId":"patch-v3-07.13-bb57b298598-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 07/13] gc + p4 tests: use \"test_hook\", remove sub-shells","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:12Z","receivedAt":"2022-03-17T10:13:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor the repository setup code for tests that test hooks the use\nof sub-shells when setting up the test repository and hooks, and use\nthe \"test_hook\" wrapper instead of \"write_scripts\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6500-gc.sh           | 22 ++++++++++------------\n t/t9800-git-p4-basic.sh | 23 ++++++++++++++---------\n 2 files changed, 24 insertions(+), 21 deletions(-)\n\ndiff --git a/t/t6500-gc.sh b/t/t6500-gc.sh\nindex c2021267f2c..cd6c53360d2 100755\n--- a/t/t6500-gc.sh\n+++ b/t/t6500-gc.sh\n@@ -101,12 +101,12 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tEOF\n \n \tgit init pre-auto-gc-hook &&\n+\ttest_hook -C pre-auto-gc-hook pre-auto-gc <<-\\EOF &&\n+\techo >&2 no gc for you &&\n+\texit 1\n+\tEOF\n \t(\n \t\tcd pre-auto-gc-hook &&\n-\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n-\t\techo >&2 no gc for you &&\n-\t\texit 1\n-\t\tEOF\n \n \t\tgit config gc.auto 3 &&\n \t\tgit config gc.autoDetach false &&\n@@ -128,14 +128,12 @@ test_expect_success 'pre-auto-gc hook can stop auto gc' '\n \tSee \"git help gc\" for manual housekeeping.\n \tEOF\n \n-\t(\n-\t\tcd pre-auto-gc-hook &&\n-\t\twrite_script \".git/hooks/pre-auto-gc\" <<-\\EOF &&\n-\t\techo >&2 will gc for you &&\n-\t\texit 0\n-\t\tEOF\n-\t\tgit gc --auto >../out.actual 2>../err.actual\n-\t) &&\n+\ttest_hook -C pre-auto-gc-hook --clobber pre-auto-gc <<-\\EOF &&\n+\techo >&2 will gc for you &&\n+\texit 0\n+\tEOF\n+\n+\tgit -C pre-auto-gc-hook gc --auto >out.actual 2>err.actual &&\n \n \ttest_must_be_empty out.actual &&\n \ttest_cmp err.expect err.actual\ndiff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh\nindex 806005a793a..8b30062c0cf 100755\n--- a/t/t9800-git-p4-basic.sh\n+++ b/t/t9800-git-p4-basic.sh\n@@ -277,16 +277,21 @@ test_expect_success 'run hook p4-pre-submit before submit' '\n \t\tgit commit -m \"add hello.txt\" &&\n \t\tgit config git-p4.skipSubmitEdit true &&\n \t\tgit p4 submit --dry-run >out &&\n-\t\tgrep \"Would apply\" out &&\n-\t\tmkdir -p .git/hooks &&\n-\t\twrite_script .git/hooks/p4-pre-submit <<-\\EOF &&\n-\t\texit 0\n-\t\tEOF\n+\t\tgrep \"Would apply\" out\n+\t) &&\n+\ttest_hook -C \"$git\" p4-pre-submit <<-\\EOF &&\n+\texit 0\n+\tEOF\n+\t(\n+\t\tcd \"$git\" &&\n \t\tgit p4 submit --dry-run >out &&\n-\t\tgrep \"Would apply\" out &&\n-\t\twrite_script .git/hooks/p4-pre-submit <<-\\EOF &&\n-\t\texit 1\n-\t\tEOF\n+\t\tgrep \"Would apply\" out\n+\t) &&\n+\ttest_hook -C \"$git\" --clobber p4-pre-submit <<-\\EOF &&\n+\texit 1\n+\tEOF\n+\t(\n+\t\tcd \"$git\" &&\n \t\ttest_must_fail git p4 submit --dry-run >errs 2>&1 &&\n \t\t! grep \"Would apply\" errs\n \t)\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451550","messageId":"patch-v3-09.13-f908e27da82-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 09/13] tests: change \"mkdir -p && write_script\" to use \"test_hook\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:14Z","receivedAt":"2022-03-17T10:13:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change tests that used a \"mkdir -p .git/hooks && write_script\" pattern\nto use the new \"test_hook\" helper instead. The new helper does not\ncreate the .git/hooks directory, rather we assume that the default\ntemplate will do so for us.\n\nAn upcoming series[1] will extend \"test_hook\" to operate in a\n\"--template=\" mode, but for now assuming that we have a .git/hooks\nalready is a safe assumption. If that assumption becomes false in the\nfuture we'll only need to change 'test_hook\", instead of all of these\ncallsites.\n\n1. https://lore.kernel.org/git/cover-00.13-00000000000-20211212T201308Z-avarab@gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t0029-core-unsetenvvars.sh      |  3 +--\n t/t1350-config-hooks-path.sh      |  4 ++--\n t/t3404-rebase-interactive.sh     | 10 ++--------\n t/t3430-rebase-merges.sh          |  6 +++---\n t/t4150-am.sh                     | 24 ++++++------------------\n t/t5403-post-checkout-hook.sh     |  3 +--\n t/t5534-push-signed.sh            | 26 ++++++++------------------\n t/t7113-post-index-change-hook.sh |  7 +++----\n t/t9001-send-email.sh             |  4 +---\n 9 files changed, 27 insertions(+), 60 deletions(-)\n\ndiff --git a/t/t0029-core-unsetenvvars.sh b/t/t0029-core-unsetenvvars.sh\nindex b138e1d9cbc..4e8e90dd982 100755\n--- a/t/t0029-core-unsetenvvars.sh\n+++ b/t/t0029-core-unsetenvvars.sh\n@@ -12,8 +12,7 @@ then\n fi\n \n test_expect_success 'setup' '\n-\tmkdir -p \"$TRASH_DIRECTORY/.git/hooks\" &&\n-\twrite_script \"$TRASH_DIRECTORY/.git/hooks/pre-commit\" <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \techo $HOBBES >&2\n \tEOF\n '\ndiff --git a/t/t1350-config-hooks-path.sh b/t/t1350-config-hooks-path.sh\nindex fa9647a7c0b..f6dc83e2aab 100755\n--- a/t/t1350-config-hooks-path.sh\n+++ b/t/t1350-config-hooks-path.sh\n@@ -6,11 +6,11 @@ test_description='Test the core.hooksPath configuration variable'\n \n test_expect_success 'set up a pre-commit hook in core.hooksPath' '\n \t>actual &&\n-\tmkdir -p .git/custom-hooks .git/hooks &&\n+\tmkdir -p .git/custom-hooks &&\n \twrite_script .git/custom-hooks/pre-commit <<-\\EOF &&\n \techo CUSTOM >>actual\n \tEOF\n-\twrite_script .git/hooks/pre-commit <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \techo NORMAL >>actual\n \tEOF\n '\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex a38f2da7691..f31afd4a547 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -619,9 +619,7 @@ test_expect_success 'rebase a detached HEAD' '\n '\n \n test_expect_success 'rebase a commit violating pre-commit' '\n-\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-commit <<-\\EOF &&\n+\ttest_hook pre-commit <<-\\EOF &&\n \ttest -z \"$(git diff --cached --check)\"\n \tEOF\n \techo \"monde! \" >> file1 &&\n@@ -636,8 +634,6 @@ test_expect_success 'rebase a commit violating pre-commit' '\n '\n \n test_expect_success 'rebase with a file named HEAD in worktree' '\n-\n-\trm -fr .git/hooks &&\n \tgit reset --hard &&\n \tgit checkout -b branch3 A &&\n \n@@ -1688,10 +1684,8 @@ test_expect_success 'valid author header when author contains single quote' '\n '\n \n test_expect_success 'post-commit hook is called' '\n-\ttest_when_finished \"rm -f .git/hooks/post-commit\" &&\n \t>actual &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-commit <<-\\EOS &&\n+\ttest_hook post-commit <<-\\EOS &&\n \tgit rev-parse HEAD >>actual\n \tEOS\n \t(\ndiff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh\nindex 43c82d9a33b..f351701fec2 100755\n--- a/t/t3430-rebase-merges.sh\n+++ b/t/t3430-rebase-merges.sh\n@@ -292,9 +292,9 @@ test_expect_success 'post-rewrite hook and fixups work for merges' '\n \tgit commit --fixup HEAD same2.t &&\n \tfixup=\"$(git rev-parse HEAD)\" &&\n \n-\tmkdir -p .git/hooks &&\n-\ttest_when_finished \"rm .git/hooks/post-rewrite\" &&\n-\techo \"cat >actual\" | write_script .git/hooks/post-rewrite &&\n+\ttest_hook post-rewrite <<-\\EOF &&\n+\tcat >actual\n+\tEOF\n \n \ttest_tick &&\n \tgit rebase -i --autosquash -r HEAD^^^ &&\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex 159fae8d016..cdad4b68807 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -315,12 +315,10 @@ test_expect_success 'am --patch-format=hg applies hg patch' '\n '\n \n test_expect_success 'am with applypatch-msg hook' '\n-\ttest_when_finished \"rm -f .git/hooks/applypatch-msg\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \tcat \"$1\" >actual-msg &&\n \techo hook-message >\"$1\"\n \tEOF\n@@ -335,12 +333,10 @@ test_expect_success 'am with applypatch-msg hook' '\n '\n \n test_expect_success 'am with failing applypatch-msg hook' '\n-\ttest_when_finished \"rm -f .git/hooks/applypatch-msg\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/applypatch-msg <<-\\EOF &&\n+\ttest_hook applypatch-msg <<-\\EOF &&\n \texit 1\n \tEOF\n \ttest_must_fail git am patch1 &&\n@@ -350,12 +346,10 @@ test_expect_success 'am with failing applypatch-msg hook' '\n '\n \n test_expect_success 'am with pre-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/pre-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-applypatch <<-\\EOF &&\n+\ttest_hook pre-applypatch <<-\\EOF &&\n \tgit diff first >diff.actual\n \texit 0\n \tEOF\n@@ -368,12 +362,10 @@ test_expect_success 'am with pre-applypatch hook' '\n '\n \n test_expect_success 'am with failing pre-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/pre-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/pre-applypatch <<-\\EOF &&\n+\ttest_hook pre-applypatch <<-\\EOF &&\n \texit 1\n \tEOF\n \ttest_must_fail git am patch1 &&\n@@ -383,12 +375,10 @@ test_expect_success 'am with failing pre-applypatch hook' '\n '\n \n test_expect_success 'am with post-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/post-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-applypatch <<-\\EOF &&\n+\ttest_hook post-applypatch <<-\\EOF &&\n \tgit rev-parse HEAD >head.actual\n \tgit diff second >diff.actual\n \texit 0\n@@ -403,12 +393,10 @@ test_expect_success 'am with post-applypatch hook' '\n '\n \n test_expect_success 'am with failing post-applypatch hook' '\n-\ttest_when_finished \"rm -f .git/hooks/post-applypatch\" &&\n \trm -fr .git/rebase-apply &&\n \tgit reset --hard &&\n \tgit checkout first &&\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-applypatch <<-\\EOF &&\n+\ttest_hook post-applypatch <<-\\EOF &&\n \tgit rev-parse HEAD >head.actual\n \texit 1\n \tEOF\ndiff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh\nindex d1181816906..978f240cdac 100755\n--- a/t/t5403-post-checkout-hook.sh\n+++ b/t/t5403-post-checkout-hook.sh\n@@ -10,8 +10,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n \n test_expect_success setup '\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-checkout <<-\\EOF &&\n+\ttest_hook --setup post-checkout <<-\\EOF &&\n \techo \"$@\" >.git/post-checkout.args\n \tEOF\n \ttest_commit one &&\ndiff --git a/t/t5534-push-signed.sh b/t/t5534-push-signed.sh\nindex 24d374adbae..7c0a148e73c 100755\n--- a/t/t5534-push-signed.sh\n+++ b/t/t5534-push-signed.sh\n@@ -35,8 +35,7 @@ test_expect_success setup '\n \n test_expect_success 'unsigned push does not send push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -52,8 +51,7 @@ test_expect_success 'unsigned push does not send push certificate' '\n \n test_expect_success 'talking with a receiver without push certificate support' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -69,22 +67,19 @@ test_expect_success 'talking with a receiver without push certificate support' '\n \n test_expect_success 'push --signed fails with a receiver without push certificate support' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \ttest_must_fail git push --signed dst noop ff +noff 2>err &&\n \ttest_i18ngrep \"the receiving end does not support\" err\n '\n \n test_expect_success 'push --signed=1 is accepted' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \ttest_must_fail git push --signed=1 dst noop ff +noff 2>err &&\n \ttest_i18ngrep \"the receiving end does not support\" err\n '\n \n test_expect_success GPG 'no certificate for a signed push with no update' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \tif test -n \"${GIT_PUSH_CERT-}\"\n \tthen\n \t\tgit cat-file blob $GIT_PUSH_CERT >../push-cert\n@@ -96,9 +91,8 @@ test_expect_success GPG 'no certificate for a signed push with no update' '\n \n test_expect_success GPG 'signed push sends push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -139,10 +133,9 @@ test_expect_success GPG 'signed push sends push certificate' '\n \n test_expect_success GPGSSH 'ssh signed push sends push certificate' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config gpg.ssh.allowedSignersFile \"${GPGSSH_ALLOWED_SIGNERS}\" &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -223,9 +216,8 @@ test_expect_success GPG 'inconsistent push options in signed push not allowed' '\n \n test_expect_success GPG 'fail without key and heed user.signingkey' '\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -273,9 +265,8 @@ test_expect_success GPG 'fail without key and heed user.signingkey' '\n test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '\n \ttest_config gpg.format x509 &&\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\n@@ -326,10 +317,9 @@ test_expect_success GPGSM 'fail without key and heed user.signingkey x509' '\n test_expect_success GPGSSH 'fail without key and heed user.signingkey ssh' '\n \ttest_config gpg.format ssh &&\n \tprepare_dst &&\n-\tmkdir -p dst/.git/hooks &&\n \tgit -C dst config gpg.ssh.allowedSignersFile \"${GPGSSH_ALLOWED_SIGNERS}\" &&\n \tgit -C dst config receive.certnonceseed sekrit &&\n-\twrite_script dst/.git/hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C dst post-receive <<-\\EOF &&\n \t# discard the update list\n \tcat >/dev/null\n \t# record the push certificate\ndiff --git a/t/t7113-post-index-change-hook.sh b/t/t7113-post-index-change-hook.sh\nindex a21781d68a1..58e55a7c779 100755\n--- a/t/t7113-post-index-change-hook.sh\n+++ b/t/t7113-post-index-change-hook.sh\n@@ -17,8 +17,7 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'test status, add, commit, others trigger hook without flags set' '\n-\tmkdir -p .git/hooks &&\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir is set.\" >testfailure\n \t\t\texit 1\n@@ -63,7 +62,7 @@ test_expect_success 'test status, add, commit, others trigger hook without flags\n '\n \n test_expect_success 'test checkout and reset trigger the hook' '\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n \t\t\texit 1\n@@ -106,7 +105,7 @@ test_expect_success 'test checkout and reset trigger the hook' '\n '\n \n test_expect_success 'test reset --mixed and update-index triggers the hook' '\n-\twrite_script .git/hooks/post-index-change <<-\\EOF &&\n+\ttest_hook post-index-change <<-\\EOF &&\n \t\tif test \"$1\" -eq 1 && test \"$2\" -eq 1; then\n \t\t\techo \"Invalid combination of flags passed to hook; updated_workdir and updated_skipworktree are both set.\" >testfailure\n \t\t\texit 1\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 84d0f40d76a..42694fe5841 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -2288,9 +2288,7 @@ test_expect_success $PREREQ 'cmdline in-reply-to used with --no-thread' '\n '\n \n test_expect_success $PREREQ 'invoke hook' '\n-\tmkdir -p .git/hooks &&\n-\n-\twrite_script .git/hooks/sendemail-validate <<-\\EOF &&\n+\ttest_hook sendemail-validate <<-\\EOF &&\n \t# test that we have the correct environment variable, pwd, and\n \t# argument\n \tcase \"$GIT_DIR\" in\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451551","messageId":"patch-v3-11.13-f541b0b2d70-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 11/13] tests: extend \"test_hook\" for \"rm\" and \"chmod -x\", convert \"$HOOK\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:16Z","receivedAt":"2022-03-17T10:13:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Extend the \"test_hook\" function to take options to disable and remove\nhooks. Using the wrapper instead of getting the path and running\n\"chmod -x\" or \"rm\" will make it easier to eventually emulate the same\nbehavior with config-based hooks.\n\nNot all of these tests need that new mode, but since the rest are\neither closely related or use the same \"$HOOK\" pattern let's convert\nthem too.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t2400-worktree-add.sh                       |   5 +-\n t/t5543-atomic-push.sh                        |   5 +-\n t/t5571-pre-push-hook.sh                      |  38 +++--\n ...3-pre-commit-and-pre-merge-commit-hooks.sh | 150 +++++++++---------\n t/t7504-commit-msg-hook.sh                    |  43 +++--\n t/t7505-prepare-commit-msg-hook.sh            |  43 +++--\n t/t7520-ignored-hook-warning.sh               |  11 +-\n t/test-lib-functions.sh                       |  24 +++\n 8 files changed, 162 insertions(+), 157 deletions(-)\n\ndiff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh\nindex 43139af08fc..2f564d533d0 100755\n--- a/t/t2400-worktree-add.sh\n+++ b/t/t2400-worktree-add.sh\n@@ -559,10 +559,7 @@ test_expect_success 'git worktree --no-guess-remote option overrides config' '\n '\n \n post_checkout_hook () {\n-\tgitdir=${1:-.git}\n-\ttest_when_finished \"rm -f $gitdir/hooks/post-checkout\" &&\n-\tmkdir -p $gitdir/hooks &&\n-\twrite_script $gitdir/hooks/post-checkout <<-\\EOF\n+\ttest_hook -C \"$1\" post-checkout <<-\\EOF\n \t{\n \t\techo $*\n \t\tgit rev-parse --git-dir --show-toplevel\ndiff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh\nindex bfee461861e..90676365471 100755\n--- a/t/t5543-atomic-push.sh\n+++ b/t/t5543-atomic-push.sh\n@@ -164,10 +164,7 @@ test_expect_success 'atomic push obeys update hook preventing a branch to be pus\n \t) &&\n \t(\n \t\tcd upstream &&\n-\t\tHOOKDIR=\"$(git rev-parse --git-dir)/hooks\" &&\n-\t\tHOOK=\"$HOOKDIR/update\" &&\n-\t\tmkdir -p \"$HOOKDIR\" &&\n-\t\twrite_script \"$HOOK\" <<-\\EOF\n+\t\ttest_hook update <<-\\EOF\n \t\t\t# only allow update to main from now on\n \t\t\ttest \"$1\" = \"refs/heads/main\"\n \t\tEOF\ndiff --git a/t/t5571-pre-push-hook.sh b/t/t5571-pre-push-hook.sh\nindex 96d6ecc0af7..a11b20e3782 100755\n--- a/t/t5571-pre-push-hook.sh\n+++ b/t/t5571-pre-push-hook.sh\n@@ -6,16 +6,11 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-# Setup hook that always succeeds\n-HOOKDIR=\"$(git rev-parse --git-dir)/hooks\"\n-HOOK=\"$HOOKDIR/pre-push\"\n-mkdir -p \"$HOOKDIR\"\n-write_script \"$HOOK\" <<EOF\n-cat >actual\n-exit 0\n-EOF\n-\n test_expect_success 'setup' '\n+\ttest_hook pre-push <<-\\EOF &&\n+\tcat >actual\n+\tEOF\n+\n \tgit config push.default upstream &&\n \tgit init --bare repo1 &&\n \tgit remote add parent1 repo1 &&\n@@ -28,15 +23,16 @@ test_expect_success 'setup' '\n \tgit push parent1 HEAD:foreign &&\n \ttest_cmp expect actual\n '\n-write_script \"$HOOK\" <<EOF\n-cat >actual\n-exit 1\n-EOF\n \n COMMIT1=\"$(git rev-parse HEAD)\"\n export COMMIT1\n \n test_expect_success 'push with failing hook' '\n+\ttest_hook pre-push <<-\\EOF &&\n+\tcat >actual &&\n+\texit 1\n+\tEOF\n+\n \ttest_commit two &&\n \tcat >expect <<-EOF &&\n \tHEAD $(git rev-parse HEAD) refs/heads/main $(test_oid zero)\n@@ -55,13 +51,13 @@ test_expect_success '--no-verify bypasses hook' '\n COMMIT2=\"$(git rev-parse HEAD)\"\n export COMMIT2\n \n-write_script \"$HOOK\" <<'EOF'\n-echo \"$1\" >actual\n-echo \"$2\" >>actual\n-cat >>actual\n-EOF\n-\n test_expect_success 'push with hook' '\n+\ttest_hook --setup pre-push <<-\\EOF &&\n+\techo \"$1\" >actual\n+\techo \"$2\" >>actual\n+\tcat >>actual\n+\tEOF\n+\n \tcat >expect <<-EOF &&\n \tparent1\n \trepo1\n@@ -136,7 +132,9 @@ test_expect_success 'set up many-ref tests' '\n '\n \n test_expect_success 'sigpipe does not cause pre-push hook failure' '\n-\techo \"exit 0\" | write_script \"$HOOK\" &&\n+\ttest_hook --clobber pre-push <<-\\EOF &&\n+\texit 0\n+\tEOF\n \tgit push parent1 \"refs/heads/b/*:refs/heads/b/*\"\n '\n \ndiff --git a/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh\nindex 606d8d0f089..ad1eb64ba0d 100755\n--- a/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh\n+++ b/t/t7503-pre-commit-and-pre-merge-commit-hooks.sh\n@@ -7,37 +7,6 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n . ./test-lib.sh\n \n-HOOKDIR=\"$(git rev-parse --git-dir)/hooks\"\n-PRECOMMIT=\"$HOOKDIR/pre-commit\"\n-PREMERGE=\"$HOOKDIR/pre-merge-commit\"\n-\n-# Prepare sample scripts that write their $0 to actual_hooks\n-test_expect_success 'sample script setup' '\n-\tmkdir -p \"$HOOKDIR\" &&\n-\twrite_script \"$HOOKDIR/success.sample\" <<-\\EOF &&\n-\techo $0 >>actual_hooks\n-\texit 0\n-\tEOF\n-\twrite_script \"$HOOKDIR/fail.sample\" <<-\\EOF &&\n-\techo $0 >>actual_hooks\n-\texit 1\n-\tEOF\n-\twrite_script \"$HOOKDIR/non-exec.sample\" <<-\\EOF &&\n-\techo $0 >>actual_hooks\n-\texit 1\n-\tEOF\n-\tchmod -x \"$HOOKDIR/non-exec.sample\" &&\n-\twrite_script \"$HOOKDIR/require-prefix.sample\" <<-\\EOF &&\n-\techo $0 >>actual_hooks\n-\ttest $GIT_PREFIX = \"success/\"\n-\tEOF\n-\twrite_script \"$HOOKDIR/check-author.sample\" <<-\\EOF\n-\techo $0 >>actual_hooks\n-\ttest \"$GIT_AUTHOR_NAME\" = \"New Author\" &&\n-\ttest \"$GIT_AUTHOR_EMAIL\" = \"newauthor@example.com\"\n-\tEOF\n-'\n-\n test_expect_success 'root commit' '\n \techo \"root\" >file &&\n \tgit add file &&\n@@ -96,10 +65,16 @@ test_expect_success '--no-verify with no hook (merge)' '\n \ttest_path_is_missing actual_hooks\n '\n \n+setup_success_hook () {\n+\ttest_when_finished \"rm -f actual_hooks expected_hooks\" &&\n+\techo \"$1\" >expected_hooks &&\n+\ttest_hook \"$1\" <<-EOF\n+\techo $1 >>actual_hooks\n+\tEOF\n+}\n+\n test_expect_success 'with succeeding hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" expected_hooks actual_hooks\" &&\n-\tcp \"$HOOKDIR/success.sample\" \"$PRECOMMIT\" &&\n-\techo \"$PRECOMMIT\" >expected_hooks &&\n+\tsetup_success_hook \"pre-commit\" &&\n \techo \"more\" >>file &&\n \tgit add file &&\n \tgit commit -m \"more\" &&\n@@ -107,9 +82,7 @@ test_expect_success 'with succeeding hook' '\n '\n \n test_expect_success 'with succeeding hook (merge)' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" expected_hooks actual_hooks\" &&\n-\tcp \"$HOOKDIR/success.sample\" \"$PREMERGE\" &&\n-\techo \"$PREMERGE\" >expected_hooks &&\n+\tsetup_success_hook \"pre-merge-commit\" &&\n \tgit checkout side &&\n \tgit merge -m \"merge main\" main &&\n \tgit checkout main &&\n@@ -117,17 +90,14 @@ test_expect_success 'with succeeding hook (merge)' '\n '\n \n test_expect_success 'automatic merge fails; both hooks are available' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" \\\"$PRECOMMIT\\\"\" &&\n-\ttest_when_finished \"rm -f expected_hooks actual_hooks\" &&\n-\ttest_when_finished \"git checkout main\" &&\n-\tcp \"$HOOKDIR/success.sample\" \"$PREMERGE\" &&\n-\tcp \"$HOOKDIR/success.sample\" \"$PRECOMMIT\" &&\n+\tsetup_success_hook \"pre-commit\" &&\n+\tsetup_success_hook \"pre-merge-commit\" &&\n \n \tgit checkout conflicting-a &&\n \ttest_must_fail git merge -m \"merge conflicting-b\" conflicting-b &&\n \ttest_path_is_missing actual_hooks &&\n \n-\techo \"$PRECOMMIT\" >expected_hooks &&\n+\techo \"pre-commit\" >expected_hooks &&\n \techo a+b >conflicting &&\n \tgit add conflicting &&\n \tgit commit -m \"resolve conflict\" &&\n@@ -135,8 +105,7 @@ test_expect_success 'automatic merge fails; both hooks are available' '\n '\n \n test_expect_success '--no-verify with succeeding hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/success.sample\" \"$PRECOMMIT\" &&\n+\tsetup_success_hook \"pre-commit\" &&\n \techo \"even more\" >>file &&\n \tgit add file &&\n \tgit commit --no-verify -m \"even more\" &&\n@@ -144,8 +113,7 @@ test_expect_success '--no-verify with succeeding hook' '\n '\n \n test_expect_success '--no-verify with succeeding hook (merge)' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/success.sample\" \"$PREMERGE\" &&\n+\tsetup_success_hook \"pre-merge-commit\" &&\n \tgit branch -f side side-orig &&\n \tgit checkout side &&\n \tgit merge --no-verify -m \"merge main\" main &&\n@@ -153,10 +121,19 @@ test_expect_success '--no-verify with succeeding hook (merge)' '\n \ttest_path_is_missing actual_hooks\n '\n \n+setup_failing_hook () {\n+\ttest_when_finished \"rm -f actual_hooks\" &&\n+\ttest_hook \"$1\" <<-EOF\n+\techo $1-failing-hook >>actual_hooks\n+\texit 1\n+\tEOF\n+}\n+\n test_expect_success 'with failing hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" expected_hooks actual_hooks\" &&\n-\tcp \"$HOOKDIR/fail.sample\" \"$PRECOMMIT\" &&\n-\techo \"$PRECOMMIT\" >expected_hooks &&\n+\tsetup_failing_hook \"pre-commit\" &&\n+\ttest_when_finished \"rm -f expected_hooks\" &&\n+\techo \"pre-commit-failing-hook\" >expected_hooks &&\n+\n \techo \"another\" >>file &&\n \tgit add file &&\n \ttest_must_fail git commit -m \"another\" &&\n@@ -164,8 +141,7 @@ test_expect_success 'with failing hook' '\n '\n \n test_expect_success '--no-verify with failing hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/fail.sample\" \"$PRECOMMIT\" &&\n+\tsetup_failing_hook \"pre-commit\" &&\n \techo \"stuff\" >>file &&\n \tgit add file &&\n \tgit commit --no-verify -m \"stuff\" &&\n@@ -173,9 +149,8 @@ test_expect_success '--no-verify with failing hook' '\n '\n \n test_expect_success 'with failing hook (merge)' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" expected_hooks actual_hooks\" &&\n-\tcp \"$HOOKDIR/fail.sample\" \"$PREMERGE\" &&\n-\techo \"$PREMERGE\" >expected_hooks &&\n+\tsetup_failing_hook \"pre-merge-commit\" &&\n+\techo \"pre-merge-commit-failing-hook\" >expected_hooks &&\n \tgit checkout side &&\n \ttest_must_fail git merge -m \"merge main\" main &&\n \tgit checkout main &&\n@@ -183,8 +158,8 @@ test_expect_success 'with failing hook (merge)' '\n '\n \n test_expect_success '--no-verify with failing hook (merge)' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/fail.sample\" \"$PREMERGE\" &&\n+\tsetup_failing_hook \"pre-merge-commit\" &&\n+\n \tgit branch -f side side-orig &&\n \tgit checkout side &&\n \tgit merge --no-verify -m \"merge main\" main &&\n@@ -192,9 +167,18 @@ test_expect_success '--no-verify with failing hook (merge)' '\n \ttest_path_is_missing actual_hooks\n '\n \n+setup_non_exec_hook () {\n+\ttest_when_finished \"rm -f actual_hooks\" &&\n+\ttest_hook \"$1\" <<-\\EOF &&\n+\techo non-exec >>actual_hooks\n+\texit 1\n+\tEOF\n+\ttest_hook --disable \"$1\"\n+}\n+\n+\n test_expect_success POSIXPERM 'with non-executable hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/non-exec.sample\" \"$PRECOMMIT\" &&\n+\tsetup_non_exec_hook \"pre-commit\" &&\n \techo \"content\" >>file &&\n \tgit add file &&\n \tgit commit -m \"content\" &&\n@@ -202,8 +186,7 @@ test_expect_success POSIXPERM 'with non-executable hook' '\n '\n \n test_expect_success POSIXPERM '--no-verify with non-executable hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/non-exec.sample\" \"$PRECOMMIT\" &&\n+\tsetup_non_exec_hook \"pre-commit\" &&\n \techo \"more content\" >>file &&\n \tgit add file &&\n \tgit commit --no-verify -m \"more content\" &&\n@@ -211,8 +194,7 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook' '\n '\n \n test_expect_success POSIXPERM 'with non-executable hook (merge)' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/non-exec.sample\" \"$PREMERGE\" &&\n+\tsetup_non_exec_hook \"pre-merge\" &&\n \tgit branch -f side side-orig &&\n \tgit checkout side &&\n \tgit merge -m \"merge main\" main &&\n@@ -221,8 +203,7 @@ test_expect_success POSIXPERM 'with non-executable hook (merge)' '\n '\n \n test_expect_success POSIXPERM '--no-verify with non-executable hook (merge)' '\n-\ttest_when_finished \"rm -f \\\"$PREMERGE\\\" actual_hooks\" &&\n-\tcp \"$HOOKDIR/non-exec.sample\" \"$PREMERGE\" &&\n+\tsetup_non_exec_hook \"pre-merge\" &&\n \tgit branch -f side side-orig &&\n \tgit checkout side &&\n \tgit merge --no-verify -m \"merge main\" main &&\n@@ -230,10 +211,18 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook (merge)' '\n \ttest_path_is_missing actual_hooks\n '\n \n+setup_require_prefix_hook () {\n+\ttest_when_finished \"rm -f expected_hooks\" &&\n+\techo require-prefix >expected_hooks &&\n+\ttest_hook pre-commit <<-\\EOF\n+\techo require-prefix >>actual_hooks\n+\ttest $GIT_PREFIX = \"success/\"\n+\tEOF\n+}\n+\n test_expect_success 'with hook requiring GIT_PREFIX' '\n-\ttest_when_finished \"rm -rf \\\"$PRECOMMIT\\\" expected_hooks actual_hooks success\" &&\n-\tcp \"$HOOKDIR/require-prefix.sample\" \"$PRECOMMIT\" &&\n-\techo \"$PRECOMMIT\" >expected_hooks &&\n+\ttest_when_finished \"rm -rf actual_hooks success\" &&\n+\tsetup_require_prefix_hook &&\n \techo \"more content\" >>file &&\n \tgit add file &&\n \tmkdir success &&\n@@ -245,9 +234,8 @@ test_expect_success 'with hook requiring GIT_PREFIX' '\n '\n \n test_expect_success 'with failing hook requiring GIT_PREFIX' '\n-\ttest_when_finished \"rm -rf \\\"$PRECOMMIT\\\" expected_hooks actual_hooks fail\" &&\n-\tcp \"$HOOKDIR/require-prefix.sample\" \"$PRECOMMIT\" &&\n-\techo \"$PRECOMMIT\" >expected_hooks &&\n+\ttest_when_finished \"rm -rf actual_hooks fail\" &&\n+\tsetup_require_prefix_hook &&\n \techo \"more content\" >>file &&\n \tgit add file &&\n \tmkdir fail &&\n@@ -259,13 +247,23 @@ test_expect_success 'with failing hook requiring GIT_PREFIX' '\n \ttest_cmp expected_hooks actual_hooks\n '\n \n+setup_require_author_hook () {\n+\ttest_when_finished \"rm -f expected_hooks actual_hooks\" &&\n+\techo check-author >expected_hooks &&\n+\ttest_hook pre-commit <<-\\EOF\n+\techo check-author >>actual_hooks\n+\ttest \"$GIT_AUTHOR_NAME\" = \"New Author\" &&\n+\ttest \"$GIT_AUTHOR_EMAIL\" = \"newauthor@example.com\"\n+\tEOF\n+}\n+\n+\n test_expect_success 'check the author in hook' '\n-\ttest_when_finished \"rm -f \\\"$PRECOMMIT\\\" expected_hooks actual_hooks\" &&\n-\tcp \"$HOOKDIR/check-author.sample\" \"$PRECOMMIT\" &&\n+\tsetup_require_author_hook &&\n \tcat >expected_hooks <<-EOF &&\n-\t$PRECOMMIT\n-\t$PRECOMMIT\n-\t$PRECOMMIT\n+\tcheck-author\n+\tcheck-author\n+\tcheck-author\n \tEOF\n \ttest_must_fail git commit --allow-empty -m \"by a.u.thor\" &&\n \t(\ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex bba58f04806..a39de8c1126 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -54,15 +54,11 @@ test_expect_success '--no-verify with no hook (editor)' '\n \n '\n \n-# now install hook that always succeeds\n-HOOKDIR=\"$(git rev-parse --git-dir)/hooks\"\n-HOOK=\"$HOOKDIR/commit-msg\"\n-mkdir -p \"$HOOKDIR\"\n-cat > \"$HOOK\" <<EOF\n-#!/bin/sh\n-exit 0\n-EOF\n-chmod +x \"$HOOK\"\n+test_expect_success 'setup: commit-msg hook that always succeeds' '\n+\ttest_hook --setup commit-msg <<-\\EOF\n+\texit 0\n+\tEOF\n+'\n \n test_expect_success 'with succeeding hook' '\n \n@@ -98,11 +94,11 @@ test_expect_success '--no-verify with succeeding hook (editor)' '\n \n '\n \n-# now a hook that fails\n-cat > \"$HOOK\" <<EOF\n-#!/bin/sh\n-exit 1\n-EOF\n+test_expect_success 'setup: commit-msg hook that always fails' '\n+\ttest_hook --clobber commit-msg <<-\\EOF\n+\texit 1\n+\tEOF\n+'\n \n commit_msg_is () {\n \ttest \"$(git log --pretty=format:%s%b -1)\" = \"$1\"\n@@ -176,8 +172,12 @@ test_expect_success 'merge bypasses failing hook with --no-verify' '\n \tcommit_msg_is \"Merge branch '\\''main'\\'' into newbranch\"\n '\n \n+test_expect_success 'setup: commit-msg hook made non-executable' '\n+\tgit_dir=\"$(git rev-parse --git-dir)\" &&\n+\tchmod -x \"$git_dir/hooks/commit-msg\"\n+'\n+\n \n-chmod -x \"$HOOK\"\n test_expect_success POSIXPERM 'with non-executable hook' '\n \n \techo \"content\" >file &&\n@@ -212,13 +212,12 @@ test_expect_success POSIXPERM '--no-verify with non-executable hook (editor)' '\n \n '\n \n-# now a hook that edits the commit message\n-cat > \"$HOOK\" <<'EOF'\n-#!/bin/sh\n-echo \"new message\" > \"$1\"\n-exit 0\n-EOF\n-chmod +x \"$HOOK\"\n+test_expect_success 'setup: commit-msg hook that edits the commit message' '\n+\ttest_hook --clobber commit-msg <<-\\EOF\n+\techo \"new message\" >\"$1\"\n+\texit 0\n+\tEOF\n+'\n \n test_expect_success 'hook edits commit message' '\n \ndiff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh\nindex e39c809ca42..2128142a61c 100755\n--- a/t/t7505-prepare-commit-msg-hook.sh\n+++ b/t/t7505-prepare-commit-msg-hook.sh\n@@ -47,25 +47,19 @@ test_expect_success 'with no hook' '\n \n '\n \n-# set up fake editor for interactive editing\n-cat > fake-editor <<'EOF'\n-#!/bin/sh\n-exit 0\n-EOF\n-chmod +x fake-editor\n-\n-## Not using test_set_editor here so we can easily ensure the editor variable\n-## is only set for the editor tests\n-FAKE_EDITOR=\"$(pwd)/fake-editor\"\n-export FAKE_EDITOR\n+test_expect_success 'setup fake editor for interactive editing' '\n+\twrite_script fake-editor <<-\\EOF &&\n+\texit 0\n+\tEOF\n \n-# now install hook that always succeeds and adds a message\n-HOOKDIR=\"$(git rev-parse --git-dir)/hooks\"\n-HOOK=\"$HOOKDIR/prepare-commit-msg\"\n-mkdir -p \"$HOOKDIR\"\n-echo \"#!$SHELL_PATH\" > \"$HOOK\"\n-cat >> \"$HOOK\" <<'EOF'\n+\t## Not using test_set_editor here so we can easily ensure the editor variable\n+\t## is only set for the editor tests\n+\tFAKE_EDITOR=\"$(pwd)/fake-editor\" &&\n+\texport FAKE_EDITOR\n+'\n \n+test_expect_success 'setup prepare-commit-msg hook' '\n+\ttest_hook --setup prepare-commit-msg <<\\EOF\n GIT_DIR=$(git rev-parse --git-dir)\n if test -d \"$GIT_DIR/rebase-merge\"\n then\n@@ -103,7 +97,7 @@ else\n fi\n exit 0\n EOF\n-chmod +x \"$HOOK\"\n+'\n \n echo dummy template > \"$(git rev-parse --git-dir)/template\"\n \n@@ -265,10 +259,11 @@ test_expect_success 'with hook and editor (cherry-pick)' '\n \ttest \"$(git log -1 --pretty=format:%s)\" = merge\n '\n \n-cat > \"$HOOK\" <<'EOF'\n-#!/bin/sh\n-exit 1\n-EOF\n+test_expect_success 'setup: commit-msg hook that always fails' '\n+\ttest_hook --setup --clobber prepare-commit-msg <<-\\EOF\n+\texit 1\n+\tEOF\n+'\n \n test_expect_success 'with failing hook' '\n \n@@ -296,9 +291,9 @@ test_expect_success 'with failing hook (merge)' '\n \tgit checkout -B other HEAD@{1} &&\n \techo \"more\" >> file &&\n \tgit add file &&\n-\trm -f \"$HOOK\" &&\n+\ttest_hook --remove prepare-commit-msg &&\n \tgit commit -m other &&\n-\twrite_script \"$HOOK\" <<-EOF &&\n+\ttest_hook --setup prepare-commit-msg <<-\\EOF &&\n \texit 1\n \tEOF\n \tgit checkout - &&\ndiff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh\nindex 634fb7f23a0..dc57526e6f1 100755\n--- a/t/t7520-ignored-hook-warning.sh\n+++ b/t/t7520-ignored-hook-warning.sh\n@@ -5,10 +5,7 @@ test_description='ignored hook warning'\n . ./test-lib.sh\n \n test_expect_success setup '\n-\thookdir=\"$(git rev-parse --git-dir)/hooks\" &&\n-\thook=\"$hookdir/pre-commit\" &&\n-\tmkdir -p \"$hookdir\" &&\n-\twrite_script \"$hook\" <<-\\EOF\n+\ttest_hook --setup pre-commit <<-\\EOF\n \texit 0\n \tEOF\n '\n@@ -19,20 +16,20 @@ test_expect_success 'no warning if hook is not ignored' '\n '\n \n test_expect_success POSIXPERM 'warning if hook is ignored' '\n-\tchmod -x \"$hook\" &&\n+\ttest_hook --disable pre-commit &&\n \tgit commit --allow-empty -m \"even more\" 2>message &&\n \ttest_i18ngrep -e \"hook was ignored\" message\n '\n \n test_expect_success POSIXPERM 'no warning if advice.ignoredHook set to false' '\n \ttest_config advice.ignoredHook false &&\n-\tchmod -x \"$hook\" &&\n+\ttest_hook --disable pre-commit &&\n \tgit commit --allow-empty -m \"even more\" 2>message &&\n \ttest_i18ngrep ! -e \"hook was ignored\" message\n '\n \n test_expect_success 'no warning if unset advice.ignoredHook and hook removed' '\n-\trm -f \"$hook\" &&\n+\ttest_hook --remove pre-commit &&\n \ttest_unconfig advice.ignoredHook &&\n \tgit commit --allow-empty -m \"even more\" 2>message &&\n \ttest_i18ngrep ! -e \"hook was ignored\" message\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 6c9c61c79c2..a027f0c409e 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -562,9 +562,15 @@ write_script () {\n #\tOverwrite an existing <hook-name>, if it exists. Implies\n #\t--setup (i.e. the \"test_when_finished\" is assumed to have been\n #\tset up already).\n+#    --disable\n+#\tDisable (chmod -x) an existing <hook-name>, which must exist.\n+#    --remove\n+#\tRemove (rm -f) an existing <hook-name>, which must exist.\n test_hook () {\n \tsetup= &&\n \tclobber= &&\n+\tdisable= &&\n+\tremove= &&\n \tindir= &&\n \twhile test $# != 0\n \tdo\n@@ -579,6 +585,12 @@ test_hook () {\n \t\t--clobber)\n \t\t\tclobber=t\n \t\t\t;;\n+\t\t--disable)\n+\t\t\tdisable=t\n+\t\t\t;;\n+\t\t--remove)\n+\t\t\tremove=t\n+\t\t\t;;\n \t\t-*)\n \t\t\tBUG \"invalid argument: $1\"\n \t\t\t;;\n@@ -592,6 +604,18 @@ test_hook () {\n \tgit_dir=$(git -C \"$indir\" rev-parse --absolute-git-dir) &&\n \thook_dir=\"$git_dir/hooks\" &&\n \thook_file=\"$hook_dir/$1\" &&\n+\tif test -n \"$disable$remove\"\n+\tthen\n+\t\ttest_path_is_file \"$hook_file\" &&\n+\t\tif test -n \"$disable\"\n+\t\tthen\n+\t\t\tchmod -x \"$hook_file\"\n+\t\telif test -n \"$remove\"\n+\t\tthen\n+\t\t\trm -f \"$hook_file\"\n+\t\tfi &&\n+\t\treturn 0\n+\tfi &&\n \tif test -z \"$clobber\"\n \tthen\n \t\ttest_path_is_missing \"$hook_file\"\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451552","messageId":"patch-v3-13.13-2dffde32036-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 13/13] http tests: use \"test_hook\" for \"smart\" and \"dumb\" http tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:18Z","receivedAt":"2022-03-17T10:14:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the http tests to use \"test_hook\" insteadd of\n\"write_script\". In both cases we can get rid of sub-shelling. For\n\"t/t5550-http-fetch-dumb.sh\" add a trivial helper which sets up the\nhook and calls \"update-server-info\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5541-http-push-smart.sh | 10 ++++------\n t/t5550-http-fetch-dumb.sh | 25 ++++++++++---------------\n 2 files changed, 14 insertions(+), 21 deletions(-)\n\ndiff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh\nindex ab4b5cfcd11..2f09ff4fac6 100755\n--- a/t/t5541-http-push-smart.sh\n+++ b/t/t5541-http-push-smart.sh\n@@ -419,10 +419,7 @@ test_expect_success CMDLINE_LIMIT 'push 2000 tags over http' '\n '\n \n test_expect_success GPG 'push with post-receive to inspect certificate' '\n-\t(\n-\t\tcd \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git &&\n-\t\tmkdir -p hooks &&\n-\t\twrite_script hooks/post-receive <<-\\EOF &&\n+\ttest_hook -C \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git post-receive <<-\\EOF &&\n \t\t# discard the update list\n \t\tcat >/dev/null\n \t\t# record the push certificate\n@@ -437,8 +434,9 @@ test_expect_success GPG 'push with post-receive to inspect certificate' '\n \t\tNONCE_STATUS=${GIT_PUSH_CERT_NONCE_STATUS-nononcestatus}\n \t\tNONCE=${GIT_PUSH_CERT_NONCE-nononce}\n \t\tE_O_F\n-\t\tEOF\n-\n+\tEOF\n+\t(\n+\t\tcd \"$HTTPD_DOCUMENT_ROOT_PATH\"/test_repo.git &&\n \t\tgit config receive.certnonceseed sekrit &&\n \t\tgit config receive.certnonceslop 30\n \t) &&\ndiff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh\nindex 259203926a9..f0d9cd584d3 100755\n--- a/t/t5550-http-fetch-dumb.sh\n+++ b/t/t5550-http-fetch-dumb.sh\n@@ -25,16 +25,17 @@ test_expect_success 'setup repository' '\n \tgit commit -m two\n '\n \n+setup_post_update_server_info_hook () {\n+\ttest_hook --setup -C \"$1\" post-update <<-\\EOF &&\n+\texec git update-server-info\n+\tEOF\n+\tgit -C \"$1\" update-server-info\n+}\n+\n test_expect_success 'create http-accessible bare repository with loose objects' '\n \tcp -R .git \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n-\t(cd \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n-\t git config core.bare true &&\n-\t mkdir -p hooks &&\n-\t write_script \"hooks/post-update\" <<-\\EOF &&\n-\t exec git update-server-info\n-\tEOF\n-\t hooks/post-update\n-\t) &&\n+\tgit -C \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" config core.bare true &&\n+\tsetup_post_update_server_info_hook \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n \tgit remote add public \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n \tgit push public main:main\n '\n@@ -62,13 +63,7 @@ test_expect_success 'create password-protected repository' '\n \n test_expect_success 'create empty remote repository' '\n \tgit init --bare \"$HTTPD_DOCUMENT_ROOT_PATH/empty.git\" &&\n-\t(cd \"$HTTPD_DOCUMENT_ROOT_PATH/empty.git\" &&\n-\t mkdir -p hooks &&\n-\t write_script \"hooks/post-update\" <<-\\EOF &&\n-\t exec git update-server-info\n-\tEOF\n-\t hooks/post-update\n-\t)\n+\tsetup_post_update_server_info_hook \"$HTTPD_DOCUMENT_ROOT_PATH/empty.git\"\n '\n \n test_expect_success 'empty dumb HTTP repository has default hash algorithm' '\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451553","messageId":"patch-v3-12.13-5b764ffc65a-20220317T100820Z-avarab@gmail.com","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"[PATCH v3 12/13] proc-receive hook tests: use \"test_hook\" instead of \"write_script\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T10:13:17Z","receivedAt":"2022-03-17T10:14:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the t5411/*.sh tests to use the test_hook helper instead of\n\"write_script\". Unfortunately these tests do the setup and test across\ndifferent test_expect_success blocks, so we have to use\n--clobber (implying --setup) for these.\n\nLet's change those that can use a quoted here-doc to do so while we're\nat it.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t5411/once-0010-report-status-v1.sh         |  2 +-\n t/t5411/test-0002-pre-receive-declined.sh     |  4 ++--\n ...st-0003-pre-receive-declined--porcelain.sh |  2 +-\n t/t5411/test-0013-bad-protocol.sh             | 20 +++++++++----------\n t/t5411/test-0014-bad-protocol--porcelain.sh  | 18 ++++++++---------\n t/t5411/test-0020-report-ng.sh                |  4 ++--\n t/t5411/test-0021-report-ng--porcelain.sh     |  4 ++--\n t/t5411/test-0022-report-unexpect-ref.sh      |  2 +-\n ...est-0023-report-unexpect-ref--porcelain.sh |  2 +-\n t/t5411/test-0024-report-unknown-ref.sh       |  2 +-\n ...test-0025-report-unknown-ref--porcelain.sh |  2 +-\n t/t5411/test-0026-push-options.sh             |  6 +++---\n t/t5411/test-0027-push-options--porcelain.sh  |  6 +++---\n t/t5411/test-0030-report-ok.sh                |  2 +-\n t/t5411/test-0031-report-ok--porcelain.sh     |  2 +-\n t/t5411/test-0032-report-with-options.sh      | 14 ++++++-------\n ...est-0033-report-with-options--porcelain.sh | 14 ++++++-------\n t/t5411/test-0034-report-ft.sh                |  2 +-\n t/t5411/test-0035-report-ft--porcelain.sh     |  2 +-\n ...t-0036-report-multi-rewrite-for-one-ref.sh |  6 +++---\n ...rt-multi-rewrite-for-one-ref--porcelain.sh |  6 +++---\n t/t5411/test-0038-report-mixed-refs.sh        |  2 +-\n .../test-0039-report-mixed-refs--porcelain.sh |  2 +-\n t/t5411/test-0040-process-all-refs.sh         |  2 +-\n .../test-0041-process-all-refs--porcelain.sh  |  2 +-\n ...t-0050-proc-receive-refs-with-modifiers.sh |  4 ++--\n 26 files changed, 67 insertions(+), 67 deletions(-)\n\ndiff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh\nindex 297b10925d5..f9ffb01e509 100644\n--- a/t/t5411/once-0010-report-status-v1.sh\n+++ b/t/t5411/once-0010-report-status-v1.sh\n@@ -3,7 +3,7 @@ test_expect_success \"setup receive.procReceiveRefs\" '\n '\n \n test_expect_success \"setup proc-receive hook\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic1\" \\\ndiff --git a/t/t5411/test-0002-pre-receive-declined.sh b/t/t5411/test-0002-pre-receive-declined.sh\nindex 0c3490c9b1b..98a9d13041a 100644\n--- a/t/t5411/test-0002-pre-receive-declined.sh\n+++ b/t/t5411/test-0002-pre-receive-declined.sh\n@@ -1,6 +1,6 @@\n test_expect_success \"setup pre-receive hook ($PROTOCOL)\" '\n \tmv \"$upstream/hooks/pre-receive\" \"$upstream/hooks/pre-receive.ok\" &&\n-\twrite_script \"$upstream/hooks/pre-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber pre-receive <<-\\EOF\n \texit 1\n \tEOF\n '\n@@ -21,7 +21,7 @@ test_expect_success \"git-push is declined ($PROTOCOL)\" '\n \tEOF\n \ttest_cmp expect actual &&\n \n-\ttest_cmp_refs -C \"$upstream\" <<-EOF\n+\ttest_cmp_refs -C \"$upstream\" <<-\\EOF\n \t<COMMIT-A> refs/heads/main\n \tEOF\n '\ndiff --git a/t/t5411/test-0003-pre-receive-declined--porcelain.sh b/t/t5411/test-0003-pre-receive-declined--porcelain.sh\nindex 2393b04ad95..67ca6dc4f8f 100644\n--- a/t/t5411/test-0003-pre-receive-declined--porcelain.sh\n+++ b/t/t5411/test-0003-pre-receive-declined--porcelain.sh\n@@ -1,6 +1,6 @@\n test_expect_success \"setup pre-receive hook ($PROTOCOL/porcelain)\" '\n \tmv \"$upstream/hooks/pre-receive\" \"$upstream/hooks/pre-receive.ok\" &&\n-\twrite_script \"$upstream/hooks/pre-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber pre-receive <<-\\EOF\n \texit 1\n \tEOF\n '\ndiff --git a/t/t5411/test-0013-bad-protocol.sh b/t/t5411/test-0013-bad-protocol.sh\nindex c08a00ded29..8d22e17aee3 100644\n--- a/t/t5411/test-0013-bad-protocol.sh\n+++ b/t/t5411/test-0013-bad-protocol.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (unknown version, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --version 2\n \tEOF\n@@ -40,7 +40,7 @@ test_expect_success \"proc-receive: bad protocol (unknown version, $PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-read-version, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-read-version\n \tEOF\n@@ -65,13 +65,13 @@ test_expect_success \"proc-receive: bad protocol (hook --die-read-version, $PROTO\n \tgrep \"remote: fatal: die with the --die-read-version option\" out-$test_count &&\n \tgrep \"remote: error: fail to negotiate version with proc-receive hook\" out-$test_count &&\n \n-\ttest_cmp_refs -C \"$upstream\" <<-EOF\n+\ttest_cmp_refs -C \"$upstream\" <<-\\EOF\n \t<COMMIT-A> refs/heads/main\n \tEOF\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-write-version, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-write-version\n \tEOF\n@@ -102,7 +102,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-write-version, $PROT\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-read-commands, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-read-commands\n \tEOF\n@@ -132,7 +132,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-read-commands, $PROT\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-read-push-options, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-read-push-options\n \tEOF\n@@ -164,7 +164,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-read-push-options, $\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-write-report, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-write-report\n \tEOF\n@@ -194,7 +194,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-write-report, $PROTO\n '\n \n test_expect_success \"setup proc-receive hook (no report, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v\n \tEOF\n@@ -236,7 +236,7 @@ test_expect_success \"cleanup ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (no ref, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok\"\n@@ -269,7 +269,7 @@ test_expect_success \"proc-receive: bad protocol (no ref, $PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (unknown status, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"xx refs/for/main/topic\"\ndiff --git a/t/t5411/test-0014-bad-protocol--porcelain.sh b/t/t5411/test-0014-bad-protocol--porcelain.sh\nindex 3eaa597e0f7..298a3d1feca 100644\n--- a/t/t5411/test-0014-bad-protocol--porcelain.sh\n+++ b/t/t5411/test-0014-bad-protocol--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (unknown version, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --version 2\n \tEOF\n@@ -40,7 +40,7 @@ test_expect_success \"proc-receive: bad protocol (unknown version, $PROTOCOL/porc\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-read-version, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-read-version\n \tEOF\n@@ -71,7 +71,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-read-version, $PROTO\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-write-version, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-write-version\n \tEOF\n@@ -102,7 +102,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-write-version, $PROT\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-read-commands, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-read-commands\n \tEOF\n@@ -132,7 +132,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-read-commands, $PROT\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-read-push-options, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-read-push-options\n \tEOF\n@@ -164,7 +164,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-read-push-options, $\n '\n \n test_expect_success \"setup proc-receive hook (hook --die-write-report, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v --die-write-report\n \tEOF\n@@ -194,7 +194,7 @@ test_expect_success \"proc-receive: bad protocol (hook --die-write-report, $PROTO\n '\n \n test_expect_success \"setup proc-receive hook (no report, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v\n \tEOF\n@@ -236,7 +236,7 @@ test_expect_success \"cleanup ($PROTOCOL/porcelain)\" '\n '\n \n test_expect_success \"setup proc-receive hook (no ref, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok\"\n@@ -270,7 +270,7 @@ test_expect_success \"proc-receive: bad protocol (no ref, $PROTOCOL/porcelain)\" '\n '\n \n test_expect_success \"setup proc-receive hook (unknown status, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"xx refs/for/main/topic\"\ndiff --git a/t/t5411/test-0020-report-ng.sh b/t/t5411/test-0020-report-ng.sh\nindex e915dbc28df..6347c9629b3 100644\n--- a/t/t5411/test-0020-report-ng.sh\n+++ b/t/t5411/test-0020-report-ng.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (ng, no message, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ng refs/for/main/topic\"\n@@ -31,7 +31,7 @@ test_expect_success \"proc-receive: fail to update (ng, no message, $PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (ng message, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ng refs/for/main/topic error msg\"\ndiff --git a/t/t5411/test-0021-report-ng--porcelain.sh b/t/t5411/test-0021-report-ng--porcelain.sh\nindex 2a392e099b9..502b34fe3dd 100644\n--- a/t/t5411/test-0021-report-ng--porcelain.sh\n+++ b/t/t5411/test-0021-report-ng--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (ng, no message, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ng refs/for/main/topic\"\n@@ -32,7 +32,7 @@ test_expect_success \"proc-receive: fail to update (ng, no message, $PROTOCOL/por\n '\n \n test_expect_success \"setup proc-receive hook (ng message, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ng refs/for/main/topic error msg\"\ndiff --git a/t/t5411/test-0022-report-unexpect-ref.sh b/t/t5411/test-0022-report-unexpect-ref.sh\nindex f7a494bdb9d..7744392a626 100644\n--- a/t/t5411/test-0022-report-unexpect-ref.sh\n+++ b/t/t5411/test-0022-report-unexpect-ref.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (unexpected ref, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/heads/main\"\ndiff --git a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh\nindex 63c479e9759..6d116ef692c 100644\n--- a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh\n+++ b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/heads/main\"\ndiff --git a/t/t5411/test-0024-report-unknown-ref.sh b/t/t5411/test-0024-report-unknown-ref.sh\nindex af055aa0864..619ca2f421a 100644\n--- a/t/t5411/test-0024-report-unknown-ref.sh\n+++ b/t/t5411/test-0024-report-unknown-ref.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (unexpected ref, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\ndiff --git a/t/t5411/test-0025-report-unknown-ref--porcelain.sh b/t/t5411/test-0025-report-unknown-ref--porcelain.sh\nindex 99601ca321f..8b3f5d05a3f 100644\n--- a/t/t5411/test-0025-report-unknown-ref--porcelain.sh\n+++ b/t/t5411/test-0025-report-unknown-ref--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\ndiff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh\nindex fec5f95793b..6dfc7b1c0da 100644\n--- a/t/t5411/test-0026-push-options.sh\n+++ b/t/t5411/test-0026-push-options.sh\n@@ -1,6 +1,6 @@\n test_expect_success \"setup proc-receive hook and disable push-options ($PROTOCOL)\" '\n \tgit -C \"$upstream\" config receive.advertisePushOptions false &&\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\n@@ -31,7 +31,7 @@ test_expect_success \"enable push options ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup version=0 for proc-receive hook ($PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t--version 0 \\\n@@ -75,7 +75,7 @@ test_expect_success \"proc-receive: ignore push-options for version 0 ($PROTOCOL)\n '\n \n test_expect_success \"restore proc-receive hook ($PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\ndiff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh\nindex 8fb75a8789d..768880b40fb 100644\n--- a/t/t5411/test-0027-push-options--porcelain.sh\n+++ b/t/t5411/test-0027-push-options--porcelain.sh\n@@ -1,6 +1,6 @@\n test_expect_success \"setup proc-receive hook and disable push-options ($PROTOCOL/porcelain)\" '\n \tgit -C \"$upstream\" config receive.advertisePushOptions false &&\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\n@@ -32,7 +32,7 @@ test_expect_success \"enable push options ($PROTOCOL/porcelain)\" '\n '\n \n test_expect_success \"setup version=0 for proc-receive hook ($PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t--version 0 \\\n@@ -78,7 +78,7 @@ test_expect_success \"proc-receive: ignore push-options for version 0 ($PROTOCOL/\n '\n \n test_expect_success \"restore proc-receive hook ($PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\ndiff --git a/t/t5411/test-0030-report-ok.sh b/t/t5411/test-0030-report-ok.sh\nindex a3a6278213c..0f190a6e851 100644\n--- a/t/t5411/test-0030-report-ok.sh\n+++ b/t/t5411/test-0030-report-ok.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (ok, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\ndiff --git a/t/t5411/test-0031-report-ok--porcelain.sh b/t/t5411/test-0031-report-ok--porcelain.sh\nindex 0e175388b65..7ec39812638 100644\n--- a/t/t5411/test-0031-report-ok--porcelain.sh\n+++ b/t/t5411/test-0031-report-ok--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (ok, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\"\ndiff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh\nindex 988a4302a67..07733b94b81 100644\n--- a/t/t5411/test-0032-report-with-options.sh\n+++ b/t/t5411/test-0032-report-with-options.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (option without matching ok, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"option refname refs/pull/123/head\" \\\n@@ -30,7 +30,7 @@ test_expect_success \"proc-receive: report option without matching ok ($PROTOCOL)\n '\n \n test_expect_success \"setup proc-receive hook (option refname, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -62,7 +62,7 @@ test_expect_success \"proc-receive: report option refname ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (option refname and forced-update, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -95,7 +95,7 @@ test_expect_success \"proc-receive: report option refname and forced-update ($PRO\n '\n \n test_expect_success \"setup proc-receive hook (option refname and old-oid, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -129,7 +129,7 @@ test_expect_success \"proc-receive: report option refname and old-oid ($PROTOCOL)\n '\n \n test_expect_success \"setup proc-receive hook (option old-oid, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -161,7 +161,7 @@ test_expect_success \"proc-receive: report option old-oid ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (option old-oid and new-oid, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -195,7 +195,7 @@ test_expect_success \"proc-receive: report option old-oid and new-oid ($PROTOCOL)\n '\n \n test_expect_success \"setup proc-receive hook (report with multiple rewrites, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/a/b/c/topic\" \\\ndiff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh\nindex daacb3d69d4..2e1831b104e 100644\n--- a/t/t5411/test-0033-report-with-options--porcelain.sh\n+++ b/t/t5411/test-0033-report-with-options--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (option without matching ok, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"option refname refs/pull/123/head\" \\\n@@ -31,7 +31,7 @@ test_expect_success \"proc-receive: report option without matching ok ($PROTOCOL/\n '\n \n test_expect_success \"setup proc-receive hook (option refname, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -64,7 +64,7 @@ test_expect_success \"proc-receive: report option refname ($PROTOCOL/porcelain)\"\n '\n \n test_expect_success \"setup proc-receive hook (option refname and forced-update, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -99,7 +99,7 @@ test_expect_success \"proc-receive: report option refname and forced-update ($PRO\n '\n \n test_expect_success \"setup proc-receive hook (option refname and old-oid, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -134,7 +134,7 @@ test_expect_success \"proc-receive: report option refname and old-oid ($PROTOCOL/\n '\n \n test_expect_success \"setup proc-receive hook (option old-oid, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -167,7 +167,7 @@ test_expect_success \"proc-receive: report option old-oid ($PROTOCOL/porcelain)\"\n '\n \n test_expect_success \"setup proc-receive hook (option old-oid and new-oid, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -202,7 +202,7 @@ test_expect_success \"proc-receive: report option old-oid and new-oid ($PROTOCOL/\n '\n \n test_expect_success \"setup proc-receive hook (report with multiple rewrites, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/a/b/c/topic\" \\\ndiff --git a/t/t5411/test-0034-report-ft.sh b/t/t5411/test-0034-report-ft.sh\nindex 73a47d1ffdb..0e375350653 100644\n--- a/t/t5411/test-0034-report-ft.sh\n+++ b/t/t5411/test-0034-report-ft.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (ft, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\ndiff --git a/t/t5411/test-0035-report-ft--porcelain.sh b/t/t5411/test-0035-report-ft--porcelain.sh\nindex c3502011075..b9a05181f1a 100644\n--- a/t/t5411/test-0035-report-ft--porcelain.sh\n+++ b/t/t5411/test-0035-report-ft--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (fall-through, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-\\EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\ndiff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh\nindex 8c8a6c16e10..889e97057b8 100644\n--- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh\n+++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh\n@@ -14,7 +14,7 @@ test_expect_success \"setup git config for remote-tracking of special refs\" '\n '\n \n test_expect_success \"setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -87,7 +87,7 @@ test_expect_success \"proc-receive: check remote-tracking #1 ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -162,7 +162,7 @@ test_expect_success \"proc-receive: check remote-tracking #2 ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\ndiff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh\nindex bc44810f33a..1e523b1c173 100644\n--- a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh\n+++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -58,7 +58,7 @@ test_expect_success \"proc-receive: multiple rewrite for one ref, no refname for\n '\n \n test_expect_success \"setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\n@@ -119,7 +119,7 @@ test_expect_success \"proc-receive: multiple rewrites for one ref, no refname for\n '\n \n test_expect_success \"setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/main/topic\" \\\ndiff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh\nindex e63fe7ba110..4c70e84e410 100644\n--- a/t/t5411/test-0038-report-mixed-refs.sh\n+++ b/t/t5411/test-0038-report-mixed-refs.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook ($PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/next/topic2\" \\\ndiff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh\nindex 99d17b73afd..40f4c5b1afb 100644\n--- a/t/t5411/test-0039-report-mixed-refs--porcelain.sh\n+++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh\n@@ -1,5 +1,5 @@\n test_expect_success \"setup proc-receive hook ($PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/for/next/topic2\" \\\ndiff --git a/t/t5411/test-0040-process-all-refs.sh b/t/t5411/test-0040-process-all-refs.sh\nindex 2f405adefa8..7ae3851efb9 100644\n--- a/t/t5411/test-0040-process-all-refs.sh\n+++ b/t/t5411/test-0040-process-all-refs.sh\n@@ -17,7 +17,7 @@ test_expect_success \"setup upstream branches ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook ($PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/heads/main\" \\\ndiff --git a/t/t5411/test-0041-process-all-refs--porcelain.sh b/t/t5411/test-0041-process-all-refs--porcelain.sh\nindex c88405792ef..02e1e084d6c 100644\n--- a/t/t5411/test-0041-process-all-refs--porcelain.sh\n+++ b/t/t5411/test-0041-process-all-refs--porcelain.sh\n@@ -17,7 +17,7 @@ test_expect_success \"setup upstream branches ($PROTOCOL/porcelain)\" '\n '\n \n test_expect_success \"setup proc-receive hook ($PROTOCOL/porcelain)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/heads/main\" \\\ndiff --git a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh\nindex 31989f01850..7efdfe55987 100644\n--- a/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh\n+++ b/t/t5411/test-0050-proc-receive-refs-with-modifiers.sh\n@@ -9,7 +9,7 @@ test_expect_success \"config receive.procReceiveRefs with modifiers ($PROTOCOL)\"\n '\n \n test_expect_success \"setup proc-receive hook ($PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/heads/main\" \\\n@@ -70,7 +70,7 @@ test_expect_success \"setup upstream: create tags/v123 ($PROTOCOL)\" '\n '\n \n test_expect_success \"setup proc-receive hook ($PROTOCOL)\" '\n-\twrite_script \"$upstream/hooks/proc-receive\" <<-EOF\n+\ttest_hook -C \"$upstream\" --clobber proc-receive <<-EOF\n \tprintf >&2 \"# proc-receive hook\\n\"\n \ttest-tool proc-receive -v \\\n \t\t-r \"ok refs/heads/main\" \\\n-- \n2.35.1.1384.g7d2906948a1\n\n"},{"id":"451569","messageId":"xmqqpmmkh77b.fsf@gitster.g","threadId":"57496","inReplyTo":"cover-v3-00.13-00000000000-20220317T100820Z-avarab@gmail.com","subject":"Re: [PATCH v3 00/13] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-17T16:31:04Z","receivedAt":"2022-03-17T16:31:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Just a quick update before I finish my first integration cycle of\ntoday.  t543 has a \"test_hook\" call inside a subshell, but because\nthe helper runs test_when_finished, a sanity check kicks in and\nfails the test.\n\nI'll continue the integration cycle with this topic kicked out of\n'seen' for now.\n"},{"id":"451593","messageId":"220317.86k0cscmqp.gmgdl@evledraar.gmail.com","threadId":"57496","inReplyTo":"xmqqpmmkh77b.fsf@gitster.g","subject":"Re: [PATCH v3 00/13] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-17T21:04:39Z","receivedAt":"2022-03-17T21:06:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Mar 17 2022, Junio C Hamano wrote:\n\n> Just a quick update before I finish my first integration cycle of\n> today.  t543 has a \"test_hook\" call inside a subshell, but because\n> the helper runs test_when_finished, a sanity check kicks in and\n> fails the test.\n>\n> I'll continue the integration cycle with this topic kicked out of\n> 'seen' for now.\n\nPending a re-roll this fix-up for 11/13 should fix it.\n\nI do test with /bin/bash before submitting to catch exactly this class\nof issue, but for reasons I haven't looked into this one is odd in not\nfailing with --verbose-log, but I see the OSX CI (which I didn't wait\nfor) fails on the same issue. Sorry.\n\ndiff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh\nindex 90676365471..70431122a40 100755\n--- a/t/t5543-atomic-push.sh\n+++ b/t/t5543-atomic-push.sh\n@@ -162,13 +162,10 @@ test_expect_success 'atomic push obeys update hook preventing a branch to be pus\n \t\ttest_commit two &&\n \t\tgit push --mirror up\n \t) &&\n-\t(\n-\t\tcd upstream &&\n-\t\ttest_hook update <<-\\EOF\n-\t\t\t# only allow update to main from now on\n-\t\t\ttest \"$1\" = \"refs/heads/main\"\n-\t\tEOF\n-\t) &&\n+\ttest_hook -C upstream update <<-\\EOF &&\n+\t# only allow update to main from now on\n+\ttest \"$1\" = \"refs/heads/main\"\n+\tEOF\n \t(\n \t\tcd workbench &&\n \t\tgit checkout main &&\n"},{"id":"451597","messageId":"xmqqzglocl6o.fsf@gitster.g","threadId":"57496","inReplyTo":"220317.86k0cscmqp.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH v3 00/13] tests: add and use a \"test_hook\" wrapper + hook fixes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-03-17T21:40:15Z","receivedAt":"2022-03-17T21:40:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Pending a re-roll this fix-up for 11/13 should fix it.\n>\n> I do test with /bin/bash before submitting to catch exactly this class\n> of issue, but for reasons I haven't looked into this one is odd in not\n> failing with --verbose-log, but I see the OSX CI (which I didn't wait\n> for) fails on the same issue. Sorry.\n\nHmph, my integration run failed right away.  I use bash and dash on\nalternate days, and you got lucky today ;-)\n\n> diff --git a/t/t5543-atomic-push.sh b/t/t5543-atomic-push.sh\n> index 90676365471..70431122a40 100755\n> --- a/t/t5543-atomic-push.sh\n> +++ b/t/t5543-atomic-push.sh\n> @@ -162,13 +162,10 @@ test_expect_success 'atomic push obeys update hook preventing a branch to be pus\n>  \t\ttest_commit two &&\n>  \t\tgit push --mirror up\n>  \t) &&\n> -\t(\n> -\t\tcd upstream &&\n> -\t\ttest_hook update <<-\\EOF\n> -\t\t\t# only allow update to main from now on\n> -\t\t\ttest \"$1\" = \"refs/heads/main\"\n> -\t\tEOF\n> -\t) &&\n> +\ttest_hook -C upstream update <<-\\EOF &&\n> +\t# only allow update to main from now on\n> +\ttest \"$1\" = \"refs/heads/main\"\n> +\tEOF\n\nOK.\n\n>  \t(\n>  \t\tcd workbench &&\n>  \t\tgit checkout main &&\n"}]}