~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to tools/buildbot/master/SVNMailNotifier.py

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
#
3
 
# Licensed to the Apache Software Foundation (ASF) under one
4
 
# or more contributor license agreements.  See the NOTICE file
5
 
# distributed with this work for additional information
6
 
# regarding copyright ownership.  The ASF licenses this file
7
 
# to you under the Apache License, Version 2.0 (the
8
 
# "License"); you may not use this file except in compliance
9
 
# with the License.  You may obtain a copy of the License at
10
 
#
11
 
#   http://www.apache.org/licenses/LICENSE-2.0
12
 
#
13
 
# Unless required by applicable law or agreed to in writing,
14
 
# software distributed under the License is distributed on an
15
 
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
 
# KIND, either express or implied.  See the License for the
17
 
# specific language governing permissions and limitations
18
 
# under the License.
19
 
#
20
 
#
21
 
import os
22
 
import urllib
23
 
import re
24
 
 
25
 
from email.Message import Message
26
 
from email.Utils import formatdate
27
 
from email.MIMEText import MIMEText
28
 
 
29
 
from twisted.internet import defer
30
 
from twisted.application import service
31
 
 
32
 
from buildbot.status.builder import FAILURE, SUCCESS, WARNINGS
33
 
from buildbot.status.mail import MailNotifier
34
 
 
35
 
class SVNMailNotifier(MailNotifier):
36
 
    """Implement custom status mails for the Subversion project"""
37
 
 
38
 
    def __init__(self, fromaddr, mode="all", categories=None, builders=None,
39
 
                 addLogs=False, relayhost="localhost",
40
 
                 subject="buildbot %(result)s in %(builder)s",
41
 
                 lookup=None, extraRecipients=[],
42
 
                 sendToInterestedUsers=True,
43
 
                 body="",
44
 
                 replytoaddr=""):
45
 
        """
46
 
        @type  body: string
47
 
        @param body: a string to be used as the body of the message.
48
 
 
49
 
        @type  replytoaddr: string
50
 
        @param replytoaddr: the email address to be used in the 'Reply-To' header.
51
 
        """
52
 
 
53
 
        self.body = body
54
 
        self.replytoaddr = replytoaddr
55
 
 
56
 
        # pass the rest of the parameters to our parent.
57
 
        MailNotifier.__init__(self, fromaddr, mode, categories, builders,
58
 
                              addLogs, relayhost, subject, lookup, extraRecipients,
59
 
                              sendToInterestedUsers)
60
 
 
61
 
    def buildMessage(self, name, build, results):
62
 
        if self.mode == "all":
63
 
            intro = "The Buildbot has finished a build of %s.\n" % name
64
 
        elif self.mode == "failing":
65
 
            intro = "The Buildbot has detected a failed build of %s.\n" % name
66
 
        else:
67
 
            intro = "The Buildbot has detected a new failure of %s.\n" % name
68
 
 
69
 
        # buildurl
70
 
        buildurl = self.status.getURLForThing(build)
71
 
# lgo: url's are already quoted now.
72
 
#       if buildurl:
73
 
#            buildurl = urllib.quote(buildurl, '/:')
74
 
 
75
 
        # buildboturl
76
 
        buildboturl = self.status.getBuildbotURL()
77
 
#        if url:
78
 
#            buildboturl = urllib.quote(url, '/:')
79
 
 
80
 
        # reason of build
81
 
        buildreason = build.getReason()
82
 
 
83
 
        # source stamp
84
 
        patch = None
85
 
        ss = build.getSourceStamp()
86
 
        if ss is None:
87
 
            source = "unavailable"
88
 
        else:
89
 
            if build.getChanges():
90
 
                revision = max([int(c.revision) for c in build.getChanges()])
91
 
 
92
 
            source = ""
93
 
            if ss.branch is None:
94
 
               ss.branch = "trunk"
95
 
            source += "[branch %s] " % ss.branch
96
 
            if revision:
97
 
                source += str(revision)
98
 
            else:
99
 
                source += "HEAD"
100
 
            if ss.patch is not None:
101
 
                source += " (plus patch)"
102
 
 
103
 
        # actual buildslave
104
 
        buildslave = build.getSlavename()
105
 
 
106
 
        # TODO: maybe display changes here? or in an attachment?
