diff mbox series

[v4,4/4] ref-filter: use pretty.c logic for trailers

Message ID 9ec98917699382c2a43b29e1c552d3685f63f29a.1613181163.git.gitgitgadget@gmail.com (mailing list archive)
State Accepted
Commit ee82a487f68a7c86551fb59f6176812d63be61b6
Headers show
Series Unify trailers formatting logic for pretty.c and ref-filter.c | expand

Commit Message

Hariom verma Feb. 13, 2021, 1:52 a.m. UTC
From: Hariom Verma <hariom18599@gmail.com>

Now, ref-filter is using pretty.c logic for setting trailer options.

New to ref-filter:
  :key=<K> - only show trailers with specified key.
  :valueonly[=val] - only show the value part.
  :separator=<SEP> - inserted between trailer lines.
  :key_value_separator=<SEP> - inserted between key and value in trailer lines

Enhancement to existing options(now can take value and its optional):
  :only[=val]
  :unfold[=val]

'val' can be: true, on, yes or false, off, no.

Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Mentored-by: Heba Waly <heba.waly@gmail.com>
Signed-off-by: Hariom Verma <hariom18599@gmail.com>
---
 Documentation/git-for-each-ref.txt |  8 +--
 ref-filter.c                       | 36 ++++++-----
 t/t6300-for-each-ref.sh            | 95 ++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+), 21 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 2962f85a502a..2ae2478de706 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -260,11 +260,9 @@  contents:lines=N::
 	The first `N` lines of the message.
 
 Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
-are obtained as `trailers` (or by using the historical alias
-`contents:trailers`).  Non-trailer lines from the trailer block can be omitted
-with `trailers:only`. Whitespace-continuations can be removed from trailers so
-that each trailer appears on a line by itself with its full content with
-`trailers:unfold`. Both can be used together as `trailers:unfold,only`.
+are obtained as `trailers[:options]` (or by using the historical alias
+`contents:trailers[:options]`). For valid [:option] values see `trailers`
+section of linkgit:git-log[1].
 
 For sorting purposes, fields with numeric values sort in numeric order
 (`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`).
diff --git a/ref-filter.c b/ref-filter.c
index fd994e18744c..5224037d3da4 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -67,6 +67,12 @@  struct refname_atom {
 	int lstrip, rstrip;
 };
 
