summaryrefslogtreecommitdiff
path: root/tools/buildbot/master/SVNMailNotifier.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/buildbot/master/SVNMailNotifier.py')
-rw-r--r--tools/buildbot/master/SVNMailNotifier.py210
1 files changed, 210 insertions, 0 deletions
diff --git a/tools/buildbot/master/SVNMailNotifier.py b/tools/buildbot/master/SVNMailNotifier.py
new file mode 100644
index 0000000..1dfe839
--- /dev/null
+++ b/tools/buildbot/master/SVNMailNotifier.py
@@ -0,0 +1,210 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+import os
+import urllib
+import re
+
+from email.Message import Message
+from email.Utils import formatdate
+from email.MIMEText import MIMEText
+
+from twisted.internet import defer
+from twisted.application import service
+
+from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS
+from buildbot.status.mail import MailNotifier
+
+class SVNMailNotifier(MailNotifier):
+ """Implement custom status mails for the Subversion project"""
+
+ def __init__(self, fromaddr, mode="all", categories=None, builders=None,
+ addLogs=False, relayhost="localhost",
+ subject="buildbot %(result)s in %(builder)s",
+ lookup=None, extraRecipients=[],
+ sendToInterestedUsers=True,
+ body="",
+ replytoaddr=""):
+ """
+ @type body: string
+ @param body: a string to be used as the body of the message.
+
+ @type replytoaddr: string
+ @param replytoaddr: the email address to be used in the 'Reply-To' header.
+ """
+
+ self.body = body
+ self.replytoaddr = replytoaddr
+
+ # pass the rest of the parameters to our parent.
+ MailNotifier.__init__(self, fromaddr, mode, categories, builders,
+ addLogs, relayhost, subject, lookup, extraRecipients,
+ sendToInterestedUsers)
+
+ def buildMessage(self, name, build, results):
+ if self.mode == "all":
+ intro = "The Buildbot has finished a build of %s.\n" % name
+ elif self.mode == "failing":
+ intro = "The Buildbot has detected a failed build of %s.\n" % name
+ else:
+ intro = "The Buildbot has detected a new failure of %s.\n" % name
+
+ # buildurl
+ buildurl = self.status.getURLForThing(build)
+# lgo: url's are already quoted now.
+# if buildurl:
+# buildurl = urllib.quote(buildurl, '/:')
+
+ # buildboturl
+ buildboturl = self.status.getBuildbotURL()
+# if url:
+# buildboturl = urllib.quote(url, '/:')
+
+ # reason of build
+ buildreason = build.getReason()
+
+ # source stamp
+ patch = None
+ ss = build.getSourceStamp()
+ if ss is None:
+ source = "unavailable"
+ else:
+ if build.getChanges():
+ revision = max([int(c.revision) for c in build.getChanges()])
+
+ source = ""
+ if ss.branch is None:
+ ss.branch = "trunk"
+ source += "[branch %s] " % ss.branch
+ if revision:
+ source += str(revision)
+ else:
+ source += "HEAD"
+ if ss.patch is not None:
+ source += " (plus patch)"
+
+ # actual buildslave
+ buildslave = build.getSlavename()
+
+ # TODO: maybe display changes here? or in an attachment?
+
+ # status
+ t = build.getText()
+ if t:
+ t = ": " + " ".join(t)
+ else:
+ t = ""
+
+ if results == SUCCESS:
+ status = "Build succeeded!\n"
+ res = "PASS"
+ elif results == WARNINGS:
+ status = "Build Had Warnings%s\n" % t
+ res = "WARN"
+ else:
+ status = "BUILD FAILED%s\n" % t
+ res = "FAIL"
+
+ if build.getLogs():
+ log = build.getLogs()[-1]
+ laststep = log.getStep().getName()
+ lastlog = log.getText()
+
+ # only give me the last lines of the log files.
+ lines = re.split('\n', lastlog)
+ lastlog = ''
+ for logline in lines[max(0, len(lines)-100):]:
+ lastlog = lastlog + logline
+
+ # TODO: it would be nice to provide a URL for the specific build
+ # here. That involves some coordination with html.Waterfall .
+ # Ideally we could do:
+ # helper = self.parent.getServiceNamed("html")
+ # if helper:
+ # url = helper.getURLForBuild(build)
+
+ text = self.body % { 'result': res,
+ 'builder': name,
+ 'revision': revision,
+ 'branch': ss.branch,
+ 'blamelist': ",".join(build.getResponsibleUsers()),
+ 'buildurl': buildurl,
+ 'buildboturl': buildboturl,
+ 'reason': buildreason,
+ 'source': source,
+ 'intro': intro,
+ 'status': status,
+ 'slave': buildslave,
+ 'laststep': laststep,
+ 'lastlog': lastlog,
+ }
+
+ haveAttachments = False
+ if ss.patch or self.addLogs:
+ haveAttachments = True
+ if not canDoAttachments:
+ log.msg("warning: I want to send mail with attachments, "
+ "but this python is too old to have "
+ "email.MIMEMultipart . Please upgrade to python-2.3 "
+ "or newer to enable addLogs=True")
+
+ if haveAttachments and canDoAttachments:
+ m = MIMEMultipart()
+ m.attach(MIMEText(text))
+ else:
+ m = Message()
+ m.set_payload(text)
+
+ m['Date'] = formatdate(localtime=True)
+ m['Subject'] = self.subject % { 'result': res,
+ 'builder': name,
+ 'revision': revision,
+ 'branch': ss.branch
+ }
+ m['From'] = self.fromaddr
+ # m['To'] is added later
+ m['Reply-To'] = self.replytoaddr
+
+ if ss.patch:
+ a = MIMEText(patch)
+ a.add_header('Content-Disposition', "attachment",
+ filename="source patch")
+ m.attach(a)
+ if self.addLogs:
+ for log in build.getLogs():
+ name = "%s.%s" % (log.getStep().getName(),
+ log.getName())
+ a = MIMEText(log.getText())
+ a.add_header('Content-Disposition', "attachment",
+ filename=name)
+ m.attach(a)
+
+ # 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
+