Changeset 56947 in webkit


Ignore:
Timestamp:
Apr 1, 2010 4:34:40 PM (14 years ago)
Author:
abarth@webkit.org
Message:

2010-04-01 Adam Barth <abarth@webkit.org>

Reviewed by Eric Seidel.

Add rollout command to sheriffbot
https://bugs.webkit.org/show_bug.cgi?id=36986

This IRC command creates a new bug an attaches a rollout patch. To
actually commit the rollout, a committer needs to mark the patch
commit-queue+ in bugs.webkit.org.

Also, factored out some of the logic from the queue into a separate
object for easier testing.

  • Scripts/webkitpy/common/system/executive.py:
  • Scripts/webkitpy/tool/bot/irc_command.py:
  • Scripts/webkitpy/tool/bot/sheriff.py: Added.
  • Scripts/webkitpy/tool/bot/sheriff_unittest.py: Added.
  • Scripts/webkitpy/tool/bot/sheriffircbot.py:
  • Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
  • Scripts/webkitpy/tool/commands/queues.py:
  • Scripts/webkitpy/tool/commands/sheriffbot.py:
  • Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
Location:
trunk/WebKitTools
Files:
1 added
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/ChangeLog

    r56942 r56947  
     12010-04-01  Adam Barth  <abarth@webkit.org>
     2
     3        Reviewed by Eric Seidel.
     4
     5        Add rollout command to sheriffbot
     6        https://bugs.webkit.org/show_bug.cgi?id=36986
     7
     8        This IRC command creates a new bug an attaches a rollout patch.  To
     9        actually commit the rollout, a committer needs to mark the patch
     10        commit-queue+ in bugs.webkit.org.
     11
     12        Also, factored out some of the logic from the queue into a separate
     13        object for easier testing.
     14
     15        * Scripts/webkitpy/common/system/executive.py:
     16        * Scripts/webkitpy/tool/bot/irc_command.py:
     17        * Scripts/webkitpy/tool/bot/sheriff.py: Added.
     18        * Scripts/webkitpy/tool/bot/sheriff_unittest.py: Added.
     19        * Scripts/webkitpy/tool/bot/sheriffircbot.py:
     20        * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
     21        * Scripts/webkitpy/tool/commands/queues.py:
     22        * Scripts/webkitpy/tool/commands/sheriffbot.py:
     23        * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
     24
    1252010-04-01  Eric Seidel  <eric@webkit.org>
    226
  • trunk/WebKitTools/Scripts/webkitpy/common/system/executive.py

    r56544 r56947  
    117117                              exit_code=exit_code,
    118118                              output=child_output)
     119        return child_output
    119120
    120121    @staticmethod
  • trunk/WebKitTools/Scripts/webkitpy/tool/bot/irc_command.py

    r56883 r56947  
    2929from webkitpy.common.checkout.changelog import view_source_url
    3030from webkitpy.tool.bot.queueengine import TerminateQueue
    31 
     31from webkitpy.common.system.executive import ScriptError
    3232
    3333# FIXME: Merge with Command?
    3434class IRCCommand(object):
    35     def execute(self, args, tool):
     35    def execute(self, args, tool, sheriff):
    3636        raise NotImplementedError, "subclasses must implement"
    3737
    3838
    3939class LastGreenRevision(IRCCommand):
    40     def execute(self, args, tool):
     40    def execute(self, args, tool, sheriff):
    4141        return view_source_url(tool.buildbot.last_green_revision())
    4242
    4343
    4444class Restart(IRCCommand):
    45     def execute(self, args, tool):
     45    def execute(self, args, tool, sheriff):
    4646        tool.irc().post("Restarting...")
    4747        raise TerminateQueue()
    4848
    4949
     50class Rollout(IRCCommand):
     51    def execute(self, args, tool, sheriff):
     52        if len(args) < 2:
     53            tool.irc().post("Usage: SVN_REVISION REASON")
     54            return
     55        svn_revision = args[0]
     56        rollout_reason = " ".join(args[1:])
     57        tool.irc().post("Preparing rollout for r%s..." % svn_revision)
     58        try:
     59            bug_id = sheriff.post_rollout_patch(svn_revision, rollout_reason)
     60            bug_url = tool.bugs.bug_url_for_bug_id(bug_id)
     61            tool.irc().post("Created rollout: %s" % bug_url)
     62        except ScriptError, e:
     63            tool.irc().post("Failed to create rollout patch:")
     64            tool.irc().post("%s" % e)
     65
     66
    5067class Hi(IRCCommand):
    51     def execute(self, args, tool):
     68    def execute(self, args, tool, sheriff):
    5269        return '"Only you can prevent forest fires." -- Smokey the Bear'
  • trunk/WebKitTools/Scripts/webkitpy/tool/bot/sheriff_unittest.py

    r56946 r56947  
    2828
    2929import os
     30import unittest
    3031
    3132from webkitpy.common.net.buildbot import Builder
    3233from webkitpy.thirdparty.mock import Mock
    33 from webkitpy.tool.commands.queuestest import QueuesTest
    34 from webkitpy.tool.commands.sheriffbot import SheriffBot
     34from webkitpy.tool.bot.sheriff import Sheriff
    3535from webkitpy.tool.mocktool import MockTool, mock_builder
    3636
    37 class SheriffBotTest(QueuesTest):
    38     def test_sheriff_bot(self):
    39         mock_work_item = {
    40             "svn_revision": 29837,
    41             "builders": [mock_builder]
    42         }
    43         expected_stderr = {
    44             "begin_work_queue": "CAUTION: sheriff-bot will discard all local changes in \"%s\"\nRunning WebKit sheriff-bot.\n" % os.getcwd(),
    45             "next_work_item": "",
    46             "process_work_item": "MOCK: irc.post: abarth, darin, eseidel: http://trac.webkit.org/changeset/29837 appears to have broken Mock builder name (Tests)\n",
    47             "handle_unexpected_error": "Mock error message\n"
    48         }
    49         self.assert_queue_outputs(SheriffBot(), work_item=mock_work_item, expected_stderr=expected_stderr)
    5037
     38class MockSheriffBot(object):
     39    def run_webkit_patch(self, args):
     40        return "Created bug https://bugs.webkit.org/show_bug.cgi?id=36936\n"
     41
     42
     43class SheriffTest(unittest.TestCase):
    5144    def test_rollout_reason(self):
    52         bot = SheriffBot()
     45        sheriff = Sheriff(MockTool(), MockSheriffBot())
    5346        builders = [
    5447            Builder("Foo", None),
     
    5649        ]
    5750        reason = "Caused builders Foo and Bar to fail."
    58         self.assertEquals(bot._rollout_reason(builders), reason)
     51        self.assertEquals(sheriff._rollout_reason(builders), reason)
    5952
    6053    def test_post_blame_comment_on_bug(self):
    61         bot = SheriffBot()
    62         bot.tool = MockTool()
     54        sheriff = Sheriff(MockTool(), MockSheriffBot())
    6355        builders = [
    6456            Builder("Foo", None),
     
    6658        ]
    6759        commit_info = Mock()
    68         commit_info.bug_id = lambda:None
    69         commit_info.revision = lambda:4321
     60        commit_info.bug_id = lambda: None
     61        commit_info.revision = lambda: 4321
    7062        # Should do nothing with no bug_id
    71         bot._post_blame_comment_on_bug(commit_info, builders)
     63        sheriff.post_blame_comment_on_bug(commit_info, builders)
    7264        # Should try to post a comment to the bug, but MockTool.bugs does nothing.
    73         commit_info.bug_id = lambda:1234
    74         bot._post_blame_comment_on_bug(commit_info, builders)
     65        commit_info.bug_id = lambda: 1234
     66        sheriff.post_blame_comment_on_bug(commit_info, builders)
  • trunk/WebKitTools/Scripts/webkitpy/tool/bot/sheriffircbot.py

    r56883 r56947  
    3333
    3434
    35 class _IRCThreadTearoff(object):
     35class _IRCThreadTearoff(IRCBotDelegate):
    3636    def __init__(self, password, message_queue, wakeup_event):
    3737        self._password = password
     
    5252
    5353
    54 class SheriffIRCBot(IRCBotDelegate):
     54class SheriffIRCBot(object):
    5555    # FIXME: Lame.  We should have an auto-registering CommandCenter.
    5656    commands = {
    5757        "last-green-revision": irc_command.LastGreenRevision,
    5858        "restart": irc_command.Restart,
     59        "rollout": irc_command.Rollout,
    5960        "hi": irc_command.Hi,
    6061    }
    6162
    62     def __init__(self, tool):
     63    def __init__(self, tool, sheriff):
    6364        self._tool = tool
     65        self._sheriff = sheriff
    6466        self._message_queue = ThreadedMessageQueue()
    6567
    6668    def irc_delegate(self):
    67         return _IRCThreadTearoff(self._tool.irc_password, self._message_queue, self._tool.wakeup_event)
     69        return _IRCThreadTearoff(self._tool.irc_password,
     70                                 self._message_queue,
     71                                 self._tool.wakeup_event)
    6872
    6973    def process_message(self, message):
     
    7377        command = self.commands.get(tokenized_message[0])
    7478        if not command:
    75             self._tool.irc().post("Available commands: %s" % ", ".join(self.commands.keys()))
     79            self._tool.irc().post(
     80                "Available commands: %s" % ", ".join(self.commands.keys()))
    7681            return
    77         response = command().execute(tokenized_message[1:], self._tool)
     82        response = command().execute(tokenized_message[1:],
     83                                     self._tool,
     84                                     self._sheriff)
    7885        if response:
    7986            self._tool.irc().post(response)
  • trunk/WebKitTools/Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py

    r56883 r56947  
    3030
    3131from webkitpy.common.system.outputcapture import OutputCapture
     32from webkitpy.tool.bot.sheriff import Sheriff
    3233from webkitpy.tool.bot.sheriffircbot import SheriffIRCBot
     34from webkitpy.tool.bot.sheriff_unittest import MockSheriffBot
    3335from webkitpy.tool.mocktool import MockTool
     36
    3437
    3538def run(message):
    3639    tool = MockTool()
    3740    tool.ensure_irc_connected(None)
    38     bot = SheriffIRCBot(tool)
     41    bot = SheriffIRCBot(tool, Sheriff(tool, MockSheriffBot()))
    3942    bot._message_queue.post(message)
    4043    bot.process_pending_messages()
     
    4750
    4851    def test_bogus(self):
    49         expected_stderr = "MOCK: irc.post: Available commands: hi, restart, last-green-revision\n"
     52        expected_stderr = "MOCK: irc.post: Available commands: rollout, hi, restart, last-green-revision\n"
    5053        OutputCapture().assert_outputs(self, run, args=["bogus"], expected_stderr=expected_stderr)
    5154
     
    5356        expected_stderr = "MOCK: irc.post: http://trac.webkit.org/changeset/9479\n"
    5457        OutputCapture().assert_outputs(self, run, args=["last-green-revision"], expected_stderr=expected_stderr)
     58
     59    def test_rollout(self):
     60        expected_stderr = "MOCK: irc.post: Preparing rollout for r21654...\nMOCK: irc.post: Created rollout: http://example.com/36936\n"
     61        OutputCapture().assert_outputs(self, run, args=["rollout 21654 This patch broke the world"], expected_stderr=expected_stderr)
     62
     63    def test_rollout_bananas(self):
     64        expected_stderr = "MOCK: irc.post: Usage: SVN_REVISION REASON\n"
     65        OutputCapture().assert_outputs(self, run, args=["rollout bananas"], expected_stderr=expected_stderr)
     66
     67    def test_rollout_no_reason(self):
     68        expected_stderr = "MOCK: irc.post: Usage: SVN_REVISION REASON\n"
     69        OutputCapture().assert_outputs(self, run, args=["rollout 21654"], expected_stderr=expected_stderr)
  • trunk/WebKitTools/Scripts/webkitpy/tool/commands/queues.py

    r56936 r56947  
    7474        webkit_patch_args += ["--status-host=%s" % self.tool.status_server.host]
    7575        webkit_patch_args += map(str, args)
    76         self.tool.executive.run_and_throw_if_fail(webkit_patch_args)
     76        return self.tool.executive.run_and_throw_if_fail(webkit_patch_args)
    7777
    7878    # QueueEngineDelegate methods
  • trunk/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot.py

    r56936 r56947  
    3030
    3131from webkitpy.common.system.deprecated_logging import log
    32 from webkitpy.common.checkout.changelog import view_source_url
    3332from webkitpy.common.config.ports import WebKitPort
     33from webkitpy.tool.bot.sheriff import Sheriff
    3434from webkitpy.tool.bot.sheriffircbot import SheriffIRCBot
    3535from webkitpy.tool.commands.queues import AbstractQueue
    36 from webkitpy.tool.grammar import join_with_separators
    3736
    3837class SheriffBot(AbstractQueue):
     
    4645    def begin_work_queue(self):
    4746        AbstractQueue.begin_work_queue(self)
    48         self._irc_bot = SheriffIRCBot(self.tool)
     47        self._sheriff = Sheriff(self.tool, self)
     48        self._irc_bot = SheriffIRCBot(self.tool, self._sheriff)
    4949        self.tool.ensure_irc_connected(self._irc_bot.irc_delegate())
    5050
     
    6363                "svn_revision": svn_revision,
    6464                "builders": builders,
    65                 # FIXME: _rollout_reason needs Build objects which we could pass here.
     65                # FIXME: Sheriff._rollout_reason needs Build objects which we could pass here.
    6666            }
    6767        return None
     
    7171        return True
    7272
    73     # _post* methods should move onto some new class where they can share more logic and state.
    74     def _post_irc_warning(self, commit_info, builders):
    75         irc_nicknames = sorted([party.irc_nickname for party in commit_info.responsible_parties() if party.irc_nickname])
    76         irc_prefix = ": " if irc_nicknames else ""
    77         irc_message = "%s%s%s appears to have broken %s" % (
    78             ", ".join(irc_nicknames),
    79             irc_prefix,
    80             view_source_url(commit_info.revision()),
    81             join_with_separators([builder.name() for builder in builders]))
    82 
    83         self.tool.irc().post(irc_message)
    84 
    85     def _rollout_reason(self, builders):
    86         # FIXME: This should explain which layout tests failed
    87         # however, that would require Build objects here, either passed
    88         # in through failure_info, or through Builder.latest_build.
    89         builder_names = [builder.name() for builder in builders]
    90         return "Caused builders %s to fail." % join_with_separators(builder_names)
    91 
    92     def _post_rollout_patch(self, commit_info, rollout_reason):
    93         # For now we're only posting rollout patches for commit-queue'd patches.
    94         commit_bot_email = "eseidel@chromium.org"
    95         if commit_bot_email not in commit_info.committer().emails:
    96             return
    97 
    98         args = [
    99             "create-rollout",
    100             "--force-clean",
    101             "--non-interactive",
    102             "--parent-command=%s" % self.name,
    103             commit_info.revision(),
    104             self._rollout_reason(builders),
    105         ]
    106         try:
    107             self.run_webkit_patch(args)
    108         except:
    109             log("Failed to create-rollout.")
    110 
    111     def _post_blame_comment_on_bug(self, commit_info, builders):
    112         if not commit_info.bug_id():
    113             return
    114         comment = "%s appears to have broken %s" % (
    115             view_source_url(commit_info.revision()),
    116             join_with_separators([builder.name() for builder in builders]))
    117         self.tool.bugs.post_comment_to_bug(commit_info.bug_id(), comment)
    118 
    11973    def process_work_item(self, failure_info):
    12074        svn_revision = failure_info["svn_revision"]
     
    12377        self.update()
    12478        commit_info = self.tool.checkout().commit_info_for_revision(svn_revision)
    125         self._post_irc_warning(commit_info, builders)
    126         self._post_blame_comment_on_bug(commit_info, builders)
    127         self._post_rollout_patch(commit_info, builders)
     79        self._sheriff.post_irc_warning(commit_info, builders)
     80        self._sheriff.post_blame_comment_on_bug(commit_info, builders)
     81        self._sheriff.post_automatic_rollout_patch(commit_info, builders)
    12882
    12983        for builder in builders:
  • trunk/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py

    r56755 r56947  
    2929import os
    3030
    31 from webkitpy.common.net.buildbot import Builder
    32 from webkitpy.thirdparty.mock import Mock
    3331from webkitpy.tool.commands.queuestest import QueuesTest
    3432from webkitpy.tool.commands.sheriffbot import SheriffBot
    35 from webkitpy.tool.mocktool import MockTool, mock_builder
     33from webkitpy.tool.mocktool import mock_builder
     34
    3635
    3736class SheriffBotTest(QueuesTest):
     
    4443            "begin_work_queue": "CAUTION: sheriff-bot will discard all local changes in \"%s\"\nRunning WebKit sheriff-bot.\n" % os.getcwd(),
    4544            "next_work_item": "",
    46             "process_work_item": "MOCK: irc.post: abarth, darin, eseidel: http://trac.webkit.org/changeset/29837 appears to have broken Mock builder name (Tests)\n",
     45            "process_work_item": "MOCK: irc.post: abarth, darin, eseidel: http://trac.webkit.org/changeset/29837 might have broken Mock builder name (Tests)\n",
    4746            "handle_unexpected_error": "Mock error message\n"
    4847        }
    4948        self.assert_queue_outputs(SheriffBot(), work_item=mock_work_item, expected_stderr=expected_stderr)
    50 
    51     def test_rollout_reason(self):
    52         bot = SheriffBot()
    53         builders = [
    54             Builder("Foo", None),
    55             Builder("Bar", None),
    56         ]
    57         reason = "Caused builders Foo and Bar to fail."
    58         self.assertEquals(bot._rollout_reason(builders), reason)
    59 
    60     def test_post_blame_comment_on_bug(self):
    61         bot = SheriffBot()
    62         bot.tool = MockTool()
    63         builders = [
    64             Builder("Foo", None),
    65             Builder("Bar", None),
    66         ]
    67         commit_info = Mock()
    68         commit_info.bug_id = lambda:None
    69         commit_info.revision = lambda:4321
    70         # Should do nothing with no bug_id
    71         bot._post_blame_comment_on_bug(commit_info, builders)
    72         # Should try to post a comment to the bug, but MockTool.bugs does nothing.
    73         commit_info.bug_id = lambda:1234
    74         bot._post_blame_comment_on_bug(commit_info, builders)
Note: See TracChangeset for help on using the changeset viewer.