Skip to content

Commit

Permalink
Merge branch 'zh/trailer-cmd' into seen
Browse files Browse the repository at this point in the history
The way the command line specified by the trailer.<token>.command
configuration variable receives the end-user supplied value was
both error prone and misleading.  An alternative to achieve the
same goal in a safer and more intuitive way has been added, as
the trailer.<token>.cmd configuration variable, to replace it.

* zh/trailer-cmd:
  trailer: add new .cmd config option
  docs: correct description of .command
  • Loading branch information
gitster committed Apr 30, 2021
2 parents 610137a + 1b41dec commit c4405a8
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 32 deletions.
111 changes: 95 additions & 16 deletions Documentation/git-interpret-trailers.txt
Original file line number Diff line number Diff line change
Expand Up @@ -232,25 +232,46 @@ trailer.<token>.ifmissing::
that option for trailers with the specified <token>.

trailer.<token>.command::
This option can be used to specify a shell command that will
be called to automatically add or modify a trailer with the
specified <token>.
This option behaves in the same way as 'trailer.<token>.cmd', except
that it doesn't pass anything as argument to the specified command.
Instead the first occurrence of substring $ARG is replaced by the
value that would be passed as argument.
+
When this option is specified, the behavior is as if a special
'<token>=<value>' argument were added at the beginning of the command
line, where <value> is taken to be the standard output of the
specified command with any leading and trailing whitespace trimmed
off.
The 'trailer.<token>.command' option has been deprecated in favor of
'trailer.<token>.cmd' due to the fact that $ARG in the user's command is
only replaced once and that the original way of replacing $ARG is not safe.
+
If the command contains the `$ARG` string, this string will be
replaced with the <value> part of an existing trailer with the same
<token>, if any, before the command is launched.
When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given
for the same <token>, 'trailer.<token>.cmd' is used and
'trailer.<token>.command' is ignored.

trailer.<token>.cmd::
This option can be used to specify a shell command that will be called:
once to automatically add a trailer with the specified <token>, and then
each time a '--trailer <token>=<value>' argument to modify the <value> of
the trailer that this option would produce.
+
If some '<token>=<value>' arguments are also passed on the command
line, when a 'trailer.<token>.command' is configured, the command will
also be executed for each of these arguments. And the <value> part of
these arguments, if any, will be used to replace the `$ARG` string in
the command.
When the specified command is first called to add a trailer
with the specified <token>, the behavior is as if a special
'--trailer <token>=<value>' argument was added at the beginning
of the "git interpret-trailers" command, where <value>
is taken to be the standard output of the command with any
leading and trailing whitespace trimmed off.
+
If some '--trailer <token>=<value>' arguments are also passed
on the command line, the command is called again once for each
of these arguments with the same <token>. And the <value> part
of these arguments, if any, will be passed to the command as its
first argument. This way the command can produce a <value> computed
from the <value> passed in the '--trailer <token>=<value>' argument.
+
It is worth mentioning that the command is first called to add a
trailer with the specified <token> and without positional argument.
Users can make use of this output when they need automatically add
some trailers. On the other hand, users can use a trick to suppress
this output by judging whether the number of positional parameters
is equal to one, if it is true, execute the commands, otherwise exit
with non-zero to suppress the output.

EXAMPLES
--------
Expand Down Expand Up @@ -333,6 +354,64 @@ subject
Fix #42
------------

* Configure a 'cnt' trailer with a cmd use a global script `gcount`
to record commit counts of a specified author and show how it works:
+
------------
$ cat ~/bin/gcount
#!/bin/sh
if test "$#" != 1
then
exit 1
else
test -n "$1" && git shortlog -s --author="$1" HEAD || true
fi
$ git config trailer.cnt.key "Commit-count: "
$ git config trailer.cnt.ifExists "addIfDifferentNeighbor"
$ git config trailer.cnt.cmd "~/bin/gcount"
$ git interpret-trailers --trailer="cnt:Junio" --trailer="cnt:Linus Torvalds"<<EOF
> subject
>
> message
>
> EOF
subject

message

Commit-count: 22484 Junio C Hamano
Commit-count: 1117 Linus Torvalds
------------

* Configure a 'ref' trailer with a cmd use a global script `glog-grep`
to grep last relevant commit from git log in the git repository
and show how it works:
+
------------
$ cat ~/bin/glog-grep
#!/bin/sh
if test "$#" != 1
then
exit 1
else
test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
fi
$ git config trailer.ref.key "Reference-to: "
$ git config trailer.ref.ifExists "replace"
$ git config trailer.ref.cmd "~/bin/glog-grep"
$ git interpret-trailers --trailer="ref:Add copyright notices." <<EOF
> subject
>
> message
>
> EOF
subject

