Merge branch 'la/trailer-test-and-doc-updates'

Test coverage for trailers has been improved.

* la/trailer-test-and-doc-updates:
  trailer doc: <token> is a <key> or <keyAlias>, not both
  trailer doc: separator within key suppresses default separator
  trailer doc: emphasize the effect of configuration variables
  trailer --unfold help: prefer "reformat" over "join"
  trailer --parse docs: add explanation for its usefulness
  trailer --only-input: prefer "configuration variables" over "rules"
  trailer --parse help: expose aliased options
  trailer --no-divider help: describe usual "---" meaning
  trailer: trailer location is a place, not an action
  trailer doc: narrow down scope of --where and related flags
  trailer: add tests to check defaulting behavior with --no-* flags
  trailer test description: this tests --where=after, not --where=before
  trailer tests: make test cases self-contained
maint
Junio C Hamano 2023-10-13 14:18:27 -07:00
commit c75e91499b
3 changed files with 545 additions and 156 deletions

View File

@ -9,7 +9,7 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git interpret-trailers' [--in-place] [--trim-empty] 'git interpret-trailers' [--in-place] [--trim-empty]
[(--trailer <token>[(=|:)<value>])...] [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]
[--parse] [<file>...] [--parse] [<file>...]


DESCRIPTION DESCRIPTION
@ -31,10 +31,15 @@ the last two lines starting with "Signed-off-by" are trailers.


This command reads commit messages from either the This command reads commit messages from either the
<file> arguments or the standard input if no <file> is specified. <file> arguments or the standard input if no <file> is specified.
If `--parse` is specified, the output consists of the parsed trailers. If `--parse` is specified, the output consists of the parsed trailers
Otherwise, this command applies the arguments passed using the coming from the input, without influencing them with any command line
`--trailer` option, if any, to each input file. The result is emitted on the options or configuration variables.
standard output.
Otherwise, this command applies `trailer.*` configuration variables
(which could potentially add new trailers, as well as reposition them),
as well as any command line arguments that can override configuration
variables (such as `--trailer=...` which could also add new trailers),
to each input file. The result is emitted on the standard output.


This command can also operate on the output of linkgit:git-format-patch[1], This command can also operate on the output of linkgit:git-format-patch[1],
which is more elaborate than a plain commit message. Namely, such output which is more elaborate than a plain commit message. Namely, such output
@ -48,22 +53,32 @@ are applied to each input and the way any existing trailer in
the input is changed. They also make it possible to the input is changed. They also make it possible to
automatically add some trailers. automatically add some trailers.


By default, a '<token>=<value>' or '<token>:<value>' argument given By default, a '<key>=<value>' or '<key>:<value>' argument given
using `--trailer` will be appended after the existing trailers only if using `--trailer` will be appended after the existing trailers only if
the last trailer has a different (<token>, <value>) pair (or if there the last trailer has a different (<key>, <value>) pair (or if there
is no existing trailer). The <token> and <value> parts will be trimmed is no existing trailer). The <key> and <value> parts will be trimmed
to remove starting and trailing whitespace, and the resulting trimmed to remove starting and trailing whitespace, and the resulting trimmed
<token> and <value> will appear in the output like this: <key> and <value> will appear in the output like this:


------------------------------------------------ ------------------------------------------------
token: value key: value
------------------------------------------------ ------------------------------------------------


This means that the trimmed <token> and <value> will be separated by This means that the trimmed <key> and <value> will be separated by
`': '` (one colon followed by one space). For convenience, the <token> can be a `': '` (one colon followed by one space).
shortened string key (e.g., "sign") instead of the full string which should
appear before the separator on the output (e.g., "Signed-off-by"). This can be For convenience, a <keyAlias> can be configured to make using `--trailer`
configured using the 'trailer.<token>.key' configuration variable. shorter to type on the command line. This can be configured using the
'trailer.<keyAlias>.key' configuration variable. The <keyAlias> must be a prefix
of the full <key> string, although case sensitivity does not matter. For
example, if you have

------------------------------------------------
trailer.sign.key "Signed-off-by: "
------------------------------------------------

in your configuration, you only need to specify `--trailer="sign: foo"`
on the command line instead of `--trailer="Signed-off-by: foo"`.


By default the new trailer will appear at the end of all the existing By default the new trailer will appear at the end of all the existing
trailers. If there is no existing trailer, the new trailer will appear trailers. If there is no existing trailer, the new trailer will appear
@ -80,14 +95,14 @@ non-whitespace lines before a line that starts with '---' (followed by a
space or the end of the line). space or the end of the line).


When reading trailers, there can be no whitespace before or inside the When reading trailers, there can be no whitespace before or inside the
<token>, but any number of regular space and tab characters are allowed <key>, but any number of regular space and tab characters are allowed
between the <token> and the separator. There can be whitespaces before, between the <key> and the separator. There can be whitespaces before,
inside or after the <value>. The <value> may be split over multiple lines inside or after the <value>. The <value> may be split over multiple lines
with each subsequent line starting with at least one whitespace, like with each subsequent line starting with at least one whitespace, like
the "folding" in RFC 822. Example: the "folding" in RFC 822. Example:


------------------------------------------------ ------------------------------------------------
token: This is a very long value, with spaces and key: This is a very long value, with spaces and
newlines in it. newlines in it.
------------------------------------------------ ------------------------------------------------


@ -104,35 +119,44 @@ OPTIONS
the whole trailer will be removed from the output. the whole trailer will be removed from the output.
This applies to existing trailers as well as new trailers. This applies to existing trailers as well as new trailers.


