blob: e0956581d10149a5fd0af14e83a8e91fe493eea1 [file] [log] [blame]
# Copyright 2021 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Disable pylint noise
# pylint: disable=W0621, E0401, C0415, W1632
"""Sends triage reports"""
import smtplib
import pickle
import sys
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from config import rebase_target, rebase_baseline_branch
cred_error = """\
ERROR: cred.py file not found. Create it in and initialize login, passw
variables within, for example:
login = "you@gmail.com"
passw = "your application password"
It'll work only for GMail, anyway.
"""
html_header = """<html>
<head></head>
<body><pre>
"""
html_footer = """</pre>
</body>
</html>
"""
email_text = """\
This is an automatic notification about %s -> merge/continuous/chromeos-kernelupstream-%s
uprev status.
Commits in "handled automatically" column were either dropped (due to revert or upstream)
or resolved using preexisting rerere database.
Commits counted as "need manual resolution" were skipped for the purpose of triage.
topic | commits overall | handled automatically | need manual resolution | build
---------------+-----------------+-----------------------+------------------------+------
"""
upstream_prefix = """\
upstreaming stats:
category | fromlist | fromgit
-----------+----------+--------
"""
email_subject = '%s -> %s: %d/%d commits need manual resolution'
mailing_from = 'from@example.com'
recip_limited = ['recip1@example.com', 'recip2@example.com']
recip_all = [
'recip1@example.com',
'recip2@example.com',
'recip3@example.com',
'recip4@example.com']
class Mailing:
"""Mailing class"""
def __init__(self, rebase_base, rebase_target):
"""Initializes class members"""
self.rebase_base = rebase_base
self.rebase_target = rebase_target
self.server = None
def build_mail(
self,
topic_stats,
upstream_stats,
total_stats,
topic_errors):
"""Formats statistics into an email"""
mail = email_text % (self.rebase_base, self.rebase_target[1:])
stats = [0, 0, 0]
for topic in topic_stats:
data = topic_stats[topic]
overall = data[0]
auto = data[1]
manual = data[2]
stats[0] += overall
stats[1] += auto
stats[2] += manual
if data[3]:
build = 'OK'
else:
build = 'FAIL'
mail += f'{topic:14} | {overall:15d} | {auto:21d} | {manual:22d} | {build}\n'
topic = 'ALL'
build = 'ON HOLD'
mail += '-' * len(email_text.split('\n')[6])
mail += '\n'
mail += f'{topic:14} | {stats[0]:15d} | {stats[1]:21d} | {stats[2]:22d} | {build}\n'
mail += '\n'
mail += upstream_prefix
fromlist = total_stats['fromlist']
fromgit = total_stats['fromgit']
mail += f'total | {fromlist:8} | {fromgit:7}\n'
fromlist = upstream_stats['fromlist']
fromgit = upstream_stats['fromgit']
mail += f'upstreamed | {fromlist:8} | {fromgit:7}\n\n'
for topic in topic_errors:
mail += 'Branch %s failed to build due to:\n' % topic
mail += topic_errors[topic]
mail += '\n\n'
return (mail, stats)
def send_mail(self, subject, mail, recipients):
"""Send mail"""
try:
from cred import login, passw
except: # pylint: disable=bare-except
print(cred_error)
sys.exit()
self.server = smtplib.SMTP('smtp.gmail.com', 587)
self.server.starttls()
self.server.login(login, passw)
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = mailing_from
msg['To'] = ', '.join(recipients)
part1 = MIMEText(
'This message should be viewed in HTML. Check your client.',
'plain')
part2 = MIMEText(html_header + mail + html_footer, 'html')
msg.attach(part1)
msg.attach(part2)
self.server.send_message(msg)
def notify(self, topic_stats, upstream_stats, total_stats, topic_errors):
"""Preview and send report"""
mail, stats = self.build_mail(
topic_stats, upstream_stats, total_stats, topic_errors)
subject = email_subject % (
self.rebase_base, self.rebase_target, stats[2], stats[0])
print(mail)
ans = input('Send? [y/n] ')
if ans == 'y':
# Send out to limited audience first
self.send_mail(subject, mail, recip_limited)
ans = input('Resend to all? [y/n] ')
if ans == 'y':
# Send out to all
self.send_mail(subject, mail, recip_all)
def load_and_notify():
"""Creates a report, shows preview and sends it if ok"""
m = Mailing(rebase_baseline_branch, rebase_target)
topic_stats = pickle.load(open('topic_stats.bin', 'rb'))
topic_stderr = pickle.load(open('topic_stderr.bin', 'rb'))
upstream_stats = pickle.load(open('upstream_stats.bin', 'rb'))
total_stats = pickle.load(open('total_stats.bin', 'rb'))
m.notify(topic_stats, upstream_stats, total_stats, topic_stderr)