Skip to content

Commit

Permalink
format-patch: teach --cover-from-description option
Browse files Browse the repository at this point in the history
Before, when format-patch generated a cover letter, only the body would
be populated with a branch's description while the subject would be
populated with placeholder text. However, users may want to have the
subject of their cover letter automatically populated in the same way.

Teach format-patch to accept the `--cover-from-description` option and
corresponding `format.coverFromDescription` config, allowing users to
populate different parts of the cover letter (including the subject
now).

Signed-off-by: Denton Liu <liu.denton@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Denton-L authored and gitster committed Oct 16, 2019
1 parent a92331d commit bf8e65b
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 21 deletions.
6 changes: 6 additions & 0 deletions Documentation/config/format.txt
Expand Up @@ -36,6 +36,12 @@ format.subjectPrefix::
The default for format-patch is to output files with the '[PATCH]'
subject prefix. Use this variable to change that prefix.

format.coverFromDescription::
The default mode for format-patch to determine which parts of
the cover letter will be populated using the branch's
description. See the `--cover-from-description` option in
linkgit:git-format-patch[1].

format.signature::
The default for format-patch is to output a signature containing
the Git version number. Use this variable to change that default.
Expand Down
22 changes: 22 additions & 0 deletions Documentation/git-format-patch.txt
Expand Up @@ -19,6 +19,7 @@ SYNOPSIS
[--start-number <n>] [--numbered-files]
[--in-reply-to=<message id>] [--suffix=.<sfx>]
[--ignore-if-in-upstream]
[--cover-from-description=<mode>]
[--rfc] [--subject-prefix=<subject prefix>]
[(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
Expand Down Expand Up @@ -171,6 +172,26 @@ will want to ensure that threading is disabled for `git send-email`.
patches being generated, and any patch that matches is
ignored.

--cover-from-description=<mode>::
Controls which parts of the cover letter will be automatically
populated using the branch's description.
+
If `<mode>` is `message` or `default`, the cover letter subject will be
populated with placeholder text. The body of the cover letter will be
populated with the branch's description. This is the default mode when
no configuration nor command line option is specified.
+
If `<mode>` is `subject`, the first paragraph of the branch description will
populate the cover letter subject. The remainder of the description will
populate the body of the cover letter.
+
If `<mode>` is `auto`, if the first paragraph of the branch description
is greater than 100 bytes, then the mode will be `message`, otherwise
`subject` will be used.
+
If `<mode>` is `none`, both the cover letter subject and body will be
populated with placeholder text.

--subject-prefix=<subject prefix>::
Instead of the standard '[PATCH]' prefix in the subject
line, instead use '[<subject prefix>]'. This
Expand Down Expand Up @@ -347,6 +368,7 @@ with configuration variables.
signOff = true
outputDirectory = <directory>
coverLetter = auto
coverFromDescription = auto
------------


Expand Down
95 changes: 75 additions & 20 deletions builtin/log.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1057,15 +1072,51 @@ 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,
const char *branch_name,
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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 },
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit bf8e65b

Please sign in to comment.