--trailer <token>[(=|:)<value>]:: --trailer <key>[(=|:)<value>]::
Specify a (<token>, <value>) pair that should be applied as a Specify a (<key>, <value>) pair that should be applied as a
trailer to the inputs. See the description of this trailer to the inputs. See the description of this
command. command.


--where <placement>:: --where <placement>::
--no-where:: --no-where::
Specify where all new trailers will be added. A setting Specify where all new trailers will be added. A setting
provided with '--where' overrides all configuration variables provided with '--where' overrides the `trailer.where` and any
applicable `trailer.<keyAlias>.where` configuration variables
and applies to all '--trailer' options until the next occurrence of and applies to all '--trailer' options until the next occurrence of
'--where' or '--no-where'. Possible values are `after`, `before`, '--where' or '--no-where'. Upon encountering '--no-where', clear the
`end` or `start`. effect of any previous use of '--where', such that the relevant configuration
variables are no longer overridden. Possible placements are `after`,
`before`, `end` or `start`.


--if-exists <action>:: --if-exists <action>::
--no-if-exists:: --no-if-exists::
Specify what action will be performed when there is already at Specify what action will be performed when there is already at
least one trailer with the same <token> in the input. A setting least one trailer with the same <key> in the input. A setting
provided with '--if-exists' overrides all configuration variables provided with '--if-exists' overrides the `trailer.ifExists` and any
applicable `trailer.<keyAlias>.ifExists` configuration variables
and applies to all '--trailer' options until the next occurrence of and applies to all '--trailer' options until the next occurrence of
'--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`, '--if-exists' or '--no-if-exists'. Upon encountering '--no-if-exists, clear the
effect of any previous use of '--if-exists, such that the relevant configuration
variables are no longer overridden. Possible actions are `addIfDifferent`,
`addIfDifferentNeighbor`, `add`, `replace` and `doNothing`. `addIfDifferentNeighbor`, `add`, `replace` and `doNothing`.


--if-missing <action>:: --if-missing <action>::
--no-if-missing:: --no-if-missing::
Specify what action will be performed when there is no other Specify what action will be performed when there is no other
trailer with the same <token> in the input. A setting trailer with the same <key> in the input. A setting
provided with '--if-missing' overrides all configuration variables provided with '--if-missing' overrides the `trailer.ifMissing` and any
applicable `trailer.<keyAlias>.ifMissing` configuration variables
and applies to all '--trailer' options until the next occurrence of and applies to all '--trailer' options until the next occurrence of
'--if-missing' or '--no-if-missing'. Possible actions are `doNothing` '--if-missing' or '--no-if-missing'. Upon encountering '--no-if-missing,
clear the effect of any previous use of '--if-missing, such that the relevant
configuration variables are no longer overridden. Possible actions are `doNothing`
or `add`. or `add`.


--only-trailers:: --only-trailers::
@ -140,16 +164,19 @@ OPTIONS


--only-input:: --only-input::
Output only trailers that exist in the input; do not add any Output only trailers that exist in the input; do not add any
from the command-line or by following configured `trailer.*` from the command-line or by applying `trailer.*` configuration
rules. variables.


--unfold:: --unfold::
Remove any whitespace-continuation in trailers, so that each If a trailer has a value that runs over multiple lines (aka "folded"),
trailer appears on a line by itself with its full content. reformat the value into a single line.


--parse:: --parse::
A convenience alias for `--only-trailers --only-input A convenience alias for `--only-trailers --only-input
--unfold`. --unfold`. This makes it easier to only see the trailers coming from the
input without influencing them with any command line options or
configuration variables, while also making the output machine-friendly with
--unfold.


--no-divider:: --no-divider::
Do not treat `---` as the end of the commit message. Use this Do not treat `---` as the end of the commit message. Use this
@ -170,11 +197,11 @@ used when another separator is not specified in the config for this
trailer. trailer.
+ +
For example, if the value for this option is "%=$", then only lines For example, if the value for this option is "%=$", then only lines
using the format '<token><sep><value>' with <sep> containing '%', '=' using the format '<key><sep><value>' with <sep> containing '%', '='
or '$' and then spaces will be considered trailers. And '%' will be or '$' and then spaces will be considered trailers. And '%' will be
the default separator used, so by default trailers will appear like: the default separator used, so by default trailers will appear like:
'<token>% <value>' (one percent sign and one space will appear between '<key>% <value>' (one percent sign and one space will appear between
the token and the value). the key and the value).


trailer.where:: trailer.where::
This option tells where a new trailer will be added. This option tells where a new trailer will be added.
@ -188,41 +215,41 @@ If it is `start`, then each new trailer will appear at the start,
instead of the end, of the existing trailers. instead of the end, of the existing trailers.
+ +
If it is `after`, then each new trailer will appear just after the If it is `after`, then each new trailer will appear just after the
last trailer with the same <token>. last trailer with the same <key>.
+ +
If it is `before`, then each new trailer will appear just before the If it is `before`, then each new trailer will appear just before the
first trailer with the same <token>. first trailer with the same <key>.


