git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Denton Liu <liu.denton@gmail.com>
To: Git Mailing List <git@vger.kernel.org>
Subject: [PATCH 7/7] format-patch: read branch-specific To: and Cc: headers
Date: Sun, 5 May 2019 12:24:49 -0400	[thread overview]
Message-ID: <7e625b688883c0528348f77d181bc28195d8ab92.1557072929.git.liu.denton@gmail.com> (raw)
In-Reply-To: <cover.1557072929.git.liu.denton@gmail.com>

If a user wishes to keep track of whom to Cc: on individual patchsets,
they must manually keep track of each recipient and fill it in with the
`--cc` option on git-format-patch each time. However, on the Git mailing
list, Cc:'s are typically never dropped. As a result, it would be nice
to have a method to keep track of recipients on a per-branch basis.

Currently, git-format-patch gets its To: headers from the `--to` options
and the `format.to` config variable. The Cc: header is derived
similarly.

In addition to the above, read To: and Cc: headers from
`branch.<name>.to` and `branch.<name>.cc` so that users can have
branch-specific configuration options.

Signed-off-by: Denton Liu <liu.denton@gmail.com>
---
 Documentation/config/branch.txt    |   6 ++
 Documentation/git-format-patch.txt |  10 +--
 builtin/log.c                      |  63 +++++++++++++++--
 t/t4014-format-patch.sh            | 108 +++++++++++++++++++++++------
 4 files changed, 159 insertions(+), 28 deletions(-)

diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index 2bff738982..22b9bf3d0d 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -104,3 +104,9 @@ branch.<name>.description::
 branch.<name>.coverSubject::
 	When format-patch generates a cover letter, use the specified
 	subject for the cover letter instead of the generic template.
+
+branch.<name>.to::
+branch.<name>.cc::
+	Additional recipients to include in a patch to be submitted
+	by mail.  See the --to and --cc options in
+	linkgit:git-format-patch[1].
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index af7883acbe..1c972f683a 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -199,7 +199,7 @@ will want to ensure that threading is disabled for `git send-email`.
 	Add a `To:` header to the email headers. This is in addition
 	to any configured headers, and may be used multiple times. The
 	emails given will be used along with any emails given by
-	`format.to` configurations.
+	`format.to` and `branch.<name>.to` configurations.
 	The negated form `--no-to` discards all `To:` headers added so
 	far (from config or command line).
 
@@ -207,7 +207,7 @@ will want to ensure that threading is disabled for `git send-email`.
 	Add a `Cc:` header to the email headers. This is in addition
 	to any configured headers, and may be used multiple times. The
 	emails given will be used along with any emails given by
-	`format.cc` configurations.
+	`format.cc` and `branch.<name>.cc` configurations.
 	The negated form `--no-cc` discards all `Cc:` headers added so
 	far (from config or command line).
 
@@ -335,7 +335,7 @@ CONFIGURATION
 -------------
 You can specify extra mail header lines to be added to each message,
 defaults for the subject prefix and file suffix, number patches when
-outputting more than one patch, add "To" or "Cc:" headers, configure
+outputting more than one patch, add "To:" or "Cc:" headers, configure
 attachments, and sign off patches with configuration variables.
 
 ------------
@@ -352,11 +352,13 @@ attachments, and sign off patches with configuration variables.
 ------------
 
 In addition, for a specific branch, you can specify a custom cover
-letter subject.
+letter subject, and add additional "To:" or "Cc:" headers.
 
 ------------
 [branch "branch-name"]
 	coverSubject = "subject for branch-name only"
+	to = <email>
+	cc = <email>
 ------------
 
 DISCUSSION
diff --git a/builtin/log.c b/builtin/log.c
index 685e319078..6825d95c5f 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -738,6 +738,8 @@ static char *default_attach = NULL;
 static struct string_list extra_hdr = STRING_LIST_INIT_NODUP;
 static struct string_list extra_to = STRING_LIST_INIT_NODUP;
 static struct string_list extra_cc = STRING_LIST_INIT_NODUP;
