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

Source Code for Module buildbot.status.web.build

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16   
 17  from twisted.web import html 
 18  from twisted.internet import defer, reactor 
 19  from twisted.web.util import Redirect, DeferredResource 
 20   
 21  import urllib, time 
 22  from twisted.python import log 
 23  from buildbot.status.web.base import HtmlResource, \ 
 24       css_classes, path_to_build, path_to_builder, path_to_slave, \ 
 25       getAndCheckProperties, ActionResource, path_to_authzfail 
 26  from buildbot.schedulers.forcesched import ForceScheduler, TextParameter 
 27  from buildbot.status.web.step import StepsResource 
 28  from buildbot.status.web.tests import TestsResource 
 29  from buildbot import util, interfaces 
30 31 -class ForceBuildActionResource(ActionResource):
32
33 - def __init__(self, build_status, builder):
34 self.build_status = build_status 35 self.builder = builder 36 self.action = "forceBuild"
37 38 @defer.deferredGenerator
39 - def performAction(self, req):
40 url = None 41 authz = self.getAuthz(req) 42 d = authz.actionAllowed(self.action, req, self.builder) 43 wfd = defer.waitForDeferred(d) 44 yield wfd 45 res = wfd.getResult() 46 47 if not res: 48 url = path_to_authzfail(req) 49 else: 50 # get a control object 51 c = interfaces.IControl(self.getBuildmaster(req)) 52 bc = c.getBuilder(self.builder.getName()) 53 54 b = self.build_status 55 builder_name = self.builder.getName() 56 log.msg("web rebuild of build %s:%s" % (builder_name, b.getNumber())) 57 name =authz.getUsernameFull(req) 58 comments = req.args.get("comments", ["<no reason specified>"])[0] 59 reason = ("The web-page 'rebuild' button was pressed by " 60 "'%s': %s\n" % (name, comments)) 61 msg = "" 62 extraProperties = getAndCheckProperties(req) 63 if not bc or not b.isFinished() or extraProperties is None: 64 msg = "could not rebuild: " 65 if b.isFinished(): 66 msg += "build still not finished " 67 if bc: 68 msg += "could not get builder control" 69 else: 70 d = bc.rebuildBuild(b, reason, extraProperties) 71 wfd = defer.waitForDeferred(d) 72 yield wfd 73 tup = wfd.getResult() 74 # check that (bsid, brids) were properly stored 75 if not (isinstance(tup, tuple) and 76 isinstance(tup[0], int) and 77 isinstance(tup[1], dict)): 78 msg = "rebuilding a build failed "+ str(tup) 79 # we're at 80 # http://localhost:8080/builders/NAME/builds/5/rebuild?[args] 81 # Where should we send them? 82 # 83 # Ideally it would be to the per-build page that they just started, 84 # but we don't know the build number for it yet (besides, it might 85 # have to wait for a current build to finish). The next-most 86 # preferred place is somewhere that the user can see tangible 87 # evidence of their build starting (or to see the reason that it 88 # didn't start). This should be the Builder page. 89 90 url = path_to_builder(req, self.builder), msg 91 yield url
92
93 94 -class StopBuildActionResource(ActionResource):
95
96 - def __init__(self, build_status):
97 self.build_status = build_status 98 self.action = "stopBuild"
99 100 @defer.deferredGenerator
101 - def performAction(self, req):
102 authz = self.getAuthz(req) 103 d = authz.actionAllowed(self.action, req, self.build_status) 104 wfd = defer.waitForDeferred(d) 105 yield wfd 106 res = wfd.getResult() 107 108 if not res: 109 yield path_to_authzfail(req) 110 return 111 112 b = self.build_status 113 log.msg("web stopBuild of build %s:%s" % \ 114 (b.getBuilder().getName(), b.getNumber())) 115 name = authz.getUsernameFull(req) 116 comments = req.args.get("comments", ["<no reason specified>"])[0] 117 # html-quote both the username and comments, just to be safe 118 reason = ("The web-page 'stop build' button was pressed by " 119 "'%s': %s\n" % (html.escape(name), html.escape(comments))) 120 121 c = interfaces.IControl(self.getBuildmaster(req)) 122 bldrc = c.getBuilder(self.build_status.getBuilder().getName()) 123 if bldrc: 124 bldc = bldrc.getBuild(self.build_status.getNumber()) 125 if bldc: 126 bldc.stopBuild(reason) 127 128 yield path_to_builder(req, self.build_status.getBuilder()) 129 return
130
131 # /builders/$builder/builds/$buildnum 132 -class StatusResourceBuild(HtmlResource):
133 addSlash = True 134
135 - def __init__(self, build_status):
138
139 - def getPageTitle(self, request):
140 return ("Buildbot: %s Build #%d" % 141 (self.build_status.getBuilder().getName(), 142 self.build_status.getNumber()))
143
144 - def content(self, req, cxt):
145 b = self.build_status 146 status = self.getStatus(req) 147 req.setHeader('Cache-Control', 'no-cache') 148 149 cxt['b'] = b 150 cxt['path_to_builder'] = path_to_builder(req, b.getBuilder()) 151 152 if not b.isFinished(): 153 step = b.getCurrentStep() 154 if not step: 155 cxt['current_step'] = "[waiting for Lock]" 156 else: 157 if step.isWaitingForLocks(): 158 cxt['current_step'] = "%s [waiting for Lock]" % step.getName() 159 else: 160 cxt['current_step'] = step.getName() 161 when = b.getETA() 162 if when is not None: 163 cxt['when'] = util.formatInterval(when) 164 cxt['when_time'] = time.strftime("%H:%M:%S", 165 time.localtime(time.time() + when)) 166 167 else: 168 cxt['result_css'] = css_classes[b.getResults()] 169 if b.getTestResults(): 170 cxt['tests_link'] = req.childLink("tests") 171 172 ss = cxt['ss'] = b.getSourceStamp() 173 174 if ss.branch is None and ss.revision is None and ss.patch is None and not ss.changes: 175 cxt['most_recent_rev_build'] = True 176 177 178 got_revision = b.getProperty("got_revision") 179 if got_revision: 180 cxt['got_revision'] = str(got_revision) 181 182 try: 183 cxt['slave_url'] = path_to_slave(req, status.getSlave(b.getSlavename())) 184 except KeyError: 185 pass 186 187 cxt['steps'] = [] 188 189 for s in b.getSteps(): 190 step = {'name': s.getName() } 191 192 if s.isFinished(): 193 if s.isHidden(): 194 continue 195 196 step['css_class'] = css_classes[s.getResults()[0]] 197 (start, end) = s.getTimes() 198 step['time_to_run'] = util.formatInterval(end - start) 199 elif s.isStarted(): 200 if s.isWaitingForLocks(): 201 step['css_class'] = "waiting" 202 step['time_to_run'] = "waiting for locks" 203 else: 204 step['css_class'] = "running" 205 step['time_to_run'] = "running" 206 else: 207 step['css_class'] = "not_started" 208 step['time_to_run'] = "" 209 210 cxt['steps'].append(step) 211 212 step['link'] = req.childLink("steps/%s" % 213 urllib.quote(s.getName(), safe='')) 214 step['text'] = " ".join(s.getText()) 215 step['urls'] = map(lambda x:dict(url=x[1],logname=x[0]), s.getURLs().items()) 216 217 step['logs']= [] 218 for l in s.getLogs(): 219 logname = l.getName() 220 step['logs'].append({ 'link': req.childLink("steps/%s/logs/%s" % 221 (urllib.quote(s.getName(), safe=''), 222 urllib.quote(logname, safe=''))), 223 'name': logname }) 224 225 scheduler = b.getProperty("scheduler", None) 226 parameters = {} 227 master = self.getBuildmaster(req) 228 for sch in master.allSchedulers(): 229 if isinstance(sch, ForceScheduler) and scheduler == sch.name: 230 for p in sch.all_fields: 231 parameters[p.name] = p 232 233 ps = cxt['properties'] = [] 234 for name, value, source in b.getProperties().asList(): 235 uvalue = unicode(value) 236 p = { 'name': name, 'value': uvalue, 'source': source} 237 if len(uvalue) > 500: 238 p['short_value'] = uvalue[:500] 239 if name in parameters: 240 param = parameters[name] 241 if isinstance(param, TextParameter): 242 p['text'] = param.value_to_text(value) 243 p['cols'] = param.cols 244 p['rows'] = param.rows 245 p['label'] = param.label 246 ps.append(p) 247 248 249 cxt['responsible_users'] = list(b.getResponsibleUsers()) 250 251 (start, end) = b.getTimes() 252 cxt['start'] = time.ctime(start) 253 if end: 254 cxt['end'] = time.ctime(end) 255 cxt['elapsed'] = util.formatInterval(end - start) 256 else: 257 now = util.now() 258 cxt['elapsed'] = util.formatInterval(now - start) 259 260 cxt['exactly'] = (ss.revision is not None) or b.getChanges() 261 262 cxt['build_url'] = path_to_build(req, b) 263 cxt['authz'] = self.getAuthz(req) 264 265 template = req.site.buildbot_service.templates.get_template("build.html") 266 return template.render(**cxt)
267
268 - def stop(self, req, auth_ok=False):
269 # check if this is allowed 270 if not auth_ok: 271 return StopBuildActionResource(self.build_status) 272 273 b = self.build_status 274 log.msg("web stopBuild of build %s:%s" % \ 275 (b.getBuilder().getName(), b.getNumber())) 276 277 name = self.getAuthz(req).getUsernameFull(req) 278 comments = req.args.get("comments", ["<no reason specified>"])[0] 279 # html-quote both the username and comments, just to be safe 280 reason = ("The web-page 'stop build' button was pressed by " 281 "'%s': %s\n" % (html.escape(name), html.escape(comments))) 282 283 c = interfaces.IControl(self.getBuildmaster(req)) 284 bldrc = c.getBuilder(self.build_status.getBuilder().getName()) 285 if bldrc: 286 bldc = bldrc.getBuild(self.build_status.getNumber()) 287 if bldc: 288 bldc.stopBuild(reason) 289 290 # we're at http://localhost:8080/svn-hello/builds/5/stop?[args] and 291 # we want to go to: http://localhost:8080/svn-hello 292 r = Redirect(path_to_builder(req, self.build_status.getBuilder())) 293 d = defer.Deferred() 294 reactor.callLater(1, d.callback, r) 295 return DeferredResource(d)
296
297 - def rebuild(self, req):
300
301 - def getChild(self, path, req):
302 if path == "stop": 303 return self.stop(req) 304 if path == "rebuild": 305 return self.rebuild(req) 306 if path == "steps": 307 return StepsResource(self.build_status) 308 if path == "tests": 309 return TestsResource(self.build_status) 310 311 return HtmlResource.getChild(self, path, req)
312
313 # /builders/$builder/builds 314 -class BuildsResource(HtmlResource):
315 addSlash = True 316
317 - def __init__(self, builder_status):
318 HtmlResource.__init__(self) 319 self.builder_status = builder_status
320
321 - def content(self, req, cxt):
322 return "subpages shows data for each build"
323
324 - def getChild(self, path, req):
325 try: 326 num = int(path) 327 except ValueError: 328 num = None 329 if num is not None: 330 build_status = self.builder_status.getBuild(num) 331 if build_status: 332 return StatusResourceBuild(build_status) 333 334 return HtmlResource.getChild(self, path, req)
335