trailer.ifexists:: trailer.ifexists::
This option makes it possible to choose what action will be This option makes it possible to choose what action will be
performed when there is already at least one trailer with the performed when there is already at least one trailer with the
same <token> in the input. same <key> in the input.
+ +
The valid values for this option are: `addIfDifferentNeighbor` (this The valid values for this option are: `addIfDifferentNeighbor` (this
is the default), `addIfDifferent`, `add`, `replace` or `doNothing`. is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
+ +
With `addIfDifferentNeighbor`, a new trailer will be added only if no With `addIfDifferentNeighbor`, a new trailer will be added only if no
trailer with the same (<token>, <value>) pair is above or below the line trailer with the same (<key>, <value>) pair is above or below the line
where the new trailer will be added. where the new trailer will be added.
+ +
With `addIfDifferent`, a new trailer will be added only if no trailer With `addIfDifferent`, a new trailer will be added only if no trailer
with the same (<token>, <value>) pair is already in the input. with the same (<key>, <value>) pair is already in the input.
+ +
With `add`, a new trailer will be added, even if some trailers with With `add`, a new trailer will be added, even if some trailers with
the same (<token>, <value>) pair are already in the input. the same (<key>, <value>) pair are already in the input.
+ +
With `replace`, an existing trailer with the same <token> will be With `replace`, an existing trailer with the same <key> will be
deleted and the new trailer will be added. The deleted trailer will be deleted and the new trailer will be added. The deleted trailer will be
the closest one (with the same <token>) to the place where the new one the closest one (with the same <key>) to the place where the new one
will be added. will be added.
+ +
With `doNothing`, nothing will be done; that is no new trailer will be With `doNothing`, nothing will be done; that is no new trailer will be
added if there is already one with the same <token> in the input. added if there is already one with the same <key> in the input.


trailer.ifmissing:: trailer.ifmissing::
This option makes it possible to choose what action will be This option makes it possible to choose what action will be
performed when there is not yet any trailer with the same performed when there is not yet any trailer with the same
<token> in the input. <key> in the input.
+ +
The valid values for this option are: `add` (this is the default) and The valid values for this option are: `add` (this is the default) and
`doNothing`. `doNothing`.
@ -231,34 +258,40 @@ With `add`, a new trailer will be added.
+ +
With `doNothing`, nothing will be done. With `doNothing`, nothing will be done.


trailer.<token>.key:: trailer.<keyAlias>.key::
This `key` will be used instead of <token> in the trailer. At Defines a <keyAlias> for the <key>. The <keyAlias> must be a
the end of this key, a separator can appear and then some prefix (case does not matter) of the <key>. For example, in `git
space characters. By default the only valid separator is ':', config trailer.ack.key "Acked-by"` the "Acked-by" is the <key> and
but this can be changed using the `trailer.separators` config the "ack" is the <keyAlias>. This configuration allows the shorter
variable. `--trailer "ack:..."` invocation on the command line using the "ack"
<keyAlias> instead of the longer `--trailer "Acked-by:..."`.
+ +
If there is a separator, then the key will be used instead of both the At the end of the <key>, a separator can appear and then some
<token> and the default separator when adding the trailer. space characters. By default the only valid separator is ':',
but this can be changed using the `trailer.separators` config
variable.
+
If there is a separator in the key, then it overrides the default
separator when adding the trailer.


trailer.<token>.where:: trailer.<keyAlias>.where::
This option takes the same values as the 'trailer.where' This option takes the same values as the 'trailer.where'
configuration variable and it overrides what is specified by configuration variable and it overrides what is specified by
that option for trailers with the specified <token>. that option for trailers with the specified <keyAlias>.


trailer.<token>.ifexists:: trailer.<keyAlias>.ifexists::
This option takes the same values as the 'trailer.ifexists' This option takes the same values as the 'trailer.ifexists'
configuration variable and it overrides what is specified by configuration variable and it overrides what is specified by
that option for trailers with the specified <token>. that option for trailers with the specified <keyAlias>.


trailer.<token>.ifmissing:: trailer.<keyAlias>.ifmissing::
This option takes the same values as the 'trailer.ifmissing' This option takes the same values as the 'trailer.ifmissing'
configuration variable and it overrides what is specified by configuration variable and it overrides what is specified by
that option for trailers with the specified <token>. that option for trailers with the specified <keyAlias>.


trailer.<token>.command:: trailer.<keyAlias>.command::
Deprecated in favor of 'trailer.<token>.cmd'. Deprecated in favor of 'trailer.<keyAlias>.cmd'.
This option behaves in the same way as 'trailer.<token>.cmd', except This option behaves in the same way as 'trailer.<keyAlias>.cmd', except
that it doesn't pass anything as argument to the specified command. that it doesn't pass anything as argument to the specified command.
Instead the first occurrence of substring $ARG is replaced by the Instead the first occurrence of substring $ARG is replaced by the
<value> that would be passed as argument. <value> that would be passed as argument.
@ -266,29 +299,29 @@ trailer.<token>.command::
Note that $ARG in the user's command is Note that $ARG in the user's command is
only replaced once and that the original way of replacing $ARG is not safe. only replaced once and that the original way of replacing $ARG is not safe.
+ +
When both 'trailer.<token>.cmd' and 'trailer.<token>.command' are given When both 'trailer.<keyAlias>.cmd' and 'trailer.<keyAlias>.command' are given
for the same <token>, 'trailer.<token>.cmd' is used and for the same <keyAlias>, 'trailer.<keyAlias>.cmd' is used and
'trailer.<token>.command' is ignored. 'trailer.<keyAlias>.command' is ignored.


trailer.<token>.cmd:: trailer.<keyAlias>.cmd::
This option can be used to specify a shell command that will be called 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 once to automatically add a trailer with the specified <keyAlias>, and then
called each time a '--trailer <token>=<value>' argument is specified to called each time a '--trailer <keyAlias>=<value>' argument is specified to
modify the <value> of the trailer that this option would produce. modify the <value> of the trailer that this option would produce.
+ +
When the specified command is first called to add a trailer When the specified command is first called to add a trailer
with the specified <token>, the behavior is as if a special with the specified <keyAlias>, the behavior is as if a special
'--trailer <token>=<value>' argument was added at the beginning '--trailer <keyAlias>=<value>' argument was added at the beginning
of the "git interpret-trailers" command, where <value> of the "git interpret-trailers" command, where <value>
is taken to be the standard output of the command with any is taken to be the standard output of the command with any
leading and trailing whitespace trimmed off. leading and trailing whitespace trimmed off.
+ +
If some '--trailer <token>=<value>' arguments are also passed If some '--trailer <keyAlias>=<value>' arguments are also passed
on the command line, the command is called again once for each 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 with the same <keyAlias>. And the <value> part
of these arguments, if any, will be passed to the command as its of these arguments, if any, will be passed to the command as its
first argument. This way the command can produce a <value> computed first argument. This way the command can produce a <value> computed
from the <value> passed in the '--trailer <token>=<value>' argument. from the <value> passed in the '--trailer <keyAlias>=<value>' argument.


EXAMPLES EXAMPLES
-------- --------

View File

@ -14,7 +14,7 @@


static const char * const git_interpret_trailers_usage[] = { static const char * const git_interpret_trailers_usage[] = {
N_("git interpret-trailers [--in-place] [--trim-empty]\n" N_("git interpret-trailers [--in-place] [--trim-empty]\n"
" [(--trailer <token>[(=|:)<value>])...]\n" " [(--trailer (<key>|<keyAlias>)[(=|:)<value>])...]\n"
" [--parse] [<file>...]"), " [--parse] [<file>...]"),
NULL NULL
}; };
@ -100,7 +100,7 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")), OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")), OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),


