def getAttachments(self, build, key): sourcestamps = build["buildset"]["sourcestamps"] attachments = [] for sourcestamp in sourcestamps: sha = sourcestamp["revision"] title = "Build #{buildid}".format(buildid=build["buildid"]) project = sourcestamp["project"] if project: title += " for {project} {sha}".format(project=project, sha=sha) sub_build = bool(build["buildset"]["parent_buildid"]) if sub_build: title += " {relationship}: #{parent_build_id}".format( relationship=build["buildset"]["parent_relationship"], parent_build_id=build["buildset"]["parent_buildid"], ) fields = [] if not sub_build: branch_name = sourcestamp["branch"] if branch_name: fields.append({ "title": "Branch", "value": branch_name, "short": True }) repositories = sourcestamp["repository"] if repositories: fields.append({ "title": "Repository", "value": repositories, "short": True }) responsible_users = yield utils.getResponsibleUsersForBuild( self.master, build["buildid"]) if responsible_users: fields.append({ "title": "Commiters", "value": ", ".join(responsible_users), "short": True, }) attachments.append({ "title": title, "title_link": build["url"], "fallback": "{}: <{}>".format(title, build["url"]), "text": "Status: *{status}*".format( status=statusToString(build["results"])), "color": STATUS_COLORS.get(statusToString(build["results"]), ""), "mrkdwn_in": ["text", "title", "fallback"], "fields": fields, }) return attachments
def printBuild(self, build, out=sys.stdout, withLogs=False): # helper for debugging: print a build yield self.enrichBuild(build, wantSteps=True, wantProperties=True, wantLogs=True) print(u"*** BUILD {} *** ==> {} ({})".format(build['buildid'], build['state_string'], statusToString(build['results'])), file=out) for step in build['steps']: print(u" *** STEP {} *** ==> {} ({})".format(step['name'], step['state_string'], statusToString(step['results'])), file=out) for url in step['urls']: print(u" url:{} ({})".format(url['name'], url['url']), file=out) for log in step['logs']: print(u" log:{} ({})".format(log['name'], log['num_lines']), file=out) if step['results'] != SUCCESS or withLogs: self.printLog(log, out)
def printBuild(self, build, out=sys.stdout, withLogs=False): # helper for debugging: print a build yield self.enrichBuild(build, wantSteps=True, wantProperties=True, wantLogs=True) print("*** BUILD %d *** ==> %s (%s)" % (build['buildid'], build['state_string'], statusToString(build['results'])), file=out) for step in build['steps']: print(" *** STEP %s *** ==> %s (%s)" % (step['name'], step['state_string'], statusToString(step['results'])), file=out) for url in step['urls']: print(" url:%s (%s)" % (url['name'], url['url']), file=out) for log in step['logs']: print(" log:%s (%d)" % (log['name'], log['num_lines']), file=out) if step['results'] != SUCCESS or withLogs: self.printLog(log, out)
def sendMessage(self, reports): dl = [] for report in reports: if report['type'] != 'discord': log.msg("DiscordStatusPush: got report of unexpected type {}". format(report['type'])) continue report['results_text'] = statusToString(report['results']) # No color in markdown, so use emoji to be visual report['results_emoji'] = EMOJIS.get(report['results'], UNKNOWN_EMOJI) json = {} json['content'] = self.message_template.render(report) embeds = report['body'] while len(embeds) > 0: # One message for a group of 10 embeds json['embeds'] = embeds[0:10] d = self._http.post("", json=json) dl.append(d) embeds = embeds[10:] responses = yield defer.gatherResults(dl, consumeErrors=True) for response in responses: if not (200 <= response.code < 300): log.msg("{}: unable to upload status: {}".format( response.code, response.content))
def stepDone(self, results, step): """This method is called when the BuildStep completes. It is passed a status object from the BuildStep and is responsible for merging the Step's results into those of the overall Build.""" terminate = False text = None if isinstance(results, tuple): results, text = results assert isinstance(results, type(SUCCESS)), "got %r" % (results,) summary = yield step.getBuildResultSummary() if 'build' in summary: text = [summary['build']] log.msg(" step '%s' complete: %s (%s)" % (step.name, statusToString(results), text)) if text: self.text.extend(text) self.master.data.updates.setBuildStateString(self.buildid, bytes2unicode(" ".join(self.text))) self.results, terminate = computeResultAndTermination(step, results, self.results) if not self.conn: # force the results to retry if the connection was lost self.results = RETRY terminate = True defer.returnValue(terminate)
def main(): # This code fetches build data from the data api, and give it to the # template builders = mydashboardapp.buildbot_api.dataGet("/builders") builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20) # properties are actually not used in the template example, but this is # how you get more properties for build in builds: build['properties'] = mydashboardapp.buildbot_api.dataGet( ("builds", build['buildid'], "properties")) build['results_text'] = statusToString(build['results']) # Example on how to use requests to get some info from other web servers code_frequency_url = "https://api.github.com/repos/buildbot/buildbot/stats/code_frequency" results = requests.get(code_frequency_url) while results.status_code == 202: # while github calculates statistics, it returns code 202. # this is no problem, we just sleep in our thread.. time.sleep(500) results = requests.get(code_frequency_url) # some post processing of the data from github graph_data = [] for i, data in enumerate(results.json()): graph_data.append(dict(x=data[0], y=data[1])) # mydashboard.html is a template inside the template directory return render_template('mydashboard.html', builders=builders, builds=builds, graph_data=graph_data)
def getMessage(self, build, event_name): event_messages = { 'new': 'Buildbot started build %s here: %s' % (build['builder']['name'], build['url']), 'finished': 'Buildbot finished build %s with result %s here: %s' % (build['builder']['name'], statusToString(build['results']), build['url']) } return event_messages.get(event_name, '')
def main(): # This code fetches build data from the data api, and give it to the # template builders = mydashboardapp.buildbot_api.dataGet("/builders") builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20) # properties are actually not used in the template example, but this is # how you get more properties for build in builds: build['properties'] = mydashboardapp.buildbot_api.dataGet( ("builds", build['buildid'], "properties")) build['results_text'] = statusToString(build['results']) graph_data = [ {'x': 1, 'y': 100}, {'x': 2, 'y': 200}, {'x': 3, 'y': 300}, {'x': 4, 'y': 0}, {'x': 5, 'y': 100}, {'x': 6, 'y': 200}, {'x': 7, 'y': 300}, {'x': 8, 'y': 0}, {'x': 9, 'y': 100}, {'x': 10, 'y': 200}, ] # mydashboard.html is a template inside the template directory return render_template('mydashboard.html', builders=builders, builds=builds, graph_data=graph_data)
def build_message(self, formatter, master, reporter, build): patches = self._get_patches_for_build(build) logs = yield self._get_logs_for_build(master, build) users = yield reporter.getResponsibleUsersForBuild( master, build['buildid']) buildmsg = yield formatter.format_message_for_build(master, build, mode=self.mode, users=users) results = build['results'] subject = buildmsg['subject'] if subject is None and self.subject is not None: subject = self.subject % { 'result': statusToString(results), 'projectName': master.config.title, 'title': master.config.title, 'builder': build['builder']['name'] } return { 'body': buildmsg['body'], 'subject': subject, 'type': buildmsg['type'], 'results': results, 'builds': [build], 'users': list(users), 'patches': patches, 'logs': logs }
def main(): # This code fetches build data from the data api, and give it to the # template builders = mydashboardapp.buildbot_api.dataGet("/builders") builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20) # properties are actually not used in the template example, but this is # how you get more properties for build in builds: build['properties'] = mydashboardapp.buildbot_api.dataGet( ("builds", build['buildid'], "properties")) build['results_text'] = statusToString(build['results']) # Example on how to use requests to get some info from other web servers code_frequency_url = "https://api.github.com/repos/buildbot/buildbot/stats/code_frequency" results = requests.get(code_frequency_url) while results.status_code == 202: # while github calculates statistics, it returns code 202. # this is no problem, we just sleep in our thread.. time.sleep(500) results = requests.get(code_frequency_url) # some post processing of the data from github graph_data = [] for i, data in enumerate(results.json()): graph_data.append( dict(x=data[0], y=data[1]) ) # mydashboard.html is a template inside the template directory return render_template('mydashboard.html', builders=builders, builds=builds, graph_data=graph_data)
def notify_for_finished(self, build): if self.notify_for('finished'): return True result = build['results'] result_name = statusToString(result) if self.notify_for(result_name): return True if result in self.bot.results_severity and \ (self.notify_for('better', 'worse', 'problem', 'recovery') or any('To' in e for e in self.notify_events)): prev_build = yield self.master.data.get( ('builders', build['builderid'], 'builds', build['number'] - 1)) if prev_build: prev_result = prev_build['results'] if prev_result in self.bot.results_severity: result_severity = self.bot.results_severity.index(result) prev_result_severity = self.bot.results_severity.index( prev_result) if self.notify_for('better') and \ result_severity < prev_result_severity: return True if self.notify_for('worse') and \ result_severity > prev_result_severity: return True if self.notify_for('problem') \ and prev_result in (SUCCESS, WARNINGS) \ and result in (FAILURE, EXCEPTION): return True if self.notify_for('recovery') \ and prev_result in (FAILURE, EXCEPTION) \ and result in (SUCCESS, WARNINGS): return True # DEPRECATED required_notification_control_string = ''.join( (statusToString(prev_result).lower(), 'To', result_name.capitalize())) if self.notify_for(required_notification_control_string): return True return False
def build_message(self, master, reporter, name, builds, results): # The given builds must refer to builds from a single buildset patches = [] logs = [] body = None subject = None msgtype = None users = set() for build in builds: if self.add_patch: ss_list = build['buildset']['sourcestamps'] for ss in ss_list: if 'patch' in ss and ss['patch'] is not None: patches.append(ss['patch']) if self.add_logs: build_logs = yield self._get_logs_for_build(master, build) if isinstance(self.add_logs, list): build_logs = [ log for log in build_logs if self._should_attach_log(log) ] logs.extend(build_logs) blamelist = yield reporter.getResponsibleUsersForBuild( master, build['buildid']) buildmsg = yield self.formatter.format_message_for_build( self.mode, name, build, master, blamelist) users.update(set(blamelist)) msgtype = buildmsg['type'] if body is None: body = buildmsg['body'] elif buildmsg['body'] is not None: body = body + buildmsg['body'] if buildmsg['subject'] is not None: subject = buildmsg['subject'] if subject is None: subject = self.subject % { 'result': statusToString(results), 'projectName': master.config.title, 'title': master.config.title, 'builder': name } return { 'body': body, 'subject': subject, 'type': msgtype, 'builder_name': name, 'results': results, 'builds': builds, 'users': list(users), 'patches': patches, 'logs': logs }
def getMessage(self, build, event_name): event_messages = { "new": "Buildbot started build %s" % build["builder"]["name"], "finished": "Buildbot finished build %s with result: %s" % (build["builder"]["name"], statusToString(build["results"])), } return event_messages.get(event_name, "")
def getMessage(self, build): event_messages = { False: "Buildbot started build %s" % build["builder"]["name"], True: "Buildbot finished build %s with result: %s" % (build["builder"]["name"], statusToString(build["results"])), } return event_messages.get(build['complete'], "")
def getAttachments(self, build, key): sourcestamps = build["buildset"]["sourcestamps"] attachments = [] for sourcestamp in sourcestamps: title = "<{url}|Build #{buildid}> - *{status}*".format( url=build["url"], buildid=build["buildid"], status=statusToString(build["results"]) ) blocks = [] blocks.append( { "type": "section", "text": { "type": "mrkdwn", "text": title } } ) if build["results"] != results.SUCCESS: responsible_users = yield utils.getResponsibleUsersForBuild(self.master, build["buildid"]) if responsible_users: commiters = "*Commiters:*\n{}".format(", ".join(responsible_users)) blocks.append( { "type": "section", "text": { "type": "mrkdwn", "text": commiters } } ) attachments.append( { "color": STATUS_COLORS.get(statusToString(build["results"]), ""), "blocks": blocks, } ) return attachments
def getBuildBotData(): """Fetches build data from the data api""" builds = octavedownloadapp.buildbot_api.dataGet("/builds", order=["-started_at"], limit=100) builds_by_id = {} for item in builds: item["properties"] = octavedownloadapp.buildbot_api.dataGet( ("builds", item["buildid"], "properties")) item["results_text"] = statusToString(item["results"]) if "OCTAVE_BUILD_ID" in item["properties"].keys(): builds_by_id.setdefault(item["properties"]["OCTAVE_BUILD_ID"][0], []).append(item) return builds_by_id
def addBuildUrls(self, rclist): brids = {} for was_cb, results in rclist: if isinstance(results, tuple): results, brids = results if was_cb: # errors were already logged in worstStatus for builderid, br in iteritems(brids): builderDict = yield self.master.data.get(("builders", builderid)) builds = yield self.master.db.builds.getBuilds(buildrequestid=br) for build in builds: num = build["number"] url = self.master.status.getURLForBuild(builderid, num) yield self.addURL("%s: %s #%d" % (statusToString(results), builderDict["name"], num), url)
def buildset_message(self, formatter, master, reporter, builds, results): # The given builds must refer to builds from a single buildset patches = [] logs = [] body = None subject = None msgtype = None users = set() for build in builds: patches.extend(self._get_patches_for_build(build)) build_logs = yield self._get_logs_for_build(master, build) logs.extend(build_logs) blamelist = yield reporter.getResponsibleUsersForBuild( master, build['buildid']) users.update(set(blamelist)) buildmsg = yield formatter.format_message_for_build( master, build, mode=self.mode, users=blamelist) msgtype, ok = self._merge_msgtype(msgtype, buildmsg['type']) if not ok: continue subject = self._merge_subject(subject, buildmsg['subject']) body, ok = self._merge_body(body, buildmsg['body']) if not ok: continue if subject is None and self.subject is not None: subject = self.subject % { 'result': statusToString(results), 'projectName': master.config.title, 'title': master.config.title, 'builder': 'whole buildset' } return { 'body': body, 'subject': subject, 'type': msgtype, 'results': results, 'builds': builds, 'users': list(users), 'patches': patches, 'logs': logs }
def addBuildUrls(self, rclist): brids = {} for was_cb, results in rclist: if isinstance(results, tuple): results, brids = results if was_cb: # errors were already logged in worstStatus for builderid, br in iteritems(brids): builderDict = yield self.master.data.get(("builders", builderid)) builds = yield self.master.db.builds.getBuilds(buildrequestid=br) for build in builds: num = build['number'] url = self.master.status.getURLForBuild(builderid, num) yield self.addURL("%s: %s #%d" % (statusToString(results), builderDict["name"], num), url)
def getCurrentSummary(self): if not self.triggeredNames: return {'step': 'running'} summary = "" if self._result_list: for status in ALL_RESULTS: count = self._result_list.count(status) if count: summary = summary + ", {} {}".format( self._result_list.count(status), statusToString(status, count)) return { 'step': 'triggered {}{}'.format(', '.join(self.triggeredNames), summary) }
def main(): # This code fetches build data from the data api, and give it to the template builders = griddashboardapp.buildbot_api.dataGet("/builders") # request last 20 builds builds = griddashboardapp.buildbot_api.dataGet("/builds", order=["-buildid"], limit=20) used_builders = list(map(lambda x: x['builderid'], builds)) builders = list(filter(lambda x: x['builderid'] in used_builders, builders)) # to store all revisions from builds above revisions = [] # properties are actually not used in the template example, but this is how you get more properties for build in builds: build['properties'] = griddashboardapp.buildbot_api.dataGet( ("builds", build['buildid'], "properties")) build['results_text'] = statusToString( build['results']) # translate result to string build['state'] = griddashboardapp.buildbot_api.dataGet( ("builds", build['buildid'])) try: if build["properties"]["revision"][0] not in revisions: revisions.append(build["properties"]["revision"][0]) except KeyError as e: # this means the build didn't get to the point of getting a revision, # more than likely an environment isssue such as disk full, power outtage, etc... print('Error', str(e)) pass # would like to display newest first revisions.sort(reverse=True) print(revisions, builds) # grid.html is a template inside the template directory return render_template('grid.html', builders=builders, builds=builds, revisions=revisions)
def getBuildDetailsAndSendMessage(self, build, key): yield utils.getDetailsForBuild(self.master, build, **self.neededDetails) attachments = yield self.getAttachments(build, key) postData = {} if key == "new": postData["text"] = "Buildbot started build <{}|{}>".format(build["url"], build["builder"]["name"]) if key == "finished": postData["text"] = "Buildbot finished build {}".format(build["builder"]["name"]) postData["attachments"] = attachments if self.channel: postData["channel"] = self.channel postData["icon_emoji"] = STATUS_EMOJIS.get( statusToString(build["results"]), ":facepalm:" ) extra_params = yield self.getExtraParams(build, key) postData.update(extra_params) return postData
def addBuildUrls(self, rclist): brids = {} for was_cb, results in rclist: if isinstance(results, tuple): results, brids = results builderNames = {} if was_cb: # errors were already logged in worstStatus for builderid, br in brids.items(): builds = yield self.master.db.builds.getBuilds(buildrequestid=br) for build in builds: builderid = build['builderid'] # When virtual builders are used, the builderid used for triggering # is not the same as the one that the build actually got if builderid not in builderNames: builderDict = yield self.master.data.get(("builders", builderid)) builderNames[builderid] = builderDict["name"] num = build['number'] url = self.master.status.getURLForBuild(builderid, num) yield self.addURL("%s: %s #%d" % (statusToString(build["results"]), builderNames[builderid], num), url)
def stepDone(self, results, step): """This method is called when the BuildStep completes. It is passed a status object from the BuildStep and is responsible for merging the Step's results into those of the overall Build.""" terminate = False text = None if isinstance(results, tuple): results, text = results assert isinstance(results, type(SUCCESS)), "got %r" % (results,) log.msg(" step '%s' complete: %s" % (step.name, statusToString(results))) if text: self.text.extend(text) self.results, terminate = computeResultAndTermination(step, results, self.results) if not self.conn: # force the results to retry if the connection was lost self.results = RETRY terminate = True return terminate
def get_detected_status_text(mode, results, previous_results): if results == FAILURE: if ('change' in mode or 'problem' in mode) and previous_results is not None \ and previous_results != FAILURE: text = "new failure" else: text = "failed build" elif results == WARNINGS: text = "problem in the build" elif results == SUCCESS: if "change" in mode and previous_results is not None and previous_results != results: text = "restored build" else: text = "passing build" elif results == EXCEPTION: text = "build exception" else: text = "{} build".format(statusToString(results)) return text
def getBuildDetailsAndSendMessage(self, build): yield utils.getDetailsForBuild(self.master, build, **self.neededDetails) text = yield self.getMessage(build) postData = {} if self.attachments: attachments = yield self.getAttachments(build) if attachments: postData["attachments"] = attachments else: text += " here: " + build["url"] postData["text"] = text if self.channel: postData["channel"] = self.channel postData["icon_emoji"] = STATUS_EMOJIS.get( statusToString(build["results"]), ":facepalm:") extra_params = yield self.getExtraParams(build) postData.update(extra_params) return postData
def getDetectedStatus(self, mode, results, previous_results): if results == FAILURE: if "change" in mode and previous_results is not None and previous_results != results or \ "problem" in mode and previous_results and previous_results != FAILURE: text = "new failure" else: text = "failed build" elif results == WARNINGS: text = "The Buildbot has detected a problem in the build" elif results == SUCCESS: if "change" in mode and previous_results is not None and previous_results != results: text = "restored build" else: text = "passing build" elif results == EXCEPTION: text = "build exception" else: text = "%s build" % (statusToString(results)) return text
def main(): bigData = {} epoch_time = int(time.time()) earliestSubmittedTime = epoch_time - (60 * 60 * 24 * 7) # last week out_file = open("/tmp/buildotTmpLogFriDash", "w") fribuilders = fridashboardapp.buildbot_api.dataGet( "/builders", filters=[ Filter("tags", "contains", ["fri"]), Filter("masterids", "ne", [[]]) ]) buildsets = fridashboardapp.buildbot_api.dataGet( "buildsets", limit=128, order=["-bsid"], filters=[Filter("submitted_at", "gt", [earliestSubmittedTime])]) for buildset in buildsets: sourcestamps = buildset['sourcestamps'] if len(sourcestamps[0]) != 1: out_file.write("ERROR: more that 1 sourcestamp for buildset" + str(buildset["bsid"]) + "\n") sourcestamp = sourcestamps[0] proj = sourcestamp['project'] if proj != "fri": continue ssid = sourcestamp['ssid'] if ssid not in bigData: bigData[ssid] = {} bigData[ssid]['change'] = common.getChangeFromBbSourceStamp( sourcestamp) bigData[ssid]['builders'] = {} buildrequests = fridashboardapp.buildbot_api.dataGet( "buildrequests", filters=[Filter("buildsetid", "eq", [buildset['bsid']])]) for buildrequest in buildrequests: id = buildrequest['builderid'] if id not in bigData[ssid]['builders']: bigData[ssid]['builders'][id] = [] if buildrequest["claimed"]: builds = fridashboardapp.buildbot_api.dataGet( ("buildrequests", buildrequest["buildrequestid"], "builds")) for build in builds: results_text = statusToString(build['results']).upper() if results_text == 'NOT FINISHED': results_text = 'PENDING pulse' bigData[ssid]['builders'][id].append({ 'type': 'build', 'number': build["number"], 'results_text': results_text }) else: bigData[ssid]['builders'][id].append({ 'type': 'buildrequest', 'id': buildrequest["buildrequestid"], 'results_text': "UNKNOWN" }) out_file.close() # fridashboard.html is a template inside the template directory return render_template('fridashboard.html', builders=fribuilders, bigdata=bigData)
def __repr__(self): return "<Build %s number:%r results:%s>" % ( self.builder.name, self.number, statusToString(self.results))
def main(): # This code fetches build data from the data api, and give it to the # template from buildbot.data.resultspec import Filter builders = dashapp.buildbot_api.dataGet( "/builders", filters=[ Filter("tags", "contains", ["hello-world"]), Filter("masterids", "ne", [[]]) ]) bigData = {} import time epoch_time = int(time.time()) earliestSubmittedTime = epoch_time - (60 * 60 * 24 * 7) buildsets = dashapp.buildbot_api.dataGet( "buildsets", limit=128, order=["-bsid"], filters=[Filter("submitted_at", "gt", [earliestSubmittedTime])]) for buildset in buildsets: sourcestamps = buildset['sourcestamps'] sourcestamp = sourcestamps[0] proj = sourcestamp['project'] if proj != "hello-world": continue ssid = sourcestamp['ssid'] if ssid not in bigData: bigData[ssid] = {} bigData[ssid]['change'] = common.getChangeFromBbSourceStamp( sourcestamp) bigData[ssid]['builders'] = {} buildrequests = dashapp.buildbot_api.dataGet( "buildrequests", filters=[Filter("buildsetid", "eq", [buildset['bsid']])]) for buildrequest in buildrequests: id = buildrequest['builderid'] if id not in bigData[ssid]['builders']: bigData[ssid]['builders'][id] = [] if buildrequest["claimed"]: builds = dashapp.buildbot_api.dataGet( ("buildrequests", buildrequest["buildrequestid"], "builds")) for build in builds: results_text = statusToString(build['results']).upper() if results_text == 'NOT FINISHED': results_text = 'PENDING pulse' bigData[ssid]['builders'][id].append({ 'type': 'build', 'number': build["number"], 'results_text': results_text }) else: bigData[ssid]['builders'][id].append({ 'type': 'buildrequest', 'id': buildrequest["buildrequestid"], 'results_text': "UNKNOWN" }) # dash.html is a template inside the template directory return render_template('dash.html', builders=builders, bigdata=bigData)
def getExtraParams(self, build, event_name): result = {} state_message = build['state_string'] # // build text build_url = build['url'] builder_name = build['builder']['name'] build_number = build['number'] result['slack_message'] = { "channel": "", "attachments": [{ "fallback": "%s - %s" % (state_message, build_url), "text": "<%s|%s # %s> - %s" % (build_url, builder_name, build_number, state_message), "color": self.BUILD_RESULT[statusToString(build['results'])] }] } # basic message for new event if event_name == 'new': defer.returnValue(result) # build finished message build_properties = build.get('properties') if build_properties is not None: #warning please use util.GetBuildPropertyValue(build_property, property_name) build_commit_description = util.GetBuildPropertyValue( build_properties, 'commit-description') build_worker_name = util.GetBuildPropertyValue( build_properties, 'workername') # for environment #https://api.slack.com/docs/messages#how_to_send_messages result['slack_message']['attachments'][0]['fields'] = [] message_fields = result['slack_message']['attachments'][0][ 'fields'] if build_commit_description is not None: commit_field = { "title": "Tag", "value": build_commit_description, "short": "true" } message_fields.append(commit_field) if build_worker_name is not None: worker_name_field = { "title": "Worker", "value": build_worker_name, "short": "true" } message_fields.append(worker_name_field) #add custom property custom_message_properties = yield self.getCustomMessageProperties( build, event_name) if custom_message_properties is not None: for custom_property in custom_message_properties: custom_property_value = util.GetBuildPropertyValue( build_properties, custom_property) # for environment custom_property_field = { "title": custom_property, "value": custom_property_value, "short": "true" } message_fields.append(custom_property_field) # Add Reponsable Users Field blamelist = yield utils.getResponsibleUsersForBuild( self.master, build['buildid']) if len(blamelist) > 0: blamelist_str = ''.join(blamelist) blameField = { "title": "Responsable Users", "value": blamelist_str, "short": "true" } message_fields.append(blameField) defer.returnValue(result)
def __repr__(self): return "<Build {} number:{} results:{}>".format( self.builder.name, repr(self.number), statusToString(self.results))
def main(): # This code fetches build data from the data api, and give it to the # template builders = mydashboardapp.buildbot_api.dataGet("/builders") builds = mydashboardapp.buildbot_api.dataGet("/builds", limit=20) # properties are actually not used in the template example, but this is # how you get more properties for build in builds: build['properties'] = mydashboardapp.buildbot_api.dataGet( ("builds", build['buildid'], "properties")) build['results_text'] = statusToString(build['results']) graph_data = [ { 'x': 1, 'y': 100 }, { 'x': 2, 'y': 200 }, { 'x': 3, 'y': 300 }, { 'x': 4, 'y': 0 }, { 'x': 5, 'y': 100 }, { 'x': 6, 'y': 200 }, { 'x': 7, 'y': 300 }, { 'x': 8, 'y': 0 }, { 'x': 9, 'y': 100 }, { 'x': 10, 'y': 200 }, ] # mydashboard.html is a template inside the template directory return render_template('mydashboard.html', builders=builders, builds=builds, graph_data=graph_data)
def get_log_details(build): text = "" try: for step in build['steps']: results = step['results'] if results == SUCCESS or results == SKIPPED: continue text += "Step {} ({}) {}: {}\n".format(step['number'], step['name'], statusToString(results), step['state_string']) logs = step['logs'] if logs: log_index = -1 log_type = 0 for i, _log in enumerate(logs): if _log['name'].startswith( "FAIL: "): # Use only first logchunk FAIL: log_type = 3 log_index = i elif log_type < 2 and _log['name'].startswith("warnings "): log_type = 2 log_index = i elif log_type < 1 and _log['type'] == "s": # stdio log_type = 1 log_index = i if log_index < 0: continue log_text = logs[log_index]['content']['content'] if log_type == 1: # Parse stdio lines = log_text.splitlines() for line in lines[:]: if line.startswith("h"): lines.remove(line) for j, line in enumerate(lines): if line.startswith("o") or line.startswith("e"): lines[j] = line[1:] for j, line in enumerate(lines): if line.find("FAIL:") != -1 or line.find( "FAILED") != -1: if j > 10: del lines[:j - 10] # Start 10 lines before FAIL lines = ["..."] + lines del lines[50:] # Keep up to 50 lines around FAIL break if len(lines) > 50: del lines[:len(lines) - 50] # Otherwise keep last 50 lines lines = ["..."] + lines log_text = "\n".join(lines) elif logs[log_index]['num_lines'] > 50: # Keep first 50 lines lines = log_text.splitlines() del lines[50:] log_text = "\n".join(lines + ["..."]) text += log_text + "\n" except Exception as err: print("Exception in LLVMMessageFormatter.get_log_details(): {}\n{}". format(err, traceback.format_exc())) # TODO: We should send something useful in this case. return dict(details=text)