def execute(self, nick, args, tool, sheriff): svn_revision_list, rollout_reason = self._parse_args(args) if (not svn_revision_list or not rollout_reason): # return is equivalent to an irc().post(), but makes for easier unit testing. return "%s: Usage: rollout SVN_REVISION [SVN_REVISIONS] REASON" % nick revision_urls_string = join_with_separators([ urls.view_revision_url(revision) for revision in svn_revision_list ]) tool.irc().post("%s: Preparing rollout for %s..." % (nick, revision_urls_string)) self._update_working_copy(tool) # FIXME: IRCCommand should bind to a tool and have a self._tool like Command objects do. # Likewise we should probably have a self._sheriff. nicks_string = self._nicks_string(tool, sheriff, nick, svn_revision_list) try: complete_reason = "%s (Requested by %s on %s)." % ( rollout_reason, nick, config_irc.channel) bug_id = sheriff.post_rollout_patch(svn_revision_list, complete_reason) bug_url = tool.bugs.bug_url_for_bug_id(bug_id) tool.irc().post("%s: Created rollout: %s" % (nicks_string, bug_url)) except ScriptError, e: tool.irc().post("%s: Failed to create rollout patch:" % nicks_string) _post_error_and_check_for_bug_url(tool, nicks_string, e)
def _create_bug_for_flaky_test(self, flaky_test, author_emails, latest_flake_message): format_values = { 'test': flaky_test, 'authors': join_with_separators(sorted(author_emails)), 'flake_message': latest_flake_message, 'test_url': self._view_source_url_for_test(flaky_test), 'bot_name': self._bot_name, } title = "Flaky Test: %(test)s" % format_values description = """This is an automatically generated bug from the %(bot_name)s. %(test)s has been flaky on the %(bot_name)s. %(test)s was authored by %(authors)s. %(test_url)s %(flake_message)s The bots will update this with information from each new failure. If you believe this bug to be fixed or invalid, feel free to close. The bots will re-open if the flake re-occurs. If you would like to track this test fix with another bug, please close this bug as a duplicate. The bots will follow the duplicate chain when making future comments. """ % format_values master_flake_bug = 50856 # MASTER: Flaky tests found by the commit-queue return self._tool.bugs.create_bug(title, description, component="Tools / Tests", cc=",".join(author_emails), blocked="50856")
def execute(self, nick, args, tool, sheriff): if len(args) != 1: return "%s: Usage: whois SEARCH_STRING" % nick search_string = args[0] # FIXME: We should get the ContributorList off the tool somewhere. contributors = CommitterList().contributors_by_search_string( search_string) if not contributors: return "%s: Sorry, I don't know any contributors matching '%s'." % ( nick, search_string) if len(contributors) > 5: return "%s: More than 5 contributors match '%s', could you be more specific?" % ( nick, search_string) if len(contributors) == 1: contributor = contributors[0] if not contributor.irc_nicknames: return "%s: %s hasn't told me their nick. Boo hoo :-(" % ( nick, contributor) if contributor.emails and search_string.lower() not in map( lambda email: email.lower(), contributor.emails): formattedEmails = ', '.join(contributor.emails) return "%s: %s is %s (%s). Why do you ask?" % ( nick, search_string, self._nick_or_full_record(contributor), formattedEmails) else: return "%s: %s is %s. Why do you ask?" % ( nick, search_string, self._nick_or_full_record(contributor)) contributor_nicks = map(self._nick_or_full_record, contributors) contributors_string = join_with_separators(contributor_nicks, only_two_separator=" or ", last_separator=', or ') return "%s: I'm not sure who you mean? %s could be '%s'." % ( nick, contributors_string, search_string)
def execute(self, nick, args, tool, sheriff): if not args: return self.usage(nick) search_string = unicode(" ".join(args)) # FIXME: We should get the ContributorList off the tool somewhere. contributors = CommitterList().contributors_by_search_string( search_string) if not contributors: return unicode( "%s: Sorry, I don't know any contributors matching '%s'.") % ( nick, search_string) if len(contributors) > 5: return unicode( "%s: More than 5 contributors match '%s', could you be more specific?" ) % (nick, search_string) if len(contributors) == 1: contributor = contributors[0] if not contributor.irc_nicknames: return unicode("%s: %s hasn't told me their nick. Boo hoo :-(" ) % (nick, contributor) return unicode("%s: %s is %s. Why do you ask?") % ( nick, search_string, self._full_record_and_nick(contributor)) contributor_nicks = map(self._full_record_and_nick, contributors) contributors_string = join_with_separators(contributor_nicks, only_two_separator=" or ", last_separator=', or ') return unicode("%s: I'm not sure who you mean? %s could be '%s'.") % ( nick, contributors_string, search_string)
def execute(self, nick, args, tool, sheriff): svn_revision_list, rollout_reason = self._parse_args(args) if (not svn_revision_list or not rollout_reason): return self.usage(nick) revision_urls_string = join_with_separators([urls.view_revision_url(revision) for revision in svn_revision_list]) tool.irc().post("%s: Preparing rollout for %s ..." % (nick, revision_urls_string)) self._update_working_copy(tool) # FIXME: IRCCommand should bind to a tool and have a self._tool like Command objects do. # Likewise we should probably have a self._sheriff. nicks_string = self._nicks_string(tool, sheriff, nick, svn_revision_list) try: complete_reason = "%s (Requested by %s on %s)." % ( rollout_reason, nick, config_irc.channel) bug_id = sheriff.post_rollout_patch(svn_revision_list, complete_reason) bug_url = tool.bugs.bug_url_for_bug_id(bug_id) tool.irc().post("%s: Created rollout: %s" % (nicks_string, bug_url)) except ScriptError, e: tool.irc().post("%s: Failed to create rollout patch:" % nicks_string) diff_failure = self._check_diff_failure(e.output, tool) if diff_failure: return "%s: %s" % (nicks_string, diff_failure) _post_error_and_check_for_bug_url(tool, nicks_string, e)
def execute(self, nick, args, tool, sheriff): svn_revision_list, rollout_reason = self._parse_args(args) if (not svn_revision_list or not rollout_reason): return self.usage(nick) revision_urls_string = join_with_separators([ urls.view_revision_url(revision) for revision in svn_revision_list ]) tool.irc().post("%s: Preparing rollout for %s ..." % (nick, revision_urls_string)) self._update_working_copy(tool) # FIXME: IRCCommand should bind to a tool and have a self._tool like Command objects do. # Likewise we should probably have a self._sheriff. nicks_string = self._nicks_string(tool, sheriff, nick, svn_revision_list) try: complete_reason = "%s (Requested by %s on %s)." % ( rollout_reason, nick, config_irc.channel) bug_id = sheriff.post_rollout_patch(svn_revision_list, complete_reason) bug_url = tool.bugs.bug_url_for_bug_id(bug_id) tool.irc().post("%s: Created rollout: %s" % (nicks_string, bug_url)) except ScriptError as e: tool.irc().post("%s: Failed to create rollout patch:" % nicks_string) diff_failure = self._check_diff_failure(e.output, tool) if diff_failure: return "%s: %s" % (nicks_string, diff_failure) _post_error_and_check_for_bug_url(tool, nicks_string, e)
def execute(self, nick, args, tool, sheriff): svn_revision_list, rollout_reason = self._parse_args(args) if (not svn_revision_list or not rollout_reason): # return is equivalent to an irc().post(), but makes for easier unit testing. return "%s: Usage: rollout SVN_REVISION [SVN_REVISIONS] REASON" % nick self._update_working_copy(tool) # FIXME: IRCCommand should bind to a tool and have a self._tool like Command objects do. # Likewise we should probably have a self._sheriff. nicks_string = self._nicks_string(tool, sheriff, nick, svn_revision_list) revision_urls_string = join_with_separators([urls.view_revision_url(revision) for revision in svn_revision_list]) tool.irc().post("%s: Preparing rollout for %s..." % (nicks_string, revision_urls_string)) try: complete_reason = "%s (Requested by %s on %s)." % ( rollout_reason, nick, config_irc.channel) bug_id = sheriff.post_rollout_patch(svn_revision_list, complete_reason) bug_url = tool.bugs.bug_url_for_bug_id(bug_id) tool.irc().post("%s: Created rollout: %s" % (nicks_string, bug_url)) except ScriptError, e: tool.irc().post("%s: Failed to create rollout patch:" % nicks_string) _post_error_and_check_for_bug_url(tool, nicks_string, e)
def _optional_author_string(self, author_emails): if not author_emails: return "" heading_string = plural( 'author') if len(author_emails) > 1 else 'author' authors_string = join_with_separators(sorted(author_emails)) return " (%s: %s)" % (heading_string, authors_string)
def report_flaky_tests(self, patch, flaky_tests): message = "The %s encountered the following flaky tests while processing attachment %s:" % (self.name, patch.id()) message += "\n\n%s\n\n" % ("\n".join(flaky_tests)) message += "Please file bugs against the tests. " author_emails = self._author_emails_for_tests(flaky_tests) if author_emails: message += "These tests were authored by %s. " % (join_with_separators(sorted(author_emails))) message += "The commit-queue is continuing to process your patch." self._tool.bugs.post_comment_to_bug(patch.bug_id(), message)
def _flags_to_clear_on_patch(self, patch): if not patch.is_obsolete(): return None what_was_cleared = [] if patch.review() == "+": if patch.reviewer(): what_was_cleared.append(u"%s's review+" % patch.reviewer().full_name) else: what_was_cleared.append("review+") return join_with_separators(what_was_cleared)
def _flags_to_clear_on_patch(self, patch): if not patch.is_obsolete(): return None what_was_cleared = [] if patch.review() == "+": if patch.reviewer(): what_was_cleared.append("%s's review+" % patch.reviewer().full_name) else: what_was_cleared.append("review+") return join_with_separators(what_was_cleared)
def post_irc_warning(self, commit_info, builders): irc_nicknames = sorted( self.responsible_nicknames_from_commit_info(commit_info)) irc_prefix = ": " if irc_nicknames else "" irc_message = "%s%s%s might have broken %s" % ( ", ".join(irc_nicknames), irc_prefix, urls.view_revision_url(commit_info.revision()), join_with_separators([builder.name() for builder in builders])) self._tool.irc().post(irc_message)
def post_irc_warning(self, commit_info, builders): irc_nicknames = sorted(self.responsible_nicknames_from_commit_info(commit_info)) irc_prefix = ": " if irc_nicknames else "" irc_message = "%s%s%s might have broken %s" % ( ", ".join(irc_nicknames), irc_prefix, urls.view_revision_url(commit_info.revision()), join_with_separators([builder.name() for builder in builders])) self._tool.irc().post(irc_message)
def _message_for_revert(cls, revision_list, reason, bug_url=None): message = "Unreviewed, rolling out %s.\n" % join_with_separators(['r' + str(revision) for revision in revision_list]) for revision in revision_list: message += "%s\n" % urls.view_revision_url(revision) if bug_url: message += "%s\n" % bug_url # Add an extra new line after the rollout links, before any reason. message += "\n" if reason: message += "%s\n\n" % reason return message
def post_blame_comment_on_bug(self, commit_info, builders, blame_list): if not commit_info.bug_id(): return comment = "%s might have broken %s" % ( view_source_url(commit_info.revision()), join_with_separators([builder.name() for builder in builders])) if len(blame_list) > 1: comment += "\nThe following changes are on the blame list:\n" comment += "\n".join(map(view_source_url, blame_list)) self._tool.bugs.post_comment_to_bug(commit_info.bug_id(), comment, cc=self._sheriffbot.watchers)
def post_blame_comment_on_bug(self, commit_info, builders, tests): if not commit_info.bug_id(): return comment = "%s might have broken %s" % ( urls.view_revision_url(commit_info.revision()), join_with_separators([builder.name() for builder in builders])) if tests: comment += "\nThe following tests are not passing:\n" comment += "\n".join(tests) self._tool.bugs.post_comment_to_bug(commit_info.bug_id(), comment, cc=self._sheriffbot.watchers)
def run(self, state): commit_comment = bug_comment_from_commit_text(self._tool.scm(), state["commit_text"]) revision_list = join_with_separators(['r' + str(revision) for revision in state["revision_list"]]) comment_text = "Reverted %s for reason:\n\n%s\n\n%s" % (revision_list, state["reason"], commit_comment) bug_ids = state["bug_id_list"] if not bug_ids: _log.info(comment_text) _log.info("No bugs were updated.") return for bug_id in bug_ids: if bug_id: self._tool.bugs.reopen_bug(bug_id, comment_text)
def post_irc_warning(self, commit_info, builders): irc_nicknames = sorted([party.irc_nickname for party in commit_info.responsible_parties() if party.irc_nickname]) irc_prefix = ": " if irc_nicknames else "" irc_message = "%s%s%s might have broken %s" % ( ", ".join(irc_nicknames), irc_prefix, view_source_url(commit_info.revision()), join_with_separators([builder.name() for builder in builders])) self._tool.irc().post(irc_message)
def post_irc_warning(self, commit_info, builders): irc_nicknames = sorted([ party.irc_nickname for party in commit_info.responsible_parties() if party.irc_nickname ]) irc_prefix = ": " if irc_nicknames else "" irc_message = "%s%s%s might have broken %s" % ( ", ".join(irc_nicknames), irc_prefix, view_source_url(commit_info.revision()), join_with_separators([builder.name() for builder in builders])) self._tool.irc().post(irc_message)
def run(self, state): commit_comment = bug_comment_from_commit_text(self._tool.scm(), state["commit_text"]) revision_list = join_with_separators( ['r' + str(revision) for revision in state["revision_list"]]) comment_text = "Reverted %s for reason:\n\n%s\n\n%s" % ( revision_list, state["reason"], commit_comment) bug_ids = state["bug_id_list"] if not bug_ids: _log.info(comment_text) _log.info("No bugs were updated.") return for bug_id in bug_ids: if bug_id: self._tool.bugs.reopen_bug(bug_id, comment_text)
def _print_nominations(self, nominations, counters_by_email): nominations = sorted(nominations, key=lambda a: a['roles']) nominations = sorted(nominations, key=lambda a: a['patch_count']) nominations = sorted(nominations, key=lambda a: a['author_name']) for nomination in nominations: # This is a little bit of a hack, but its convienent to just pass the nomination dictionary to the formating operator. nomination['roles_string'] = grammar.join_with_separators( nomination['roles']).upper() print( "%(roles_string)s: %(author_name)s (%(author_email)s) has %(patch_count)s reviewed patches" % nomination) counter = counters_by_email[nomination['author_email']] if self.show_commits: print(counter['commits'])
def _message_for_revert(cls, revision_list, reason, description_list, reverted_bug_url_list, rollout_bug_url=None): message = "Unreviewed, rolling out %s.\n" % grammar.join_with_separators(['r' + str(revision) for revision in revision_list]) if rollout_bug_url: message += "%s\n" % rollout_bug_url message += "\n" if reason: message += "%s\n" % reason message += "\n" message += "Reverted %s:\n\n" % grammar.pluralize(len(revision_list), "changeset", showCount=False) for index in range(len(revision_list)): if description_list[index]: message += "\"%s\"\n" % description_list[index] if reverted_bug_url_list[index]: message += "%s\n" % reverted_bug_url_list[index] message += "%s\n\n" % urls.view_revision_url(revision_list[index]) return message
def _message_for_revert(cls, revision_list, reason, description_list, reverted_bug_url_list, rollout_bug_url=None): message = "Unreviewed, rolling out %s.\n" % join_with_separators(['r' + str(revision) for revision in revision_list]) if rollout_bug_url: message += "%s\n" % rollout_bug_url message += "\n" if reason: message += "%s\n" % reason message += "\n" pluralSuffix = 's' if len(revision_list) > 1 else '' message += "Reverted changeset%s:\n\n" % pluralSuffix for index in range(len(revision_list)): if description_list[index]: message += "\"%s\"\n" % description_list[index] if reverted_bug_url_list[index]: message += "%s\n" % reverted_bug_url_list[index] message += "%s\n\n" % urls.view_revision_url(revision_list[index]) return message
def execute(self, nick, args, tool, sheriff): if not args: return self.usage(nick) search_string = unicode(" ".join(args)) # FIXME: We should get the ContributorList off the tool somewhere. contributors = CommitterList().contributors_by_search_string(search_string) if not contributors: return unicode("%s: Sorry, I don't know any contributors matching '%s'.") % (nick, search_string) if len(contributors) > 5: return unicode("%s: More than 5 contributors match '%s', could you be more specific?") % (nick, search_string) if len(contributors) == 1: contributor = contributors[0] if not contributor.irc_nicknames: return unicode("%s: %s hasn't told me their nick. Boo hoo :-(") % (nick, contributor) return unicode("%s: %s is %s. Why do you ask?") % (nick, search_string, self._full_record_and_nick(contributor)) contributor_nicks = map(self._full_record_and_nick, contributors) contributors_string = join_with_separators(contributor_nicks, only_two_separator=" or ", last_separator=', or ') return unicode("%s: I'm not sure who you mean? %s could be '%s'.") % (nick, contributors_string, search_string)
def _print_nominations(self, nominations, counters_by_email): def nomination_cmp(a_nomination, b_nomination): roles_result = cmp(a_nomination['roles'], b_nomination['roles']) if roles_result: return -roles_result count_result = cmp(a_nomination['patch_count'], b_nomination['patch_count']) if count_result: return -count_result return cmp(a_nomination['author_name'], b_nomination['author_name']) for nomination in sorted(nominations, nomination_cmp): # This is a little bit of a hack, but its convienent to just pass the nomination dictionary to the formating operator. nomination['roles_string'] = grammar.join_with_separators(nomination['roles']).upper() print "%(roles_string)s: %(author_name)s (%(author_email)s) has %(patch_count)s reviewed patches" % nomination counter = counters_by_email[nomination['author_email']] if self.show_commits: print counter['commits']
def execute(self, nick, args, tool, sheriff): if not args: return self.usage(nick) search_string = " ".join(args) # FIXME: We should get the ContributorList off the tool somewhere. contributors = CommitterList().contributors_by_search_string(search_string) if not contributors: return "%s: Sorry, I don't know any contributors matching '%s'." % (nick, search_string) if len(contributors) > 5: return "%s: More than 5 contributors match '%s', could you be more specific?" % (nick, search_string) if len(contributors) == 1: contributor = contributors[0] if not contributor.irc_nicknames: return "%s: %s hasn't told me their nick. Boo hoo :-(" % (nick, contributor) if contributor.emails and search_string.lower() not in map(lambda email: email.lower(), contributor.emails): formattedEmails = ', '.join(contributor.emails) return "%s: %s is %s (%s). Why do you ask?" % (nick, search_string, self._nick_or_full_record(contributor), formattedEmails) else: return "%s: %s is %s. Why do you ask?" % (nick, search_string, self._nick_or_full_record(contributor)) contributor_nicks = map(self._nick_or_full_record, contributors) contributors_string = join_with_separators(contributor_nicks, only_two_separator=" or ", last_separator=', or ') return "%s: I'm not sure who you mean? %s could be '%s'." % (nick, contributors_string, search_string)
def _message_for_revert(cls, revision_list, reason, description_list, reverted_bug_url_list, revert_bug_url=None): message = "Unreviewed, reverting %s.\n" % grammar.join_with_separators( ['r' + str(revision) for revision in revision_list]) if revert_bug_url: message += "%s\n" % revert_bug_url message += "\n" if reason: message += "%s\n" % reason message += "\n" message += "Reverted %s:\n\n" % grammar.pluralize( len(revision_list), "changeset", showCount=False) for index in range(len(revision_list)): if description_list[index]: message += "\"%s\"\n" % description_list[index] if reverted_bug_url_list[index]: message += "%s\n" % reverted_bug_url_list[index] message += "%s\n\n" % urls.view_revision_url(revision_list[index]) return message
def execute(self, nick, args, tool, sheriff): svn_revision_list, rollout_reason = self._parse_args(args) if (len(svn_revision_list) == 0) or (len(rollout_reason) == 0): tool.irc().post("%s: Usage: SVN_REVISION [SVN_REVISIONS] REASON" % nick) return rollout_reason = " ".join(rollout_reason) tool.irc().post("Preparing rollout for %s..." % join_with_separators(["r" + str(revision) for revision in svn_revision_list])) try: complete_reason = "%s (Requested by %s on %s)." % ( rollout_reason, nick, config_irc.channel) bug_id = sheriff.post_rollout_patch(svn_revision_list, complete_reason) bug_url = tool.bugs.bug_url_for_bug_id(bug_id) tool.irc().post("%s: Created rollout: %s" % (nick, bug_url)) except ScriptError, e: tool.irc().post("%s: Failed to create rollout patch:" % nick) tool.irc().post("%s" % e) bug_id = parse_bug_id(e.output) if bug_id: tool.irc().post("Ugg... Might have created %s" % tool.bugs.bug_url_for_bug_id(bug_id))
def _rollout_reason(self, builders): # FIXME: This should explain which layout tests failed # however, that would require Build objects here, either passed # in through failure_info, or through Builder.latest_build. names = [builder.name() for builder in builders] return "Caused builders %s to fail." % join_with_separators(names)
def test_join_with_separators_two(self): self.assertEqual("one and two", grammar.join_with_separators(["one", "two"]))
def test_join_with_separators(self): self.assertEqual(join_with_separators(["one"]), "one") self.assertEqual(join_with_separators(["one", "two"]), "one and two") self.assertEqual(join_with_separators(["one", "two", "three"]), "one, two, and three")
def test_join_with_separators_one(self): self.assertEqual('one', grammar.join_with_separators(['one']))
def _optional_author_string(self, author_emails): if not author_emails: return "" heading_string = plural('author') if len(author_emails) > 1 else 'author' authors_string = join_with_separators(sorted(author_emails)) return " (%s: %s)" % (heading_string, authors_string)
def test_join_with_separators_two(self): self.assertEqual('one and two', grammar.join_with_separators(['one', 'two']))
def test_join_with_separators_three(self): self.assertEqual('one, two, and three', grammar.join_with_separators(['one', 'two', 'three']))
def test_join_with_separators_three(self): self.assertEqual("one, two, and three", grammar.join_with_separators(["one", "two", "three"]))
def test_join_with_separators_zero(self): self.assertEqual('', grammar.join_with_separators([]))
def test_join_with_separators_one(self): self.assertEqual("one", grammar.join_with_separators(["one"]))