Skip to content

Commit

Permalink
[GSOC]trailer: pass arg as positional parameter
Browse files Browse the repository at this point in the history
Original implementation of `trailer.<token>.command` use
`strbuf_replace` to replace $ARG in command with the <value>
of the trailer, but it have a problem: `strbuf_replace`
replace the $ARG only once, If the user's trailer command
have used more than one $ARG, the remaining replacement will
fail.

If directly modify the implementation of the original
`trailer.<token>.command`, The user’s previous `'$ARG'` in
trailer command will not be replaced. So now add new config
"trailer.<token>.cmd", pass trailer's value as positional
parameter 1 to the user's command, the user can use $1 as
trailer's value, to implement original variable replacement.

If the user has these two configuration: "trailer.<token>.cmd"
and "trailer.<token>.command", "cmd" will execute and "command"
will not executed.

Original `trailer.<token>.command` can still be used until git
completely abandoned it.

Signed-off-by: ZheNing Hu <adlternative@gmail.com>
  • Loading branch information
adlternative committed Mar 25, 2021
1 parent 1424303 commit b268ecd
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 12 deletions.
10 changes: 10 additions & 0 deletions Documentation/git-interpret-trailers.txt
Expand Up @@ -252,6 +252,16 @@ 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.

trailer.<token>.cmd::
Similar to 'trailer.<token>.command'. But the difference is that
`$1` is used in the command to replace the value of the trailer
instead of the original `$ARG`, which means that we can pass the
trailer value multiple times in the command.
E.g. `git config trailer.sign.cmd "test -n \"$1\" && echo \"$1\" || true "`.
If the user has these two configuration: "trailer.<token>.cmd"
and "trailer.<token>.command", "cmd" will be executed and "command"
will not be executed.

EXAMPLES
--------

Expand Down
43 changes: 42 additions & 1 deletion t/t7513-interpret-trailers.sh
Expand Up @@ -1274,9 +1274,50 @@ test_expect_success 'setup a commit' '
git commit -m "Add file a.txt"
'

test_expect_success 'with cmd and $1' '
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 (%s)\" \
--abbrev-commit --abbrev=14 \"\$1\" || true" &&
FIXED=$(git log -1 --oneline --format="%h (%s)" --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 '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" &&
git config trailer.fix.command "git log -1 --oneline --format=\"%h (%s)\" \
--abbrev-commit --abbrev=14 \$ARG" &&
FIXED=$(git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14 HEAD) &&
cat complex_message_body >expected &&
sed -e "s/ Z\$/ /" >>expected <<-EOF &&
Expand Down
37 changes: 26 additions & 11 deletions trailer.c
Expand Up @@ -14,6 +14,7 @@ struct conf_info {
char *name;
char *key;
char *command;
char *cmd;
enum trailer_where where;
enum trailer_if_exists if_exists;
enum trailer_if_missing if_missing;
Expand Down Expand Up @@ -127,6 +128,7 @@ static void free_arg_item(struct arg_item *item)
free(item->conf.name);
free(item->conf.key);
free(item->conf.command);
free(item->conf.cmd);
free(item->token);
free(item->value);
free(item);
Expand Down Expand Up @@ -216,18 +218,24 @@ static int check_if_different(struct trailer_item *in_tok,
return 1;
}

static char *apply_command(const char *command, const char *arg)
static char *apply_command(const char *command, const char *cmd_, const char *arg)
{
struct strbuf cmd = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
struct child_process cp = CHILD_PROCESS_INIT;
char *result;

strbuf_addstr(&cmd, command);
if (arg)
strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);

strvec_push(&cp.args, cmd.buf);
if (cmd_) {
strbuf_addstr(&cmd, cmd_);
strvec_push(&cp.args, cmd.buf);
if (arg)
strvec_push(&cp.args, arg);
} else if (command) {
strbuf_addstr(&cmd, command);
strvec_push(&cp.args, cmd.buf);
if (arg)
strbuf_replace(&cmd, TRAILER_ARG_STRING, arg);
}
cp.env = local_repo_env;
cp.no_stdin = 1;
cp.use_shell = 1;
Expand All @@ -247,7 +255,7 @@ static char *apply_command(const char *command, const char *arg)

static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg_tok)
{
if (arg_tok->conf.command) {
if (arg_tok->conf.command || arg_tok->conf.cmd) {
const char *arg;
if (arg_tok->value && arg_tok->value[0]) {
arg = arg_tok->value;
Expand All @@ -257,7 +265,7 @@ static void apply_item_command(struct trailer_item *in_tok, struct arg_item *arg
else
arg = xstrdup("");
}
arg_tok->value = apply_command(arg_tok->conf.command, arg);
arg_tok->value = apply_command(arg_tok->conf.command, arg_tok->conf.cmd, arg);
free((char *)arg);
}
}
Expand Down Expand Up @@ -430,6 +438,7 @@ static void duplicate_conf(struct conf_info *dst, const struct conf_info *src)
dst->name = xstrdup_or_null(src->name);
dst->key = xstrdup_or_null(src->key);
dst->command = xstrdup_or_null(src->command);
dst->cmd = xstrdup_or_null(src->cmd);
}

static struct arg_item *get_conf_item(const char *name)
Expand All @@ -454,15 +463,16 @@ static struct arg_item *get_conf_item(const char *name)
return item;
}

enum trailer_info_type { TRAILER_KEY, TRAILER_COMMAND, TRAILER_WHERE,
TRAILER_IF_EXISTS, TRAILER_IF_MISSING };
enum trailer_info_type { TRAILER_KEY, TRAILER_COMMAND, TRAILER_CMD,
TRAILER_WHERE, TRAILER_IF_EXISTS, TRAILER_IF_MISSING };

static struct {
const char *name;
enum trailer_info_type type;
} trailer_config_items[] = {
{ "key", TRAILER_KEY },
{ "command", TRAILER_COMMAND },
{ "cmd", TRAILER_CMD },
{ "where", TRAILER_WHERE },
{ "ifexists", TRAILER_IF_EXISTS },
{ "ifmissing", TRAILER_IF_MISSING }
Expand Down Expand Up @@ -542,6 +552,11 @@ static int git_trailer_config(const char *conf_key, const char *value, void *cb)
warning(_("more than one %s"), conf_key);
conf->command = xstrdup(value);
break;
case TRAILER_CMD:
if (conf->cmd)
warning(_("more than one %s"), conf_key);
conf->cmd = xstrdup(value);
break;
case TRAILER_WHERE:
if (trailer_set_where(&conf->where, value))
warning(_("unknown value '%s' for key '%s'"), value, conf_key);
Expand Down Expand Up @@ -708,7 +723,7 @@ static void process_command_line_args(struct list_head *arg_head,
/* Add an arg item for each configured trailer with a command */
list_for_each(pos, &conf_head) {
item = list_entry(pos, struct arg_item, list);
if (item->conf.command)
if (item->conf.cmd || item->conf.command)
add_arg_item(arg_head,
xstrdup(token_from_item(item, NULL)),
xstrdup(""),
Expand Down

0 comments on commit b268ecd

Please sign in to comment.