OPT_CALLBACK(0, "where", &where, N_("action"), OPT_CALLBACK(0, "where", &where, N_("placement"),
N_("where to place the new trailer"), option_parse_where), N_("where to place the new trailer"), option_parse_where),
OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"), OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
N_("action if trailer already exists"), option_parse_if_exists), N_("action if trailer already exists"), option_parse_if_exists),
@ -108,11 +108,11 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
N_("action if trailer is missing"), option_parse_if_missing), N_("action if trailer is missing"), option_parse_if_missing),


OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")), OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply config rules")), OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
OPT_BOOL(0, "unfold", &opts.unfold, N_("join whitespace-continued values")), OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("set parsing options"), OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse), PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat --- specially")), OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"), OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
N_("trailer(s) to add"), option_parse_trailer), N_("trailer(s) to add"), option_parse_trailer),
OPT_END() OPT_END()

View File

@ -489,7 +489,7 @@ test_expect_success 'multiline field treated as atomic for neighbor check' '
' '


test_expect_success 'with config setup' ' test_expect_success 'with config setup' '
git config trailer.ack.key "Acked-by: " && test_config trailer.ack.key "Acked-by: " &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&


Acked-by: Peff Acked-by: Peff
@ -503,8 +503,8 @@ test_expect_success 'with config setup' '
' '


test_expect_success 'with config setup and ":=" as separators' ' test_expect_success 'with config setup and ":=" as separators' '
git config trailer.separators ":=" && test_config trailer.separators ":=" &&
git config trailer.ack.key "Acked-by= " && test_config trailer.ack.key "Acked-by= " &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&


Acked-by= Peff Acked-by= Peff
@ -518,7 +518,7 @@ test_expect_success 'with config setup and ":=" as separators' '
' '


test_expect_success 'with config setup and "%" as separators' ' test_expect_success 'with config setup and "%" as separators' '
git config trailer.separators "%" && test_config trailer.separators "%" &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&


bug% 42 bug% 42
@ -532,6 +532,7 @@ test_expect_success 'with config setup and "%" as separators' '
' '


test_expect_success 'with "%" as separators and a message with trailers' ' test_expect_success 'with "%" as separators and a message with trailers' '
test_config trailer.separators "%" &&
cat >special_message <<-\EOF && cat >special_message <<-\EOF &&
Special Message Special Message


@ -553,8 +554,8 @@ test_expect_success 'with "%" as separators and a message with trailers' '
' '


test_expect_success 'with config setup and ":=#" as separators' ' test_expect_success 'with config setup and ":=#" as separators' '
git config trailer.separators ":=#" && test_config trailer.separators ":=#" &&
git config trailer.bug.key "Bug #" && test_config trailer.bug.key "Bug #" &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&


Bug #42 Bug #42
@ -581,6 +582,8 @@ test_expect_success 'with basic patch' '
' '


test_expect_success 'with commit complex message as argument' ' test_expect_success 'with commit complex message as argument' '
test_config trailer.separators ":=" &&
test_config trailer.ack.key "Acked-by= " &&
cat complex_message_body complex_message_trailers >complex_message && cat complex_message_body complex_message_trailers >complex_message &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
@ -594,6 +597,8 @@ test_expect_success 'with commit complex message as argument' '
' '


test_expect_success 'with 2 files arguments' ' test_expect_success 'with 2 files arguments' '
test_config trailer.separators ":=" &&
test_config trailer.ack.key "Acked-by= " &&
cat basic_message >>expected && cat basic_message >>expected &&
echo >>expected && echo >>expected &&
cat basic_patch >>expected && cat basic_patch >>expected &&
@ -677,6 +682,9 @@ test_expect_success 'with message that has an old style conflict block' '
' '


test_expect_success 'with commit complex message and trailer args' ' test_expect_success 'with commit complex message and trailer args' '
test_config trailer.separators ":=#" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.bug.key "Bug #" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -692,6 +700,9 @@ test_expect_success 'with commit complex message and trailer args' '
' '


