public inbox for tools@linux.kernel.org
 help / color / mirror / Atom feed
* [PATCH b4] send: Add --force-cover-letter to send separate cover for single patch patch series
@ 2026-01-27 12:53 Breno Leitao
  2026-01-28 18:14 ` Luca Ceresoli
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Breno Leitao @ 2026-01-27 12:53 UTC (permalink / raw)
  To: Kernel.org Tools; +Cc: Konstantin Ryabitsev, kernel-team, Breno Leitao

By default, b4 mixes the cover letter content into the patch body
(under the --- cut line) when sending a single-patch series. Add
--force-cover-letter option to allow sending a separate cover letter
message (as 0/1) even for single-patch series.

This is useful when developers want to send a long cover letter with
extra information about an issue, and a commit. Having the cover-letter
"mixed-in" makes it hard to follow.

Example:
 * https://lore.kernel.org/all/20260127-ipmi-v1-0-ba5cc90f516f@debian.org/

Signed-off-by: Breno Leitao <leitao@debian.org>
---
 src/b4/command.py |  2 ++
 src/b4/ez.py      | 16 +++++++++-------
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/b4/command.py b/src/b4/command.py
index 1f8b8f1..0e685cd 100644
--- a/src/b4/command.py
+++ b/src/b4/command.py
@@ -397,6 +397,8 @@ def setup_parser() -> argparse.ArgumentParser:
                          help='Resend a previously sent version of the series')
     sp_send.add_argument('--no-sign', action='store_true', default=False,
                          help='Do not add the cryptographic attestation signature header')
+    sp_send.add_argument('--force-cover-letter', action='store_true', default=False,
+                         help='Send a cover letter even for single-patch series')
     sp_send.add_argument('--use-web-endpoint', dest='send_web', action='store_true', default=False,
                          help="Force going through the web endpoint")
     ag_sendh = sp_send.add_argument_group('Web submission', 'Authenticate with the web submission endpoint')
diff --git a/src/b4/ez.py b/src/b4/ez.py
index 298e382..42379a7 100644
--- a/src/b4/ez.py
+++ b/src/b4/ez.py
@@ -1567,7 +1567,7 @@ def rethread(patches: List[Tuple[str, EmailMessage]]) -> None:
 
 def get_prep_branch_as_patches(movefrom: bool = True, thread: bool = True, addtracking: bool = True,
                                prefixes: Optional[List[str]] = None, usebranch: Optional[str] = None,
-                               expandprereqs: bool = True,
+                               expandprereqs: bool = True, force_cover: bool = False,
                                ) -> Tuple[List[Tuple[str, str]], List[Tuple[str, str]], str, List[Tuple[str, EmailMessage]]]:
     cover, tracking = load_cover(strip_comments=True, usebranch=usebranch)
 
@@ -1735,7 +1735,7 @@ def get_prep_branch_as_patches(movefrom: bool = True, thread: bool = True, addtr
     thdata = ''.join(wrapped).replace('X-B4-Tracking: ', '')
 
     alltos, allccs, cbody = get_cover_dests(cover_letter)
-    if len(patches) == 1:
+    if len(patches) == 1 and not force_cover:
         mixin_cover(cbody, patches)
     else:
         add_cover(csubject, msgid_tpt, patches, cbody, seriests, thread=thread, presubject=presubject)
@@ -1767,7 +1767,7 @@ def get_prep_branch_as_patches(movefrom: bool = True, thread: bool = True, addtr
     return alltos, allccs, tag_msg, patches
 
 
-def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None) \
+def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None, force_cover: bool = False) \
         -> Tuple[List[Tuple[str, str]], List[Tuple[str, str]], List[Tuple[str, EmailMessage]]]:
     cover, base_commit, change_id = get_base_changeid_from_tag(tagname)
 
@@ -1787,7 +1787,7 @@ def get_sent_tag_as_patches(tagname: str, revision: int, presubject: str = None)
                                       presubject=presubject)
 
     alltos, allccs, cbody = get_cover_dests(cbody)
-    if len(patches) == 1:
+    if len(patches) == 1 and not force_cover:
         mixin_cover(cbody, patches)
     else:
         add_cover(csubject, msgid_tpt, patches, cbody, seriests)
@@ -1942,8 +1942,9 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
         presubject = tracking['series'].get('presubject', None)
 
         try:
-            todests, ccdests, patches = get_sent_tag_as_patches(tagname, revision=revision, 
-                                                                presubject=presubject)
+            todests, ccdests, patches = get_sent_tag_as_patches(tagname, revision=revision,
+                                                                presubject=presubject,
+                                                                force_cover=cmdargs.force_cover_letter)
         except RuntimeError as ex:
             logger.critical('CRITICAL: Failed to convert tag to patches: %s', ex)
             sys.exit(1)
@@ -1963,7 +1964,8 @@ def cmd_send(cmdargs: argparse.Namespace) -> None:
             prefixes = None
 
         try:
-            todests, ccdests, tag_msg, patches = get_prep_branch_as_patches(prefixes=prefixes)
+            todests, ccdests, tag_msg, patches = get_prep_branch_as_patches(prefixes=prefixes,
+                                                                            force_cover=cmdargs.force_cover_letter)
         except RuntimeError as ex:
             logger.critical('CRITICAL: Failed to convert range to patches: %s', ex)
             sys.exit(1)

---
base-commit: 477734000555ffc24bf873952e40367deee26f17
change-id: 20260127-force-cover-letter-e17dfceb28e4

Best regards,
--  
Breno Leitao <leitao@debian.org>


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-02-24 18:57 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-27 12:53 [PATCH b4] send: Add --force-cover-letter to send separate cover for single patch patch series Breno Leitao
2026-01-28 18:14 ` Luca Ceresoli
2026-01-28 18:47   ` Breno Leitao
2026-01-29 11:18 ` Antonin Godard
2026-01-29 13:21   ` Breno Leitao
2026-01-29 13:51     ` Antonin Godard
2026-01-29 14:03       ` Breno Leitao
2026-01-29 14:15         ` Mark Brown
2026-01-29 15:00           ` Breno Leitao
2026-02-24 18:57 ` Konstantin Ryabitsev

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox