def buildMessage(self, builder_name, build_status, results, step_name):
        """Send an email about the tree closing.

    Don't attach the patch as MailNotifier.buildMessage does.

    @type builder_name: string
    @type build_status: L{buildbot.status.builder.BuildStatus}
    @type step_name: name of this step
    """
        # TODO(maruel): Update function signature to match
        # mail.MailNotifier.buildMessage().
        if (self._last_time_mail_sent and self._last_time_mail_sent >
                time.time() - self.minimum_delay_between_alert):
            # Rate limit tree alerts.
            log.msg('Suppressing repeat email')
            return
        log.msg('About to email')
        self._last_time_mail_sent = time.time()

        # TODO(maruel): Use self.createEmail().
        blame_interested_users = self.shouldBlameCommitters(step_name)
        project_name = self.master_status.getTitle()
        revisions_list = build_utils.getAllRevisions(build_status)
        build_url = self.master_status.getURLForThing(build_status)
        waterfall_url = self.master_status.getBuildbotURL()
        status_text = self.status_header % {
            'buildbotURL': waterfall_url,
            'builder': builder_name,
            'builderName': builder_name,
            'buildProperties': build_status.getProperties(),
            'buildURL': build_url,
            'project': project_name,
            'reason': build_status.getReason(),
            'slavename': build_status.getSlavename(),
            'steps': step_name,
        }
        # Use the first line as a title.
        status_title = status_text.split('\n', 1)[0]
        blame_list = ','.join(build_status.getResponsibleUsers())
        revisions_string = ''
        latest_revision = 0
        if revisions_list:
            revisions_string = ', '.join([str(rev) for rev in revisions_list])
            latest_revision = max([rev for rev in revisions_list])
        if results[0] == FAILURE:
            result = 'failure'
        else:
            result = 'warning'

        # Generate a HTML table looking like the waterfall.
        # WARNING: Gmail ignores embedded CSS style. I don't know how to fix that so
        # meanwhile, I just won't embedded the CSS style.
        html_content = (
            """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>%s</title>
</head>
<body>
  <a href="%s">%s</a><p>
  %s<p>
  <a href="%s">%s</a><p>
  Revision: %s<br>
""" % (status_title, waterfall_url, waterfall_url,
        status_text.replace('\n',
                           "<br>\n"), build_url, build_url, revisions_string))

        # Only include the blame list if relevant.
        if blame_interested_users:
            html_content += "  Blame list: %s<p>\n" % blame_list

        html_content += build_utils.EmailableBuildTable(
            build_status, waterfall_url)
        html_content += "<p>"
        # Add the change list descriptions. getChanges() returns a tuple of
        # buildbot.changes.changes.Change
        for change in build_status.getChanges():
            html_content += change.asHTML()
        html_content += "</body>\n</html>"

        # Simpler text content for non-html aware clients.
        text_content = ("""%s

%s

%swaterfall?builder=%s

--=>  %s  <=--

Revision: %s
Blame list: %s

Buildbot waterfall: http://build.chromium.org/
""" % (status_title, build_url, urllib.quote(waterfall_url, '/:'),
        urllib.quote(builder_name), status_text, revisions_string, blame_list))

        m = MIMEMultipart('alternative')
        # The HTML message, is best and preferred.
        m.attach(MIMEText(text_content, 'plain', 'iso-8859-1'))
        m.attach(MIMEText(html_content, 'html', 'iso-8859-1'))

        m['Date'] = formatdate(localtime=True)
        m['Subject'] = self.subject % {
            'result': result,
            'projectName': project_name,
            'builder': builder_name,
            'reason': build_status.getReason(),
            'revision': str(latest_revision),
            'buildnumber': str(build_status.getNumber()),
            'date': str(datetime.date.today()),
            'steps': step_name,
            'slavename': build_status.getSlavename(),
        }
        m['From'] = self.fromaddr
        if self.reply_to:
            m['Reply-To'] = self.reply_to

        recipients = list(self.extraRecipients[:])
        if self.sheriffs:
            recipients.extend(
                BuildSheriffs.GetSheriffs(classes=self.sheriffs,
                                          data_dir=self.public_html))

        dl = []
        if self.sendToInterestedUsers and self.lookup and blame_interested_users:
            for u in build_status.getInterestedUsers():
                d = defer.maybeDeferred(self.lookup.getAddress, u)
                d.addCallback(recipients.append)
                dl.append(d)
        defered_object = defer.DeferredList(dl)
        if not self.enable_mail:
            defered_object.addCallback(self._logMail, recipients, m)
        else:
            defered_object.addCallback(self._gotRecipients, recipients, m)
        defered_object.addCallback(self.getFinishedMessage, builder_name,
                                   build_status, step_name)
        return defered_object