test_expect_success 'with complex patch, args and --trim-empty' ' test_expect_success 'with complex patch, args and --trim-empty' '
test_config trailer.separators ":=#" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.bug.key "Bug #" &&
cat complex_message >complex_patch && cat complex_message >complex_patch &&
cat basic_patch >>complex_patch && cat basic_patch >>complex_patch &&
cat complex_message_body >expected && cat complex_message_body >expected &&
@ -746,7 +757,10 @@ test_expect_success POSIXPERM,SANITY "in-place editing doesn't clobber original
' '


test_expect_success 'using "where = before"' ' test_expect_success 'using "where = before"' '
git config trailer.bug.where "before" && test_config trailer.separators ":=#" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -762,7 +776,9 @@ test_expect_success 'using "where = before"' '
' '


test_expect_success 'overriding configuration with "--where after"' ' test_expect_success 'overriding configuration with "--where after"' '
git config trailer.ack.where "before" && test_config trailer.separators ":=" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "before" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -776,7 +792,12 @@ test_expect_success 'overriding configuration with "--where after"' '
test_cmp expected actual test_cmp expected actual
' '


test_expect_success 'using "where = before" with "--no-where"' ' test_expect_success 'using "--where after" with "--no-where"' '
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "before" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -791,8 +812,59 @@ test_expect_success 'using "where = before" with "--no-where"' '
test_cmp expected actual test_cmp expected actual
' '


# Check whether using "--no-where" clears out only the "--where after", such
# that we still use the configuration in trailer.where (which is different from
# the hardcoded default (in WHERE_END) assuming the absence of .gitconfig).
# Here, the "start" setting of trailer.where is respected, so the new "Acked-by"
# and "Bug" trailers are placed at the beginning, and not at the end which is
# the harcoded default.
test_expect_success 'using "--where after" with "--no-where" defaults to configuration' '
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.separators ":=#" &&
test_config trailer.where "start" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42
Acked-by= Peff
Fixes: Z
Acked-by= Z
Reviewed-by: Z
Signed-off-by: Z
EOF
git interpret-trailers --where after --no-where --trailer "ack: Peff" \
--trailer "bug: 42" complex_message >actual &&
test_cmp expected actual
'

# The "--where after" will only get respected for the trailer that came
# immediately after it. For the next trailer (Bug #42), we default to using the
# hardcoded WHERE_END because we don't have any "trailer.where" or
# "trailer.bug.where" configured.
test_expect_success 'using "--no-where" defaults to harcoded default if nothing configured' '
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
Acked-by= Z
Acked-by= Peff
Reviewed-by: Z
Signed-off-by: Z
Bug #42
EOF
git interpret-trailers --where after --trailer "ack: Peff" --no-where \
--trailer "bug: 42" complex_message >actual &&
test_cmp expected actual
'

test_expect_success 'using "where = after"' ' test_expect_success 'using "where = after"' '
git config trailer.ack.where "after" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -808,8 +880,11 @@ test_expect_success 'using "where = after"' '
' '


test_expect_success 'using "where = end"' ' test_expect_success 'using "where = end"' '
git config trailer.review.key "Reviewed-by" && test_config trailer.review.key "Reviewed-by" &&
git config trailer.review.where "end" && test_config trailer.review.where "end" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -827,8 +902,11 @@ test_expect_success 'using "where = end"' '
' '


test_expect_success 'using "where = start"' ' test_expect_success 'using "where = start"' '
git config trailer.review.key "Reviewed-by" && test_config trailer.review.key "Reviewed-by" &&
git config trailer.review.where "start" && test_config trailer.review.where "start" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Reviewed-by: Johannes Reviewed-by: Johannes
@ -846,8 +924,13 @@ test_expect_success 'using "where = start"' '
' '


test_expect_success 'using "where = before" for a token in the middle of the message' ' test_expect_success 'using "where = before" for a token in the middle of the message' '
git config trailer.review.key "Reviewed-by:" && test_config trailer.review.key "Reviewed-by:" &&
git config trailer.review.where "before" && test_config trailer.review.where "before" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -864,6 +947,12 @@ test_expect_success 'using "where = before" for a token in the middle of the mes
' '


test_expect_success 'using "where = before" and --trim-empty' ' test_expect_success 'using "where = before" and --trim-empty' '
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
cat >>expected <<-\EOF && cat >>expected <<-\EOF &&
Bug #46 Bug #46
@ -878,6 +967,13 @@ test_expect_success 'using "where = before" and --trim-empty' '
' '


test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' ' test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' '
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.review.where "before" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -896,7 +992,13 @@ test_expect_success 'the default is "ifExists = addIfDifferentNeighbor"' '
' '


test_expect_success 'default "ifExists" is now "addIfDifferent"' ' test_expect_success 'default "ifExists" is now "addIfDifferent"' '
git config trailer.ifexists "addIfDifferent" && test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -914,8 +1016,14 @@ test_expect_success 'default "ifExists" is now "addIfDifferent"' '
' '


test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' ' test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' '
git config trailer.ack.ifExists "addIfDifferent" && test_config trailer.ack.ifExists "addIfDifferent" &&
git config trailer.ack.where "end" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "end" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -932,8 +1040,14 @@ test_expect_success 'using "ifExists = addIfDifferent" with "where = end"' '
' '


test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' ' test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' '
git config trailer.ack.ifExists "addIfDifferent" && test_config trailer.ack.ifExists "addIfDifferent" &&
git config trailer.ack.where "before" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "before" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -950,8 +1064,14 @@ test_expect_success 'using "ifExists = addIfDifferent" with "where = before"' '
' '


