Ticket #74: bug74.patch
| File bug74.patch, 11.2 KB (added by dustin, 19 months ago) |
|---|
-
master/buildbot/status/mail.py
diff --git a/master/buildbot/status/mail.py b/master/buildbot/status/mail.py index 11727bc..66b200c 100644
a b import urllib 11 11 12 12 from zope.interface import implements 13 13 from twisted.internet import defer, reactor 14 from twisted.mail.smtp import ESMTPSenderFactory14 from twisted.mail.smtp import sendmail, ESMTPSenderFactory 15 15 from twisted.python import log as twlog 16 16 17 have_ssl = True18 17 try: 19 18 from twisted.internet import ssl 20 19 from OpenSSL.SSL import SSLv3_METHOD 21 20 except ImportError: 22 have_ssl = False21 pass 23 22 24 23 from buildbot import interfaces, util 25 24 from buildbot.status import base 26 from buildbot.status.builder import FAILURE, SUCCESS, Results25 from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS, Results 27 26 28 27 VALID_EMAIL = re.compile("[a-zA-Z0-9\.\_\%\-\+]+@[a-zA-Z0-9\.\_\%\-]+.[a-zA-Z]{2,6}") 29 28 … … def defaultMessage(mode, name, build, results, master_status): 55 54 text += "The Buildbot has finished a build" 56 55 elif mode == "failing": 57 56 text += "The Buildbot has detected a failed build" 57 elif attrs['mode'] == "warnings": 58 text += "The Buildbot has detected a problem in the build" 58 59 elif mode == "passing": 59 60 text += "The Buildbot has detected a passing build" 60 61 elif mode == "change" and result == 'success': … … class MailNotifier(base.StatusReceiverMultiService): 149 150 @type fromaddr: string 150 151 @param fromaddr: the email address to be used in the 'From' header. 151 152 @type sendToInterestedUsers: boolean 152 @param sendToInterestedUsers: if True (the default), send mail to all 153 @param sendToInterestedUsers: if True (the default), send mail to all 153 154 of the Interested Users. If False, only 154 155 send mail to the extraRecipients list. 155 156 … … class MailNotifier(base.StatusReceiverMultiService): 160 161 developers who made Changes that went into this 161 162 build). It is a good idea to create a small 162 163 mailing list and deliver to that, then let 163 subscribers come and go as they please. The 164 addresses in this list are used literally (they 165 are not processed by lookup). 164 subscribers come and go as they please. 166 165 167 166 @type subject: string 168 167 @param subject: a string to be used as the subject line of the message. … … class MailNotifier(base.StatusReceiverMultiService): 173 172 @param mode: one of: 174 173 - 'all': send mail about all builds, passing and failing 175 174 - 'failing': only send mail about builds which fail 175 - 'warnings': send mail if builds contain warnings or fail 176 176 - 'passing': only send mail about builds which succeed 177 177 - 'problem': only send mail about a build which failed 178 178 when the previous build passed … … class MailNotifier(base.StatusReceiverMultiService): 205 205 206 206 @type lookup: implementor of {IEmailLookup} 207 207 @param lookup: object which provides IEmailLookup, which is 208 responsible for mapping User names for Interested209 Users (which come from the VC system) into valid210 email addresses. If not provided, the notifier will211 only be able to send mail to the addresses in the212 extraRecipients list. Most of the time you can usea213 s imple Domain instance. As a shortcut, you can pass214 as string: this will be treated as if you had provided215 Domain(str). For example, lookup='twistedmatrix.com'216 will allow mail to be sent to all developers whose SVN217 usernamesmatch their twistedmatrix.com account names.218 208 responsible for mapping User names (which come from 209 the VC system) into valid email addresses. If not 210 provided, the notifier will only be able to send mail 211 to the addresses in the extraRecipients list. Most of 212 the time you can use a simple Domain instance. As a 213 shortcut, you can pass as string: this will be 214 treated as if you had provided Domain(str). For 215 example, lookup='twistedmatrix.com' will allow mail 216 to be sent to all developers whose SVN usernames 217 match their twistedmatrix.com account names. 218 219 219 @type customMesg: func 220 220 @param customMesg: (this function is deprecated) 221 221 222 222 @type messageFormatter: func 223 223 @param messageFormatter: function taking (mode, name, build, result, 224 master_status ) and returning a dictionary224 master_status ) and returning a dictionary 225 225 containing two required keys "body" and "type", 226 226 with a third optional key, "subject". The 227 227 "body" key gives a string that contains the … … class MailNotifier(base.StatusReceiverMultiService): 258 258 assert isinstance(extraRecipients, (list, tuple)) 259 259 for r in extraRecipients: 260 260 assert isinstance(r, str) 261 # require full email addresses, not User names 262 assert VALID_EMAIL.search(r), "%s is not a valid email" % r 261 assert VALID_EMAIL.search(r) # require full email addresses, not User names 263 262 self.extraRecipients = extraRecipients 264 263 self.sendToInterestedUsers = sendToInterestedUsers 265 264 self.fromaddr = fromaddr 266 assert mode in ('all', 'failing', 'problem', 'change', 'passing' )265 assert mode in ('all', 'failing', 'problem', 'change', 'passing', 'warnings') 267 266 self.mode = mode 268 267 self.categories = categories 269 268 self.builders = builders … … class MailNotifier(base.StatusReceiverMultiService): 290 289 291 290 # you should either limit on builders or categories, not both 292 291 if self.builders != None and self.categories != None: 293 twlog.err("Please specify only builders or categories to include not both.")294 raise interfaces.ParameterError("Please specify only builders or categories to include not both.")292 twlog.err("Please specify only builders to ignore or categories to include") 293 raise # FIXME: the asserts above do not raise some Exception either 295 294 296 295 if customMesg: 297 296 twlog.msg("customMesg is deprecated; please use messageFormatter instead") … … class MailNotifier(base.StatusReceiverMultiService): 337 336 builder.category not in self.categories: 338 337 return # ignore this build 339 338 339 if self.mode == "warnings" and results == SUCCESS: 340 return 340 341 if self.mode == "failing" and results != FAILURE: 341 342 return 342 343 if self.mode == "passing" and results != SUCCESS: … … class MailNotifier(base.StatusReceiverMultiService): 452 453 for k,v in self.extraHeaders.items(): 453 454 k = properties.render(k) 454 455 if k in m: 455 twlog .msg("Warning: Got header " + k + " in self.extraHeaders "456 twlog("Warning: Got header " + k + " in self.extraHeaders " 456 457 "but it already exists in the Message - " 457 458 "not adding it.") 458 459 continue … … class MailNotifier(base.StatusReceiverMultiService): 498 499 return logname in self.addLogs 499 500 500 501 def _gotRecipients(self, res, rlist, m): 501 to_recipients = set() 502 cc_recipients = set() 502 recipients = set() 503 503 504 504 for r in rlist: 505 505 if r is None: # getAddress didn't like this address … … class MailNotifier(base.StatusReceiverMultiService): 511 511 r = r[:r.rindex('@')] 512 512 513 513 if VALID_EMAIL.search(r): 514 to_recipients.add(r)514 recipients.add(r) 515 515 else: 516 516 twlog.msg("INVALID EMAIL: %r" + r) 517 517 518 # If we're sending to interested users put the extras in the 519 # CC list so they can tell if they are also interested in the 520 # change: 521 if self.sendToInterestedUsers and to_recipients: 522 cc_recipients.update(self.extraRecipients) 518 # if we're sending to interested users move the extra's to the CC 519 # list so they can tell if they are also interested in the change 520 # unless there are no interested users 521 if self.sendToInterestedUsers and len(recipients): 522 extra_recips = self.extraRecipients[:] 523 extra_recips.sort() 524 m['CC'] = ", ".join(extra_recips) 523 525 else: 524 to_recipients.update(self.extraRecipients) 526 [recipients.add(r) for r in self.extraRecipients[:]] 527 528 rlist = list(recipients) 529 rlist.sort() 530 m['To'] = ", ".join(rlist) 525 531 526 m['To'] = ", ".join(sorted(to_recipients)) 527 if cc_recipients: 528 m['CC'] = ", ".join(sorted(cc_recipients)) 532 # The extras weren't part of the TO list so add them now 533 if self.sendToInterestedUsers: 534 for r in self.extraRecipients: 535 recipients.add(r) 529 536 530 return self.sendMessage(m, list(to_recipients | cc_recipients)) 537 return self.sendMessage(m, list(recipients)) 538 539 def tls_sendmail(self, s, recipients): 540 client_factory = ssl.ClientContextFactory() 541 client_factory.method = SSLv3_METHOD 531 542 532 def sendmail(self, s, recipients):533 543 result = defer.Deferred() 534 535 if have_ssl and self.useTls:536 client_factory = ssl.ClientContextFactory()537 client_factory.method = SSLv3_METHOD538 else:539 client_factory = None540 544 541 if self.smtpUser and self.smtpPassword:542 useAuth = True543 else:544 useAuth = False545 545 546 546 sender_factory = ESMTPSenderFactory( 547 547 self.smtpUser, self.smtpPassword, 548 548 self.fromaddr, recipients, StringIO(s), 549 result, contextFactory=client_factory, 550 requireTransportSecurity=self.useTls, 551 requireAuthentication=useAuth) 549 result, contextFactory=client_factory) 552 550 553 551 reactor.connectTCP(self.relayhost, self.smtpPort, sender_factory) 554 552 … … class MailNotifier(base.StatusReceiverMultiService): 557 555 def sendMessage(self, m, recipients): 558 556 s = m.as_string() 559 557 twlog.msg("sending mail (%d bytes) to" % len(s), recipients) 560 return self.sendmail(s, recipients) 561 558 if self.useTls: 559 return self.tls_sendmail(s, recipients) 560 else: 561 return sendmail(self.relayhost, self.fromaddr, recipients, s, 562 port=self.smtpPort)
![[Buildbot Logo]](/chrome/site/header-text-transparent.png)