1
# jhbuild - a build script for GNOME 1.x and 2.x
2
# Copyright (C) 2008 apinheiro@igalia.com, John Carr, Frederic Peters
4
# __init__.py: custom buildbot web pages
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
from twisted.web import server, static, resource
23
from buildbot.status.web.base import HtmlResource, ITopBox, build_get_class
24
from buildbot import interfaces, util
25
from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION
26
from buildbot.status.web.baseweb import WebStatus
28
from waterfall import JhWaterfallStatusResource
29
from changes import ChangesResource
30
from builder import JhBuildersResource
31
from bot import JhBuildbotsResource
34
def content(self, request):
36
We want to give /all/ HTMLResource objects this replacement content method
39
s = request.site.buildbot_service
41
data = data.replace('@@GNOME_BUILDBOT_TITLE@@', self.getTitle(request))
42
data = data.replace('@@GNOME_BUILDBOT_BODY@@', self.body(request))
44
HtmlResource.content = content
46
class ProjectsSummary(HtmlResource):
50
def getTitle(self, request):
51
status = self.getStatus(request)
52
p = status.getProjectName()
55
def body(self, request):
56
parent = request.site.buildbot_service
57
status = self.getStatus(request)
60
result += '<table class="ProjectSummary">\n'
64
for slave in parent.slaves:
65
for module in parent.modules:
66
builder = status.getBuilder("%s-%s" % (module, slave))
67
state, builds = builder.getState()
68
if state == 'offline':
69
slave_status[slave] = ('offline', [])
71
elif state == 'building':
72
if slave in slave_status:
73
modules = slave_status[slave][1] or []
74
slave_status[slave] = (state, modules + [module])
76
slave_status[slave] = (state, [module])
78
if not slave in slave_status:
79
slave_status[slave] = ('idle', None)
81
result += '<thead><tr><td> </td><td> </td><th>' + parent.moduleset + '</td>'
82
for name in parent.slaves:
84
name = name[:25] + '(...)'
85
klass, modules = slave_status.get(name)
86
if klass == 'building':
87
title = 'Building %s' % ', '.join(modules)
90
result += '<th class="%s" title="%s"><a href="bots/%s">%s</a></th>' % (
91
klass, title, name, name)
94
# stop it here as a row with totals will be added here once every rows
101
for slave in parent.slaves:
102
slave_results[slave] = [0, 0, 0]
104
for module in parent.modules:
106
result += '<td class="feed"><a href="%s/atom">' % module
107
result += '<img src="/feed-atom.png" alt="Atom"></a></td>'
108
result += '<td class="feed"><a href="%s/rss">' % module
109
result += '<img src="/feed.png" alt="RSS"></a></td>\n'
110
result += '<th><a href="%s">%s</a></td>' % (module, module)
112
for slave in parent.slaves:
113
builder = status.getBuilder("%s-%s" % (module, slave))
114
box = ITopBox(builder).getBox(request)
117
if bt == 'successful' or bt == 'failed':
120
if lastbuild == 'successful':
121
last_build = builder.getLastFinishedBuild()
123
class_ = build_get_class(last_build)
126
lastbuild_label = 'Success'
127
if last_build and class_:
128
# use a different class/label if make check failed
129
steps = last_build.getSteps()
130
for step in reversed(steps):
131
if step.name.split()[-1] == 'check':
132
if step.results == WARNINGS:
134
class_ = 'failedchecks'
135
lastbuild_label = 'Failed Checks'
137
elif lastbuild == 'failed':
138
lastbuild_label = 'Failed'
139
last_build = builder.getLastFinishedBuild()
141
class_ = build_get_class(last_build)
146
lastbuild_label = lastbuild
147
state, builds = builder.getState()
148
if state == 'building':
149
result += '<td class="%s">%s</td>' % (state, state)
151
result += '<td class="%s">%s</td>' % (class_, lastbuild_label)
153
if lastbuild in ('failed', 'successful'):
154
slave_results[slave][2] += 1
155
if class_ == 'failedchecks':
156
slave_results[slave][1] += 1
157
elif lastbuild == 'successful':
158
slave_results[slave][0] += 1
159
slave_results[slave][1] += 1
162
result += '</tbody>\n'
163
result += '<tfoot><tr class="totals"><td colspan="3"></td>'
164
thead += '<tr class="totals"><td colspan="3"></td>'
165
for slave in parent.slaves:
166
td = '<td><span title="Successful builds">%s</span> '\
167
'<span title="(ignoring test suites failures)">(%s)</span> / '\
168
'<span title="Total">%s</span></td>' % tuple(slave_results[slave])
171
thead += '</tr>\n</thead>\n'
172
result += '</tr></tfoot>\n'
177
class JHBuildWebStatus(WebStatus):
179
def __init__(self, moduleset, modules, slaves, *args, **kwargs):
180
WebStatus.__init__(self, *args, **kwargs)
181
self.moduleset = moduleset
182
self.modules = modules
185
# set up the per-module waterfalls
186
for module in self.modules:
187
self.putChild(module, JhWaterfallStatusResource(categories=[module]))
189
# set the summary homepage
190
self.putChild("", ProjectsSummary())
192
# set custom changes pages
193
self.putChild('changes', ChangesResource())
194
self.putChild('builders', JhBuildersResource())
195
self.putChild('bots', JhBuildbotsResource())
198
WebStatus.setupSite(self)
200
# load the template into memory
201
self.template = open(os.path.join(self.parent.basedir, "template.html")).read()