blob: eebaf6e1f13f9b35b0b1d428d9ea9167671e0696 [file] [log] [blame]
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A StatusReceiver module to mail someone when a step warns/fails.
Since the behavior is very similar to the MailNotifier, we simply inherit from
it and also reuse some of its methods to send emails.
"""
# This module comes from $(TOPLEVEL_DIR)/third_party/buildbot_<VERSION> ,
# which must be in the PYTHONPATH.
from buildbot.status.mail import MailNotifier
from buildbot.status.results import Results
from master.try_mail_notifier import TryMailNotifier
from skia_master_scripts import utils
import builder_name_schema
import datetime
import re
import urllib
_COMMIT_QUEUE_AUTHOR_LINE = 'Author: '
_COMMIT_QUEUE_REVIEWERS_LINE = 'R='
_COMMIT_BOT = 'commit-bot@chromium.org'
class SkiaNotifier(MailNotifier):
"""This is Skia's status notifier."""
def __init__(self, **kwargs):
MailNotifier.__init__(self, **kwargs)
def createEmail(self, msgdict, builderName, title, results, builds=None,
patches=None, logs=None):
# Trybots have their own Notifier
if builder_name_schema.IsTrybot(builderName):
return None
m = MailNotifier.createEmail(self, msgdict, builderName, title,
results, builds, patches, logs)
if builds and builds[0].getSourceStamp().revision:
m.replace_header('Subject',
'buildbot %(result)s in %(title)s for %(revision)s' % {
'result': Results[results],
'title': title,
'revision': builds[0].getSourceStamp().revision,
})
return m
def buildMessage(self, name, builds, results):
if self.sendToInterestedUsers and self.lookup:
for build in builds: # Loop through all builds we are emailing about
if builder_name_schema.IsTrybot(build.getBuilder().name):
return
blame_list = set(build.getResponsibleUsers())
for change in build.getChanges(): # Loop through all changes in a build
if (change.comments and
_COMMIT_BOT == utils.FixGitSvnEmail(change.who)):
# If the change has been submitted by the commit bot then find the
# original author and the reviewers and add them to the blame list
for commit_queue_line in (_COMMIT_QUEUE_AUTHOR_LINE,
_COMMIT_QUEUE_REVIEWERS_LINE):
users = re.search(
'%s(.*?)\n' % commit_queue_line,
change.comments).group(1).split(',')
blame_list = blame_list.union(users)
if change.who in blame_list:
# Remove the commit bot from the blame list.
blame_list.remove(change.who)
# Git-svn tacks a git-svn-id onto the email addresses. Remove it.
new_blamelist = [utils.FixGitSvnEmail(email) for email in blame_list]
# pylint: disable=C0301
# Set the extended blamelist. It was originally set in
# http://buildbot.net/buildbot/docs/0.8.4/reference/buildbot.process.build-pysrc.html
# (line 339)
build.setBlamelist(new_blamelist)
return MailNotifier.buildMessage(self, name, builds, results)
def _ParseTimeStampFromURL(url):
""" Parse a timestamp from a diff-file url.
url: string; the url from which to parse the timestamp.
"""
diff_file_name = urllib.unquote(url).split('/')[-1]
m = re.search('\S+\.\S+\.(\d+)-(\d+)-(\d+)\s(\d+)\.(\d+)\.(\d+)\.\d+\.diff',
diff_file_name)
# If there are no matches or an incorrect number of matches, use the current
# date as a default. We don't include the time because that would result in
# many try result emails being sent with different subject lines. It is
# preferable to group all emails for the same changelist on the same day (even
# if they are from separate try requests).
expected_num_matches = 6
if not m or len(m.groups()) != expected_num_matches:
now = datetime.datetime.now()
return '%s-%s-%s' % (now.year, now.month, now.day)
return '%s-%s-%s %s:%s:%s' % m.groups()
class SkiaTryMailNotifier(TryMailNotifier):
""" The TryMailNotifier sends mail for every build by default. Since we use
a single build master for both try builders and regular builders, this causes
mail to be sent for every single build. So, we subclass TryMailNotifier here
and add logic to prevent sending mail on anything but a try job. """
def buildMessage(self, name, build, results):
if builder_name_schema.IsTrybot(build[0].getBuilder().name):
if not hasattr(build[0].source, 'timestamp'):
if 'patch_file_url' in build[0].getProperties():
build[0].source.timestamp = _ParseTimeStampFromURL(
build[0].getProperty('patch_file_url'))
subject = (
'try %(result)s for changelist "%(reason)s" at %(timestamp)s')
else:
subject = 'try %(result)s for issue-patchset "%(reason)s"'
# pylint: disable=W0201
self.subject = subject
return TryMailNotifier.buildMessage(self, name, build, results)