test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end"' ' test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end"' '
git config trailer.ack.ifExists "addIfDifferentNeighbor" && test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
git config trailer.ack.where "end" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "end" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -973,8 +1093,14 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = end
' '


test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = after"' ' test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = after"' '
git config trailer.ack.ifExists "addIfDifferentNeighbor" && test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
git config trailer.ack.where "after" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -995,7 +1121,11 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" with "where = af
' '


test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty' ' test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty' '
git config trailer.ack.ifExists "addIfDifferentNeighbor" && test_config trailer.ack.ifExists "addIfDifferentNeighbor" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
cat >>expected <<-\EOF && cat >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1011,8 +1141,14 @@ test_expect_success 'using "ifExists = addIfDifferentNeighbor" and --trim-empty'
' '


test_expect_success 'using "ifExists = add" with "where = end"' ' test_expect_success 'using "ifExists = add" with "where = end"' '
git config trailer.ack.ifExists "add" && test_config trailer.ack.ifExists "add" &&
git config trailer.ack.where "end" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "end" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1036,8 +1172,14 @@ test_expect_success 'using "ifExists = add" with "where = end"' '
' '


test_expect_success 'using "ifExists = add" with "where = after"' ' test_expect_success 'using "ifExists = add" with "where = after"' '
git config trailer.ack.ifExists "add" && test_config trailer.ack.ifExists "add" &&
git config trailer.ack.where "after" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1058,8 +1200,15 @@ test_expect_success 'using "ifExists = add" with "where = after"' '
' '


test_expect_success 'overriding configuration with "--if-exists replace"' ' test_expect_success 'overriding configuration with "--if-exists replace"' '
git config trailer.fix.key "Fixes: " && test_config trailer.fix.key "Fixes: " &&
git config trailer.fix.ifExists "add" && test_config trailer.fix.ifExists "add" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.review.where "before" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1074,9 +1223,66 @@ test_expect_success 'overriding configuration with "--if-exists replace"' '
test_cmp expected actual test_cmp expected actual
' '


# "trailer.ifexists" is set to "doNothing", so using "--no-if-exists" defaults
# to this "doNothing" behavior. So the "Fixes: 53" trailer does not get added.
test_expect_success 'using "--if-exists replace" with "--no-if-exists" defaults to configuration' '
test_config trailer.ifexists "doNothing" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
Acked-by: Z
Reviewed-by: Z
Signed-off-by: Z
EOF
git interpret-trailers --if-exists replace --no-if-exists --trailer "Fixes: 53" \
<complex_message >actual &&
test_cmp expected actual
'

# No "ifexists" configuration is set, so using "--no-if-exists" makes it default
# to addIfDifferentNeighbor. Because we do have a different neighbor "Fixes: 53"
# (because it got added by overriding with "--if-exists replace" earlier in the
# arguments list), we add "Signed-off-by: addme".
test_expect_success 'using "--no-if-exists" defaults to hardcoded default if nothing configured' '
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Acked-by: Z
Reviewed-by: Z
Signed-off-by: Z
Fixes: 53
Signed-off-by: addme
EOF
git interpret-trailers --if-exists replace --trailer "Fixes: 53" --no-if-exists \
--trailer "Signed-off-by: addme" <complex_message >actual &&
test_cmp expected actual
'

# The second "Fixes: 53" trailer is discarded, because the "--no-if-exists" here
# makes us default to addIfDifferentNeighbor, and we already added the "Fixes:
# 53" trailer earlier in the argument list.
test_expect_success 'using "--no-if-exists" defaults to hardcoded default if nothing configured (no addition)' '
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Acked-by: Z
Reviewed-by: Z
Signed-off-by: Z
Fixes: 53
EOF
git interpret-trailers --if-exists replace --trailer "Fixes: 53" --no-if-exists \
--trailer "Fixes: 53" <complex_message >actual &&
test_cmp expected actual
'

test_expect_success 'using "ifExists = replace"' ' test_expect_success 'using "ifExists = replace"' '
git config trailer.fix.key "Fixes: " && test_config trailer.fix.key "Fixes: " &&
git config trailer.fix.ifExists "replace" && test_config trailer.fix.ifExists "replace" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1095,7 +1301,16 @@ test_expect_success 'using "ifExists = replace"' '
' '


test_expect_success 'using "ifExists = replace" with "where = after"' ' test_expect_success 'using "ifExists = replace" with "where = after"' '
git config trailer.fix.where "after" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.fix.ifExists "replace" &&
test_config trailer.fix.where "after" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1114,7 +1329,15 @@ test_expect_success 'using "ifExists = replace" with "where = after"' '
' '


test_expect_success 'using "ifExists = doNothing"' ' test_expect_success 'using "ifExists = doNothing"' '
git config trailer.fix.ifExists "doNothing" && test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1133,8 +1356,17 @@ test_expect_success 'using "ifExists = doNothing"' '
' '


test_expect_success 'the default is "ifMissing = add"' ' test_expect_success 'the default is "ifMissing = add"' '
git config trailer.cc.key "Cc: " && test_config trailer.ack.key "Acked-by= " &&
git config trailer.cc.where "before" && test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.cc.key "Cc: " &&
test_config trailer.cc.where "before" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1154,7 +1386,14 @@ test_expect_success 'the default is "ifMissing = add"' '
' '


test_expect_success 'overriding configuration with "--if-missing doNothing"' ' test_expect_success 'overriding configuration with "--if-missing doNothing"' '
git config trailer.ifmissing "add" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.ifmissing "add" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -1173,7 +1412,13 @@ test_expect_success 'overriding configuration with "--if-missing doNothing"' '
' '


