]> git.ipfire.org Git - thirdparty/git.git/blobdiff - builtin/log.c
format-patch: teach --cover-from-description option
[thirdparty/git.git] / builtin / log.c
index d212a8305d32c81003ce0f03ee245658c3141272..04be559bd23f57563932deb0a9ac4feb7aa5dd57 100644 (file)
@@ -37,6 +37,7 @@
 #include "range-diff.h"
 
 #define MAIL_DEFAULT_WRAP 72
+#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
 
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
@@ -777,6 +778,13 @@ enum thread_level {
        THREAD_DEEP
 };
 
+enum cover_from_description {
+       COVER_FROM_NONE,
+       COVER_FROM_MESSAGE,
+       COVER_FROM_SUBJECT,
+       COVER_FROM_AUTO
+};
+
 static enum thread_level thread;
 static int do_signoff;
 static int base_auto;
@@ -785,6 +793,23 @@ static const char *signature = git_version_string;
 static const char *signature_file;
 static enum cover_setting config_cover_letter;
 static const char *config_output_directory;
+static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
+
+static enum cover_from_description parse_cover_from_description(const char *arg)
+{
+       if (!arg || !strcmp(arg, "default"))
+               return COVER_FROM_MESSAGE;
+       else if (!strcmp(arg, "none"))
+               return COVER_FROM_NONE;
+       else if (!strcmp(arg, "message"))
+               return COVER_FROM_MESSAGE;
+       else if (!strcmp(arg, "subject"))
+               return COVER_FROM_SUBJECT;
+       else if (!strcmp(arg, "auto"))
+               return COVER_FROM_AUTO;
+       else
+               die(_("%s: invalid cover from description mode"), arg);
+}
 
 static int git_format_config(const char *var, const char *value, void *cb)
 {
@@ -891,6 +916,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
                }
                return 0;
        }
+       if (!strcmp(var, "format.coverfromdescription")) {
+               cover_from_description_mode = parse_cover_from_description(value);
+               return 0;
+       }
 
        return git_log_config(var, value, cb);
 }
@@ -997,20 +1026,6 @@ static void print_signature(FILE *file)
        putc('\n', file);
 }
 
-static void add_branch_description(struct strbuf *buf, const char *branch_name)
-{
-       struct strbuf desc = STRBUF_INIT;
-       if (!branch_name || !*branch_name)
-               return;
-       read_branch_desc(&desc, branch_name);
-       if (desc.len) {
-               strbuf_addch(buf, '\n');
-               strbuf_addbuf(buf, &desc);
-               strbuf_addch(buf, '\n');
-       }
-       strbuf_release(&desc);
-}
-
 static char *find_branch_name(struct rev_info *rev)
 {
        int i, positive = -1;
@@ -1057,6 +1072,44 @@ static void show_diffstat(struct rev_info *rev,
        fprintf(rev->diffopt.file, "\n");
 }
 
+static void prepare_cover_text(struct pretty_print_context *pp,
+                              const char *branch_name,
+                              struct strbuf *sb,
+                              const char *encoding,
+                              int need_8bit_cte)
+{
+       const char *subject = "*** SUBJECT HERE ***";
+       const char *body = "*** BLURB HERE ***";
+       struct strbuf description_sb = STRBUF_INIT;
+       struct strbuf subject_sb = STRBUF_INIT;
+
+       if (cover_from_description_mode == COVER_FROM_NONE)
+               goto do_pp;
+
+       if (branch_name && *branch_name)
+               read_branch_desc(&description_sb, branch_name);
+       if (!description_sb.len)
+               goto do_pp;
+
+       if (cover_from_description_mode == COVER_FROM_SUBJECT ||
+                       cover_from_description_mode == COVER_FROM_AUTO)
+               body = format_subject(&subject_sb, description_sb.buf, " ");
+
+       if (cover_from_description_mode == COVER_FROM_MESSAGE ||
+                       (cover_from_description_mode == COVER_FROM_AUTO &&
+                        subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+               body = description_sb.buf;
+       else
+               subject = subject_sb.buf;
+
+do_pp:
+       pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
+       pp_remainder(pp, &body, sb, 0);
+
+       strbuf_release(&description_sb);
+       strbuf_release(&subject_sb);
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              struct commit *origin,
                              int nr, struct commit **list,
@@ -1064,8 +1117,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              int quiet)
 {
        const char *committer;
-       const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
-       const char *msg;
        struct shortlog log;
        struct strbuf sb = STRBUF_INIT;
        int i;
@@ -1095,15 +1146,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
        if (!branch_name)
                branch_name = find_branch_name(rev);
 
-       msg = body;
        pp.fmt = CMIT_FMT_EMAIL;
        pp.date_mode.type = DATE_RFC2822;
        pp.rev = rev;
        pp.print_email_subject = 1;
        pp_user_info(&pp, NULL, &sb, committer, encoding);
-       pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
-       pp_remainder(&pp, &msg, &sb, 0);
-       add_branch_description(&sb, branch_name);
+       prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
        fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
        strbuf_release(&sb);
@@ -1545,6 +1593,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int use_patch_format = 0;
        int quiet = 0;
        int reroll_count = -1;
+       char *cover_from_description_arg = NULL;
        char *branch_name = NULL;
        char *base_commit = NULL;
        struct base_tree_info bases;
@@ -1581,6 +1630,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 0, "rfc", &rev, NULL,
                            N_("Use [RFC PATCH] instead of [PATCH]"),
                            PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback },
+               OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
+                           N_("cover-from-description-mode"),
+                           N_("generate parts of a cover letter based on a branch's description")),
                { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
                            N_("Use [<prefix>] instead of [PATCH]"),
                            PARSE_OPT_NONEG, subject_prefix_callback },
@@ -1672,6 +1724,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                             PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
                             PARSE_OPT_KEEP_DASHDASH);
 
+       if (cover_from_description_arg)
+               cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+
        if (0 < reroll_count) {
                struct strbuf sprefix = STRBUF_INIT;
                strbuf_addf(&sprefix, "%s v%d",