+int to_cleared;
+int cc_cleared;
 
 static void add_header(const char *value)
 {
@@ -1030,6 +1032,55 @@ static void show_diffstat(struct rev_info *rev,
 	fprintf(rev->diffopt.file, "\n");
 }
 
+static void add_branch_headers(struct rev_info *rev, const char *branch_name)
+{
+	struct strbuf buf = STRBUF_INIT;
+	const struct string_list *values;
+
+	if (!branch_name)
+		branch_name = find_branch_name(rev);
+
+	if (!branch_name || !*branch_name)
+		return;
+
+	/*
+	 * HACK: We only use branch-specific recipients iff the list has not
+	 * been cleared by an earlier --no-{to,cc} option on the command-line.
+	 *
+	 * When we get format.{to,cc} options, they can be cleared by
+	 * --no-{to,cc} options since the `git_config` call comes before the
+	 *  `parse_options` call.
+	 *
+	 *  However, in the case of branch.<name>.{to,cc}, this function needs
+	 *  to be called after `setup_revisions`, which must be called after
+	 *  `parse_options`. However, in order for the --no-{to,cc} logic to
+	 *  clear the extra_{to,cc} string_list, this function should actually
+	 *  be called _before_ `parse_options`. As a result, we have a circular
+	 *  dependency.
+	 *
+	 *  The {to,cc}_cleared flag lets us workaround this by just no
+	 *  including branch-specific recipients iff --no-{to,cc} has been
+	 *  specified on the command-line.
+	 */
+
+	if (!to_cleared) {
+		strbuf_addf(&buf, "branch.%s.to", branch_name);
+		values = git_config_get_value_multi(buf.buf);
+		if (values)
+			string_list_append_all(&extra_to, values);
+	}
+
+	if (!cc_cleared) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "branch.%s.cc", branch_name);
+		values = git_config_get_value_multi(buf.buf);
+		if (values)
+			string_list_append_all(&extra_cc, values);
+	}
+
+	strbuf_release(&buf);
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
 			      struct commit *origin,
 			      int nr, struct commit **list,
@@ -1289,18 +1340,20 @@ static int header_callback(const struct option *opt, const char *arg, int unset)
 
 static int to_callback(const struct option *opt, const char *arg, int unset)
 {
-	if (unset)
+	if (unset) {
+		to_cleared = 1;
 		string_list_clear(&extra_to, 0);
-	else
+	} else
 		string_list_append(&extra_to, arg);
 	return 0;
 }
 
 static int cc_callback(const struct option *opt, const char *arg, int unset)
 {
-	if (unset)
+	if (unset) {
+		cc_cleared = 1;
 		string_list_clear(&extra_cc, 0);
-	else
+	} else
 		string_list_append(&extra_cc, arg);
 	return 0;
 }
