aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Ryabitsev <konstantin@linuxfoundation.org>2021-06-08 10:57:05 -0400
committerKonstantin Ryabitsev <konstantin@linuxfoundation.org>2021-06-08 10:57:05 -0400
commit1ac98d05d1a665f4376e3652163b9f3c17b6f808 (patch)
treee96d6cea41a2bacc1deccb548c270ba09dcc10c4
parentc2e1aa9cbbf3d89aef501a23befa3dd59e0309dc (diff)
downloadb4-1ac98d05d1a665f4376e3652163b9f3c17b6f808.tar.gz
Tentative suport for sending exploded series
I've been working on a way to automatically convert pull requests into series, complete with mailing them out to arbitrary destinations. This would allow folks to send a pull request to a dedicated list and have it automatically converted into a well-formed series. This is a tentative implementation that relies on git-send-email to do most of the heavy lifting. I have misgivings about using git-send-email for this purpose, but it does reduce the amount of duplicated code we would have otherwise had to write, and allows us to hook into things like tocmd/cccmd, etc. For example, adding the following to your .git/config: [sendemail "autopr"] smtpserver = [your.server.here] smtpserverport = 587 smtpencryption = tls smtpuser = [your-user] smtppass = [your-pass] transferEncoding = 8bit suppressFrom = yes confirm = never validate = no tocmd = "$(git rev-parse --show-toplevel)/scripts/get_maintainer.pl --norolestats --nol" cccmd = "$(git rev-parse --show-toplevel)/scripts/get_maintainer.pl --norolestats --nom" This would allow doing the following: b4 pr -e -f "AutoPR Exploder <autopr@yourdomain.here>" -s autopr [--dry-run] The pull request will be exploded into a patch series and sent to all the proper destinations as returned by get_maintainer.pl. We construct the message headers in a way that allow regular code review and "b4 am" usage after the auto-exploded series is sent out. If testing goes well, we'll implement this as a kernel.org service and then hook a similar implementation via Gitlab/Github. Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
-rw-r--r--b4/command.py5
-rw-r--r--b4/pr.py94
2 files changed, 66 insertions, 33 deletions
diff --git a/b4/command.py b/b4/command.py
index 3f130c8..2d6994d 100644
--- a/b4/command.py
+++ b/b4/command.py
@@ -160,6 +160,11 @@ def cmd():
help='Attempt to retrieve any Link: URLs (use with -e)')
sp_pr.add_argument('-f', '--from-addr', dest='mailfrom', default=None,
help='Use this From: in exploded messages (use with -e)')
+ sp_pr.add_argument('-s', '--send-as-identity', dest='sendidentity', default=None,
+ help=('Use git-send-email to send exploded series (use with -e);'
+ 'the identity must match a [sendemail "identity"] config section'))
+ sp_pr.add_argument('--dry-run', dest='dryrun', action='store_true', default=False,
+ help='Force a --dry-run on git-send-email invocation (use with -s)')
sp_pr.add_argument('msgid', nargs='?',
help='Message ID to process, or pipe a raw message')
sp_pr.set_defaults(func=cmd_pr)
diff --git a/b4/pr.py b/b4/pr.py
index 98de07b..1e308d8 100644
--- a/b4/pr.py
+++ b/b4/pr.py
@@ -322,19 +322,22 @@ def explode(gitdir, lmsg, mailfrom=None, retrieve_links=True, fpopts=None):
# Is this the cover letter?
if msubj.counter == 0:
# We rebuild the message from scratch
- cmsg = MIMEMultipart()
- cmsg.add_header('From', mailfrom)
- cmsg.add_header('Subject', '[' + ' '.join(msubj.prefixes) + '] ' + lmsg.subject)
- cmsg.add_header('Date', lmsg.msg.get('Date'))
-
# The cover letter body is the pull request body, plus a few trailers
body = '%s\n\nbase-commit: %s\nPR-Link: %s\n' % (
lmsg.body.strip(), lmsg.pr_base_commit, config['linkmask'] % lmsg.msgid)
- cmsg.attach(MIMEText(body, 'plain'))
- # now we attach the original request
- # XXX: seems redundant, so turned off for now
- # cmsg.attach(MIMEMessage(lmsg.msg))
+ # Make it a multipart if we're doing retrieve_links
+ if retrieve_links:
+ cmsg = MIMEMultipart()
+ cmsg.attach(MIMEText(body, 'plain'))
+ else:
+ cmsg = email.message.EmailMessage()
+ cmsg.set_payload(body)
+
+ cmsg.add_header('From', mailfrom)
+ cmsg.add_header('Subject', '[' + ' '.join(msubj.prefixes) + '] ' + lmsg.subject)
+ cmsg.add_header('Date', lmsg.msg.get('Date'))
+
msg = cmsg
else:
@@ -456,20 +459,6 @@ def main(cmdargs):
lmsg.pr_tip_commit = lmsg.pr_remote_tip_commit
if cmdargs.explode:
- config = b4.get_main_config()
- if config.get('save-maildirs', 'no') == 'yes':
- save_maildir = True
- dftext = 'maildir'
- else:
- save_maildir = False
- dftext = 'mbx'
- savefile = cmdargs.outmbox
- if savefile is None:
- savefile = f'{lmsg.msgid}.{dftext}'
- if os.path.exists(savefile):
- logger.info('File exists: %s', savefile)
- sys.exit(1)
-
# Set up a temporary clone
with b4.git_temp_clone(gitdir) as tc:
try:
@@ -478,19 +467,58 @@ def main(cmdargs):
logger.critical('Nothing exploded.')
sys.exit(1)
- if msgs:
- if save_maildir:
- b4.save_maildir(msgs, savefile)
- else:
- with open(savefile, 'wb') as fh:
- b4.save_git_am_mbox(msgs, fh)
- logger.info('---')
- logger.info('Saved %s', savefile)
- sys.exit(0)
+ if msgs:
+ if cmdargs.sendidentity:
+ # Pass exploded series via git-send-email
+ config = b4.get_config_from_git(rf'sendemail\.{cmdargs.sendidentity}\..*')
+ if not len(config):
+ logger.critical('Not able to find sendemail.%s configuration', cmdargs.sendidentity)
+ sys.exit(1)
+ # Make sure from is not overridden by current user
+ mailfrom = msgs[0].get('from')
+ gitargs = ['send-email', '--identity', cmdargs.sendidentity, '--from', mailfrom]
+ if cmdargs.dryrun:
+ gitargs.append('--dry-run')
+ # Write out everything into a temporary dir
+ counter = 0
+ with tempfile.TemporaryDirectory() as tfd:
+ for msg in msgs:
+ outfile = os.path.join(tfd, '%04d' % counter)
+ with open(outfile, 'wb') as tfh:
+ tfh.write(msg.as_string(policy=b4.emlpolicy).encode())
+ gitargs.append(outfile)
+ counter += 1
+ ecode, out = b4.git_run_command(cmdargs.gitdir, gitargs, logstderr=True)
+ if cmdargs.dryrun:
+ logger.info(out)
+ sys.exit(ecode)
+
+ config = b4.get_main_config()
+ if config.get('save-maildirs', 'no') == 'yes':
+ save_maildir = True
+ dftext = 'maildir'
else:
- logger.critical('Nothing exploded.')
+ save_maildir = False
+ dftext = 'mbx'
+ savefile = cmdargs.outmbox
+ if savefile is None:
+ savefile = f'{lmsg.msgid}.{dftext}'
+ if os.path.exists(savefile):
+ logger.info('File exists: %s', savefile)
sys.exit(1)
+ if save_maildir:
+ b4.save_maildir(msgs, savefile)
+ else:
+ with open(savefile, 'wb') as fh:
+ b4.save_git_am_mbox(msgs, fh)
+ logger.info('---')
+ logger.info('Saved %s', savefile)
+ sys.exit(0)
+ else:
+ logger.critical('Nothing exploded.')
+ sys.exit(1)
+
exists = b4.git_commit_exists(gitdir, lmsg.pr_tip_commit)
if exists:
# Is it in any branch, or just flapping in the wind?