message

Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
------------

* Configure a 'see' trailer with a command to show the subject of a
commit that is related, and show how it works:
+
Expand Down
122 changes: 122 additions & 0 deletions t/t7513-interpret-trailers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,107 @@ test_expect_success 'setup' '
EOF
'

test_expect_success 'with cmd' '
test_when_finished "git config --remove-section trailer.bug" &&
git config trailer.bug.key "Bug-maker: " &&
git config trailer.bug.ifExists "add" &&
git config trailer.bug.cmd "echo \"maybe is\"" &&
cat >expected2 <<-EOF &&
Bug-maker: maybe is
Bug-maker: maybe is him
Bug-maker: maybe is me
EOF
git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
>actual2 &&
test_cmp expected2 actual2
'

test_expect_success 'with cmd and $1' '
test_when_finished "git config --remove-section trailer.bug" &&
git config trailer.bug.key "Bug-maker: " &&
git config trailer.bug.ifExists "add" &&
git config trailer.bug.cmd "echo \"\$1\" is" &&
cat >expected2 <<-EOF &&
Bug-maker: is
Bug-maker: him is him
Bug-maker: me is me
EOF
git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
>actual2 &&
test_cmp expected2 actual2
'

test_expect_success 'with cmd and $1 with sh -c' '
test_when_finished "git config --remove-section trailer.bug" &&
git config trailer.bug.key "Bug-maker: " &&
git config trailer.bug.ifExists "replace" &&
git config trailer.bug.cmd "sh -c \"echo who is \"\$1\"\"" &&
cat >expected2 <<-EOF &&
Bug-maker: who is me
EOF
git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
>actual2 &&
test_cmp expected2 actual2
'

test_expect_success 'with cmd and $1 with shell script' '
test_when_finished "git config --remove-section trailer.bug" &&
git config trailer.bug.key "Bug-maker: " &&
git config trailer.bug.ifExists "replace" &&
git config trailer.bug.cmd "./echoscript" &&
cat >expected2 <<-EOF &&
Bug-maker: who is me
EOF
cat >echoscript <<-EOF &&
#!/bin/sh
if test "\$#" != 1
then
exit 1
else
echo who is "\$1"
fi
EOF
chmod +x echoscript &&
git interpret-trailers --trailer "bug: him" --trailer "bug:me" \
>actual2 &&
test_cmp expected2 actual2
'

test_expect_success 'with cmd, $1 and without --trailer' '
test_when_finished "git config --remove-section trailer.bug" &&
test_when_finished "git config --remove-section trailer.gub" &&
git config trailer.bug.key "Bug-maker: " &&
git config trailer.bug.ifExists "replace" &&
git config trailer.bug.cmd "./echoscript" &&
git config trailer.gub.key "Gub-maker: " &&
git config trailer.gub.ifExists "replace" &&
git config trailer.gub.cmd "./echoscript2" &&
cat >expected2 <<-EOF &&
Gub-maker: si ohw
EOF
cat >echoscript <<-EOF &&
#!/bin/sh
if test "\$#" != 1
then
exit 1
else
echo who is "\$1"
fi
EOF
cat >echoscript2 <<-EOF &&
echo si ohw "\$1"
EOF
chmod +x echoscript &&
chmod +x echoscript2 &&
git interpret-trailers >actual2 &&
test_cmp expected2 actual2
'

test_expect_success 'without config' '
sed -e "s/ Z\$/ /" >expected <<-\EOF &&
Expand Down Expand Up @@ -1274,6 +1375,27 @@ test_expect_success 'setup a commit' '
git commit -m "Add file a.txt"
'

test_expect_success 'cmd takes precedence over command' '
test_when_finished "git config --unset trailer.fix.cmd" &&
git config trailer.fix.ifExists "replace" &&
git config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
--abbrev-commit --abbrev=14 \"\$1\" || true" &&
git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
--abbrev-commit --abbrev=14 \$ARG" &&
FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
cat complex_message_body >expected2 &&
sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
Fixes: $FIXED
Acked-by= Z
Reviewed-by:
Signed-off-by: Z
Signed-off-by: A U Thor <author@example.com>
EOF
git interpret-trailers --trailer "review:" --trailer "fix=HEAD" \
<complex_message >actual2 &&
test_cmp expected2 actual2
'

test_expect_success 'with command using $ARG' '
git config trailer.fix.ifExists "replace" &&
git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
Expand Down

0 comments on commit c4405a8

Please sign in to comment.