ref-filter: add support to display trailers as part of contents
authorJacob Keller <jacob.keller@gmail.com>
Sat, 19 Nov 2016 00:58:15 +0000 (16:58 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 11 Dec 2016 21:58:41 +0000 (13:58 -0800)
Add %(trailers) and %(contents:trailers) to display the trailers as
interpreted by trailer_info_get. Update documentation and add a test for
the new feature.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-for-each-ref.txt
ref-filter.c
t/t6300-for-each-ref.sh
index f57e69bc83e33e3de3d02e339fd71066b93e7d4d..e5807eede787dec3482d1b17e4d7149bcc585059 100644 (file)
@@ -165,6 +165,8 @@ of all lines of the commit message up to the first blank line.  The next
 line is 'contents:body', where body is all of the lines after the first
 blank line.  The optional GPG signature is `contents:signature`.  The
 first `N` lines of the message is obtained using `contents:lines=N`.
+Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
+are obtained as 'contents:trailers'.
 
 For sorting purposes, fields with numeric values sort in numeric order
 (`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`).
index d4c2931f3aab14accaa5720c87b2fc58aed83faa..b6f1bb73ed374178173906b7078a1fca5a6f84d0 100644 (file)
@@ -13,6 +13,7 @@
 #include "utf8.h"
 #include "git-compat-util.h"
 #include "version.h"
+#include "trailer.h"
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 
@@ -40,7 +41,7 @@ static struct used_atom {
                enum { RR_NORMAL, RR_SHORTEN, RR_TRACK, RR_TRACKSHORT }
                        remote_ref;
                struct {
-                       enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB } option;
+                       enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
                        unsigned int nlines;
                } contents;
                enum { O_FULL, O_SHORT } objectname;
@@ -85,6 +86,13 @@ static void subject_atom_parser(struct used_atom *atom, const char *arg)
        atom->u.contents.option = C_SUB;
 }
 
+static void trailers_atom_parser(struct used_atom *atom, const char *arg)
+{
+       if (arg)
+               die(_("%%(trailers) does not take arguments"));
+       atom->u.contents.option = C_TRAILERS;
+}
+
 static void contents_atom_parser(struct used_atom *atom, const char *arg)
 {
        if (!arg)
@@ -95,6 +103,8 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
                atom->u.contents.option = C_SIG;
        else if (!strcmp(arg, "subject"))
                atom->u.contents.option = C_SUB;
+       else if (!strcmp(arg, "trailers"))
+               atom->u.contents.option = C_TRAILERS;
        else if (skip_prefix(arg, "lines=", &arg)) {
                atom->u.contents.option = C_LINES;
                if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
@@ -194,6 +204,7 @@ static struct {
        { "creatordate", FIELD_TIME },
        { "subject", FIELD_STR, subject_atom_parser },
        { "body", FIELD_STR, body_atom_parser },
+       { "trailers", FIELD_STR, trailers_atom_parser },
        { "contents", FIELD_STR, contents_atom_parser },
        { "upstream", FIELD_STR, remote_ref_atom_parser },
        { "push", FIELD_STR, remote_ref_atom_parser },
@@ -785,6 +796,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
                        name++;
                if (strcmp(name, "subject") &&
                    strcmp(name, "body") &&
+                   strcmp(name, "trailers") &&
                    !starts_with(name, "contents"))
                        continue;
                if (!subpos)
@@ -808,6 +820,14 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
                        /*  Size is the length of the message after removing the signature */
                        append_lines(&s, subpos, contents_end - subpos, atom->u.contents.nlines);
                        v->s = strbuf_detach(&s, NULL);
+               } else if (atom->u.contents.option == C_TRAILERS) {
+                       struct trailer_info info;
+
+                       /* Search for trailer info */
+                       trailer_info_get(&info, subpos);
+                       v->s = xmemdupz(info.trailer_start,
+                                       info.trailer_end - info.trailer_start);
+                       trailer_info_release(&info);
                } else if (atom->u.contents.option == C_BARE)
                        v->s = xstrdup(subpos);
        }
index 19a2823025e794a6adc3f75d65dd175a2021f282..eb4bac0fe47785164e0f0bc3d1d0ea4aa5f452ff 100755 (executable)
@@ -553,4 +553,30 @@ test_expect_success 'Verify sort with multiple keys' '
                refs/tags/bogo refs/tags/master > actual &&
        test_cmp expected actual
 '
+
+cat >trailers <<EOF
+Reviewed-by: A U Thor <author@example.com>
+Signed-off-by: A U Thor <author@example.com>
+EOF
+
+test_expect_success 'basic atom: head contents:trailers' '
+       echo "Some contents" > two &&
+       git add two &&
+       git commit -F - <<-EOF &&
+       trailers: this commit message has trailers
+
+       Some message contents
+
+       $(cat trailers)
+       EOF
+       git for-each-ref --format="%(contents:trailers)" refs/heads/master >actual &&
+       sanitize_pgp <actual >actual.clean &&
+       # git for-each-ref ends with a blank line
+       cat >expect <<-EOF &&
+       $(cat trailers)
+
+       EOF
+       test_cmp expect actual.clean
+'
+
 test_done