From patchwork Mon Oct 14 20:46:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 11189411 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 E6DC217E6 for ; Mon, 14 Oct 2019 20:47:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C8827217D9 for ; Mon, 14 Oct 2019 20:47:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ADXkIpHo" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387973AbfJNUrD (ORCPT ); Mon, 14 Oct 2019 16:47:03 -0400 Received: from mail-pg1-f196.google.com ([209.85.215.196]:43525 "EHLO mail-pg1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727879AbfJNUrC (ORCPT ); Mon, 14 Oct 2019 16:47:02 -0400 Received: by mail-pg1-f196.google.com with SMTP id i32so10732992pgl.10 for ; Mon, 14 Oct 2019 13:47:02 -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=9PdrpY76MAcG/lD3vgaxj2WyD/3XJP3q2wgW4VbWKYQ=; b=ADXkIpHo6/eog3seRUUNz2JgIysxTuVdH2pTLtdU3AKx6eg9u3GANKg2SXuobnqsW3 CgXYx9N7nzHziT/0tjdwzafIZnjgcdjIgZEDLZtfW5JaZoJOVCC98zZuiNMnTak2uwco MvG0ROBUnZDbjWKEXTNmCfFf4aRg8Ne8X05gopoKzD+MaUfsYAg9SMYXfMGLGO7Fhimn 7IDHp4T/o/D8IJt8U1MNQENGlKbs8+0DHSkV5VoIjuNPNxtXy+Ady2ynINaxsrpr9X/w kSjujzOpbPQ2ehHR4Fv38XYjuybxLMBpd534gFajEYcUJHDtxlSa4wbpslU/Hc/W7FSq BZOA== 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=9PdrpY76MAcG/lD3vgaxj2WyD/3XJP3q2wgW4VbWKYQ=; b=o/4lcZ7l1v0puvEgC3vbx4ukxcXXk9TeF3H29EvRz6uaq8NbYNSAzFSGsGnhixmWio YQyQ2RytCjRIAbfUG3hRZGDa8s4meQnzWwNxqXXDHto73ht6iOePKpF5mcXZHPDmvCCv imXd/J3GnoiBfRBeXPpU6/4PGD9oJMDpyTXyJREnM19fGvTzx19n48PaEyyveks+RDWY UlWvSb5n2GN7Olws5yoGX1Glg7YYVUYSaNXWAvOrKBCGvZw9Fs5AyD0MTWP/q3R9xkZc CMGToA/Am09TzlBuuLw8ntAGTX3LI+LA4U/h9Wz6LXYiAJaECtrsOREoU+ggcKsTUqCW nGTA== X-Gm-Message-State: APjAAAUf/a0gegtDw33DcaF6sqSq0B37J8djWH6Eq1oAKyaE/cSF24c0 Fkn+LzOkgCChU7qd7CNbNHhk52Cx X-Google-Smtp-Source: APXvYqyNkRHKfU/XNo5kdEH/lNnp38HUGPIO09NgGddAGuUWgsUUpGWXR+cIktWppnc8wMHNgpej0w== X-Received: by 2002:a63:c40e:: with SMTP id h14mr34705890pgd.254.1571086021493; Mon, 14 Oct 2019 13:47:01 -0700 (PDT) Received: from generichostname ([204.14.239.53]) by smtp.gmail.com with ESMTPSA id r28sm24113245pfg.62.2019.10.14.13.47.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Oct 2019 13:47:00 -0700 (PDT) Date: Mon, 14 Oct 2019 13:46:59 -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 v5 1/3] format-patch: change erroneous and condition Message-ID: <56fb230ad271dc9aa91c0f43ac8e4e7085c15775.1571085952.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. In Python, `x and y` is equivalent to `y if x else x`[1]. Since this seems to be a Python-ism that's mistakenly leaked into our code, convert this to the equivalent C expression. [1]: https://docs.python.org/3/reference/expressions.html#boolean-operations 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 Mon Oct 14 20:47:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 11189415 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 AD9E017D4 for ; Mon, 14 Oct 2019 20:47:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8D8E421721 for ; Mon, 14 Oct 2019 20:47:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Dwd9igEt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388141AbfJNUrF (ORCPT ); Mon, 14 Oct 2019 16:47:05 -0400 Received: from mail-pl1-f193.google.com ([209.85.214.193]:35557 "EHLO mail-pl1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727879AbfJNUrF (ORCPT ); Mon, 14 Oct 2019 16:47:05 -0400 Received: by mail-pl1-f193.google.com with SMTP id c3so8513742plo.2 for ; Mon, 14 Oct 2019 13:47:05 -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=Z76E7X52AQXx+/EuqnvQYe44BKFe0tLNUdXqX5tBhLk=; b=Dwd9igEtPfzOsWBEP3K3txzRYAH13kwMGTQAl+QOl1sI7O7gTf8vjNloq0dgSC90F2 fzjqazaiP/lBLOf1jua9sXIK/UIxVfmmJwqrWvMLTjtUvkuDohhBVhorBwijpHu5JOEN vYIqdNF5uqwLI1SzNmt1Tw4beKS6nk1yeiStjrOvj51zbEZlBhi4+Y7jfP1lt7K0sHfK /IHMMltEeWUFS09CWeu+6dxdWOBTBENBbVcHBTHu6EdA/UTvdZOq3E9RmLx0yhYK83o9 da95mvPeqGg1d5CFdjG+Y7JdeTOFDKL2cUmgZy2j6+cfpUHENmnaCqbN8kANFKc2ZjLy Z7vw== 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=Z76E7X52AQXx+/EuqnvQYe44BKFe0tLNUdXqX5tBhLk=; b=aWK/kqlYxh2IQKq7crYbx63QH2u3dQLhVaXdkflgdKs00sY6HQKDoTzCxRE/0H7Xfa qXnG3PGFX2fQDFsNEaSk08X+1npKg3M17I6HGeOhMQ64oTXOfr9rmyLWpjG1tM0gWc0J pOSM42hYu6pD6V4y7RfQDd1YNBSY/VPZMirFo4fLIzUkfn0EXc6P1ITWVsAWEoo7y5hs pG3ALUkCaiP880Zr06jxnsPfUcXEqufzFs6h26XXlZSdA18GKje+p2Si+72X9sqVNZUC ZtmGD5Yppfjad9fKx0BlIP7virJCpzNubUREQz1CPv+yu/1AkwmvranXnM2I6YyZko2O gtvw== X-Gm-Message-State: APjAAAUKXwV2pTZqxwclsBXm5hs5jw/UT90i0QaZVDSdaDC074o2vJTQ wbHG4bYMu5ktgw1vOamOUwPPwyxQ X-Google-Smtp-Source: APXvYqwK4N19lY15zbuZL2Ngdn7rxbU1dbzDAtfQzQEOBR6yPStrV116ESYpukW9MaZfhE/Ot+dFSA== X-Received: by 2002:a17:902:b685:: with SMTP id c5mr15653149pls.215.1571086024109; Mon, 14 Oct 2019 13:47:04 -0700 (PDT) Received: from generichostname ([204.14.239.53]) by smtp.gmail.com with ESMTPSA id b3sm15360249pjp.13.2019.10.14.13.47.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Oct 2019 13:47:03 -0700 (PDT) Date: Mon, 14 Oct 2019 13:47:01 -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 v5 2/3] format-patch: use enum variables Message-ID: 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 --- Hi Junio, I double-checked and made sure that there is no arithmetic done on the new enums. 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 Mon Oct 14 20:47:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denton Liu X-Patchwork-Id: 11189417 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 B1D7E17D4 for ; Mon, 14 Oct 2019 20:47:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8032D217D9 for ; Mon, 14 Oct 2019 20:47:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ugB3VqTn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388285AbfJNUrI (ORCPT ); Mon, 14 Oct 2019 16:47:08 -0400 Received: from mail-pl1-f195.google.com ([209.85.214.195]:43422 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727879AbfJNUrI (ORCPT ); Mon, 14 Oct 2019 16:47:08 -0400 Received: by mail-pl1-f195.google.com with SMTP id f21so8496146plj.10 for ; Mon, 14 Oct 2019 13:47:07 -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=iII+H9c8Lu+bzOTXm20oOZW/Oh2JydL5XSy0HlJcZB0=; b=ugB3VqTncQvYEyqkp5sHeDLCkarqLq/OVzZMsAMHy9Tn7SEf1ewKv/sIpggFMjH/ae fe3tI2Vdfx9DqjxoncF6CSYJj6LDNXAMPNA9dzOcUYxWuQQpTe45wYu6EYX/6mXIPO+q n96eMQq86S8eukQioBiVqiCCRz3DZ5MbAVG2K1bna8XmcTJMNSf2GkVxaPv3QXib14ZZ bZ/2y8Ywis1uYhKNyywlK2Pnez9itNpS81Zsz57IzbISLZDBAAzfxZc58L2QMcuPyYnf osKhcxOI2p4SoAJp0SZbugXk0820DJVW+KLwidWuaGvNy7H/w4YhNrkuEMuY34F+d0UE 3N9w== 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=iII+H9c8Lu+bzOTXm20oOZW/Oh2JydL5XSy0HlJcZB0=; b=Lkbp5Z2DXFJcN97QIbv8ejRw3X6dSZEkbnpFipDmR5J2IpnrGmD51ASQCfGS8dAvxR L3YF3/tNr8kj707Eso+KJZZc1tzkJp1W3PM8NpfAnjTZtFtOBKzRLyuS+JKefCdsgFgC OMjOi7RGNY/hCksm9L4GfM7HEmK24JVl7czSbE10owFd11Ao0Blh18UEfB2P+j04koeW PsPzptnPKQNV+/NNxI07kzRQng/C8I267rmIvn5KQFrpv2icNREa0kfc37pgrva8qGgJ DqLZSkaZ6HKIQAQwxbStu1ZyWcJqFO3FBbvfbDkJJA86iYnDmithIrHkdbZodgPYyr2B k8jg== X-Gm-Message-State: APjAAAWq0dXicroDOktqZjFmSgUCEgD0eGB4T/svdPhpi5CqVHH3zop2 11jiUDUI4jiEzhuiw4ws59zNWpgK X-Google-Smtp-Source: APXvYqy1uhCmCxk8u7TYiKDej0IAzG5OOvuH/MkflgIXyo96s2SPv+XdqoUeVQLX0YKapo4Smo4ceA== X-Received: by 2002:a17:902:7c8a:: with SMTP id y10mr15595487pll.115.1571086026698; Mon, 14 Oct 2019 13:47:06 -0700 (PDT) Received: from generichostname ([204.14.239.53]) by smtp.gmail.com with ESMTPSA id r18sm25614187pfc.3.2019.10.14.13.47.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Oct 2019 13:47:06 -0700 (PDT) Date: Mon, 14 Oct 2019 13:47:04 -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 v5 3/3] format-patch: teach --cover-from-description option Message-ID: <315c308950270968293c92c94fdadd3be3340c33.1571085952.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 --- 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..af33fe9ffb 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 pp_from_desc(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); + pp_from_desc(&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 " '