Package buildbot :: Package status :: Module tinderbox
[frames] | no frames]

Source Code for Module buildbot.status.tinderbox

  1   
  2  from email.Message import Message 
  3  from email.Utils import formatdate 
  4   
  5  from zope.interface import implements 
  6  from twisted.internet import defer 
  7   
  8  from buildbot import interfaces 
  9  from buildbot.status import mail 
 10  from buildbot.status.builder import SUCCESS, WARNINGS 
 11  from buildbot.steps.shell import WithProperties 
 12   
 13  import zlib, bz2, base64 
 14   
 15  # TODO: docs, maybe a test of some sort just to make sure it actually imports 
 16  # and can format email without raising an exception. 
 17   
18 -class TinderboxMailNotifier(mail.MailNotifier):
19 """This is a Tinderbox status notifier. It can send e-mail to a number of 20 different tinderboxes or people. E-mails are sent at the beginning and 21 upon completion of each build. It can be configured to send out e-mails 22 for only certain builds. 23 24 The most basic usage is as follows:: 25 TinderboxMailNotifier(fromaddr="buildbot@localhost", 26 tree="MyTinderboxTree", 27 extraRecipients=["tinderboxdaemon@host.org"]) 28 29 The builder name (as specified in master.cfg) is used as the "build" 30 tinderbox option. 31 32 """ 33 implements(interfaces.IEmailSender) 34 35 compare_attrs = ["extraRecipients", "fromaddr", "categories", "builders", 36 "addLogs", "relayhost", "subject", "binaryURL", "tree", 37 "logCompression", "errorparser", "columnName", 38 "useChangeTime"] 39
40 - def __init__(self, fromaddr, tree, extraRecipients, 41 categories=None, builders=None, relayhost="localhost", 42 subject="buildbot %(result)s in %(builder)s", binaryURL="", 43 logCompression="", errorparser="unix", columnName=None, 44 useChangeTime=False):
45 """ 46 @type fromaddr: string 47 @param fromaddr: the email address to be used in the 'From' header. 48 49 @type tree: string 50 @param tree: The Tinderbox tree to post to. 51 52 @type extraRecipients: tuple of string 53 @param extraRecipients: E-mail addresses of recipients. This should at 54 least include the tinderbox daemon. 55 56 @type categories: list of strings 57 @param categories: a list of category names to serve status 58 information for. Defaults to None (all 59 categories). Use either builders or categories, 60 but not both. 61 62 @type builders: list of strings 63 @param builders: a list of builder names for which mail should be 64 sent. Defaults to None (send mail for all builds). 65 Use either builders or categories, but not both. 66 67 @type relayhost: string 68 @param relayhost: the host to which the outbound SMTP connection 69 should be made. Defaults to 'localhost' 70 71 @type subject: string 72 @param subject: a string to be used as the subject line of the message. 73 %(builder)s will be replaced with the name of the 74 %builder which provoked the message. 75 This parameter is not significant for the tinderbox 76 daemon. 77 78 @type binaryURL: string 79 @param binaryURL: If specified, this should be the location where final 80 binary for a build is located. 81 (ie. http://www.myproject.org/nightly/08-08-2006.tgz) 82 It will be posted to the Tinderbox. 83 84 @type logCompression: string 85 @param logCompression: The type of compression to use on the log. 86 Valid options are"bzip2" and "gzip". gzip is 87 only known to work on Python 2.4 and above. 88 89 @type errorparser: string 90 @param errorparser: The error parser that the Tinderbox server 91 should use when scanning the log file. 92 Default is "unix". 93 94 @type columnName: string 95 @param columnName: When columnName is None, use the buildername as 96 the Tinderbox column name. When columnName is a 97 string this exact string will be used for all 98 builders that this TinderboxMailNotifier cares 99 about (not recommended). When columnName is a 100 WithProperties instance it will be interpolated 101 as such. See WithProperties for more detail. 102 @type useChangeTime: bool 103 @param useChangeTime: When True, the time of the first Change for a 104 build is used as the builddate. When False, 105 the current time is used as the builddate. 106 """ 107 108 mail.MailNotifier.__init__(self, fromaddr, categories=categories, 109 builders=builders, relayhost=relayhost, 110 subject=subject, 111 extraRecipients=extraRecipients, 112 sendToInterestedUsers=False) 113 self.tree = tree 114 self.binaryURL = binaryURL 115 self.logCompression = logCompression 116 self.errorparser = errorparser 117 self.useChangeTime = useChangeTime 118 assert columnName is None or type(columnName) is str \ 119 or isinstance(columnName, WithProperties), \ 120 "columnName must be None, a string, or a WithProperties instance" 121 self.columnName = columnName
122
123 - def buildStarted(self, name, build):
124 builder = build.getBuilder() 125 if self.builders is not None and name not in self.builders: 126 return # ignore this Build 127 if self.categories is not None and \ 128 builder.category not in self.categories: 129 return # ignore this build 130 self.buildMessage(name, build, "building")
131
132 - def buildMessage(self, name, build, results):
133 text = "" 134 res = "" 135 # shortform 136 t = "tinderbox:" 137 138 text += "%s tree: %s\n" % (t, self.tree) 139 # the start time 140 # getTimes() returns a fractioned time that tinderbox doesn't understand 141 builddate = int(build.getTimes()[0]) 142 # attempt to pull a Change time from this Build's Changes. 143 # if that doesn't work, fall back on the current time 144 if self.useChangeTime: 145 try: 146 builddate = build.getChanges()[-1].when 147 except: 148 pass 149 text += "%s builddate: %s\n" % (t, builddate) 150 text += "%s status: " % t 151 152 if results == "building": 153 res = "building" 154 text += res 155 elif results == SUCCESS: 156 res = "success" 157 text += res 158 elif results == WARNINGS: 159 res = "testfailed" 160 text += res 161 else: 162 res += "busted" 163 text += res 164 165 text += "\n"; 166 167 if self.columnName is None: 168 # use the builder name 169 text += "%s build: %s\n" % (t, name) 170 elif type(self.columnName) is str: 171 # use the exact string given 172 text += "%s build: %s\n" % (t, self.columnName) 173 elif isinstance(self.columnName, WithProperties): 174 # interpolate the WithProperties instance, use that 175 text += "%s build: %s\n" % (t, build.getProperties().render(self.columnName)) 176 else: 177 raise Exception("columnName is an unhandled value") 178 text += "%s errorparser: %s\n" % (t, self.errorparser) 179 180 # if the build just started... 181 if results == "building": 182 text += "%s END\n" % t 183 # if the build finished... 184 else: 185 text += "%s binaryurl: %s\n" % (t, self.binaryURL) 186 text += "%s logcompression: %s\n" % (t, self.logCompression) 187 188 # logs will always be appended 189 logEncoding = "" 190 tinderboxLogs = "" 191 for log in build.getLogs(): 192 l = "" 193 if self.logCompression == "bzip2": 194 compressedLog = bz2.compress(log.getText()) 195 l = base64.encodestring(compressedLog) 196 logEncoding = "base64"; 197 elif self.logCompression == "gzip": 198 compressedLog = zlib.compress(log.getText()) 199 l = base64.encodestring(compressedLog) 200 logEncoding = "base64"; 201 else: 202 l = log.getText() 203 tinderboxLogs += l 204 205 text += "%s logencoding: %s\n" % (t, logEncoding) 206 text += "%s END\n\n" % t 207 text += tinderboxLogs 208 text += "\n" 209 210 m = Message() 211 m.set_payload(text) 212 213 m['Date'] = formatdate(localtime=True) 214 m['Subject'] = self.subject % { 'result': res, 215 'builder': name, 216 } 217 m['From'] = self.fromaddr 218 # m['To'] is added later 219 220 d = defer.DeferredList([]) 221 d.addCallback(self._gotRecipients, self.extraRecipients, m) 222 return d
223