interpret-trailers: add options for actions
Allow using non-default values for trailers without having to set them up in .gitconfig first. For example, if you have the following configuration trailer.signed-off-by.where = end you may use "--where before" when a patch author forgets his Signed-off-by and provides it in a separate email. Likewise for --if-exists and --if-missing Reverting to the behavior specified by .gitconfig is done with --no-where, --no-if-exists and --no-if-missing. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Paolo Bonzini committed
Aug 1, 2017 at 11:03 UTC
0ea5292e6be2f37b647b744177cfe6cc5e6f605d
5 files changed
+156
-6
Documentation/git-interpret-trailers.txt
+23
@@ -80,6 +80,29 @@ OPTIONS
80
trailer to the input messages. See the description of this
81
command.
82
83
+--where <placement>::
84
+--no-where::
85
+ Specify where all new trailers will be added. A setting
86
+ provided with '--where' overrides all configuration variables
87
+ and applies to all '--trailer' options until the next occurrence of
88
+ '--where' or '--no-where'.
89
+
90
+--if-exists <action>::
91
+--no-if-exists::
92
+ Specify what action will be performed when there is already at
93
+ least one trailer with the same <token> in the message. A setting
94
+ provided with '--if-exists' overrides all configuration variables
95
+ and applies to all '--trailer' options until the next occurrence of
96
+ '--if-exists' or '--no-if-exists'.
97
+
98
+--if-missing <action>::
99
+--no-if-missing::
100
+ Specify what action will be performed when there is no other
101
+ trailer with the same <token> in the message. A setting
102
+ provided with '--if-missing' overrides all configuration variables
103
+ and applies to all '--trailer' options until the next occurrence of
104
+ '--if-missing' or '--no-if-missing'.
105
+
106
CONFIGURATION VARIABLES
107
-----------------------
108
builtin/interpret-trailers.c
+32
@@ -16,6 +16,28 @@ static const char * const git_interpret_trailers_usage[] = {
16
NULL
17
};
18
19
+static enum trailer_where where;
20
+static enum trailer_if_exists if_exists;
21
+static enum trailer_if_missing if_missing;
22
+
23
+static int option_parse_where(const struct option *opt,
24
+ const char *arg, int unset)
25
+{
26
+ return trailer_set_where(&where, arg);
27
+}
28
+
29
+static int option_parse_if_exists(const struct option *opt,
30
+ const char *arg, int unset)
31
+{
32
+ return trailer_set_if_exists(&if_exists, arg);
33
+}
34
+
35
+static int option_parse_if_missing(const struct option *opt,
36
+ const char *arg, int unset)
37
+{
38
+ return trailer_set_if_missing(&if_missing, arg);
39
+}
40
+
41
static void new_trailers_clear(struct list_head *trailers)
42
{
43
struct list_head *pos, *tmp;
@@ -44,6 +66,9 @@ static int option_parse_trailer(const struct option *opt,
66
67
item = xmalloc(sizeof(*item));
68
item->text = arg;
69
+ item->where = where;
70
+ item->if_exists = if_exists;
71
+ item->if_missing = if_missing;
72
list_add_tail(&item->list, trailers);
73
return 0;
74
}
@@ -58,6 +83,13 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
83
OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
84
OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")),
85
86
+ OPT_CALLBACK(0, "where", NULL, N_("action"),
87
+ N_("where to place the new trailer"), option_parse_where),
88
+ OPT_CALLBACK(0, "if-exists", NULL, N_("action"),
89
+ N_("action if trailer already exists"), option_parse_if_exists),
90
+ OPT_CALLBACK(0, "if-missing", NULL, N_("action"),
91
+ N_("action if trailer is missing"), option_parse_if_missing),
92
+
93
OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
94
N_("trailer(s) to add"), option_parse_trailer),
95
OPT_END()
t/t7513-interpret-trailers.sh
+66
@@ -681,6 +681,36 @@ test_expect_success 'using "where = before"' '
681
test_cmp expected actual
682
'
683
684
+test_expect_success 'overriding configuration with "--where after"' '
685
+ git config trailer.ack.where "before" &&
686
+ cat complex_message_body >expected &&
687
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
688
+ Fixes: Z
689
+ Acked-by= Z
690
+ Acked-by= Peff
691
+ Reviewed-by: Z
692
+ Signed-off-by: Z
693
+ EOF
694
+ git interpret-trailers --where after --trailer "ack: Peff" \
695
+ complex_message >actual &&
696
+ test_cmp expected actual
697
+'
698
+
699
+test_expect_success 'using "where = before" with "--no-where"' '
700
+ cat complex_message_body >expected &&
701
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
702
+ Bug #42
703
+ Fixes: Z
704
+ Acked-by= Peff
705
+ Acked-by= Z
706
+ Reviewed-by: Z
707
+ Signed-off-by: Z
708
+ EOF
709
+ git interpret-trailers --where after --no-where --trailer "ack: Peff" \
710
+ --trailer "bug: 42" complex_message >actual &&
711
+ test_cmp expected actual
712
+'
713
+
714
test_expect_success 'using "where = after"' '
715
git config trailer.ack.where "after" &&
716
cat complex_message_body >expected &&
@@ -947,6 +977,23 @@ test_expect_success 'using "ifExists = add" with "where = after"' '
977
test_cmp expected actual
978
'
979
980
+test_expect_success 'overriding configuration with "--if-exists replace"' '
981
+ git config trailer.fix.key "Fixes: " &&
982
+ git config trailer.fix.ifExists "add" &&
983
+ cat complex_message_body >expected &&
984
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
985
+ Bug #42
986
+ Acked-by= Z
987
+ Reviewed-by:
988
+ Signed-off-by: Z
989
+ Fixes: 22
990
+ EOF
991
+ git interpret-trailers --if-exists replace --trailer "review:" \
992
+ --trailer "fix=53" --trailer "fix=22" --trailer "bug: 42" \
993
+ <complex_message >actual &&
994
+ test_cmp expected actual
995
+'
996
+
997
test_expect_success 'using "ifExists = replace"' '
998
git config trailer.fix.key "Fixes: " &&
999
git config trailer.fix.ifExists "replace" &&
@@ -1026,6 +1073,25 @@ test_expect_success 'the default is "ifMissing = add"' '
1073
test_cmp expected actual
1074
'
1075
1076
+test_expect_success 'overriding configuration with "--if-missing doNothing"' '
1077
+ git config trailer.ifmissing "add" &&
1078
+ cat complex_message_body >expected &&
1079
+ sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
1080
+ Fixes: Z
1081
+ Acked-by= Z
1082
+ Acked-by= Junio
1083
+ Acked-by= Peff
1084
+ Reviewed-by:
1085
+ Signed-off-by: Z
1086
+ EOF
1087
+ git interpret-trailers --if-missing doNothing \
1088
+ --trailer "review:" --trailer "fix=53" \
1089
+ --trailer "cc=Linus" --trailer "ack: Junio" \
1090
+ --trailer "fix=22" --trailer "bug: 42" --trailer "ack: Peff" \
1091
+ <complex_message >actual &&
1092
+ test_cmp expected actual
1093
+'
1094
+
1095
test_expect_success 'when default "ifMissing" is "doNothing"' '
1096
git config trailer.ifmissing "doNothing" &&
1097
cat complex_message_body >expected &&
trailer.c
+28
-6
@@ -295,6 +295,9 @@ static void apply_arg_if_exists(struct trailer_item *in_tok,
295
else
296
free_arg_item(arg_tok);
297
break;
298
+ default:
299
+ die("BUG: trailer.c: unhandled value %d",
300
+ arg_tok->conf.if_exists);
301
}
302
}
303
@@ -316,6 +319,10 @@ static void apply_arg_if_missing(struct list_head *head,
319
list_add_tail(&to_add->list, head);
320
else
321
list_add(&to_add->list, head);
322
+ break;
323
+ default:
324
+ die("BUG: trailer.c: unhandled value %d",
325
+ arg_tok->conf.if_missing);
326
}
327
}
328
@@ -370,7 +377,9 @@ static void process_trailers_lists(struct list_head *head,
377
378
int trailer_set_where(enum trailer_where *item, const char *value)
379
{
373
- if (!strcasecmp("after", value))
380
+ if (!value)
381
+ *item = WHERE_DEFAULT;
382
+ else if (!strcasecmp("after", value))
383
*item = WHERE_AFTER;
384
else if (!strcasecmp("before", value))
385
*item = WHERE_BEFORE;
@@ -385,7 +394,9 @@ int trailer_set_where(enum trailer_where *item, const char *value)
394
395
int trailer_set_if_exists(enum trailer_if_exists *item, const char *value)
396
{
388
- if (!strcasecmp("addIfDifferent", value))
397
+ if (!value)
398
+ *item = EXISTS_DEFAULT;
399
+ else if (!strcasecmp("addIfDifferent", value))
400
*item = EXISTS_ADD_IF_DIFFERENT;
401
else if (!strcasecmp("addIfDifferentNeighbor", value))
402
*item = EXISTS_ADD_IF_DIFFERENT_NEIGHBOR;
@@ -402,7 +413,9 @@ int trailer_set_if_exists(enum trailer_if_exists *item, const char *value)
413
414
int trailer_set_if_missing(enum trailer_if_missing *item, const char *value)
415
{
405
- if (!strcasecmp("doNothing", value))
416
+ if (!value)
417
+ *item = MISSING_DEFAULT;
418
+ else if (!strcasecmp("doNothing", value))
419
*item = MISSING_DO_NOTHING;
420
else if (!strcasecmp("add", value))
421
*item = MISSING_ADD;
@@ -659,12 +672,21 @@ static struct trailer_item *add_trailer_item(struct list_head *head, char *tok,
672
}
673
674
static void add_arg_item(struct list_head *arg_head, char *tok, char *val,
662
- const struct conf_info *conf)
675
+ const struct conf_info *conf,
676
+ const struct new_trailer_item *new_trailer_item)
677
{
678
struct arg_item *new = xcalloc(sizeof(*new), 1);
679
new->token = tok;
680
new->value = val;
681
duplicate_conf(&new->conf, conf);
682
+ if (new_trailer_item) {
683
+ if (new_trailer_item->where != WHERE_DEFAULT)
684
+ new->conf.where = new_trailer_item->where;
685
+ if (new_trailer_item->if_exists != EXISTS_DEFAULT)
686
+ new->conf.if_exists = new_trailer_item->if_exists;
687
+ if (new_trailer_item->if_missing != MISSING_DEFAULT)
688
+ new->conf.if_missing = new_trailer_item->if_missing;
689
+ }
690
list_add_tail(&new->list, arg_head);
691
}
692
@@ -690,7 +712,7 @@ static void process_command_line_args(struct list_head *arg_head,
712
add_arg_item(arg_head,
713
xstrdup(token_from_item(item, NULL)),
714
xstrdup(""),
693
- &item->conf);
715
+ &item->conf, NULL);
716
}
717
718
/* Add an arg item for each trailer on the command line */
@@ -712,7 +734,7 @@ static void process_command_line_args(struct list_head *arg_head,
734
add_arg_item(arg_head,
735
strbuf_detach(&tok, NULL),
736
strbuf_detach(&val, NULL),
715
- conf);
737
+ conf, tr);
738
}
739
}
740
trailer.h
+7
@@ -4,12 +4,14 @@
4
#include "list.h"
5
6
enum trailer_where {
7
+ WHERE_DEFAULT,
8
WHERE_END,
9
WHERE_AFTER,
10
WHERE_BEFORE,
11
WHERE_START
12
};
13
enum trailer_if_exists {
14
+ EXISTS_DEFAULT,
15
EXISTS_ADD_IF_DIFFERENT_NEIGHBOR,
16
EXISTS_ADD_IF_DIFFERENT,
17
EXISTS_ADD,
@@ -17,6 +19,7 @@ enum trailer_if_exists {
19
EXISTS_DO_NOTHING
20
};
21
enum trailer_if_missing {
22
+ MISSING_DEFAULT,
23
MISSING_ADD,
24
MISSING_DO_NOTHING
25
};
@@ -54,6 +57,10 @@ struct new_trailer_item {
57
struct list_head list;
58
59
const char *text;
60
+
61
+ enum trailer_where where;
62
+ enum trailer_if_exists if_exists;
63
+ enum trailer_if_missing if_missing;
64
};
65
66
void process_trailers(const char *file, int in_place, int trim_empty,