From patchwork Tue Oct 15 09:06:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 11189891 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 696F617E6 for ; Tue, 15 Oct 2019 09:06:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 48137217F9 for ; Tue, 15 Oct 2019 09:06:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jYCNNsZK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728644AbfJOJGj (ORCPT ); Tue, 15 Oct 2019 05:06:39 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:37137 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726343AbfJOJGj (ORCPT ); Tue, 15 Oct 2019 05:06:39 -0400 Received: by mail-pf1-f196.google.com with SMTP id y5so12062025pfo.4 for ; Tue, 15 Oct 2019 02:06:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=z+V3gh7RsiwKissOWqhzfFZziqx3l9b4hRqeC4UdPEs=; b=jYCNNsZKF1prCQ24zjcAFYT1ZlqYE6FR3kG18/c7nIXfn57kzbm+SWZQprpwJpgT93 61trjqdP0pwsBuooceB9SCojsKlLvIMjbvKKSt+G4wqOEnDP2dpjHzQUsVflbslXy0H3 Dk1Ut2eI3Qx2atw904+ZdrGcd1DUfNLSQoPQTj7/3m74snfQpRqbP0+uQbwLqubX0FyZ EKBp6cfoIRhdJjmq6FT/qcQQRb+jUW++VLUpAksDWsgq2Ci7EX9uDea1PnBPo5DnVeKf vI9IUFSeG7zF++8sSl/IzBGyltEbMI8p8Q2K+iRuPvv46Go1N+OqMnCbnUjTXmJMKehj EhgA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=z+V3gh7RsiwKissOWqhzfFZziqx3l9b4hRqeC4UdPEs=; b=KMFYnerSMWgYWWTyRQ8HQnKUG4WRrhrGCuCTgbgnt/ssBFbm5GBUBz9tTDsLSt+F6g cDKEPHmfnoh0SSHlFAiiOGzOWABsFmEsGKWqAb5qzft0XmZ0M7iKhOxn29AShLvbfMhD VMGldrPfE4NBi+jo9T6tya5ZpZM+UvmKwhA7uamQ4lNFjlmoKd7Nm+QeYL4MVsKPDCvH WSPiX5qLhU6Wv2RU/DrG+7H2+7zH1UwdTylovldRvgsubxRi7UAFWKGACB0Wrkp3ZuwX sUJ31TYeP/d9be0ZupGdWj7xvAs2MB4Wg4LNsZvcg9zhfpV9O3w/osBiWWCgy04FDa4P I0Ag== X-Gm-Message-State: APjAAAVkQRe+/0UBIDsAoR45Z5YTW4FQWyLj6CklWa7uVQi+uKCXqUgT CW2i/KqNB2d21p/6MKruqwWb/joV X-Google-Smtp-Source: APXvYqwmhoUpIAnMg4GC4IFOZ15ysnnsRVQsbe5nIqeLLQcBEs5BjIEwh6wYyBBdeE0/ibm19XycVQ== X-Received: by 2002:a63:ea45:: with SMTP id l5mr24048802pgk.189.1571130397700; Tue, 15 Oct 2019 02:06:37 -0700 (PDT) Received: from generichostname ([2601:646:280:1b30:80db:d816:4d15:ae2a]) by smtp.gmail.com with ESMTPSA id c8sm24356162pfi.117.2019.10.15.02.06.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Oct 2019 02:06:37 -0700 (PDT) Date: Tue, 15 Oct 2019 02:06:35 -0700 From: Denton Liu To: Git Mailing List Cc: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Junio C Hamano , Eric Sunshine , Johannes Sixt , Philip Oakley Subject: [PATCH v6 1/3] format-patch: replace erroneous and condition Message-ID: <9d41068e73f54cbac82267a6ebd2f13cf343c076.1571130298.git.liu.denton@gmail.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.2 (2019-09-21) Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Commit 30984ed2e9 (format-patch: support deep threading, 2009-02-19), introduced the following lines: #define THREAD_SHALLOW 1 [...] thread = git_config_bool(var, value) && THREAD_SHALLOW; Since git_config_bool() returns a bool, the trailing `&& THREAD_SHALLOW` is a no-op. Replace this errorneous and condition with a ternary statement so that it is clear what the configured value is when a boolean is given. Signed-off-by: Denton Liu --- builtin/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/log.c b/builtin/log.c index 44b10b3415..351f4ffcfd 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -835,7 +835,7 @@ static int git_format_config(const char *var, const char *value, void *cb) thread = THREAD_SHALLOW; return 0; } - thread = git_config_bool(var, value) && THREAD_SHALLOW; + thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET; return 0; } if (!strcmp(var, "format.signoff")) { From patchwork Tue Oct 15 09:06:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 11189893 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A637A14E5 for ; Tue, 15 Oct 2019 09:06:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 876A7217F9 for ; Tue, 15 Oct 2019 09:06:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nFy0T9OH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728678AbfJOJGl (ORCPT ); Tue, 15 Oct 2019 05:06:41 -0400 Received: from mail-pg1-f195.google.com ([209.85.215.195]:45086 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726343AbfJOJGl (ORCPT ); Tue, 15 Oct 2019 05:06:41 -0400 Received: by mail-pg1-f195.google.com with SMTP id r1so10546626pgj.12 for ; Tue, 15 Oct 2019 02:06:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=u0NadWrCUcjcBtAkG0sbT61miwZyQjEaFhEdj7Qo+Ik=; b=nFy0T9OHJWjUI74D74wpNMbStJprqILj94FgXQY9gkCICHLsNdiuzp9CKXT5lbXVX6 rRUGqkG7yd+4RH9ak+qnL3nzartE3ld8dRwraJjFWAxf6ZSlUgl1j7BT7vJxDdODtEyP AT1CR904qQiup6vKo4K2bNx0YnwmnCbhsRWUbNSMtrHEW9CYceMKwXES7abkPX/8VFH0 9nfJphBlCgInaUOHCOv9Z/S19FZTmYQkIqyvfOUjyFpWH44NRW0aYVA6HYp7Gb/uW0Jd 8UnGYp55cZDOzwTE0899tpFH6RlmVukM0zwpH28iVSdTpCncm1nWtEtRvO3p9kt+gfSc Ayow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=u0NadWrCUcjcBtAkG0sbT61miwZyQjEaFhEdj7Qo+Ik=; b=oG56cykak8jXbtnSTNL3czI/TNJDOWo9KxQgfc9gdihx16FKWRQrG6zCFIXuQp5yj/ 2oAWWx3iepNlSi56sGPUsu9ksXibGww3jKF34fQdFSluthYhKNqnbU8bKq8EzBri+PG/ h/H4nwf5TOGW3Kj1qcQLZZz58hc0YrlFzW4cY+/r1CUJETUaHN4vObzBD9HdvK/sUMBy WG3vqxZcKobJfZ+07PhA+CqcTiZX4V78XxIHSTNuJd7pq2GSEXjusEqoxijNOPe+ZTNL hTyOJIe0gmc0a3SXrsHuIo0QU27la9U4uMYZEbmjJ87Qwf18bmpjoYvyNG0QyH0rvJUT fwmA== X-Gm-Message-State: APjAAAWh1kpBfor+XIy4KJIAwLxjeHEJWbwQybNlmRrpFdVgb7Tt+V0z ibOdm2iDxH56WA9+fb3iWTEUuMsq X-Google-Smtp-Source: APXvYqy3KAuVIr1+79ceHUjuTS2hXydAvHCXoQEV1f+HNRMmrpFQMG4TDBSMGr/+l8ogJRcWu9kTsQ== X-Received: by 2002:a17:90a:86c2:: with SMTP id y2mr40405956pjv.105.1571130400292; Tue, 15 Oct 2019 02:06:40 -0700 (PDT) Received: from generichostname ([2601:646:280:1b30:80db:d816:4d15:ae2a]) by smtp.gmail.com with ESMTPSA id e16sm9457686pgt.68.2019.10.15.02.06.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Oct 2019 02:06:39 -0700 (PDT) Date: Tue, 15 Oct 2019 02:06:37 -0700 From: Denton Liu To: Git Mailing List Cc: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Junio C Hamano , Eric Sunshine , Johannes Sixt , Philip Oakley Subject: [PATCH v6 2/3] format-patch: use enum variables Message-ID: <821e706bae6fd15a3d41022934ee0b290bb47ca5.1571130298.git.liu.denton@gmail.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.2 (2019-09-21) Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Before, `thread` and `config_cover_letter` were defined as ints even though they behaved as enums. Define actual enums and change these variables to use these new definitions. Signed-off-by: Denton Liu Signed-off-by: Junio C Hamano --- builtin/log.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 351f4ffcfd..d212a8305d 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -764,24 +764,28 @@ static void add_header(const char *value) item->string[len] = '\0'; } -#define THREAD_SHALLOW 1 -#define THREAD_DEEP 2 -static int thread; +enum cover_setting { + COVER_UNSET, + COVER_OFF, + COVER_ON, + COVER_AUTO +}; + +enum thread_level { + THREAD_UNSET, + THREAD_SHALLOW, + THREAD_DEEP +}; + +static enum thread_level thread; static int do_signoff; static int base_auto; static char *from; static const char *signature = git_version_string; static const char *signature_file; -static int config_cover_letter; +static enum cover_setting config_cover_letter; static const char *config_output_directory; -enum { - COVER_UNSET, - COVER_OFF, - COVER_ON, - COVER_AUTO -}; - static int git_format_config(const char *var, const char *value, void *cb) { struct rev_info *rev = cb; @@ -1248,9 +1252,9 @@ static int output_directory_callback(const struct option *opt, const char *arg, static int thread_callback(const struct option *opt, const char *arg, int unset) { - int *thread = (int *)opt->value; + enum thread_level *thread = (enum thread_level *)opt->value; if (unset) - *thread = 0; + *thread = THREAD_UNSET; else if (!arg || !strcmp(arg, "shallow")) *thread = THREAD_SHALLOW; else if (!strcmp(arg, "deep")) From patchwork Tue Oct 15 09:06:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 11189895 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEEA014E5 for ; Tue, 15 Oct 2019 09:06:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 84C1020659 for ; Tue, 15 Oct 2019 09:06:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fbgEO0+G" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726564AbfJOJGo (ORCPT ); Tue, 15 Oct 2019 05:06:44 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:35834 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728706AbfJOJGo (ORCPT ); Tue, 15 Oct 2019 05:06:44 -0400 Received: by mail-pg1-f194.google.com with SMTP id p30so11746195pgl.2 for ; Tue, 15 Oct 2019 02:06:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=ep4r63v6s7SqFWriW3mEnhmMApyluvDqGoFVb7HcxUM=; b=fbgEO0+G5j8EJ3yvEsnqIHflZIEBn2HUCL1rN7YkSj6sclXRn3QY89zpuz1qvMmqpV UBQ/Lkp+q19HX47RT9mHJxWcf1ncO/HVR5wrj/M3pqeQolyFpsfN17qFw9rnnK8S9BY6 3Y2CcCFRGBk6pkXWL16I5mDpaiQ9ZZ54dFrumKbMrFNZLPFtFrGmsyqDIwDyRj+6b6uI j9+n+4zrSSogbrvIvnHaTogjmD/m4vkYgbtcoK8sUHXLZCbO/HmskML+xJAhWFG9ogV4 QpY06lYGK4HE3BiYIQFDz1UGfEVCqFfBB9Y1nyfBFjqy2uMwLgyZhJkmD67xRV5c2XG7 C+SQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=ep4r63v6s7SqFWriW3mEnhmMApyluvDqGoFVb7HcxUM=; b=Jreze51UNcYREVfIHxjoRrItXbiuS2PNclWtg189QIG3mDTZH9IUVJqHign5afFxDD fkjITAd/xCSzyu3dapwn628DRkuOmNCKb/7NmvDvtTm8jsX0Al5U5OqsQHLCYIolG1g/ rP7Z+6nK/WCEdmrx5D346re8CE3k4a9xtrOVHxHMW9+4scmQf4VYx1G/qAsA8hpi0faH no/V81ghBb1EjFIm4hVtiHHkxmlr+aCvlSUIUHkV7i33QcghGFng27LLkqR1fsQTz/Gz ePt1aX+TiFeFOp28wjuCr/j2gLJh3Ve4l7kP1G18RJdppTzyEUmZRyQxEoLiqmYVFIZa xtcQ== X-Gm-Message-State: APjAAAWUwvG806SYjoaYwvVK2I0Xbm1GRHSdCPmHgUcL/u97Poa0UOTo YZmayIFLXLYxIapJ5mjbo9BdR/lo X-Google-Smtp-Source: APXvYqxFpJ/12VSVfoHCKyAYTs167geGjAdT740j4n81kALNn18OYPqdPkeAxWXUl5yhFxZeLbZFBw== X-Received: by 2002:a62:68c1:: with SMTP id d184mr37709423pfc.195.1571130402874; Tue, 15 Oct 2019 02:06:42 -0700 (PDT) Received: from generichostname ([2601:646:280:1b30:80db:d816:4d15:ae2a]) by smtp.gmail.com with ESMTPSA id b16sm27442156pfb.54.2019.10.15.02.06.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Oct 2019 02:06:42 -0700 (PDT) Date: Tue, 15 Oct 2019 02:06:40 -0700 From: Denton Liu To: Git Mailing List Cc: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsA==?= Bjarmason , Junio C Hamano , Eric Sunshine , Johannes Sixt , Philip Oakley Subject: [PATCH v6 3/3] format-patch: teach --cover-from-description option Message-ID: <42b4a60fd29678f2de62c784027b9d355a913397.1571130298.git.liu.denton@gmail.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.2 (2019-09-21) Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org 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 Signed-off-by: Junio C Hamano --- Documentation/config/format.txt | 6 + Documentation/git-format-patch.txt | 22 ++++ builtin/log.c | 95 ++++++++++++---- t/t4014-format-patch.sh | 172 +++++++++++++++++++++++++++++ t/t9902-completion.sh | 5 +- 5 files changed, 279 insertions(+), 21 deletions(-) diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt index cb629fa769..735dfcf827 100644 --- a/Documentation/config/format.txt +++ b/Documentation/config/format.txt @@ -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. diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 0ac56f4b70..6800e1ab9a 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -19,6 +19,7 @@ SYNOPSIS [--start-number ] [--numbered-files] [--in-reply-to=] [--suffix=.] [--ignore-if-in-upstream] + [--cover-from-description=] [--rfc] [--subject-prefix=] [(--reroll-count|-v) ] [--to=] [--cc=] @@ -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=:: + Controls which parts of the cover letter will be automatically + populated using the branch's description. ++ +If `` 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 `` 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 `` 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 `` is `none`, both the cover letter subject and body will be +populated with placeholder text. + --subject-prefix=:: Instead of the standard '[PATCH]' prefix in the subject line, instead use '[]'. This @@ -347,6 +368,7 @@ with configuration variables. signOff = true outputDirectory = coverLetter = auto + coverFromDescription = auto ------------ diff --git a/builtin/log.c b/builtin/log.c index d212a8305d..04be559bd2 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -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 [] 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", diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 72b09896cf..88db01308a 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1517,6 +1517,178 @@ test_expect_success 'format patch ignores color.ui' ' test_cmp expect actual ' +test_expect_success 'cover letter with invalid --cover-from-description and config' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_must_fail git format-patch --cover-letter --cover-from-description garbage master && + test_config format.coverFromDescription garbage && + test_must_fail git format-patch --cover-letter master +' + +test_expect_success 'cover letter with format.coverFromDescription = default' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.coverFromDescription default && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with --cover-from-description default' ' + test_config branch.rebuild-1.description "config subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description default master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with format.coverFromDescription = none' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.coverFromDescription none && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + ! grep "^body$" actual +' + +test_expect_success 'cover letter with --cover-from-description none' ' + test_config branch.rebuild-1.description "config subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description none master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + ! grep "^body$" actual +' + +test_expect_success 'cover letter with format.coverFromDescription = message' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.coverFromDescription message && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with --cover-from-description message' ' + test_config branch.rebuild-1.description "config subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description message master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with format.coverFromDescription = subject' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.coverFromDescription subject && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with --cover-from-description subject' ' + test_config branch.rebuild-1.description "config subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description subject master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with format.coverFromDescription = auto (short subject line)' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.coverFromDescription auto && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with --cover-from-description auto (short subject line)' ' + test_config branch.rebuild-1.description "config subject + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description auto master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with format.coverFromDescription = auto (long subject line)' ' + test_config branch.rebuild-1.description "this is a really long first line and it is over 100 characters long which is the threshold for long subjects + +body" && + test_config format.coverFromDescription auto && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + grep "^this is a really long first line and it is over 100 characters long which is the threshold for long subjects$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with --cover-from-description auto (long subject line)' ' + test_config branch.rebuild-1.description "this is a really long first line and it is over 100 characters long which is the threshold for long subjects + +body" && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description auto master >actual && + grep "^Subject: \[PATCH 0/2\] \*\*\* SUBJECT HERE \*\*\*$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + grep "^this is a really long first line and it is over 100 characters long which is the threshold for long subjects$" actual && + grep "^body$" actual +' + +test_expect_success 'cover letter with command-line --cover-from-description overrides config' ' + test_config branch.rebuild-1.description "config subject + +body" && + test_config format.coverFromDescription none && + git checkout rebuild-1 && + git format-patch --stdout --cover-letter --cover-from-description subject master >actual && + grep "^Subject: \[PATCH 0/2\] config subject$" actual && + ! grep "^\*\*\* BLURB HERE \*\*\*$" actual && + ! grep "^config subject$" actual && + grep "^body$" actual +' + test_expect_success 'cover letter using branch description (1)' ' git checkout rebuild-1 && test_config branch.rebuild-1.description hello && diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 75512c3403..5187e2ede5 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -1548,7 +1548,10 @@ test_expect_success 'complete tree filename with metacharacters' ' ' test_expect_success PERL 'send-email' ' - test_completion "git send-email --cov" "--cover-letter " && + test_completion "git send-email --cov" <<-\EOF && + --cover-from-description=Z + --cover-letter Z + EOF test_completion "git send-email ma" "master " '