1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 from twisted.web import html
18 from twisted.web.util import Redirect
19 import urllib, time
20 from twisted.python import log
21 from twisted.internet import defer
22 from buildbot import interfaces
23 from buildbot.status.web.base import HtmlResource, BuildLineMixin, \
24 path_to_build, path_to_slave, path_to_builder, path_to_change, \
25 path_to_root, getAndCheckProperties, ICurrentBox, build_get_class, \
26 map_branches, path_to_authfail, ActionResource
27
28 from buildbot.status.web.build import BuildsResource, StatusResourceBuild
29 from buildbot import util
33 addSlash = True
34
38
39 - def getPageTitle(self, request):
40 return "Buildbot: %s" % self.builder_status.getName()
41
67
68 @defer.deferredGenerator
69 - def content(self, req, cxt):
70 b = self.builder_status
71
72 cxt['name'] = b.getName()
73 req.setHeader('Cache-Control', 'no-cache')
74 slaves = b.getSlaves()
75 connected_slaves = [s for s in slaves if s.isConnected()]
76
77 cxt['current'] = [self.builder(x, req) for x in b.getCurrentBuilds()]
78
79 cxt['pending'] = []
80 wfd = defer.waitForDeferred(
81 b.getPendingBuildRequestStatuses())
82 yield wfd
83 statuses = wfd.getResult()
84 for pb in statuses:
85 changes = []
86
87 wfd = defer.waitForDeferred(
88 pb.getSourceStamp())
89 yield wfd
90 source = wfd.getResult()
91
92 wfd = defer.waitForDeferred(
93 pb.getSubmitTime())
94 yield wfd
95 submitTime = wfd.getResult()
96
97 if source.changes:
98 for c in source.changes:
99 changes.append({ 'url' : path_to_change(req, c),
100 'who' : c.who,
101 'revision' : c.revision,
102 'repo' : c.repository })
103
104 cxt['pending'].append({
105 'when': time.strftime("%b %d %H:%M:%S",
106 time.localtime(submitTime)),
107 'delay': util.formatInterval(util.now() - submitTime),
108 'id': pb.brid,
109 'changes' : changes,
110 'num_changes' : len(changes),
111 })
112
113 numbuilds = int(req.args.get('numbuilds', ['5'])[0])
114 recent = cxt['recent'] = []
115 for build in b.generateFinishedBuilds(num_builds=int(numbuilds)):
116 recent.append(self.get_line_values(req, build, False))
117
118 sl = cxt['slaves'] = []
119 connected_slaves = 0
120 for slave in slaves:
121 s = {}
122 sl.append(s)
123 s['link'] = path_to_slave(req, slave)
124 s['name'] = slave.getName()
125 c = s['connected'] = slave.isConnected()
126 if c:
127 s['admin'] = unicode(slave.getAdmin() or '', 'utf-8')
128 connected_slaves += 1
129 cxt['connected_slaves'] = connected_slaves
130
131 cxt['authz'] = self.getAuthz(req)
132 cxt['builder_url'] = path_to_builder(req, b)
133
134 template = req.site.buildbot_service.templates.get_template("builder.html")
135 yield template.render(**cxt)
136
137 - def force(self, req, auth_ok=False):
138 name = req.args.get("username", ["<unknown>"])[0]
139 reason = req.args.get("comments", ["<no reason specified>"])[0]
140 branch = req.args.get("branch", [""])[0]
141 revision = req.args.get("revision", [""])[0]
142 repository = req.args.get("repository", [""])[0]
143 project = req.args.get("project", [""])[0]
144
145 log.msg("web forcebuild of builder '%s', branch='%s', revision='%s',"
146 " repository='%s', project='%s' by user '%s'" % (
147 self.builder_status.getName(), branch, revision, repository,
148 project, name))
149
150
151 if not auth_ok:
152 if not self.getAuthz(req).actionAllowed('forceBuild', req, self.builder_status):
153 log.msg("..but not authorized")
154 return Redirect(path_to_authfail(req))
155
156 master = self.getBuildmaster(req)
157
158
159 branch_validate = master.config.validation['branch']
160 revision_validate = master.config.validation['revision']
161 if not branch_validate.match(branch):
162 log.msg("bad branch '%s'" % branch)
163 return Redirect(path_to_builder(req, self.builder_status))
164 if not revision_validate.match(revision):
165 log.msg("bad revision '%s'" % revision)
166 return Redirect(path_to_builder(req, self.builder_status))
167 properties = getAndCheckProperties(req)
168 if properties is None:
169 return Redirect(path_to_builder(req, self.builder_status))
170 if not branch:
171 branch = None
172 if not revision:
173 revision = None
174
175 d = master.db.sourcestamps.addSourceStamp(branch=branch,
176 revision=revision, project=project, repository=repository)
177 def make_buildset(ssid):
178 r = ("The web-page 'force build' button was pressed by '%s': %s\n"
179 % (html.escape(name), html.escape(reason)))
180 return master.addBuildset(
181 builderNames=[self.builder_status.getName()],
182 ssid=ssid, reason=r, properties=properties.asDict())
183 d.addCallback(make_buildset)
184 d.addErrback(log.err, "(ignored) while trying to force build")
185
186 return Redirect(path_to_builder(req, self.builder_status))
187
188 - def ping(self, req):
198
212
214
218
219 @defer.deferredGenerator
254
256
257 @defer.deferredGenerator
259 try:
260 request_change = req.args.get("change", [None])[0]
261 request_change = int(request_change)
262 except:
263 request_change = None
264
265 authz = self.getAuthz(req)
266 if request_change:
267 c = interfaces.IControl(self.getBuildmaster(req))
268 builder_control = c.getBuilder(builder_status.getName())
269
270 wfd = defer.waitForDeferred(
271 builder_control.getPendingBuildRequestControls())
272 yield wfd
273 brcontrols = wfd.getResult()
274
275 build_controls = dict((x.brid, x) for x in brcontrols)
276
277 wfd = defer.waitForDeferred(
278 builder_status.getPendingBuildRequestStatuses())
279 yield wfd
280 build_req_statuses = wfd.getResult()
281
282 for build_req in build_req_statuses:
283 wfd = defer.waitForDeferred(
284 build_req.getSourceStamp())
285 yield wfd
286 ss = wfd.getResult()
287
288 if not ss.changes:
289 continue
290
291 for change in ss.changes:
292 if change.number == request_change:
293 control = build_controls[build_req.brid]
294 log.msg("Cancelling %s" % control)
295 if (auth_ok or authz.actionAllowed('stopChange',
296 req, control)):
297 control.cancel()
298 else:
299 yield False
300 return
301
302 yield True
303
306
310
311 @defer.deferredGenerator
323
326
330
331 @defer.deferredGenerator
349
398
445
449 pageTitle = "Builders"
450 addSlash = True
451
452 @defer.deferredGenerator
453 - def content(self, req, cxt):
454 status = self.getStatus(req)
455
456 builders = req.args.get("builder", status.getBuilderNames())
457 branches = [b for b in req.args.get("branch", []) if b]
458
459
460 brstatus_ds = []
461 brcounts = {}
462 def keep_count(statuses, builderName):
463 brcounts[builderName] = len(statuses)
464 for builderName in builders:
465 builder_status = status.getBuilder(builderName)
466 d = builder_status.getPendingBuildRequestStatuses()
467 d.addCallback(keep_count, builderName)
468 brstatus_ds.append(d)
469 wfd = defer.waitForDeferred(
470 defer.gatherResults(brstatus_ds))
471 yield wfd
472 wfd.getResult()
473
474 cxt['branches'] = branches
475 bs = cxt['builders'] = []
476
477 building = 0
478 online = 0
479 base_builders_url = path_to_root(req) + "builders/"
480 for bn in builders:
481 bld = { 'link': base_builders_url + urllib.quote(bn, safe=''),
482 'name': bn }
483 bs.append(bld)
484
485 builder = status.getBuilder(bn)
486 builds = list(builder.generateFinishedBuilds(map_branches(branches),
487 num_builds=1))
488 if builds:
489 b = builds[0]
490 bld['build_url'] = (bld['link'] + "/builds/%d" % b.getNumber())
491 try:
492 label = b.getProperty("got_revision")
493 except KeyError:
494 label = None
495 if not label or len(str(label)) > 20:
496 label = "#%d" % b.getNumber()
497
498 bld['build_label'] = label
499 bld['build_text'] = " ".join(b.getText())
500 bld['build_css_class'] = build_get_class(b)
501
502 current_box = ICurrentBox(builder).getBox(status, brcounts)
503 bld['current_box'] = current_box.td()
504
505 builder_status = builder.getState()[0]
506 if builder_status == "building":
507 building += 1
508 online += 1
509 elif builder_status != "offline":
510 online += 1
511
512 cxt['authz'] = self.getAuthz(req)
513 cxt['num_building'] = building
514 cxt['num_online'] = online
515
516 template = req.site.buildbot_service.templates.get_template("builders.html")
517 yield template.render(**cxt)
518
530