def getBuildDetailsAndSendMessage(self, build, key): yield utils.getDetailsForBuild(self.master, build, **self.neededDetails) postData = yield self.getRecipientList(build, key) postData['message'] = yield self.getMessage(build, key) extra_params = yield self.getExtraParams(build, key) postData.update(extra_params) return postData
def buildComplete(self, key, build): if self.buildSetSummary: return br = yield self.master.data.get( ("buildrequests", build["buildrequestid"])) buildset = yield self.master.data.get(("buildsets", br["buildsetid"])) yield utils.getDetailsForBuilds( self.master, buildset, [build], wantProperties=self.messageFormatter.wantProperties, wantSteps=self.messageFormatter.wantSteps, wantPreviousBuild=self.wantPreviousBuild(), wantLogs=self.messageFormatter.wantLogs, ) if "changesteps" in self.mode: yield utils.getDetailsForBuild(self.master, build["prev_build"], wantProperties=True, wantSteps=True) # only include builds for which isMessageNeeded returns true if self.isMessageNeeded(build): self.buildMessage(build["builder"]["name"], [build], build["results"])
def getBuildDetailsAndSendMessage(self, build, key): yield utils.getDetailsForBuild(self.master, build, **self.neededDetails) postData = yield self.getRecipientList(build, key) postData['message'] = yield self.getMessage(build, key) extra_params = yield self.getExtraParams(build, key) postData.update(extra_params) defer.returnValue(postData)
def getBuildDetailsAndSendMessage(self, build, key): yield utils.getDetailsForBuild(self.master, build, wantProperties=self.wantProperties, wantSteps=self.wantSteps, wantPreviousBuild=self.wantPreviousBuild, wantLogs=self.wantLogs) postData = yield self.getRecipientList(build, key) postData['message'] = yield self.getMessage(build, key) extra_params = yield self.getExtraParams(build, key) postData.update(extra_params) return postData
def getMoreInfoAndSend(self, build): yield utils.getDetailsForBuild( self.master, build, wantProperties=self.wantProperties, wantSteps=self.wantSteps, wantPreviousBuild=self.wantPreviousBuild, wantLogs=self.wantLogs) if self.filterBuilds(build): yield self.send(build)
def test_getDetailsForBuildWithParent(self): self.setupDb() build = yield self.master.data.get(("builds", 22)) yield utils.getDetailsForBuild(self.master, build, wantProperties=False, wantSteps=False, wantPreviousBuild=False, wantLogs=False) self.assertEqual(build['parentbuild']['buildid'], 21) self.assertEqual(build['parentbuilder']['name'], "Builder1")
def test_getDetailsForBuild(self): self.setupDb() build = yield self.master.data.get(("builds", 21)) yield utils.getDetailsForBuild(self.master, build, want_properties=False, want_steps=False, want_previous_build=False, want_logs=False) self.assertEqual(build['parentbuild'], None) self.assertEqual(build['parentbuilder'], None)
def test_createEmail_extraHeaders_two_builds(self): build = yield self.insert_build_finished(SUCCESS) yield utils.getDetailsForBuild(self.master, build, want_properties=True) builds = [build, copy.deepcopy(build)] builds[1]['builder']['name'] = 'builder2' msgdict = create_msgdict() mn = yield self.setupMailNotifier('*****@*****.**', extraHeaders=dict(hhh='vvv')) m = yield mn.createEmail(msgdict, 'project-n\u00E5me', SUCCESS, builds) txt = m.as_string() # note that the headers are *not* rendered self.assertIn('hhh: vvv', txt)
def do_test_createEmail_cte(self, funnyChars, expEncoding): build = yield self.insert_build_finished(SUCCESS) yield utils.getDetailsForBuild(self.master, build, wantProperties=True) msgdict = create_msgdict(funnyChars) mn = yield self.setupMailNotifier('*****@*****.**') m = yield mn.createEmail(msgdict, 'builder-name', 'project-name', SUCCESS, [build]) cte_lines = [l for l in m.as_string().split("\n") if l.startswith('Content-Transfer-Encoding:')] self.assertEqual(cte_lines, ['Content-Transfer-Encoding: {}'.format(expEncoding)], repr(m.as_string()))
def getDetailsForTriggeredBuilds(self, build): # noqa """Get details for triggered builds.""" for step in build['steps']: step.setdefault('triggered_builds', []) for url in step['urls']: matched = re.search(r'builders/(\d+)/builds/(\d+)', url['url']) if not matched: continue builds = self.master.db.builds trig_build = yield builds.getBuildByNumber(*matched.groups()) trig_build['buildid'] = trig_build['id'] yield utils.getDetailsForBuild(self.master, trig_build, **self.neededDetails) yield self.getDetailsForTriggeredBuilds(trig_build) step['triggered_builds'].append(trig_build)
def buildStarted(self, key, build): yield utils.getDetailsForBuild(self.master, build, **self.needed) builderName = build['builder']['name'] # TODO: this all seems a bit overly complex? if builderName != "nightly" and not self.isTriggered(build)\ and not self.isNightlyRunning(): # If a build has been started which isn't nightly and a nightly # build isn't running, chances are a single builder has been # started in order to test something and it just finished. if not self.logBuild(build): log.err("wkl: Failed to log build %s on %s" % (build.getNumber(), builderName)) elif builderName == "nightly": if not self.logBuild(build): log.err("wkl: Failed to log build %s on %s" % (build.getNumber(), builderName))
def generate(self, master, reporter, key, build): _, _, event = key is_new = event == 'new' formatter = self.start_formatter if is_new else self.end_formatter yield utils.getDetailsForBuild(master, build, want_properties=formatter.want_properties, want_steps=formatter.want_steps, want_logs=formatter.want_logs, want_logs_content=formatter.want_logs_content) if not self.is_message_needed_by_props(build): return None report = yield self.build_message(formatter, master, reporter, build) return report
def generate(self, master, reporter, key, build): _, _, event = key is_new = event == 'new' want_previous_build = False if is_new else self._want_previous_build() yield utils.getDetailsForBuild(master, build, want_properties=self.formatter.want_properties, want_steps=self.formatter.want_steps, want_previous_build=want_previous_build, want_logs=self.formatter.want_logs, want_logs_content=self.formatter.want_logs_content) if not self.is_message_needed_by_props(build): return None if not is_new and not self.is_message_needed_by_results(build): return None report = yield self.build_message(self.formatter, master, reporter, build) return report
def generate(self, master, reporter, key, build): _, _, event = key is_new = event == 'new' formatter = self.start_formatter if is_new else self.end_formatter yield utils.getDetailsForBuild(master, build, wantProperties=formatter.wantProperties, wantSteps=formatter.wantSteps, wantLogs=formatter.wantLogs) if not self.is_message_needed_by_props(build): return None report = yield self.build_message(formatter, master, reporter, build['builder']['name'], [build], build['results']) return report
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 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 generate(self, master, reporter, key, build): _, _, event = key is_new = event == 'new' want_previous_build = False if is_new else self._want_previous_build() if self._want_previous_build_override is not None: want_previous_build = self._want_previous_build_override yield utils.getDetailsForBuild(master, build, wantProperties=self.formatter.wantProperties, wantSteps=self.formatter.wantSteps, wantPreviousBuild=want_previous_build, wantLogs=self.formatter.wantLogs) if not self.is_message_needed_by_props(build): return None if not is_new and not self.is_message_needed_by_results(build): return None report = yield self.build_message(master, reporter, build['builder']['name'], [build], build['results']) return report
def buildFinished(self, key, build): yield utils.getDetailsForBuild(self.master, build) doSend = False if self.reportOnlyFailures: if isFailure(build["results"]): doSend = True elif self.reportFixedBuild: status = self.getPrevBuildResult(build) if isSuccess(build["results"]) and isFailure(status): doSend = True else: doSend = True if doSend: return self.send(build, key[2]) if not doSend and self.reportFixedBuild: self.storePrevBuildResult(build) return None
def send(self, build): props = Properties.fromDict(build["properties"]) props.master = self.master if build["complete"]: state = { SUCCESS: "success", WARNINGS: "success", FAILURE: "failure", SKIPPED: "success", EXCEPTION: "error", RETRY: "pending", CANCELLED: "error", }.get(build["results"], "error") else: return if state != "failure": return yield getDetailsForBuild(self.master, build, wantLogs=True, wantSteps=True) logs, tracebacks = get_logs_and_tracebacks_from_build(build) context = yield props.render(self.context) sourcestamps = build["buildset"].get("sourcestamps") if not (sourcestamps and sourcestamps[0]): return changes = yield self.master.data.get(("builds", build["buildid"], "changes")) if len(changes) != 1: return change = changes[0] change_comments = change["comments"] if not change_comments: return m = re.search(r"\((?:GH-|#)(\d+)\)", change_comments) if m is None: return issue = m.groups()[-1] project = sourcestamps[0]["project"] if "/" in project: repoOwner, repoName = project.split("/") else: giturl = giturlparse(sourcestamps[0]["repository"]) repoOwner = giturl.owner repoName = giturl.repo if self.verbose: log.msg( "Updating github status: repoOwner={repoOwner}, repoName={repoName}".format( repoOwner=repoOwner, repoName=repoName ) ) try: repo_user = repoOwner repo_name = repoName sha = change["revision"] target_url = build["url"] context = context yield self.createStatus( build=build, repo_user=repo_user, repo_name=repo_name, sha=sha, state=state, target_url=target_url, context=context, issue=issue, tracebacks=tracebacks, logs=logs, ) if self.verbose: log.msg( "Issued a Pull Request comment for {repoOwner}/{repoName} " 'at {sha}, context "{context}", issue {issue}.'.format( repoOwner=repoOwner, repoName=repoName, sha=sha, issue=issue, context=context, ) ) except Exception as e: log.err( e, "Failed to issue a Pull Request comment for {repoOwner}/{repoName} " 'at {sha}, context "{context}", issue {issue}.'.format( repoOwner=repoOwner, repoName=repoName, sha=sha, issue=issue, context=context, ), )
def insert_build_finished_get_props(self, results, **kwargs): build = yield self.insert_build_finished(results, **kwargs) yield utils.getDetailsForBuild(self.master, build, wantProperties=True) return build
def getMoreInfoAndSend(self, build): yield utils.getDetailsForBuild(self.master, build, **self.neededDetails) if self.filterBuilds(build): yield self.send(build)
def buildFinished(self, key, build): yield utils.getDetailsForBuild(self.master, build, wantProperties=True, wantSteps=True, wantPreviousBuild=False, wantLogs=False) prop = lambda name: build['properties'].get(name, [None])[0] build_url = build['url'] source_stamps = build['buildset']['sourcestamps'] branch = prop('branch') build_name = prop('build_name') variant_name = prop('variant_name') buildername = prop('buildername') if not buildername.startswith('build-'): return buildername = buildername[len('build-'):] buildnumber = prop('buildnumber') worker = prop('workername') rev = prop('got_revision') repository_name = prop('repository_name') repository_url = prop('repository_url') blamelist = yield utils.getResponsibleUsersForBuild( self.master, build['buildid']) responsible_users = '\n'.join(blamelist) status = Results[build['results']] if build['results'] == SUCCESS: color = "good" elif build['results'] == FAILURE: color = "#EE3435" else: color = '#AB12EF' message = "Build <{url}|#{buildnumber} {build_name} {variant_name} on {worker}> finished".format( url=build_url, buildnumber=buildnumber, build_name=build_name, variant_name=variant_name, worker=worker, ) fields = [{ 'title': 'Status', 'value': status, 'short': True, }, { "title": "Repository", "value": self.templates['repository'].format(repository=repository_name), "short": True }] if responsible_users: fields.append({ "title": "Responsible users", "value": responsible_users, 'rev_short': True, }) if branch: fields.append({ "title": "Branch", "value": self.templates['branch'].format( repository=repository_name, branch=branch, ), "short": True }) if rev: fields.append({ "title": "Revision", "value": self.templates['revision'].format(repository=repository_name, revision=rev, revision_short=rev[:8]), "short": True }) payload = { "attachments": [{ "text": message, "color": color, "mrkdwn_in": ["text", "title", "fallback", "fields"], "fields": fields }], 'mrkdwn': True, } if self.username: payload['username'] = self.username if self.icon: if self.icon.startswith(':'): payload['icon_emoji'] = self.icon else: payload['icon_url'] = self.icon response = yield self._http.post("", json=payload) if response.code != 200: content = yield response.content() log.error("{code}: unable to upload status: {content}", code=response.code, content=content)
def send(self, build): props = Properties.fromDict(build["properties"]) props.master = self.master if build["complete"]: state = { SUCCESS: "success", WARNINGS: "success", FAILURE: "failure", SKIPPED: "success", EXCEPTION: "error", RETRY: "pending", CANCELLED: "error", }.get(build["results"], "error") else: return if state != "failure": return yield getDetailsForBuild(self.master, build, wantLogs=True, wantSteps=True) tracebacks = list() try: test_log = build["steps"][TESTS_STEP]["logs"][0]["content"]["content"] test_log = "\n".join([line.lstrip("eo") for line in test_log.splitlines()]) tracebacks = TRACEBACK_REGEX.findall(test_log) except IndexError: pass if not tracebacks: tracebacks = list(self._construct_tracebacks_from_stderr(build)) context = yield props.render(self.context) sourcestamps = build["buildset"].get("sourcestamps") if not sourcestamps or not sourcestamps[0]: return changes = yield self.master.data.get(("builds", build["buildid"], "changes")) if len(changes) > 1: return change, = changes m = re.search(r"\((?:GH-|#)(\d+)\)", change["comments"]) if m is None: return issue = m.groups()[-1] project = sourcestamps[0]["project"] if "/" in project: repoOwner, repoName = project.split("/") else: giturl = giturlparse(sourcestamps[0]["repository"]) repoOwner = giturl.owner repoName = giturl.repo if self.verbose: log.msg( "Updating github status: repoOwner={repoOwner}, repoName={repoName}".format( repoOwner=repoOwner, repoName=repoName ) ) try: repo_user = unicode2NativeString(repoOwner) repo_name = unicode2NativeString(repoName) sha = unicode2NativeString(change["revision"]) target_url = unicode2NativeString(build["url"]) context = unicode2NativeString(context) yield self.createStatus( build=build, repo_user=repo_user, repo_name=repo_name, sha=sha, state=state, target_url=target_url, context=context, issue=issue, tracebacks=tracebacks, ) if self.verbose: log.msg( "Issued a Pull Request comment for {repoOwner}/{repoName} " 'at {sha}, context "{context}", issue {issue}.'.format( repoOwner=repoOwner, repoName=repoName, sha=sha, issue=issue, context=context, ) ) except Exception as e: log.err( e, "Failed to issue a Pull Request comment for {repoOwner}/{repoName} " 'at {sha}, context "{context}", issue {issue}.'.format( repoOwner=repoOwner, repoName=repoName, sha=sha, issue=issue, context=context, ), )