@@ -1767,6 +1820,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	add_branch_headers(&rev, branch_name);
+
 	for (i = 0; i < extra_hdr.nr; i++) {
 		strbuf_addstr(&buf, extra_hdr.items[i].string);
 		strbuf_addch(&buf, '\n');
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 1cf4dfbce2..6578e6b433 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -234,6 +234,65 @@ test_expect_failure 'configuration To: header (rfc2047)' '
 	grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" hdrs9
 '
 
+test_expect_success 'branch-specific configuration To: header (ascii)' '
+
+	test_unconfig format.to &&
+	git config branch.side.to "R E Cipient <rcipient@example.com>" &&
+	git format-patch --stdout master..side >patch10 &&
+	sed -e "/^\$/q" patch10 >hdrs10 &&
+	grep "^To: R E Cipient <rcipient@example.com>\$" hdrs10
+'
+
+test_expect_failure 'branch-specific configuration To: header (rfc822)' '
+
+	git config branch.side.to "R. E. Cipient <rcipient@example.com>" &&
+	git format-patch --stdout master..side >patch10 &&
+	sed -e "/^\$/q" patch10 >hdrs10 &&
+	grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" hdrs10
+'
+
+test_expect_failure 'branch-specific configuration To: header (rfc2047)' '
+
+	git config branch.side.to "R Ä Cipient <rcipient@example.com>" &&
+	git format-patch --stdout master..side >patch10 &&
+	sed -e "/^\$/q" patch10 >hdrs10 &&
+	grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" hdrs10
+'
+
+test_expect_success 'all recipients included from all sources' '
+
+	git config format.to "Format To1 <formatto1@example.com>" &&
+	git config --add format.to "Format To2 <formatto2@example.com>" &&
+	git config format.cc "Format Cc1 <formatcc1@example.com>" &&
+	git config --add format.cc "Format Cc2 <formatcc2@example.com>" &&
+	git config branch.side.to "Branch To1 <branchto1@example.com>" &&
+	git config --add branch.side.to "Branch To2 <branchto2@example.com>" &&
+	git config branch.side.cc "Branch Cc1 <branchcc1@example.com>" &&
+	git config --add branch.side.cc "Branch Cc2 <branchcc2@example.com>" &&
+	cat <<-\EOF >expect &&
+	To: Format To1 <formatto1@example.com>,
+	    Format To2 <formatto2@example.com>,
+	    Command-line To1 <commandlineto1@example.com>,
+	    Command-line To2 <commandlineto2@example.com>,
+	    Branch To1 <branchto1@example.com>,
+	    Branch To2 <branchto2@example.com>
+	Cc: Format Cc1 <formatcc1@example.com>,
+	    Format Cc2 <formatcc2@example.com>,
+	    Command-line Cc1 <commandlinecc1@example.com>,
+	    Command-line Cc2 <commandlinecc2@example.com>,
+	    Branch Cc1 <branchcc1@example.com>,
+	    Branch Cc2 <branchcc2@example.com>
+
+	EOF
+	git format-patch --stdout \
+		--to="Command-line To1 <commandlineto1@example.com>" \
+		--to="Command-line To2 <commandlineto2@example.com>" \
+		--cc="Command-line Cc1 <commandlinecc1@example.com>" \
+		--cc="Command-line Cc2 <commandlinecc2@example.com>" \
+		master..side | sed -ne "/^To:/,/^$/p;/^$/q" >patch10 &&
+	test_cmp expect patch10
+'
+
 # check_patch <patch>: Verify that <patch> looks like a half-sane
 # patch email to avoid a false positive with !grep
 check_patch () {
@@ -286,42 +345,51 @@ test_expect_success '--no-to overrides config.to' '
 
 	git config --replace-all format.to \
 		"R E Cipient <rcipient@example.com>" &&
-	git format-patch --no-to --stdout master..side >patch10 &&
-	sed -e "/^\$/q" patch10 >hdrs10 &&
-	check_patch hdrs10 &&
-	! grep "^To: R E Cipient <rcipient@example.com>\$" hdrs10
+	git config --replace-all branch.side.to \
+		"B R Anch <branch@example.com>" &&
+	git format-patch --no-to --stdout master..side >patch11 &&
+	sed -e "/^\$/q" patch11 >hdrs11 &&
+	check_patch hdrs11 &&
+	! grep "R E Cipient <rcipient@example.com>" hdrs11 &&
+	! grep "B R Anch <branch@example.com>" hdrs11
 '
 
 test_expect_success '--no-to and --to replaces config.to' '
 
 	git config --replace-all format.to \
 		"Someone <someone@out.there>" &&
+	git config --replace-all branch.side.to \
+		"B R Anch2 <branch2@example.com>" &&
 	git format-patch --no-to --to="Someone Else <else@out.there>" \
-		--stdout master..side >patch11 &&
-	sed -e "/^\$/q" patch11 >hdrs11 &&
-	check_patch hdrs11 &&
-	! grep "^To: Someone <someone@out.there>\$" hdrs11 &&
-	grep "^To: Someone Else <else@out.there>\$" hdrs11
+		--stdout master..side >patch12 &&
+	sed -e "/^\$/q" patch12 >hdrs12 &&
+	check_patch hdrs12 &&
+	! grep "Someone <someone@out.there>" hdrs12 &&
+	! grep "B R Anch2 <branch2@example.com>" hdrs12 &&
+	grep "^To: Someone Else <else@out.there>\$" hdrs12
 '
 
 test_expect_success '--no-cc overrides config.cc' '
 
 	git config --replace-all format.cc \
 		"C E Cipient <rcipient@example.com>" &&
-	git format-patch --no-cc --stdout master..side >patch12 &&
-	sed -e "/^\$/q" patch12 >hdrs12 &&
-	check_patch hdrs12 &&
-	! grep "^Cc: C E Cipient <rcipient@example.com>\$" hdrs12
+	git config --replace-all branch.side.cc \
+		"B R Anch3 <branch3@example.com>" &&
+	git format-patch --no-cc --stdout master..side >patch13 &&
+	sed -e "/^\$/q" patch13 >hdrs13 &&
+	check_patch hdrs13 &&
+	! grep "C E Cipient <rcipient@example.com>" hdrs13 &&
+	! grep "B R Anch3 <branch3@example.com>" hdrs13
 '
 
 test_expect_success '--no-add-header overrides config.headers' '
 
 	git config --replace-all format.headers \
 		"Header1: B E Cipient <rcipient@example.com>" &&
-	git format-patch --no-add-header --stdout master..side >patch13 &&
-	sed -e "/^\$/q" patch13 >hdrs13 &&
-	check_patch hdrs13 &&
-	! grep "^Header1: B E Cipient <rcipient@example.com>\$" hdrs13
+	git format-patch --no-add-header --stdout master..side >patch14 &&
+	sed -e "/^\$/q" patch14 >hdrs14 &&
+	check_patch hdrs14 &&
+	! grep "^Header1: B E Cipient <rcipient@example.com>\$" hdrs14
 '
 
 test_expect_success 'multiple files' '
@@ -957,7 +1025,7 @@ test_expect_success 'format-patch wraps extremely long subject (ascii)' '
 	git add file &&
 	git commit -m "$M512" &&
 	git format-patch --stdout -1 >patch &&
-	sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+	sed -n "/^Subject/p; /^ /p; /^Header1:/q" <patch >subject &&
 	test_cmp expect subject
 '
 
@@ -996,7 +1064,7 @@ test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
 	git add file &&
 	git commit -m "$M512" &&
 	git format-patch --stdout -1 >patch &&
-	sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+	sed -n "/^Subject/p; /^ /p; /^Header1:/q" <patch >subject &&
 	test_cmp expect subject
 '
 
@@ -1005,7 +1073,7 @@ check_author() {
 	git add file &&
 	GIT_AUTHOR_NAME=$1 git commit -m author-check &&
 	git format-patch --stdout -1 >patch &&
-	sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
+	sed -n "/^From: /p; /^ /p; /^Date:/q" <patch >actual &&
 	test_cmp expect actual
 }
 
-- 
2.21.0.1049.geb646f7864


  parent reply	other threads:[~2019-05-05 16:24 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-05 16:24 [PATCH 0/7] teach branch-specific options for format-patch Denton Liu
2019-05-05 16:24 ` [PATCH 1/7] t4014: clean up style Denton Liu
2019-05-05 16:24 ` [PATCH 2/7] Doc: add more detail for git-format-patch Denton Liu
2019-05-05 16:24 ` [PATCH 3/7] branch.c: extract read_branch_config function Denton Liu
2019-05-05 16:24 ` [PATCH 4/7] format-patch: make cover letter subject configurable Denton Liu
2019-05-05 16:24 ` [PATCH 5/7] format-patch: move extra_headers logic later Denton Liu
2019-05-05 16:24 ` [PATCH 6/7] string-list: create string_list_append_all Denton Liu
2019-05-05 16:24 ` Denton Liu [this message]
2019-05-07  8:56 ` [PATCH 0/7] teach branch-specific options for format-patch Junio C Hamano
2019-05-07 14:19   ` Denton Liu
2019-05-07 15:05     ` Junio C Hamano
2019-05-07 15:21       ` Denton Liu
2019-05-07 15:46         ` Ævar Arnfjörð Bjarmason
2019-05-08  1:45           ` Junio C Hamano
2019-05-31  2:00             ` [RFC PATCH] config: learn the "onbranch:" includeIf condition Denton Liu
2019-05-31 12:58               ` Johannes Schindelin
2019-05-31 13:16                 ` Denton Liu
2019-05-31 17:23                   ` Johannes Schindelin
2019-05-31 18:44                     ` Denton Liu
2019-05-31 19:33               ` [PATCH v2] " Denton Liu
2019-05-31 20:14                 ` Johannes Schindelin
2019-06-05  8:02                   ` Johannes Schindelin
2019-06-05 10:08                 ` Duy Nguyen
2019-06-05 21:21                 ` [PATCH v3] " Denton Liu
2019-06-06 12:52                   ` Johannes Schindelin
2019-05-17  0:27 ` [PATCH v2 0/6] teach branch-specific options for format-patch Denton Liu
2019-05-17  0:27   ` [PATCH v2 1/6] t4014: clean up style Denton Liu
2019-05-17  0:27   ` [PATCH v2 2/6] Doc: add more detail for git-format-patch Denton Liu
2019-05-17  0:27   ` [PATCH v2 3/6] format-patch: make cover letter subject configurable Denton Liu
2019-05-17  0:27   ` [PATCH v2 4/6] format-patch: move extra_headers logic later Denton Liu
2019-05-17  0:27   ` [PATCH v2 5/6] string-list: create string_list_append_all Denton Liu
2019-05-17  0:27   ` [PATCH v2 6/6] format-patch: read branch-specific To: and Cc: headers Denton Liu
2019-05-17  4:12   ` [PATCH v2 0/6] teach branch-specific options for format-patch Junio C Hamano
2019-05-17  7:25     ` Denton Liu
2019-05-17 16:54       ` Denton Liu
2019-05-22  2:44   ` [PATCH v3 0/8] " Denton Liu
2019-05-22  2:44     ` [PATCH v3 1/8] t4014: clean up style Denton Liu
2019-05-22  2:44     ` [PATCH v3 2/8] Doc: add more detail for git-format-patch Denton Liu
2019-05-22  2:44     ` [PATCH v3 3/8] format-patch: infer cover letter from branch description Denton Liu
2019-05-22  2:44     ` [PATCH v3 4/8] format-patch: move extra_headers logic later Denton Liu
2019-05-22  2:44     ` [PATCH v3 5/8] string-list: create string_list_append_all Denton Liu
2019-05-22  2:44     ` [PATCH v3 6/8] format-patch: read branch-specific To: and Cc: headers Denton Liu
2019-05-22  2:44     ` [PATCH v3 7/8] format-patch: move output_directory logic later Denton Liu
2019-05-22  2:44     ` [PATCH v3 8/8] format-patch: read branch-specific output directory Denton Liu
2019-05-31  0:30     ` [PATCH v3 0/8] teach branch-specific options for format-patch Denton Liu
2019-06-14 21:56     ` [RESEND PATCH " Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 1/8] t4014: clean up style Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 2/8] Doc: add more detail for git-format-patch Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 3/8] format-patch: infer cover letter from branch description Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 4/8] format-patch: move extra_headers logic later Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 5/8] string-list: create string_list_append_all Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 6/8] format-patch: read branch-specific To: and Cc: headers Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 7/8] format-patch: move output_directory logic later Denton Liu
2019-06-14 21:56       ` [RESEND PATCH v3 8/8] format-patch: read branch-specific output directory Denton Liu
2019-10-15  9:06     ` [PATCH v6 0/3] format-patch: learn --infer-cover-subject option (also t4014 cleanup) Denton Liu
2019-10-15  9:06       ` [PATCH v6 1/3] format-patch: replace erroneous and condition Denton Liu
2019-10-15  9:06       ` [PATCH v6 2/3] format-patch: use enum variables Denton Liu
2019-10-15  9:06       ` [PATCH v6 3/3] format-patch: teach --cover-from-description option Denton Liu
2019-10-16  1:28       ` [PATCH v6 0/3] format-patch: learn --infer-cover-subject option (also t4014 cleanup) Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7e625b688883c0528348f77d181bc28195d8ab92.1557072929.git.liu.denton@gmail.com \
    --to=liu.denton@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).