def testGetSheriffForAutorollCommit_AutoRoll_ReturnsSheriff(self): self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit( '*****@*****.**', 'This is a roll.\n\[email protected],[email protected]\n\n')) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit( 'v8-ci-autoroll-builder@' 'chops-service-accounts.iam.gserviceaccount.com', '[email protected]')) # Some alternative spellings for TBR. self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit( 'v8-ci-autoroll-builder@' 'chops-service-accounts.iam.gserviceaccount.com', 'TBR: [email protected]')) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit( 'v8-ci-autoroll-builder@' 'chops-service-accounts.iam.gserviceaccount.com', 'Tbr: [email protected]')) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit( 'v8-ci-autoroll-builder@' 'chops-service-accounts.iam.gserviceaccount.com', 'TBR= [email protected]'))
def testGetSheriffForAutorollCommit_NotAutoroll_ReturnsNone(self): self.assertIsNone( utils.GetSheriffForAutorollCommit('*****@*****.**', '[email protected]')) self.assertIsNone( utils.GetSheriffForAutorollCommit('*****@*****.**', '[email protected]'))
def testGetSheriffForAutorollCommit_NotAutoroll_ReturnsNone(self): self.assertIsNone(utils.GetSheriffForAutorollCommit({ 'author': {'email': '*****@*****.**'}, 'message': '[email protected]', })) self.assertIsNone(utils.GetSheriffForAutorollCommit({ 'author': {'email': '*****@*****.**'}, 'message': '[email protected]', }))
def _PeopleToNotify(self): """Return the people to notify for these differences. This looks at the top commits (by absolute change), and returns a tuple of: * owner (str, will be ignored if the bug is already assigned) * cc_list (list, authors of the top 2 commits) * why_text (str, text explaining why this owner was chosen) """ ordered_commits = [ diff.commit_info for diff in self._OrderedDifferencesByDelta() ] # CC the folks in the top N commits. N is scaled by the number of commits # (fewer than 10 means N=1, fewer than 100 means N=2, etc.) commits_cap = int(math.floor(math.log10(len(ordered_commits)))) + 1 cc_list = set() for commit in ordered_commits[:commits_cap]: cc_list.add(commit['author']) # Assign to the author of the top commit. If that is an autoroll, assign to # a sheriff instead. why_text = '' top_commit = ordered_commits[0] owner = top_commit['author'] sheriff = utils.GetSheriffForAutorollCommit(owner, top_commit['message']) if sheriff: owner = sheriff why_text = 'Assigning to sheriff %s because "%s" is a roll.' % ( sheriff, top_commit['subject']) return owner, cc_list, why_text
def testGetSheriffForAutorollCommit_AutoRoll_ReturnsSheriff(self): self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit({ 'author': { 'email': '*****@*****.**', }, 'message': 'This is a roll.\n\[email protected],[email protected]\n\n', })) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit({ 'author': { 'email': '*****@*****.**', }, 'message': '[email protected]', })) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit({'tbr': '*****@*****.**'}))
def _ComputePostOwnerSheriffCCList(self, commit_infos): owner = None sheriff = None cc_list = set() for cur_commit in commit_infos: # TODO: Assign the largest difference, not the last one. owner = cur_commit['author'] sheriff = utils.GetSheriffForAutorollCommit(owner, cur_commit['message']) cc_list.add(cur_commit['author']) if sheriff: owner = sheriff return owner, sheriff, cc_list
def testGetSheriffForAutorollCommit_AutoRoll_ReturnsSheriff(self): self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit({ 'author': { 'email': '*****@*****.**', }, 'message': 'This is a roll.\n\[email protected],[email protected]\n\n', })) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit({ 'author': { 'email': 'v8-ci-autoroll-builder@' 'chops-service-accounts.iam.gserviceaccount.com', }, 'message': '[email protected]', })) self.assertEqual( '*****@*****.**', utils.GetSheriffForAutorollCommit({'tbr': '*****@*****.**'}))
def _ComputePostOwnerSheriffCCList(commit_infos, authors_with_deltas): owner = None sheriff = None cc_list = set() if authors_with_deltas: owner, _ = max(authors_with_deltas.items(), key=lambda i: abs(i[1])) for cur_commit in commit_infos: if not owner: owner = cur_commit['author'] sheriff = utils.GetSheriffForAutorollCommit(owner, cur_commit['message']) cc_list.add(cur_commit['author']) if sheriff: owner = sheriff return owner, sheriff, cc_list
def _AssignBugToCLAuthor(bug_id, alert, service): """Assigns the bug to the author of the given revision.""" repository_url = None repositories = namespaced_stored_object.Get('repositories') test_path = utils.TestPath(alert.test) if test_path.startswith('ChromiumPerf'): repository_url = repositories['chromium']['repository_url'] elif test_path.startswith('ClankInternal'): repository_url = repositories['clank']['repository_url'] if not repository_url: # Can't get committer info from this repository. return rev = str(auto_bisect.GetRevisionForBisect(alert.end_revision, alert.test)) # TODO(sullivan, dtu): merge this with similar pinoint code. if (re.match(r'^[0-9]{5,7}$', rev) and repository_url == repositories['chromium']['repository_url']): # This is a commit position, need the git hash. result = crrev_service.GetNumbering( number=rev, numbering_identifier='refs/heads/master', numbering_type='COMMIT_POSITION', project='chromium', repo='chromium/src') rev = result['git_sha'] if not re.match(r'[a-fA-F0-9]{40}$', rev): # This still isn't a git hash; can't assign bug. return commit_info = gitiles_service.CommitInfo(repository_url, rev) author = commit_info['author']['email'] message = commit_info['message'] sheriff = utils.GetSheriffForAutorollCommit(author, message) if sheriff: service.AddBugComment( bug_id, ('Assigning to sheriff %s because this autoroll is ' 'the only CL in range:\n%s') % (sheriff, message), status='Assigned', owner=sheriff) else: service.AddBugComment( bug_id, 'Assigning to %s because this is the only CL in range:\n%s' % (author, message), status='Assigned', owner=author)
def _ComputePostOwnerSheriffCCList(commits_with_deltas): owner = None sheriff = None cc_list = set() # First, we sort the list of commits by absolute change. ordered_commits_by_delta = [ commit for _, commit in sorted( commits_with_deltas, key=lambda i: abs(i[0]), reverse=True) ] # We assign the issue to the author of the CL at the head of the ordered list. # Then we only CC the folks in the top two commits. for commit in ordered_commits_by_delta[:2]: if not owner: owner = commit['author'] sheriff = utils.GetSheriffForAutorollCommit(owner, commit['message']) cc_list.add(commit['author']) if sheriff: owner = sheriff return owner, sheriff, cc_list
def _FormatAndPostBugCommentOnComplete(self): if not self.comparison_mode: # There is no comparison metric. title = "<b>%s Job complete. See results below.</b>" % _ROUND_PUSHPIN self._PostBugComment('\n'.join((title, self.url))) return # There is a comparison metric. differences = self.state.Differences() if not differences: title = "<b>%s Couldn't reproduce a difference.</b>" % _ROUND_PUSHPIN self._PostBugComment('\n'.join((title, self.url))) return # Include list of Changes. owner = None sheriff = None cc_list = set() difference_details = [] for change_a, change_b in differences: if change_b.patch: commit_info = change_b.patch.AsDict() else: commit_info = change_b.last_commit.AsDict() # TODO: Assign the largest difference, not the last one. owner = commit_info['author'] sheriff = utils.GetSheriffForAutorollCommit( commit_info['author'], commit_info['message']) cc_list.add(commit_info['author']) values_a = self.state.ResultValues(change_a) values_b = self.state.ResultValues(change_b) difference = _FormatDifferenceForBug(commit_info, values_a, values_b, self.state.metric) difference_details.append(difference) # Header. if len(differences) == 1: status = 'Found a significant difference after 1 commit.' else: status = ('Found significant differences after each of %d commits.' % len(differences)) title = '<b>%s %s</b>' % (_ROUND_PUSHPIN, status) header = '\n'.join((title, self.url)) # Body. body = '\n\n'.join(difference_details) if sheriff: owner = sheriff body += '\n\nAssigning to sheriff %s because "%s" is a roll.' % ( sheriff, commit_info['subject']) # Footer. footer = ('Understanding performance regressions:\n' ' http://g.co/ChromePerformanceRegressions') if differences: footer += self._FormatDocumentationUrls() # Bring it all together. comment = '\n\n'.join((header, body, footer)) current_bug_status = self._GetBugStatus() if (not current_bug_status or current_bug_status in ['Untriaged', 'Unconfirmed', 'Available']): # Set the bug status and owner if this bug is opened and unowned. self._PostBugComment(comment, status='Assigned', cc_list=sorted(cc_list), owner=owner) else: # Only update the comment and cc list if this bug is assigned or closed. self._PostBugComment(comment, cc_list=sorted(cc_list))
def FileBug(http, owner, cc, summary, description, labels, components, urlsafe_keys, needs_bisect=True): alert_keys = [ndb.Key(urlsafe=k) for k in urlsafe_keys] alerts = ndb.get_multi(alert_keys) if not description: description = 'See the link to graphs below.' milestone_label = _MilestoneLabel(alerts) if milestone_label: labels.append(milestone_label) user_issue_tracker_service = issue_tracker_service.IssueTrackerService( http) new_bug_response = user_issue_tracker_service.NewBug( summary, description, labels=labels, components=components, owner=owner, cc=[email for email in cc.split(',') if email.strip()]) if 'error' in new_bug_response: return {'error': new_bug_response['error']} bug_id = new_bug_response['bug_id'] bug_data.Bug(id=bug_id).put() for a in alerts: a.bug_id = bug_id ndb.put_multi(alerts) comment_body = _AdditionalDetails(bug_id, alerts) # Add the bug comment with the service account, so that there are no # permissions issues. dashboard_issue_tracker_service = issue_tracker_service.IssueTrackerService( utils.ServiceAccountHttp()) dashboard_issue_tracker_service.AddBugComment(bug_id, comment_body) template_params = {'bug_id': bug_id} if all(k.kind() == 'Anomaly' for k in alert_keys): logging.info('Kicking bisect for bug ' + str(bug_id)) culprit_rev = _GetSingleCLForAnomalies(alerts) if culprit_rev is not None: commit_info = _GetCommitInfoForAlert(alerts[0]) if commit_info: author = commit_info['author']['email'] message = commit_info['message'] if not utils.GetSheriffForAutorollCommit(author, message): needs_bisect = False _AssignBugToCLAuthor(bug_id, commit_info, dashboard_issue_tracker_service) if needs_bisect: bisect_result = auto_bisect.StartNewBisectForBug(bug_id) if 'error' in bisect_result: logging.info('Failed to kick bisect for ' + str(bug_id)) template_params['bisect_error'] = bisect_result['error'] else: logging.info('Successfully kicked bisect for ' + str(bug_id)) template_params.update(bisect_result) else: kinds = set() for k in alert_keys: kinds.add(k.kind()) logging.info( 'Didn\'t kick bisect for bug id %s because alerts had kinds %s', bug_id, list(kinds)) return template_params
def _Complete(self): try: results2.ScheduleResults2Generation(self) except taskqueue.Error: pass # Format bug comment. if not self.auto_explore: # There is no comparison metric. title = "<b>%s Job complete. See results below.</b>" % _ROUND_PUSHPIN self._PostBugComment('\n'.join((title, self.url))) return # There is a comparison metric. differences = tuple(self.state.Differences()) if not differences: title = "<b>%s Couldn't reproduce a difference.</b>" % _ROUND_PUSHPIN self._PostBugComment('\n'.join((title, self.url))) return # Include list of Changes. owner = None sheriff = None cc_list = set() commit_details = [] for _, change in differences: if change.patch: commit_info = change.patch.AsDict() else: commit_info = change.last_commit.AsDict() # TODO: Assign the largest difference, not the last one. owner = commit_info['author'] sheriff = utils.GetSheriffForAutorollCommit(commit_info) cc_list.add(commit_info['author']) commit_details.append(_FormatCommitForBug(commit_info)) # Header. if len(differences) == 1: status = 'Found a significant difference after 1 commit.' else: status = ('Found significant differences after each of %d commits.' % len(differences)) title = '<b>%s %s</b>' % (_ROUND_PUSHPIN, status) header = '\n'.join((title, self.url)) # Body. body = '\n\n'.join(commit_details) if sheriff: owner = sheriff body += '\n\nAssigning to sheriff %s because "%s" is a roll.' % ( sheriff, commit_info['subject']) # Footer. footer = ('Understanding performance regressions:\n' ' http://g.co/ChromePerformanceRegressions') # Bring it all together. comment = '\n\n'.join((header, body, footer)) current_bug_status = self._GetBugStatus() if (not current_bug_status or current_bug_status in ['Untriaged', 'Unconfirmed', 'Available']): # Set the bug status and owner if this bug is opened and unowned. self._PostBugComment(comment, status='Assigned', cc_list=sorted(cc_list), owner=owner) else: # Only update the comment and cc list if this bug is assigned or closed. self._PostBugComment(comment, cc_list=sorted(cc_list))
def testGetSheriffForAutorollCommit_InvalidCommit_ReturnsNone(self): self.assertIsNone(utils.GetSheriffForAutorollCommit(None)) self.assertIsNone(utils.GetSheriffForAutorollCommit({})) self.assertIsNone(utils.GetSheriffForAutorollCommit({'author': {}}))