Ticket #74: bug74.patch

File bug74.patch, 11.2 KB (added by dustin, 19 months ago)

patch version

  • 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 
    1111 
    1212from zope.interface import implements 
    1313from twisted.internet import defer, reactor 
    14 from twisted.mail.smtp import ESMTPSenderFactory 
     14from twisted.mail.smtp import sendmail, ESMTPSenderFactory 
    1515from twisted.python import log as twlog 
    1616 
    17 have_ssl = True 
    1817try: 
    1918    from twisted.internet import ssl 
    2019    from OpenSSL.SSL import SSLv3_METHOD 
    2120except ImportError: 
    22     have_ssl = False 
     21    pass 
    2322 
    2423from buildbot import interfaces, util 
    2524from buildbot.status import base 
    26 from buildbot.status.builder import FAILURE, SUCCESS, Results 
     25from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS, Results 
    2726 
    2827VALID_EMAIL = re.compile("[a-zA-Z0-9\.\_\%\-\+]+@[a-zA-Z0-9\.\_\%\-]+.[a-zA-Z]{2,6}") 
    2928 
    def defaultMessage(mode, name, build, results, master_status): 
    5554        text += "The Buildbot has finished a build" 
    5655    elif mode == "failing": 
    5756        text += "The Buildbot has detected a failed build" 
     57    elif attrs['mode'] == "warnings": 
     58        text += "The Buildbot has detected a problem in the build" 
    5859    elif mode == "passing": 
    5960        text += "The Buildbot has detected a passing build" 
    6061    elif mode == "change" and result == 'success': 
    class MailNotifier(base.StatusReceiverMultiService): 
    149150        @type  fromaddr: string 
    150151        @param fromaddr: the email address to be used in the 'From' header. 
    151152        @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  
    153154                                      of the Interested Users. If False, only 
    154155                                      send mail to the extraRecipients list. 
    155156 
    class MailNotifier(base.StatusReceiverMultiService): 
    160161                                developers who made Changes that went into this 
    161162                                build). It is a good idea to create a small 
    162163                                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. 
    166165 
    167166        @type  subject: string 
    168167        @param subject: a string to be used as the subject line of the message. 
    class MailNotifier(base.StatusReceiverMultiService): 
    173172        @param mode: one of: 
    174173                     - 'all': send mail about all builds, passing and failing 
    175174                     - 'failing': only send mail about builds which fail 
     175                     - 'warnings': send mail if builds contain warnings or fail  
    176176                     - 'passing': only send mail about builds which succeed 
    177177                     - 'problem': only send mail about a build which failed 
    178178                     when the previous build passed 
    class MailNotifier(base.StatusReceiverMultiService): 
    205205 
    206206        @type  lookup:    implementor of {IEmailLookup} 
    207207        @param lookup:    object which provides IEmailLookup, which is 
    208                           responsible for mapping User names for Interested 
    209                           Users (which come from the VC system) into valid 
    210                           email addresses. If not provided, the notifier will 
    211                           only be able to send mail to the addresses in the 
    212                           extraRecipients list. Most of the time you can use a 
    213                           simple Domain instance. As a shortcut, you can pass 
    214                           as string: this will be treated as if you had provided 
    215                           Domain(str). For example, lookup='twistedmatrix.com' 
    216                           will allow mail to be sent to all developers whose SVN 
    217                           usernames match 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                           
    219219        @type  customMesg: func 
    220220        @param customMesg: (this function is deprecated) 
    221221 
    222222        @type  messageFormatter: func 
    223223        @param messageFormatter: function taking (mode, name, build, result, 
    224                                  master_status) and returning a dictionary 
     224                                 master_status ) and returning a dictionary 
    225225                                 containing two required keys "body" and "type", 
    226226                                 with a third optional key, "subject". The 
    227227                                 "body" key gives a string that contains the 
    class MailNotifier(base.StatusReceiverMultiService): 
    258258        assert isinstance(extraRecipients, (list, tuple)) 
    259259        for r in extraRecipients: 
    260260            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 
    263262        self.extraRecipients = extraRecipients 
    264263        self.sendToInterestedUsers = sendToInterestedUsers 
    265264        self.fromaddr = fromaddr 
    266         assert mode in ('all', 'failing', 'problem', 'change', 'passing') 
     265        assert mode in ('all', 'failing', 'problem', 'change', 'passing', 'warnings') 
    267266        self.mode = mode 
    268267        self.categories = categories 
    269268        self.builders = builders 
    class MailNotifier(base.StatusReceiverMultiService): 
    290289 
    291290        # you should either limit on builders or categories, not both 
    292291        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 
    295294 
    296295        if customMesg: 
    297296            twlog.msg("customMesg is deprecated; please use messageFormatter instead") 
    class MailNotifier(base.StatusReceiverMultiService): 
    337336               builder.category not in self.categories: 
    338337            return # ignore this build 
    339338 
     339        if self.mode == "warnings" and results == SUCCESS: 
     340            return 
    340341        if self.mode == "failing" and results != FAILURE: 
    341342            return 
    342343        if self.mode == "passing" and results != SUCCESS: 
    class MailNotifier(base.StatusReceiverMultiService): 
    452453            for k,v in self.extraHeaders.items(): 
    453454                k = properties.render(k) 
    454455                if k in m: 
    455                     twlog.msg("Warning: Got header " + k + " in self.extraHeaders " 
     456                    twlog("Warning: Got header " + k + " in self.extraHeaders " 
    456457                          "but it already exists in the Message - " 
    457458                          "not adding it.") 
    458459                    continue 
    class MailNotifier(base.StatusReceiverMultiService): 
    498499        return logname in self.addLogs 
    499500 
    500501    def _gotRecipients(self, res, rlist, m): 
    501         to_recipients = set() 
    502         cc_recipients = set() 
     502        recipients = set() 
    503503 
    504504        for r in rlist: 
    505505            if r is None: # getAddress didn't like this address 
    class MailNotifier(base.StatusReceiverMultiService): 
    511511                r = r[:r.rindex('@')] 
    512512 
    513513            if VALID_EMAIL.search(r): 
    514                 to_recipients.add(r) 
     514                recipients.add(r) 
    515515            else: 
    516516                twlog.msg("INVALID EMAIL: %r" + r) 
    517517 
    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) 
    523525        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) 
    525531 
    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) 
    529536 
    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 
    531542 
    532     def sendmail(self, s, recipients): 
    533543        result = defer.Deferred() 
    534          
    535         if have_ssl and self.useTls: 
    536             client_factory = ssl.ClientContextFactory() 
    537             client_factory.method = SSLv3_METHOD 
    538         else: 
    539             client_factory = None 
    540544 
    541         if self.smtpUser and self.smtpPassword: 
    542             useAuth = True 
    543         else: 
    544             useAuth = False 
    545545         
    546546        sender_factory = ESMTPSenderFactory( 
    547547            self.smtpUser, self.smtpPassword, 
    548548            self.fromaddr, recipients, StringIO(s), 
    549             result, contextFactory=client_factory, 
    550             requireTransportSecurity=self.useTls, 
    551             requireAuthentication=useAuth) 
     549            result, contextFactory=client_factory) 
    552550 
    553551        reactor.connectTCP(self.relayhost, self.smtpPort, sender_factory) 
    554552         
    class MailNotifier(base.StatusReceiverMultiService): 
    557555    def sendMessage(self, m, recipients): 
    558556        s = m.as_string() 
    559557        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)