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