Beispiel #2
0
    def buildMessage(self, name, build, results):
        """Send an email about the result. Send it as a nice HTML message."""
        log.msg('Building try job email')
        projectName = self.master_status.getTitle()

        if len(build) != 1:
            # TODO(maruel): Panic or process them all.
            pass
        build = build[0]
        job_stamp = build.getSourceStamp()
        build_url = self.master_status.getURLForThing(build)
        waterfall_url = self.master_status.getBuildbotURL()
        if results == SUCCESS:
            status_text_html = "You are awesome! Try succeeded!"
            res = "success"
        elif results == WARNINGS:
            status_text_html = "Try Had Warnings"
            res = "warnings"
        else:
            status_text_html = self.failure_message
            if status_text_html is None:
                status_text_html = (
                    'TRY FAILED<p>'
                    '<strong>If you think the try slave is broken (it happens!),'
                    'please REPLY to this email, don\'t ask on irc, mailing '
                    'list or IM.<br>'
                    'If you think the test is flaky, notify the sheriffs.</strong><br>'
                    'Please use "rich text" replies so the links aren\'t lost.<br>'
                    'It is possible that you get no reply, don\'t worry, the reply '
                    'address isn\'t a blackhole.'
                    '<p>'
                    'Thanks!')

            res = "failure"

        info = {
            'result': res,
            'projectName': projectName,
            'builder': name,
            'reason': build.getReason(),
            'revision': job_stamp.revision,
            'timestamp': getattr(job_stamp, "timestamp", "")
        }
        subject = self.subject % info
        first_line = (
            "try %(result)s for %(reason)s on %(builder)s @ r%(revision)s" %
            info)

        html_params = {
            'subject': subject,
            'first_line': first_line,
            'waterfall_url': waterfall_url,
            'status_text_html': status_text_html,
            'build_url': build_url,
            'slave': build.getSlavename(),
        }

        # Generate a HTML table looking like the waterfall.
        # WARNING: Gmail ignores embedded CSS style unless it's inline.
        html_content = (
            """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>%(subject)s</title>
</head>
<body style="font-family: Verdana, Cursor; font-size: 10px;">
  %(first_line)s<p>
  <a href="%(waterfall_url)s">%(waterfall_url)s</a><p>
  %(status_text_html)s<p>
  <a href="%(build_url)s">%(build_url)s</a><br>
  slave: %(slave)s<br>
    """) % html_params

        html_content += build_utils.EmailableBuildTable(build, waterfall_url)
        footer = self.footer
        if self.footer is None:
            footer = """<br>
FAQ: <a href="http://sites.google.com/a/chromium.org/dev/developers/testing/try-server-usage">
http://sites.google.com/a/chromium.org/dev/developers/testing/try-server-usage</a><br>
</body>
</html>
"""
        html_content += footer
        m = MIMEMultipart()
        m.attach(MIMEText(html_content, 'html', 'iso-8859-1'))
        m['Date'] = formatdate(localtime=True)
        m['Subject'] = subject
        m['From'] = self.fromaddr
        if self.reply_to:
            m['Reply-To'] = self.reply_to
        # now, who is this message going to?
        dl = []
        recipients = self.extraRecipients[:]
        if self.sendToInterestedUsers and self.lookup:
            for u in build.getInterestedUsers():
                d = defer.maybeDeferred(self.lookup.getAddress, u)
                d.addCallback(recipients.append)
                dl.append(d)
        d = defer.DeferredList(dl)
        d.addCallback(self._gotRecipients, recipients, m)
        return d
    def buildMessage_internal(self, name, build, results):
        """Send an email about the result. Send it as a nice HTML message."""

        if results == SUCCESS and name in self.no_email_on_success:
            log.msg('Skipping success email for %s' % name)
            return

        log.msg('Building try job email')
        projectName = self.master_status.getTitle()

        if len(build) != 1:
            # TODO(maruel): Panic or process them all.
            return

        build = build[0]
        job_stamp = build.getSourceStamp()
        build_url = self.master_status.getURLForThing(build)
        builder_url = self.master_status.getURLForThing(build.getBuilder())
        waterfall_url = self.master_status.getBuildbotURL()
        if results == SUCCESS:
            status_text_html = "You are awesome! Try succeeded!"
            res = "success"
        elif results == WARNINGS:
            status_text_html = "Try Had Warnings"
            res = "warnings"
        else:
            status_text_html = self.failure_message
            if status_text_html is None:
                status_text_html = (
                    'TRY FAILED<p>'
                    '<strong>If the failure is unrelated to your change, the test may'
                    ' be flaky. Contact the sheriffs via irc or gchat, or email the'
                    ' team mailing list.<br> If you think the system is broken,'
                    ' please reply to this email.</strong><br>'
                    ' Common examples of system issues: sync or compile failures'
                    ' on a specific machine, or failures that only affect trybots.<br>'
                    'Please use "rich text" replies so the links aren\'t lost.'
                    ' If you do not receive a reply, don\'t worry. The reply address'
                    ' isn\'t a blackhole.<p>Thanks!')
            res = "failure"

        info = {
            'result':
            res,
            'projectName':
            projectName,
            'builder':
            name,
            'reason':
            build.getReason(),
            'revision':
            build.getProperties().getProperty('got_revision',
                                              job_stamp.revision),
            'timestamp':
            getattr(job_stamp, "timestamp", "")
        }
        if self.get_info:
            info = self.get_info(info, build)
        subject = self.subject % info
        first_line = (
            "try %(result)s for %(reason)s on %(builder)s @ r%(revision)s" %
            info)

        build_props = build.getProperties()
        if build_props.getProperty('requester') == '*****@*****.**':
            # CQ handles notifying people about the ultimate success/failure of
            # tryjobs by posting to rietveld. It also generates a LOT of email
            # from the tryserver which is noisy.
            return

        parent_html = ''
        if build_props:
            parent_name = build_props.getProperty('parent_buildername')
            parent_buildnum = build_props.getProperty('parent_buildnumber')
            if parent_name and parent_buildnum:
                parent_builder_url = ('%s/builders/%s' %
                                      (waterfall_url.rstrip('/'), parent_name))
                parent_build = parent_builder_url + '/builds/%s' % parent_buildnum
                parent_html = (
                    '<br>Parent build: <a href="%(build_url)s">%(buildnum)s</a>'
                    ' on <a href="%(builder_url)s">%(builder)s</a><br>' % {
                        'builder_url': parent_builder_url,
                        'builder': parent_name,
                        'build_url': parent_build,
                        'buildnum': parent_buildnum
                    })
        slave = build.getSlavename()
        slave_url = '%s/buildslaves/%s' % (waterfall_url.rstrip('/'), slave)

        html_params = {
            'subject': subject,
            'first_line': first_line,
            'waterfall_url': waterfall_url,
            'status_text_html': status_text_html,
            'build_url': build_url,
            'parent_builder_html': parent_html,
            'slave': slave,
            'slave_url': slave_url,
            'build_number': build.getNumber(),
            'builder': build.getBuilder().getName(),
            'builder_url': builder_url,
        }

        # Generate a HTML table looking like the waterfall.
        # WARNING: Gmail ignores embedded CSS style unless it's inline.
        html_content = (
            """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>%(subject)s</title>
</head>
<body style="font-family: Verdana, Cursor; font-size: 10px;">
  %(first_line)s<p>
  <a href="%(waterfall_url)s">%(waterfall_url)s</a><p>
  %(status_text_html)s<p> %(parent_builder_html)s
  Build: <a href="%(build_url)s">%(build_number)s</a> on
         <a href="%(builder_url)s">%(builder)s</a><br>
  slave: <a href="%(slave_url)s">%(slave)s</a><br>
    """) % html_params

        html_content += self.SpecialPropertiesAsHTML(build_props.asDict())
        html_content += build_utils.EmailableBuildTable(build, waterfall_url)
        footer = self.footer
        if self.footer is None:
            footer = """<br>
FAQ: <a href="https://sites.google.com/a/chromium.org/dev/developers/testing/try-server-usage">
https://sites.google.com/a/chromium.org/dev/developers/testing/try-server-usage</a><br>
</body>
</html>
"""
        html_content += footer
        m = MIMEMultipart()
        m.attach(MIMEText(html_content, 'html', 'iso-8859-1'))
        m['Date'] = formatdate(localtime=True)
        m['Subject'] = subject
        m['From'] = self.fromaddr
        return m