Package buildbot :: Package status :: Package web :: Module builder
[frames] | no frames]

Source Code for Module buildbot.status.web.builder

  1   
  2  from twisted.web import html 
  3  from twisted.web.util import Redirect 
  4   
  5  import re, urllib, time 
  6  from twisted.python import log 
  7  from buildbot import interfaces 
  8  from buildbot.status.web.base import HtmlResource, BuildLineMixin, \ 
  9      path_to_build, path_to_slave, path_to_builder, path_to_change, \ 
 10      path_to_root, getAndCheckProperties, ICurrentBox, build_get_class, \ 
 11      map_branches, path_to_authfail 
 12  from buildbot.sourcestamp import SourceStamp 
 13   
 14  from buildbot.status.web.build import BuildsResource, StatusResourceBuild 
 15  from buildbot import util 
 16   
 17  # /builders/$builder 
18 -class StatusResourceBuilder(HtmlResource, BuildLineMixin):
19 addSlash = True 20
21 - def __init__(self, builder_status):
22 HtmlResource.__init__(self) 23 self.builder_status = builder_status
24
25 - def getTitle(self, request):
26 return "Buildbot: %s" % self.builder_status.getName()
27
28 - def builder(self, build, req):
29 b = {} 30 31 b['num'] = build.getNumber() 32 b['link'] = path_to_build(req, build) 33 34 when = build.getETA() 35 if when is not None: 36 b['when'] = util.formatInterval(when) 37 b['when_time'] = time.strftime("%H:%M:%S", 38 time.localtime(time.time() + when)) 39 40 step = build.getCurrentStep() 41 if step: 42 b['current_step'] = step.getName() 43 else: 44 b['current_step'] = "[waiting for Lock]" 45 # TODO: is this necessarily the case? 46 47 b['stop_url'] = path_to_build(req, build) + '/stop' 48 49 return b
50
51 - def content(self, req, cxt):
52 b = self.builder_status 53 54 cxt['name'] = b.getName() 55 56 slaves = b.getSlaves() 57 connected_slaves = [s for s in slaves if s.isConnected()] 58 59 cxt['current'] = [self.builder(x, req) for x in b.getCurrentBuilds()] 60 61 cxt['pending'] = [] 62 for pb in b.getPendingBuilds(): 63 source = pb.getSourceStamp() 64 changes = [] 65 66 if source.changes: 67 for c in source.changes: 68 changes.append({ 'url' : path_to_change(req, c), 69 'who' : c.who}) 70 if source.revision: 71 reason = source.revision 72 else: 73 reason = "no changes specified" 74 75 cxt['pending'].append({ 76 'when': time.strftime("%b %d %H:%M:%S", time.localtime(pb.getSubmitTime())), 77 'delay': util.formatInterval(util.now() - pb.getSubmitTime()), 78 'reason': reason, 79 'id': pb.brid, 80 'changes' : changes 81 }) 82 83 numbuilds = int(req.args.get('numbuilds', ['5'])[0]) 84 recent = cxt['recent'] = [] 85 for build in b.generateFinishedBuilds(num_builds=int(numbuilds)): 86 recent.append(self.get_line_values(req, build, False)) 87 88 sl = cxt['slaves'] = [] 89 connected_slaves = 0 90 for slave in slaves: 91 s = {} 92 sl.append(s) 93 s['link'] = path_to_slave(req, slave) 94 s['name'] = slave.getName() 95 c = s['connected'] = slave.isConnected() 96 if c: 97 s['admin'] = slave.getAdmin() 98 connected_slaves += 1 99 cxt['connected_slaves'] = connected_slaves 100 101 cxt['authz'] = self.getAuthz(req) 102 cxt['builder_url'] = path_to_builder(req, b) 103 104 template = req.site.buildbot_service.templates.get_template("builder.html") 105 return template.render(**cxt)
106
107 - def force(self, req, auth_ok=False):
108 name = req.args.get("username", ["<unknown>"])[0] 109 reason = req.args.get("comments", ["<no reason specified>"])[0] 110 branch = req.args.get("branch", [""])[0] 111 revision = req.args.get("revision", [""])[0] 112 113 r = "The web-page 'force build' button was pressed by '%s': %s\n" \ 114 % (html.escape(name), html.escape(reason)) 115 log.msg("web forcebuild of builder '%s', branch='%s', revision='%s'" 116 " by user '%s'" % (self.builder_status.getName(), branch, 117 revision, name)) 118 119 # check if this is allowed 120 if not auth_ok: 121 if not self.getAuthz(req).actionAllowed('forceBuild', req, self.builder_status): 122 log.msg("..but not authorized") 123 return Redirect(path_to_authfail(req)) 124 125 # keep weird stuff out of the branch revision, and property strings. 126 # TODO: centralize this somewhere. 127 if not re.match(r'^[\w\.\-\/]*$', branch): 128 log.msg("bad branch '%s'" % branch) 129 return Redirect(path_to_builder(req, self.builder_status)) 130 if not re.match(r'^[\w\.\-\/]*$', revision): 131 log.msg("bad revision '%s'" % revision) 132 return Redirect(path_to_builder(req, self.builder_status)) 133 properties = getAndCheckProperties(req) 134 if properties is None: 135 return Redirect(path_to_builder(req, self.builder_status)) 136 if not branch: 137 branch = None 138 if not revision: 139 revision = None 140 141 # TODO: if we can authenticate that a particular User pushed the 142 # button, use their name instead of None, so they'll be informed of 143 # the results. 144 # TODO2: we can authenticate that a particular User pushed the button 145 # now, so someone can write this support. but it requires a 146 # buildbot.changes.changes.Change instance which is tedious at this 147 # stage to compute 148 s = SourceStamp(branch=branch, revision=revision) 149 try: 150 c = interfaces.IControl(self.getBuildmaster(req)) 151 bc = c.getBuilder(self.builder_status.getName()) 152 bc.submitBuildRequest(s, r, properties, now=True) 153 except interfaces.NoSlaveError: 154 # TODO: tell the web user that their request could not be 155 # honored 156 pass 157 # send the user back to the builder page 158 return Redirect(path_to_builder(req, self.builder_status))
159
160 - def ping(self, req):
161 log.msg("web ping of builder '%s'" % self.builder_status.getName()) 162 if not self.getAuthz(req).actionAllowed('pingBuilder', req, self.builder_status): 163 log.msg("..but not authorized") 164 return Redirect(path_to_authfail(req)) 165 c = interfaces.IControl(self.getBuildmaster(req)) 166 bc = c.getBuilder(self.builder_status.getName()) 167 bc.ping() 168 # send the user back to the builder page 169 return Redirect(path_to_builder(req, self.builder_status))
170
171 - def cancelbuild(self, req):
172 try: 173 request_id = req.args.get("id", [None])[0] 174 if request_id == "all": 175 cancel_all = True 176 else: 177 cancel_all = False 178 request_id = int(request_id) 179 except: 180 request_id = None 181 182 authz = self.getAuthz(req) 183 if request_id: 184 c = interfaces.IControl(self.getBuildmaster(req)) 185 bc = c.getBuilder(self.builder_status.getName()) 186 for build_req in bc.getPendingBuilds(): 187 if cancel_all or (build_req.brid == request_id): 188 log.msg("Cancelling %s" % build_req) 189 if authz.actionAllowed('cancelPendingBuild', req, build_req): 190 build_req.cancel() 191 else: 192 return Redirect(path_to_authfail(req)) 193 if not cancel_all: 194 break 195 return Redirect(path_to_builder(req, self.builder_status))
196
197 - def getChild(self, path, req):
198 if path == "force": 199 return self.force(req) 200 if path == "ping": 201 return self.ping(req) 202 if path == "cancelbuild": 203 return self.cancelbuild(req) 204 if path == "builds": 205 return BuildsResource(self.builder_status) 206 207 return HtmlResource.getChild(self, path, req)
208 209 210 # /builders/_all
211 -class StatusResourceAllBuilders(HtmlResource, BuildLineMixin):
212
213 - def __init__(self, status):
214 HtmlResource.__init__(self) 215 self.status = status
216
217 - def getChild(self, path, req):
218 if path == "forceall": 219 return self.forceall(req) 220 if path == "stopall": 221 return self.stopall(req) 222 223 return HtmlResource.getChild(self, path, req)
224
225 - def forceall(self, req):
226 authz = self.getAuthz(req) 227 if not authz.actionAllowed('forceAllBuilds', req): 228 return Redirect(path_to_authfail(req)) 229 230 for bname in self.status.getBuilderNames(): 231 builder_status = self.status.getBuilder(bname) 232 build = StatusResourceBuilder(builder_status) 233 build.force(req, auth_ok=True) # auth_ok because we already checked 234 # back to the welcome page 235 return Redirect(path_to_root(req))
236
237 - def stopall(self, req):
238 authz = self.getAuthz(req) 239 if not authz.actionAllowed('stopAllBuilds', req): 240 return Redirect(path_to_authfail(req)) 241 242 for bname in self.status.getBuilderNames(): 243 builder_status = self.status.getBuilder(bname) 244 (state, current_builds) = builder_status.getState() 245 if state != "building": 246 continue 247 for b in current_builds: 248 build_status = builder_status.getBuild(b.number) 249 if not build_status: 250 continue 251 build = StatusResourceBuild(build_status) 252 build.stop(req, auth_ok=True) 253 # go back to the welcome page 254 return Redirect(path_to_root(req))
255 256 257 # /builders
258 -class BuildersResource(HtmlResource):
259 title = "Builders" 260 addSlash = True 261
262 - def content(self, req, cxt):
263 status = self.getStatus(req) 264 265 builders = req.args.get("builder", status.getBuilderNames()) 266 branches = [b for b in req.args.get("branch", []) if b] 267 268 cxt['branches'] = branches 269 bs = cxt['builders'] = [] 270 271 building = 0 272 online = 0 273 base_builders_url = path_to_root(req) + "builders/" 274 for bn in builders: 275 bld = { 'link': base_builders_url + urllib.quote(bn, safe=''), 276 'name': bn } 277 bs.append(bld) 278 279 builder = status.getBuilder(bn) 280 builds = list(builder.generateFinishedBuilds(map_branches(branches), 281 num_builds=1)) 282 if builds: 283 b = builds[0] 284 bld['build_url'] = (bld['link'] + "/builds/%d" % b.getNumber()) 285 try: 286 label = b.getProperty("got_revision") 287 except KeyError: 288 label = None 289 if not label or len(str(label)) > 20: 290 label = "#%d" % b.getNumber() 291 292 bld['build_label'] = label 293 bld['build_text'] = " ".join(b.getText()) 294 bld['build_css_class'] = build_get_class(b) 295 296 current_box = ICurrentBox(builder).getBox(status) 297 bld['current_box'] = current_box.td() 298 299 builder_status = builder.getState()[0] 300 if builder_status == "building": 301 building += 1 302 online += 1 303 elif builder_status != "offline": 304 online += 1 305 306 cxt['authz'] = self.getAuthz(req) 307 cxt['num_building'] = building 308 cxt['num_online'] = online 309 310 template = req.site.buildbot_service.templates.get_template("builders.html") 311 return template.render(**cxt)
312
313 - def getChild(self, path, req):
314 s = self.getStatus(req) 315 if path in s.getBuilderNames(): 316 builder_status = s.getBuilder(path) 317 return StatusResourceBuilder(builder_status) 318 if path == "_all": 319 return StatusResourceAllBuilders(self.getStatus(req)) 320 321 return HtmlResource.getChild(self, path, req)
322