+static struct ref_trailer_buf {
+	struct string_list filter_list;
+	struct strbuf sepbuf;
+	struct strbuf kvsepbuf;
+} ref_trailer_buf = {STRING_LIST_INIT_NODUP, STRBUF_INIT, STRBUF_INIT};
+
 static struct expand_data {
 	struct object_id oid;
 	enum object_type type;
@@ -313,28 +319,26 @@  static int subject_atom_parser(const struct ref_format *format, struct used_atom
 static int trailers_atom_parser(const struct ref_format *format, struct used_atom *atom,
 				const char *arg, struct strbuf *err)
 {
-	struct string_list params = STRING_LIST_INIT_DUP;
-	int i;
-
 	atom->u.contents.trailer_opts.no_divider = 1;
 
 	if (arg) {
-		string_list_split(&params, arg, ',', -1);
-		for (i = 0; i < params.nr; i++) {
-			const char *s = params.items[i].string;
-			if (!strcmp(s, "unfold"))
-				atom->u.contents.trailer_opts.unfold = 1;
-			else if (!strcmp(s, "only"))
-				atom->u.contents.trailer_opts.only_trailers = 1;
-			else {
-				strbuf_addf(err, _("unknown %%(trailers) argument: %s"), s);
-				string_list_clear(&params, 0);
-				return -1;
-			}
+		const char *argbuf = xstrfmt("%s)", arg);
+		char *invalid_arg = NULL;
+
+		if (format_set_trailers_options(&atom->u.contents.trailer_opts,
+		    &ref_trailer_buf.filter_list,
+		    &ref_trailer_buf.sepbuf,
+		    &ref_trailer_buf.kvsepbuf,
+		    &argbuf, &invalid_arg)) {
+			if (!invalid_arg)
+				strbuf_addf(err, _("expected %%(trailers:key=<value>)"));
+			else
+				strbuf_addf(err, _("unknown %%(trailers) argument: %s"), invalid_arg);
+			free((char *)invalid_arg);
+			return -1;
 		}
 	}
 	atom->u.contents.option = C_TRAILERS;
-	string_list_clear(&params, 0);
 	return 0;
 }
 
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index a8faddd18a9b..cac7f443d004 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -837,6 +837,24 @@  test_trailer_option '%(trailers:only) shows only "key: value" trailers' \
 
 	EOF
 
+test_trailer_option '%(trailers:only=no,only=true) shows only "key: value" trailers' \
+	'trailers:only=no,only=true' <<-EOF
+	$(grep -v patch.description <trailers)
+
+	EOF
+
+test_trailer_option '%(trailers:only=yes) shows only "key: value" trailers' \
+	'trailers:only=yes' <<-EOF
+	$(grep -v patch.description <trailers)
+
+	EOF
+
+test_trailer_option '%(trailers:only=no) shows all trailers' \
+	'trailers:only=no' <<-EOF
+	$(cat trailers)
+
+	EOF
+
 test_trailer_option '%(trailers:only) and %(trailers:unfold) work together' \
 	'trailers:only,unfold' <<-EOF
 	$(grep -v patch.description <trailers | unfold)
@@ -849,6 +867,78 @@  test_trailer_option '%(trailers:unfold) and %(trailers:only) work together' \
 
 	EOF
 
+test_trailer_option '%(trailers:key=foo) shows that trailer' \
+	'trailers:key=Signed-off-by' <<-EOF
+	Signed-off-by: A U Thor <author@example.com>
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo) is case insensitive' \
+	'trailers:key=SiGned-oFf-bY' <<-EOF
+	Signed-off-by: A U Thor <author@example.com>
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo:) trailing colon also works' \
+	'trailers:key=Signed-off-by:' <<-EOF
+	Signed-off-by: A U Thor <author@example.com>
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo) multiple keys' \
+	'trailers:key=Reviewed-by:,key=Signed-off-by' <<-EOF
+	Reviewed-by: A U Thor <author@example.com>
+	Signed-off-by: A U Thor <author@example.com>
+
+	EOF
+
+test_trailer_option '%(trailers:key=nonexistent) becomes empty' \
+	'trailers:key=Shined-off-by:' <<-EOF
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo) handles multiple lines even if folded' \
+	'trailers:key=Acked-by' <<-EOF
+	$(grep -v patch.description <trailers | grep -v Signed-off-by | grep -v Reviewed-by)
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo,unfold) properly unfolds' \
+	'trailers:key=Signed-Off-by,unfold' <<-EOF
+	$(unfold <trailers | grep Signed-off-by)
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo,only=no) also includes nontrailer lines' \
+	'trailers:key=Signed-off-by,only=no' <<-EOF
+	Signed-off-by: A U Thor <author@example.com>
+	$(grep patch.description <trailers)
+
+	EOF
+
+test_trailer_option '%(trailers:key=foo,valueonly) shows only value' \
+	'trailers:key=Signed-off-by,valueonly' <<-EOF
+	A U Thor <author@example.com>
+
+	EOF
+
+test_trailer_option '%(trailers:separator) changes separator' \
+	'trailers:separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
+	Reviewed-by: A U Thor <author@example.com>,Signed-off-by: A U Thor <author@example.com>
+	EOF
+
+test_trailer_option '%(trailers:key_value_separator) changes key-value separator' \
+	'trailers:key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
+	Reviewed-by,A U Thor <author@example.com>
+	Signed-off-by,A U Thor <author@example.com>
+
+	EOF
+
+test_trailer_option '%(trailers:separator,key_value_separator) changes both separators' \
+	'trailers:separator=%x2C,key_value_separator=%x2C,key=Reviewed-by,key=Signed-off-by:' <<-EOF
+	Reviewed-by,A U Thor <author@example.com>,Signed-off-by,A U Thor <author@example.com>
+	EOF
+
 test_failing_trailer_option () {
 	title=$1 option=$2
 	cat >expect
@@ -866,6 +956,11 @@  test_failing_trailer_option '%(trailers) rejects unknown trailers arguments' \
 	fatal: unknown %(trailers) argument: unsupported
 	EOF
 
+test_failing_trailer_option '%(trailers:key) without value is error' \
+	'trailers:key' <<-\EOF
+	fatal: expected %(trailers:key=<value>)
+	EOF
+
 test_expect_success 'if arguments, %(contents:trailers) shows error if colon is missing' '
 	cat >expect <<-EOF &&
 	fatal: unrecognized %(contents) argument: trailersonly