diff options
Diffstat (limited to 'b4/ty.py')
-rw-r--r-- | b4/ty.py | 186 |
1 files changed, 111 insertions, 75 deletions
@@ -7,10 +7,12 @@ __author__ = 'Konstantin Ryabitsev <konstantin@linuxfoundation.org>' import os import sys + import b4 import re import email import email.message +import email.policy import json from string import Template @@ -72,28 +74,27 @@ def git_get_commit_message(gitdir, rev): return b4.git_run_command(gitdir, args) -def make_reply(reply_template, jsondata): +def make_reply(reply_template, jsondata, gitdir): body = Template(reply_template).safe_substitute(jsondata) # Conform to email standards body = body.replace('\n', '\r\n') msg = email.message_from_string(body) msg['From'] = '%s <%s>' % (jsondata['myname'], jsondata['myemail']) - allto = utils.getaddresses([jsondata['to']]) - allcc = utils.getaddresses([jsondata['cc']]) - # Remove ourselves and original sender from allto or allcc - for entry in list(allto): - if entry[1] == jsondata['myemail'] or entry[1] == jsondata['fromemail']: - allto.remove(entry) - for entry in list(allcc): - if entry[1] == jsondata['myemail'] or entry[1] == jsondata['fromemail']: - allcc.remove(entry) - - # Add original sender to the To - allto.append((jsondata['fromname'], jsondata['fromemail'])) - - msg['To'] = b4.format_addrs(allto) + excludes = b4.get_excluded_addrs() + newto = b4.cleanup_email_addrs([(jsondata['fromname'], jsondata['fromemail'])], excludes, gitdir) + + # Exclude ourselves and original sender from allto or allcc + excludes.add(jsondata['myemail']) + excludes.add(jsondata['fromemail']) + allto = b4.cleanup_email_addrs(utils.getaddresses([jsondata['to']]), excludes, gitdir) + allcc = b4.cleanup_email_addrs(utils.getaddresses([jsondata['cc']]), excludes, gitdir) + + if newto: + allto += newto + + msg.add_header('To', b4.format_addrs(allto)) if allcc: - msg['Cc'] = b4.format_addrs(allcc) + msg.add_header('Cc', b4.format_addrs(allcc)) msg['In-Reply-To'] = '<%s>' % jsondata['msgid'] if len(jsondata['references']): msg['References'] = '%s <%s>' % (jsondata['references'], jsondata['msgid']) @@ -102,9 +103,9 @@ def make_reply(reply_template, jsondata): subject = re.sub(r'^Re:\s+', '', jsondata['subject'], flags=re.I) if jsondata.get('cherrypick'): - msg['Subject'] = 'Re: (subset) ' + subject + msg.add_header('Subject', 'Re: (subset) ' + subject) else: - msg['Subject'] = 'Re: ' + subject + msg.add_header('Subject', 'Re: ' + subject) mydomain = jsondata['myemail'].split('@')[1] msg['Message-Id'] = email.utils.make_msgid(idstring='b4-ty', domain=mydomain) @@ -228,21 +229,6 @@ def auto_locate_series(gitdir, jsondata, branch, since='1.week'): return found -def read_template(tptfile): - # bubbles up FileNotFound - tpt = '' - if tptfile.find('~') >= 0: - tptfile = os.path.expanduser(tptfile) - if tptfile.find('$') >= 0: - tptfile = os.path.expandvars(tptfile) - with open(tptfile, 'r', encoding='utf-8') as fh: - for line in fh: - if len(line) and line[0] == '#': - continue - tpt += line - return tpt - - def set_branch_details(gitdir, branch, jsondata, config): binfo = get_branch_info(gitdir, branch) jsondata['branch'] = branch @@ -282,7 +268,7 @@ def generate_pr_thanks(gitdir, jsondata, branch): if config['thanks-pr-template']: # Try to load this template instead try: - thanks_template = read_template(config['thanks-pr-template']) + thanks_template = b4.read_template(config['thanks-pr-template']) except FileNotFoundError: logger.critical('ERROR: thanks-pr-template says to use %s, but it does not exist', config['thanks-pr-template']) @@ -300,7 +286,7 @@ def generate_pr_thanks(gitdir, jsondata, branch): if not cidmask: cidmask = 'merge commit: %s' jsondata['summary'] = cidmask % jsondata['merge_commit_id'] - msg = make_reply(thanks_template, jsondata) + msg = make_reply(thanks_template, jsondata, gitdir) return msg @@ -311,7 +297,7 @@ def generate_am_thanks(gitdir, jsondata, branch, since): if config['thanks-am-template']: # Try to load this template instead try: - thanks_template = read_template(config['thanks-am-template']) + thanks_template = b4.read_template(config['thanks-am-template']) except FileNotFoundError: logger.critical('ERROR: thanks-am-template says to use %s, but it does not exist', config['thanks-am-template']) @@ -348,7 +334,7 @@ def generate_am_thanks(gitdir, jsondata, branch, since): nomatch, len(commits), jsondata['subject']) logger.critical(' Please review the resulting message') - msg = make_reply(thanks_template, jsondata) + msg = make_reply(thanks_template, jsondata, gitdir) return msg @@ -389,35 +375,38 @@ def auto_thankanator(cmdargs): sys.exit(0) logger.info('---') - send_messages(applied, cmdargs.gitdir, cmdargs.outdir, wantbranch, since=cmdargs.since) + send_messages(applied, wantbranch, cmdargs) sys.exit(0) -def send_messages(listing, gitdir, outdir, branch, since='1.week'): - # Not really sending, but writing them out to be sent on your own - # We'll probably gain ability to send these once the feature is - # more mature and we're less likely to mess things up - datadir = b4.get_data_dir() +def send_messages(listing, branch, cmdargs): logger.info('Generating %s thank-you letters', len(listing)) - # Check if the outdir exists and if it has any .thanks files in it - if not os.path.exists(outdir): - os.mkdir(outdir) + gitdir = cmdargs.gitdir + datadir = b4.get_data_dir() + fromaddr = None + smtp = None + if cmdargs.sendemail: + # See if we have sendemail-identity set + config = b4.get_main_config() + identity = config.get('sendemail-identity') + try: + smtp, fromaddr = b4.get_smtp(identity) + except Exception as ex: # noqa + logger.critical('Failed to configure the smtp connection:') + logger.critical(ex) + sys.exit(1) + else: + # We write .thanks notes + # Check if the outdir exists and if it has any .thanks files in it + if not os.path.exists(cmdargs.outdir): + os.mkdir(cmdargs.outdir) usercfg = b4.get_user_config() - # Do we have a .signature file? - sigfile = os.path.join(str(Path.home()), '.signature') - if os.path.exists(sigfile): - with open(sigfile, 'r', encoding='utf-8') as fh: - signature = fh.read() - else: - signature = '%s <%s>' % (usercfg['name'], usercfg['email']) + signature = b4.get_email_signature() outgoing = 0 + msgids = list() for jsondata in listing: - slug_from = re.sub(r'\W', '_', jsondata['fromemail']) - slug_subj = re.sub(r'\W', '_', jsondata['subject']) - slug = '%s_%s' % (slug_from.lower(), slug_subj.lower()) - slug = re.sub(r'_+', '_', slug) jsondata['myname'] = usercfg['name'] jsondata['myemail'] = usercfg['email'] jsondata['signature'] = signature @@ -426,29 +415,65 @@ def send_messages(listing, gitdir, outdir, branch, since='1.week'): msg = generate_pr_thanks(gitdir, jsondata, branch) else: # This is a patch series - msg = generate_am_thanks(gitdir, jsondata, branch, since) + msg = generate_am_thanks(gitdir, jsondata, branch, cmdargs.since) if msg is None: continue + msgids.append(jsondata['msgid']) + for pdata in jsondata.get('patches', list()): + msgids.append(pdata[2]) + outgoing += 1 - outfile = os.path.join(outdir, '%s.thanks' % slug) - logger.info(' Writing: %s', outfile) msg.set_charset('utf-8') msg.replace_header('Content-Transfer-Encoding', '8bit') - with open(outfile, 'w') as fh: - fh.write(msg.as_string(policy=b4.emlpolicy)) - logger.debug('Cleaning up: %s', jsondata['trackfile']) - fullpath = os.path.join(datadir, jsondata['trackfile']) - os.rename(fullpath, '%s.sent' % fullpath) + if cmdargs.sendemail: + if not fromaddr: + fromaddr = jsondata['myemail'] + logger.info(' Sending: %s', msg.get('subject')) + # We never want to use the web endpoint for this (it's only for submitting patches) + b4.send_mail(smtp, [msg], fromaddr, dryrun=cmdargs.dryrun, use_web_endpoint=False) + else: + slug_from = re.sub(r'\W', '_', jsondata['fromemail']) + slug_subj = re.sub(r'\W', '_', jsondata['subject']) + slug = '%s_%s' % (slug_from.lower(), slug_subj.lower()) + slug = re.sub(r'_+', '_', slug) + outfile = os.path.join(cmdargs.outdir, '%s.thanks' % slug) + logger.info(' Writing: %s', outfile) + with open(outfile, 'w') as fh: + fh.write(msg.as_string(policy=b4.emlpolicy)) + if cmdargs.dryrun: + logger.info('Dry run, preserving tracked series.') + else: + logger.debug('Cleaning up: %s', jsondata['trackfile']) + fullpath = os.path.join(datadir, jsondata['trackfile']) + os.rename(fullpath, '%s.sent' % fullpath) + logger.info('---') if not outgoing: logger.info('No thanks necessary.') return - logger.debug('Wrote %s thank-you letters', outgoing) - logger.info('You can now run:') - logger.info(' git send-email %s/*.thanks', outdir) + config = b4.get_main_config() + pwstate = cmdargs.pw_set_state + if not pwstate: + pwstate = config.get('pw-accept-state') + + if cmdargs.sendemail: + if cmdargs.dryrun: + logger.info('DRYRUN: generated %s thank-you letters', outgoing) + else: + logger.info('Sent %s thank-you letters', outgoing) + if pwstate: + b4.patchwork_set_state(msgids, pwstate) + smtp.quit() + else: + if pwstate: + b4.patchwork_set_state(msgids, pwstate) + logger.info('---') + logger.debug('Wrote %s thank-you letters', outgoing) + logger.info('You can now run:') + logger.info(' git send-email %s/*.thanks', cmdargs.outdir) def list_tracked(): @@ -480,17 +505,17 @@ def write_tracked(tracked): counter += 1 -def send_selected(cmdargs): +def thank_selected(cmdargs): tracked = list_tracked() if not len(tracked): logger.info('Nothing to do') sys.exit(0) - if cmdargs.send == 'all': + if cmdargs.thankfor == 'all': listing = tracked else: listing = list() - for num in b4.parse_int_range(cmdargs.send, upper=len(tracked)): + for num in b4.parse_int_range(cmdargs.thankfor, upper=len(tracked)): try: index = int(num) - 1 listing.append(tracked[index]) @@ -509,7 +534,7 @@ def send_selected(cmdargs): sys.exit(0) wantbranch = get_wanted_branch(cmdargs) - send_messages(listing, cmdargs.gitdir, cmdargs.outdir, wantbranch, cmdargs.since) + send_messages(listing, wantbranch, cmdargs) sys.exit(0) @@ -544,10 +569,21 @@ def discard_selected(cmdargs): datadir = b4.get_data_dir() logger.info('Discarding %s messages', len(listing)) + msgids = list() for jsondata in listing: fullpath = os.path.join(datadir, jsondata['trackfile']) os.rename(fullpath, '%s.discarded' % fullpath) logger.info(' Discarded: %s', jsondata['subject']) + msgids.append(jsondata['msgid']) + for pdata in jsondata.get('patches', list()): + msgids.append(pdata[2]) + + config = b4.get_main_config() + pwstate = cmdargs.pw_set_state + if not pwstate: + pwstate = config.get('pw-discard-state') + if pwstate: + b4.patchwork_set_state(msgids, pwstate) sys.exit(0) @@ -636,9 +672,9 @@ def main(cmdargs): if cmdargs.auto: check_stale_thanks(cmdargs.outdir) auto_thankanator(cmdargs) - elif cmdargs.send: + elif cmdargs.thankfor: check_stale_thanks(cmdargs.outdir) - send_selected(cmdargs) + thank_selected(cmdargs) elif cmdargs.discard: discard_selected(cmdargs) else: @@ -649,4 +685,4 @@ def main(cmdargs): write_tracked(tracked) logger.info('---') logger.info('You can send them using number ranges, e.g:') - logger.info(' b4 ty -s 1-3,5,7-') + logger.info(' b4 ty -t 1-3,5,7-') |