SVNMailNotifier.py [plain text]
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
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 = self.status.getURLForThing(build)
buildboturl = self.status.getBuildbotURL()
buildreason = build.getReason()
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)"
buildslave = build.getSlavename()
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()
lines = re.split('\n', lastlog)
lastlog = ''
for logline in lines[max(0, len(lines)-100):]:
lastlog = lastlog + logline
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['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)
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