test_expect_success 'when default "ifMissing" is "doNothing"' ' test_expect_success 'when default "ifMissing" is "doNothing"' '
git config trailer.ifmissing "doNothing" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.ifmissing "doNothing" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -1187,14 +1432,21 @@ test_expect_success 'when default "ifMissing" is "doNothing"' '
--trailer "cc=Linus" --trailer "ack: Junio" \ --trailer "cc=Linus" --trailer "ack: Junio" \
--trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \ --trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \
<complex_message >actual && <complex_message >actual &&
test_cmp expected actual && test_cmp expected actual
git config trailer.ifmissing "add"
' '


test_expect_success 'using "ifMissing = add" with "where = end"' ' test_expect_success 'using "ifMissing = add" with "where = end"' '
git config trailer.cc.key "Cc: " && test_config trailer.ack.key "Acked-by= " &&
git config trailer.cc.where "end" && test_config trailer.ack.where "after" &&
git config trailer.cc.ifMissing "add" && test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.cc.key "Cc: " &&
test_config trailer.cc.ifMissing "add" &&
test_config trailer.cc.where "end" &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1214,9 +1466,17 @@ test_expect_success 'using "ifMissing = add" with "where = end"' '
' '


test_expect_success 'using "ifMissing = add" with "where = before"' ' test_expect_success 'using "ifMissing = add" with "where = before"' '
git config trailer.cc.key "Cc: " && test_config trailer.ack.key "Acked-by= " &&
git config trailer.cc.where "before" && test_config trailer.ack.where "after" &&
git config trailer.cc.ifMissing "add" && test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.cc.key "Cc: " &&
test_config trailer.cc.ifMissing "add" &&
test_config trailer.cc.where "before" &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Cc: Linus Cc: Linus
@ -1236,7 +1496,15 @@ test_expect_success 'using "ifMissing = add" with "where = before"' '
' '


test_expect_success 'using "ifMissing = doNothing"' ' test_expect_success 'using "ifMissing = doNothing"' '
git config trailer.cc.ifMissing "doNothing" && test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.cc.ifMissing "doNothing" &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1254,9 +1522,50 @@ test_expect_success 'using "ifMissing = doNothing"' '
test_cmp expected actual test_cmp expected actual
' '


# Ignore the "IgnoredTrailer" because of "--if-missing doNothing", but also
# ignore the "StillIgnoredTrailer" because we set "trailer.ifMissing" to
# "doNothing" in configuration.
test_expect_success 'using "--no-if-missing" defaults to configuration' '
test_config trailer.ifMissing "doNothing" &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
Acked-by: Z
Reviewed-by: Z
Signed-off-by: Z
EOF
git interpret-trailers --if-missing doNothing --trailer "IgnoredTrailer: ignoreme" --no-if-missing \
--trailer "StillIgnoredTrailer: ignoreme" <complex_message >actual &&
test_cmp expected actual
'

# Add the "AddedTrailer" because the "--no-if-missing" clears the "--if-missing
# doNothing" from earlier in the argument list.
test_expect_success 'using "--no-if-missing" defaults to hardcoded default if nothing configured' '
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z
Acked-by: Z
Reviewed-by: Z
Signed-off-by: Z
AddedTrailer: addme
EOF
git interpret-trailers --if-missing doNothing --trailer "IgnoredTrailer: ignoreme" --no-if-missing \
--trailer "AddedTrailer: addme" <complex_message >actual &&
test_cmp expected actual
'

test_expect_success 'default "where" is now "after"' ' test_expect_success 'default "where" is now "after"' '
git config trailer.where "after" && git config trailer.where "after" &&
git config --unset trailer.ack.where && test_config trailer.ack.ifExists "add" &&
test_config trailer.ack.key "Acked-by= " &&
test_config trailer.ack.where "after" &&
test_config trailer.bug.key "Bug #" &&
test_config trailer.bug.where "before" &&
test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=#" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Bug #42 Bug #42
@ -1280,10 +1589,15 @@ test_expect_success 'default "where" is now "after"' '
' '


test_expect_success 'with simple command' ' test_expect_success 'with simple command' '
git config trailer.sign.key "Signed-off-by: " && test_config trailer.ack.key "Acked-by= " &&
git config trailer.sign.where "after" && test_config trailer.fix.ifExists "doNothing" &&
git config trailer.sign.ifExists "addIfDifferentNeighbor" && test_config trailer.review.key "Reviewed-by:" &&
git config trailer.sign.command "echo \"A U Thor <author@example.com>\"" && test_config trailer.sign.command "echo \"A U Thor <author@example.com>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.sign.ifExists "addIfDifferentNeighbor" &&
test_config trailer.sign.where "after" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -1298,8 +1612,14 @@ test_expect_success 'with simple command' '
' '


test_expect_success 'with command using committer information' ' test_expect_success 'with command using committer information' '
git config trailer.sign.ifExists "addIfDifferent" && test_config trailer.ack.key "Acked-by= " &&
git config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" && test_config trailer.fix.ifExists "doNothing" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.sign.command "echo \"\$GIT_COMMITTER_NAME <\$GIT_COMMITTER_EMAIL>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.sign.ifExists "addIfDifferent" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -1314,10 +1634,15 @@ test_expect_success 'with command using committer information' '
' '