107
 
 
108
 
        # status
109
 
        t = build.getText()
110
 
        if t:
111
 
            t = ": " + " ".join(t)
112
 
        else:
113
 
            t = ""
114
 
 
115
 
        if results == SUCCESS:
116
 
            status = "Build succeeded!\n"
117
 
            res = "PASS"
118
 
        elif results == WARNINGS:
119
 
            status = "Build Had Warnings%s\n" % t
120
 
            res = "WARN"
121
 
        else:
122
 
            status = "BUILD FAILED%s\n" % t
123
 
            res = "FAIL"
124
 
 
125
 
        if build.getLogs():
126
 
            log = build.getLogs()[-1]
127
 
            laststep = log.getStep().getName()
128
 
            lastlog = log.getText()
129
 
 
130
 
            # only give me the last lines of the log files.
131
 
            lines = re.split('\n', lastlog)
132
 
            lastlog = ''
133
 
            for logline in lines[max(0, len(lines)-100):]:
134
 
                lastlog = lastlog + logline
135
 
 
136
 
        # TODO: it would be nice to provide a URL for the specific build
137
 
        # here. That involves some coordination with html.Waterfall .
138
 
        # Ideally we could do:
139
 
        #  helper = self.parent.getServiceNamed("html")
140
 
        #  if helper:
141
 
        #      url = helper.getURLForBuild(build)
142
 
 
143
 
        text = self.body % { 'result': res,
144
 
                             'builder': name,
145
 
                             'revision': revision,
146
 
                             'branch': ss.branch,
147
 
                             'blamelist': ",".join(build.getResponsibleUsers()),
148
 
                             'buildurl': buildurl,
149
 
                             'buildboturl': buildboturl,
150
 
                             'reason': buildreason,
151
 
                             'source': source,
152
 
                             'intro': intro,
153
 
                             'status': status,
154
 
                             'slave': buildslave,
155
 
                             'laststep': laststep,
156
 
                             'lastlog': lastlog,
157
 
                             }
158
 
 
159
 
        haveAttachments = False
160
 
        if ss.patch or self.addLogs:
161
 
            haveAttachments = True
162
 
            if not canDoAttachments:
163
 
                log.msg("warning: I want to send mail with attachments, "
164
 
                        "but this python is too old to have "
165
 
                        "email.MIMEMultipart . Please upgrade to python-2.3 "
166
 
                        "or newer to enable addLogs=True")
167
 
 
168
 
        if haveAttachments and canDoAttachments:
169
 
            m = MIMEMultipart()
170
 
            m.attach(MIMEText(text))
171
 
        else:
172
 
            m = Message()
173
 
            m.set_payload(text)
174
 
 
175
 
        m['Date'] = formatdate(localtime=True)
176
 
        m['Subject'] = self.subject % { 'result': res,
177
 
                                        'builder': name,
178
 
                                        'revision': revision,
179
 
                                        'branch': ss.branch
180
 
                                        }
181
 
        m['From'] = self.fromaddr
182
 
        # m['To'] is added later
183
 
        m['Reply-To'] = self.replytoaddr
184
 
 
185
 
        if ss.patch:
186
 
            a = MIMEText(patch)
187
 
            a.add_header('Content-Disposition', "attachment",
188
 
                         filename="source patch")
189
 
            m.attach(a)
190
 
        if self.addLogs:
191
 
            for log in build.getLogs():
192
 
                name = "%s.%s" % (log.getStep().getName(),
193
 
                                  log.getName())
194
 
                a = MIMEText(log.getText())
195
 
                a.add_header('Content-Disposition', "attachment",
196
 
                             filename=name)
197
 
                m.attach(a)
198
 
 
199
 
        # now, who is this message going to?
200
 
        dl = []
201
 
        recipients = self.extraRecipients[:]
202
 
        if self.sendToInterestedUsers and self.lookup:
203
 
            for u in build.getInterestedUsers():
204
 
                d = defer.maybeDeferred(self.lookup.getAddress, u)
205
 
                d.addCallback(recipients.append)
206
 
                dl.append(d)
207
 
        d = defer.DeferredList(dl)
208
 
        d.addCallback(self._gotRecipients, recipients, m)
209
 
        return d
210