def body(self, request): "This method builds the main waterfall display." status = self.getStatus(request) data = '' projectName = status.getProjectName() projectURL = status.getProjectURL() phase = request.args.get("phase", ["2"]) phase = int(phase[0]) # we start with all Builders available to this Waterfall: this is # limited by the config-file -time categories= argument, and defaults # to all defined Builders. allBuilderNames = status.getBuilderNames(categories=self.categories) builders = [status.getBuilder(name) for name in allBuilderNames] # but if the URL has one or more builder= arguments (or the old show= # argument, which is still accepted for backwards compatibility), we # use that set of builders instead. We still don't show anything # outside the config-file time set limited by categories=. showBuilders = request.args.get("show", []) showBuilders.extend(request.args.get("builder", [])) if showBuilders: builders = [b for b in builders if b.name in showBuilders] # now, if the URL has one or category= arguments, use them as a # filter: only show those builders which belong to one of the given # categories. showCategories = request.args.get("category", []) if showCategories: builders = [b for b in builders if b.category in showCategories] builderNames = [b.name for b in builders] if phase == -1: return self.body0(request, builders) (changeNames, builderNames, timestamps, eventGrid, sourceEvents) = \ self.buildGrid(request, builders) if phase == 0: return self.phase0(request, (changeNames + builderNames), timestamps, eventGrid) # start the table: top-header material data += '<table border="0" cellspacing="0">\n' if projectName and projectURL: # TODO: this is going to look really ugly topleft = '<a href="%s">%s</a><br />last build' % \ (projectURL, projectName) else: topleft = "last build" data += ' <tr class="LastBuild">\n' data += td(topleft, align="right", colspan=2, class_="Project") for b in builders: box = ITopBox(b).getBox(request) data += box.td(align="center") data += " </tr>\n" data += ' <tr class="Activity">\n' data += td('current activity', align='right', colspan=2) for b in builders: box = ICurrentBox(b).getBox(status) data += box.td(align="center") data += " </tr>\n" data += " <tr>\n" TZ = time.tzname[time.localtime()[-1]] data += td("time (%s)" % TZ, align="center", class_="Time") data += td('<a href="%s">changes</a>' % request.childLink("../changes"), align="center", class_="Change") for name in builderNames: safename = urllib.quote(name, safe='') data += td('<a href="%s">%s</a>' % (request.childLink("../builders/%s" % safename), name), align="center", class_="Builder") data += " </tr>\n" if phase == 1: f = self.phase1 else: f = self.phase2 data += f(request, changeNames + builderNames, timestamps, eventGrid, sourceEvents) data += "</table>\n" data += '<hr /><div class="footer">\n' def with_args(req, remove_args=[], new_args=[], new_path=None): # sigh, nevow makes this sort of manipulation easier newargs = req.args.copy() for argname in remove_args: newargs[argname] = [] if "branch" in newargs: newargs["branch"] = [b for b in newargs["branch"] if b] for k, v in new_args: if k in newargs: newargs[k].append(v) else: newargs[k] = [v] newquery = "&".join( ["%s=%s" % (k, v) for k in newargs for v in newargs[k]]) if new_path: new_url = new_path elif req.prepath: new_url = req.prepath[-1] else: new_url = '' if newquery: new_url += "?" + newquery return new_url if timestamps: bottom = timestamps[-1] nextpage = with_args(request, ["last_time"], [("last_time", str(int(bottom)))]) data += '[<a href="%s">next page</a>]\n' % nextpage helpurl = self.path_to_root(request) + "waterfall/help" helppage = with_args(request, new_path=helpurl) data += '[<a href="%s">help</a>]\n' % helppage welcomeurl = self.path_to_root(request) + "index.html" data += '[<a href="%s">welcome</a>]\n' % welcomeurl if self.get_reload_time(request) is not None: no_reload_page = with_args(request, remove_args=["reload"]) data += '[<a href="%s">Stop Reloading</a>]\n' % no_reload_page data += "<br />\n" bburl = "http://buildbot.net/?bb-ver=%s" % urllib.quote(version) data += '<a href="%s">Buildbot-%s</a> ' % (bburl, version) if projectName: data += "working for the " if projectURL: data += '<a href="%s">%s</a> project.' % (projectURL, projectName) else: data += "%s project." % projectName data += "<br />\n" # TODO: push this to the right edge, if possible data += ("Page built: " + time.strftime( "%a %d %b %Y %H:%M:%S", time.localtime(util.now())) + "\n") data += '</div>\n' return "%s %s" % (self.GetAnnounce(), data)
def body(self, request): "This method builds the main waterfall display." status = self.getStatus(request) data = '' projectName = status.getProjectName() projectURL = status.getProjectURL() phase = request.args.get("phase",["2"]) phase = int(phase[0]) # we start with all Builders available to this Waterfall: this is # limited by the config-file -time categories= argument, and defaults # to all defined Builders. allBuilderNames = status.getBuilderNames(categories=self.categories) builders = [status.getBuilder(name) for name in allBuilderNames] # but if the URL has one or more builder= arguments (or the old show= # argument, which is still accepted for backwards compatibility), we # use that set of builders instead. We still don't show anything # outside the config-file time set limited by categories=. showBuilders = request.args.get("show", []) showBuilders.extend(request.args.get("builder", [])) if showBuilders: builders = [b for b in builders if b.name in showBuilders] # now, if the URL has one or category= arguments, use them as a # filter: only show those builders which belong to one of the given # categories. showCategories = request.args.get("category", []) if showCategories: builders = [b for b in builders if b.category in showCategories] # If the URL has the failures_only=true argument, we remove all the # builders that are not currently red or won't be turning red at the end # of their current run. failuresOnly = request.args.get("failures_only", ["false"])[0] if failuresOnly.lower() == "true": builders = [b for b in builders if not self.isSuccess(b)] builderNames = [b.name for b in builders] if phase == -1: return self.body0(request, builders) (changeNames, builderNames, timestamps, eventGrid, sourceEvents) = \ self.buildGrid(request, builders) if phase == 0: return self.phase0(request, (changeNames + builderNames), timestamps, eventGrid) # start the table: top-header material data += '<table border="0" cellspacing="0">\n' if projectName and projectURL: # TODO: this is going to look really ugly topleft = '<a href="%s">%s</a><br />last build' % \ (projectURL, projectName) else: topleft = "last build" data += ' <tr class="LastBuild">\n' data += td(topleft, align="right", colspan=2, class_="Project") for b in builders: box = ITopBox(b).getBox(request) data += box.td(align="center") data += " </tr>\n" data += ' <tr class="Activity">\n' data += td('current activity', align='right', colspan=2) for b in builders: box = ICurrentBox(b).getBox(status) data += box.td(align="center") data += " </tr>\n" data += " <tr>\n" TZ = time.tzname[time.localtime()[-1]] data += td("time (%s)" % TZ, align="center", class_="Time") data += td('<a href="%s">changes</a>' % request.childLink("../changes"), align="center", class_="Change") for name in builderNames: safename = urllib.quote(name, safe='') data += td('<a href="%s">%s</a>' % (request.childLink("../builders/%s" % safename), name), align="center", class_="Builder") data += " </tr>\n" if phase == 1: f = self.phase1 else: f = self.phase2 data += f(request, changeNames + builderNames, timestamps, eventGrid, sourceEvents) data += "</table>\n" data += '<hr /><div class="footer">\n' def with_args(req, remove_args=[], new_args=[], new_path=None): # sigh, nevow makes this sort of manipulation easier newargs = req.args.copy() for argname in remove_args: newargs[argname] = [] if "branch" in newargs: newargs["branch"] = [b for b in newargs["branch"] if b] for k,v in new_args: if k in newargs: newargs[k].append(v) else: newargs[k] = [v] newquery = "&".join(["%s=%s" % (k, v) for k in newargs for v in newargs[k] ]) if new_path: new_url = new_path elif req.prepath: new_url = req.prepath[-1] else: new_url = '' if newquery: new_url += "?" + newquery return new_url if timestamps: bottom = timestamps[-1] nextpage = with_args(request, ["last_time"], [("last_time", str(int(bottom)))]) data += '[<a href="%s">next page</a>]\n' % nextpage helpurl = self.path_to_root(request) + "waterfall/help" helppage = with_args(request, new_path=helpurl) data += '[<a href="%s">help</a>]\n' % helppage welcomeurl = self.path_to_root(request) + "index.html" data += '[<a href="%s">welcome</a>]\n' % welcomeurl if self.get_reload_time(request) is not None: no_reload_page = with_args(request, remove_args=["reload"]) data += '[<a href="%s">Stop Reloading</a>]\n' % no_reload_page data += "<br />\n" bburl = "http://buildbot.net/?bb-ver=%s" % urllib.quote(version) data += '<a href="%s">Buildbot-%s</a> ' % (bburl, version) if projectName: data += "working for the " if projectURL: data += '<a href="%s">%s</a> project.' % (projectURL, projectName) else: data += "%s project." % projectName data += "<br />\n" # TODO: push this to the right edge, if possible data += ("Page built: " + time.strftime("%a %d %b %Y %H:%M:%S", time.localtime(util.now())) + "\n") data += '</div>\n' return data
def content_with_db_data(self, changes, brcounts, request, ctx): status = self.getStatus(request) ctx['refresh'] = self.get_reload_time(request) # we start with all Builders available to this Waterfall: this is # limited by the config-file -time categories= argument, and defaults # to all defined Builders. allBuilderNames = status.getBuilderNames(categories=self.categories) builders = [status.getBuilder(name) for name in allBuilderNames] # but if the URL has one or more builder= arguments (or the old show= # argument, which is still accepted for backwards compatibility), we # use that set of builders instead. We still don't show anything # outside the config-file time set limited by categories=. showBuilders = request.args.get("show", []) showBuilders.extend(request.args.get("builder", [])) if showBuilders: builders = [b for b in builders if b.name in showBuilders] # now, if the URL has one or category= arguments, use them as a # filter: only show those builders which belong to one of the given # categories. showCategories = request.args.get("category", []) if showCategories: builders = [b for b in builders if b.category in showCategories] # If the URL has the failures_only=true argument, we remove all the # builders that are not currently red or won't be turning red at the end # of their current run. failuresOnly = request.args.get("failures_only", ["false"])[0] if failuresOnly.lower() == "true": builders = [b for b in builders if not self.isSuccess(b)] (changeNames, builderNames, timestamps, eventGrid, sourceEvents) = \ self.buildGrid(request, builders, changes) # start the table: top-header material locale_enc = locale.getdefaultlocale()[1] if locale_enc is not None: locale_tz = unicode(time.tzname[time.localtime()[-1]], locale_enc) else: locale_tz = unicode(time.tzname[time.localtime()[-1]]) ctx['tz'] = locale_tz ctx['changes_url'] = request.childLink("../changes") bn = ctx['builders'] = [] for name in builderNames: builder = status.getBuilder(name) top_box = ITopBox(builder).getBox(request) current_box = ICurrentBox(builder).getBox(status, brcounts) bn.append({'name': name, 'url': request.childLink("../builders/%s" % urllib.quote(name, safe='')), 'top': top_box.text, 'top_class': top_box.class_, 'status': current_box.text, 'status_class': current_box.class_, }) ctx.update(self.phase2(request, changeNames + builderNames, timestamps, eventGrid, sourceEvents)) def with_args(req, remove_args=[], new_args=[], new_path=None): # sigh, nevow makes this sort of manipulation easier newargs = req.args.copy() for argname in remove_args: newargs[argname] = [] if "branch" in newargs: newargs["branch"] = [b for b in newargs["branch"] if b] for k,v in new_args: if k in newargs: newargs[k].append(v) else: newargs[k] = [v] newquery = "&".join(["%s=%s" % (urllib.quote(k), urllib.quote(v)) for k in newargs for v in newargs[k] ]) if new_path: new_url = new_path elif req.prepath: new_url = req.prepath[-1] else: new_url = '' if newquery: new_url += "?" + newquery return new_url if timestamps: bottom = timestamps[-1] ctx['nextpage'] = with_args(request, ["last_time"], [("last_time", str(int(bottom)))]) helpurl = path_to_root(request) + "waterfall/help" ctx['help_url'] = with_args(request, new_path=helpurl) if self.get_reload_time(request) is not None: ctx['no_reload_page'] = with_args(request, remove_args=["reload"]) template = request.site.buildbot_service.templates.get_template("waterfall.html") data = template.render(**ctx) return data
def body(self, request): # summary of changes between this method and the overriden one: # - more structural markup and CSS # - removal of the phase stuff, only keep one "This method builds the main waterfall display." status = self.getStatus(request) data = '' projectName = status.getProjectName() projectURL = status.getProjectURL() # we start with all Builders available to this Waterfall: this is # limited by the config-file -time categories= argument, and defaults # to all defined Builders. allBuilderNames = status.getBuilderNames(categories=self.categories) builders = [status.getBuilder(name) for name in allBuilderNames] # but if the URL has one or more builder= arguments (or the old show= # argument, which is still accepted for backwards compatibility), we # use that set of builders instead. We still don't show anything # outside the config-file time set limited by categories=. showBuilders = request.args.get("show", []) showBuilders.extend(request.args.get("builder", [])) if showBuilders: builders = [b for b in builders if b.name in showBuilders] # now, if the URL has one or category= arguments, use them as a # filter: only show those builders which belong to one of the given # categories. showCategories = request.args.get("category", []) if showCategories: builders = [b for b in builders if b.category in showCategories] builderNames = [b.name for b in builders] (changeNames, builderNames, timestamps, eventGrid, sourceEvents) = \ self.buildGrid(request, builders) # start the table: top-header material data += '<table class="waterfall">\n' data += '<thead>\n' data += '<tr>\n' data += '<td colspan="2"></td>' for b in builders: state, builds = b.getState() builder_name = b.name[len(self.module_name) + 1:] data += '<th class="%s" title="%s"><a href="%s">%s</a></th>' % ( state, state, request.childLink('../builders/%s' % urllib.quote(b.name, safe='')), builder_name) data += '</tr>\n' data += '<tr>' data += '<th>time<br/>(%s)</th>' % time.tzname[time.localtime()[-1]] data += '<th class="Change">changes</th>' for b in builders: box = ITopBox(b).getBox(request) data += box.td(align="center") data += '</tr>' data += '</thead>' data += '<tbody>' data += self.phase2(request, changeNames + builderNames, timestamps, eventGrid, sourceEvents) data += '</tbody>\n' data += '<tfoot>\n' def with_args(req, remove_args=[], new_args=[], new_path=None): # sigh, nevow makes this sort of manipulation easier newargs = req.args.copy() for argname in remove_args: newargs[argname] = [] if "branch" in newargs: newargs["branch"] = [b for b in newargs["branch"] if b] for k, v in new_args: if k in newargs: newargs[k].append(v) else: newargs[k] = [v] newquery = "&".join( ["%s=%s" % (k, v) for k in newargs for v in newargs[k]]) if new_path: new_url = new_path elif req.prepath: new_url = req.prepath[-1] else: new_url = '' if newquery: new_url += "?" + newquery return new_url if timestamps: data += '<tr>' bottom = timestamps[-1] nextpage = with_args(request, ["last_time"], [("last_time", str(int(bottom)))]) data += '<td class="Time"><a href="%s">next page</a></td>\n' % nextpage data += '</tr>' data += '</tfoot>\n' data += "</table>\n" return data
def body(self, request): parent = request.site.buildbot_service status = self.getStatus(request) result = '' result += '<table class="ProjectSummary">\n' # Headers slave_status = {} for slave in parent.slaves: for module in parent.modules: builder = status.getBuilder("%s-%s" % (module, slave)) state, builds = builder.getState() if state == 'offline': slave_status[slave] = ('offline', []) break elif state == 'building': if slave in slave_status: modules = slave_status[slave][1] or [] slave_status[slave] = (state, modules + [module]) else: slave_status[slave] = (state, [module]) else: if not slave in slave_status: slave_status[slave] = ('idle', None) if type(parent.moduleset) is list: moduleset = ', '.join(parent.moduleset) else: moduleset = parent.moduleset result += '<thead><tr><td> </td><th>' + moduleset + '</td>' for name in parent.slaves: if len(name) > 25: name = name[:25] + '(...)' klass, modules = slave_status.get(name) if klass == 'building': title = 'Building %s' % ', '.join(modules) else: title = klass result += '<th class="%s" title="%s"><a href="bots/%s">%s</a></th>' % ( klass, title, name, name) result += '</tr>' thead = result # stop it here as a row with totals will be added here once every rows # have been handled # Contents result = '<tbody>' slave_results = {} for slave in parent.slaves: slave_results[slave] = [0, 0, 0] for module in parent.modules: result += '<tr>' result += '<td class="feed"><a href="%s/atom">' % module result += '<img src="/feed.png" alt="Atom"></a></td>\n' result += '<th><a href="%s">%s</a></td>' % (module, module) for slave in parent.slaves: builder = status.getBuilder("%s-%s" % (module, slave)) box = ITopBox(builder).getBox(request) lastbuild = '' for bt in box.text: if bt == 'successful' or bt == 'failed': lastbuild = bt if lastbuild == 'successful': last_build = builder.getLastFinishedBuild() if last_build: class_ = build_get_class(last_build) else: class_ = 'success' lastbuild_label = 'Success' if last_build and class_: # use a different class/label if make check failed steps = last_build.getSteps() for step in reversed(steps): if step.name.split()[-1] == 'check': if step.results == WARNINGS: # make check failed class_ = 'failedchecks' lastbuild_label = 'Failed Checks' break elif lastbuild == 'failed': lastbuild_label = 'Failed' last_build = builder.getLastFinishedBuild() if last_build: class_ = build_get_class(last_build) else: class_ = 'failure' else: class_ = '' lastbuild_label = lastbuild state, builds = builder.getState() if state == 'building': result += '<td class="%s">%s</td>' % (state, state) else: result += '<td class="%s">%s</td>' % (class_, lastbuild_label) if lastbuild in ('failed', 'successful'): slave_results[slave][2] += 1 if class_ == 'failedchecks': slave_results[slave][1] += 1 elif lastbuild == 'successful': slave_results[slave][0] += 1 slave_results[slave][1] += 1 result += '</tr>\n' result += '</tbody>\n' result += '<tfoot><tr class="totals"><td colspan="2"></td>' thead += '<tr class="totals"><td colspan="2"></td>' for slave in parent.slaves: td = '<td><span title="Successful builds">%s</span> '\ '<span title="(ignoring test suites failures)">(%s)</span> / '\ '<span title="Total">%s</span></td>' % tuple(slave_results[slave]) thead += td result += td thead += '</tr>\n</thead>\n' result += '</tr></tfoot>\n' result += '</table>' return thead + result
def body(self, request): # summary of changes between this method and the overriden one: # - more structural markup and CSS # - removal of the phase stuff, only keep one "This method builds the main waterfall display." status = self.getStatus(request) data = "" projectName = status.getProjectName() projectURL = status.getProjectURL() # we start with all Builders available to this Waterfall: this is # limited by the config-file -time categories= argument, and defaults # to all defined Builders. allBuilderNames = status.getBuilderNames(categories=self.categories) builders = [status.getBuilder(name) for name in allBuilderNames] # but if the URL has one or more builder= arguments (or the old show= # argument, which is still accepted for backwards compatibility), we # use that set of builders instead. We still don't show anything # outside the config-file time set limited by categories=. showBuilders = request.args.get("show", []) showBuilders.extend(request.args.get("builder", [])) if showBuilders: builders = [b for b in builders if b.name in showBuilders] # now, if the URL has one or category= arguments, use them as a # filter: only show those builders which belong to one of the given # categories. showCategories = request.args.get("category", []) if showCategories: builders = [b for b in builders if b.category in showCategories] builderNames = [b.name for b in builders] (changeNames, builderNames, timestamps, eventGrid, sourceEvents) = self.buildGrid(request, builders) # start the table: top-header material data += '<table class="waterfall">\n' data += "<thead>\n" data += "<tr>\n" data += '<td colspan="2"></td>' for b in builders: state, builds = b.getState() builder_name = b.name[len(self.module_name) + 1 :] data += '<th class="%s" title="%s"><a href="%s">%s</a></th>' % ( state, state, request.childLink("../builders/%s" % urllib.quote(b.name, safe="")), builder_name, ) data += "</tr>\n" data += "<tr>" data += "<th>time<br/>(%s)</th>" % time.tzname[time.localtime()[-1]] data += '<th class="Change">changes</th>' for b in builders: box = ITopBox(b).getBox(request) data += box.td(align="center") data += "</tr>" data += "</thead>" data += "<tbody>" data += self.phase2(request, changeNames + builderNames, timestamps, eventGrid, sourceEvents) data += "</tbody>\n" data += "<tfoot>\n" def with_args(req, remove_args=[], new_args=[], new_path=None): # sigh, nevow makes this sort of manipulation easier newargs = req.args.copy() for argname in remove_args: newargs[argname] = [] if "branch" in newargs: newargs["branch"] = [b for b in newargs["branch"] if b] for k, v in new_args: if k in newargs: newargs[k].append(v) else: newargs[k] = [v] newquery = "&".join(["%s=%s" % (k, v) for k in newargs for v in newargs[k]]) if new_path: new_url = new_path elif req.prepath: new_url = req.prepath[-1] else: new_url = "" if newquery: new_url += "?" + newquery return new_url if timestamps: data += "<tr>" bottom = timestamps[-1] nextpage = with_args(request, ["last_time"], [("last_time", str(int(bottom)))]) data += '<td class="Time"><a href="%s">next page</a></td>\n' % nextpage data += "</tr>" data += "</tfoot>\n" data += "</table>\n" return data