test_expect_success 'with command using author information' ' test_expect_success 'with command using author information' '
git config trailer.sign.key "Signed-off-by: " && test_config trailer.ack.key "Acked-by= " &&
git config trailer.sign.where "after" && test_config trailer.fix.ifExists "doNothing" &&
git config trailer.sign.ifExists "addIfDifferentNeighbor" && test_config trailer.review.key "Reviewed-by:" &&
git config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" && test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.sign.ifExists "addIfDifferentNeighbor" &&
test_config trailer.sign.where "after" &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-\EOF && sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
Fixes: Z Fixes: Z
@ -1338,12 +1663,19 @@ test_expect_success 'setup a commit' '
' '


test_expect_success 'cmd takes precedence over command' ' test_expect_success 'cmd takes precedence over command' '
test_when_finished "git config --unset trailer.fix.cmd" && test_config trailer.ack.key "Acked-by= " &&
git config trailer.fix.ifExists "replace" && test_config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
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" && --abbrev-commit --abbrev=14 \$ARG" &&
test_config trailer.fix.cmd "test -n \"\$1\" && git log -1 --oneline --format=\"%h (%aN)\" \
--abbrev-commit --abbrev=14 \"\$1\" || true" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.fix.ifExists "replace" &&
test_config trailer.fix.where "after" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=" &&
FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) && FIXED=$(git log -1 --oneline --format="%h (%aN)" --abbrev-commit --abbrev=14 HEAD) &&
cat complex_message_body >expected2 && cat complex_message_body >expected2 &&
sed -e "s/ Z\$/ /" >>expected2 <<-EOF && sed -e "s/ Z\$/ /" >>expected2 <<-EOF &&
@ -1359,8 +1691,16 @@ test_expect_success 'cmd takes precedence over command' '
' '


test_expect_success 'with command using $ARG' ' test_expect_success 'with command using $ARG' '
git config trailer.fix.ifExists "replace" && test_config trailer.ack.key "Acked-by= " &&
git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" && test_config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" --abbrev-commit --abbrev=14 \$ARG" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.fix.ifExists "replace" &&
test_config trailer.fix.where "after" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=" &&
FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) && FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-EOF && sed -e "s/ Z\$/ /" >>expected <<-EOF &&
@ -1376,8 +1716,16 @@ test_expect_success 'with command using $ARG' '
' '


test_expect_success 'with failing command using $ARG' ' test_expect_success 'with failing command using $ARG' '
git config trailer.fix.ifExists "replace" && test_config trailer.ack.key "Acked-by= " &&
git config trailer.fix.command "false \$ARG" && test_config trailer.fix.command "false \$ARG" &&
test_config trailer.fix.key "Fixes: " &&
test_config trailer.fix.ifExists "replace" &&
test_config trailer.fix.where "after" &&
test_config trailer.review.key "Reviewed-by:" &&
test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.ifexists "addIfDifferent" &&
test_config trailer.separators ":=" &&
cat complex_message_body >expected && cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-EOF && sed -e "s/ Z\$/ /" >>expected <<-EOF &&
Fixes: Z Fixes: Z
@ -1392,7 +1740,9 @@ test_expect_success 'with failing command using $ARG' '
' '


test_expect_success 'with empty tokens' ' test_expect_success 'with empty tokens' '
git config --unset trailer.fix.command && test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.sign.key "Signed-off-by: " &&
test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-EOF && cat >expected <<-EOF &&


Signed-off-by: A U Thor <author@example.com> Signed-off-by: A U Thor <author@example.com>
@ -1403,7 +1753,8 @@ test_expect_success 'with empty tokens' '
' '


test_expect_success 'with command but no key' ' test_expect_success 'with command but no key' '
git config --unset trailer.sign.key && test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-EOF && cat >expected <<-EOF &&


sign: A U Thor <author@example.com> sign: A U Thor <author@example.com>
@ -1414,7 +1765,9 @@ test_expect_success 'with command but no key' '
' '


test_expect_success 'with no command and no key' ' test_expect_success 'with no command and no key' '
git config --unset trailer.review.key && test_config trailer.review.where "before" &&
test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-EOF && cat >expected <<-EOF &&


review: Junio review: Junio
@ -1426,6 +1779,8 @@ test_expect_success 'with no command and no key' '
' '


test_expect_success 'with cut line' ' test_expect_success 'with cut line' '
test_config trailer.review.where "before" &&
test_config trailer.sign.command "echo \"\$GIT_AUTHOR_NAME <\$GIT_AUTHOR_EMAIL>\"" &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&
my subject my subject


@ -1443,7 +1798,8 @@ test_expect_success 'with cut line' '
' '


test_expect_success 'only trailers' ' test_expect_success 'only trailers' '
git config trailer.sign.command "echo config-value" && test_config trailer.sign.command "echo config-value" &&
test_config trailer.ifexists "addIfDifferent" &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&
existing: existing-value existing: existing-value
sign: config-value sign: config-value
@ -1462,7 +1818,7 @@ test_expect_success 'only trailers' '
' '


test_expect_success 'only-trailers omits non-trailer in middle of block' ' test_expect_success 'only-trailers omits non-trailer in middle of block' '
git config trailer.sign.command "echo config-value" && test_config trailer.sign.command "echo config-value" &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&
Signed-off-by: nobody <nobody@nowhere> Signed-off-by: nobody <nobody@nowhere>
Signed-off-by: somebody <somebody@somewhere> Signed-off-by: somebody <somebody@somewhere>
@ -1482,7 +1838,7 @@ test_expect_success 'only-trailers omits non-trailer in middle of block' '
' '


test_expect_success 'only input' ' test_expect_success 'only input' '
git config trailer.sign.command "echo config-value" && test_config trailer.sign.command "echo config-value" &&
cat >expected <<-\EOF && cat >expected <<-\EOF &&
existing: existing-value existing: existing-value
EOF EOF