watchlist: Add webkit-patch command to run watchlist.
authorlevin@chromium.org <levin@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Oct 2011 01:08:15 +0000 (01:08 +0000)
committerlevin@chromium.org <levin@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 1 Oct 2011 01:08:15 +0000 (01:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=68973

Reviewed by Eric Seidel.

* Scripts/webkitpy/common/host.py: Exposed the watch_list.
* Scripts/webkitpy/common/watchlist/watchlist.py: Changed to return
the cc and messages as sorted lists. To allow for deterministic ordering.
* Scripts/webkitpy/common/watchlist/watchlist_unittest.py: Ditto.
* Scripts/webkitpy/tool/commands/__init__.py: Add ApplyWatchListLocal so
that it will be exposed as a command by webkit-patch.
* Scripts/webkitpy/tool/commands/applywatchlistlocal.py: Added.
* Scripts/webkitpy/tool/commands/applywatchlistlocal_unittest.py: Added.
* Scripts/webkitpy/tool/commands/download.py: Added ApplyWatchList which mimics CheckStyle.
* Scripts/webkitpy/tool/commands/download_unittest.py: Added an appropriate test.
* Scripts/webkitpy/tool/mocktool.py: Mock out the watch list.
* Scripts/webkitpy/tool/steps/__init__.py: Added ApplyWatchList.
* Scripts/webkitpy/tool/steps/applywatchlist.py: Added.
* Scripts/webkitpy/tool/steps/applywatchlist_unittest.py: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@96444 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Tools/ChangeLog
Tools/Scripts/webkitpy/common/host.py
Tools/Scripts/webkitpy/common/watchlist/watchlist.py
Tools/Scripts/webkitpy/common/watchlist/watchlist_unittest.py
Tools/Scripts/webkitpy/tool/commands/__init__.py
Tools/Scripts/webkitpy/tool/commands/applywatchlistlocal.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/commands/applywatchlistlocal_unittest.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/commands/download.py
Tools/Scripts/webkitpy/tool/commands/download_unittest.py
Tools/Scripts/webkitpy/tool/mocktool.py
Tools/Scripts/webkitpy/tool/steps/__init__.py
Tools/Scripts/webkitpy/tool/steps/applywatchlist.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/steps/applywatchlist_unittest.py [new file with mode: 0644]

index e9d1f77..a926771 100644 (file)
@@ -1,3 +1,25 @@
+2011-09-29  David Levin  <levin@chromium.org>
+
+        watchlist: Add webkit-patch command to run watchlist.
+        https://bugs.webkit.org/show_bug.cgi?id=68973
+
+        Reviewed by Eric Seidel.
+
+        * Scripts/webkitpy/common/host.py: Exposed the watch_list.
+        * Scripts/webkitpy/common/watchlist/watchlist.py: Changed to return
+        the cc and messages as sorted lists. To allow for deterministic ordering.
+        * Scripts/webkitpy/common/watchlist/watchlist_unittest.py: Ditto.
+        * Scripts/webkitpy/tool/commands/__init__.py: Add ApplyWatchListLocal so
+        that it will be exposed as a command by webkit-patch.
+        * Scripts/webkitpy/tool/commands/applywatchlistlocal.py: Added.
+        * Scripts/webkitpy/tool/commands/applywatchlistlocal_unittest.py: Added.
+        * Scripts/webkitpy/tool/commands/download.py: Added ApplyWatchList which mimics CheckStyle.
+        * Scripts/webkitpy/tool/commands/download_unittest.py: Added an appropriate test.
+        * Scripts/webkitpy/tool/mocktool.py: Mock out the watch list.
+        * Scripts/webkitpy/tool/steps/__init__.py: Added ApplyWatchList.
+        * Scripts/webkitpy/tool/steps/applywatchlist.py: Added.
+        * Scripts/webkitpy/tool/steps/applywatchlist_unittest.py: Added.
+
 2011-09-30  David Levin  <levin@chromium.org>
 
         watchlist: Add a way to detect a net increase or decrease of a pattern (in a file).
index 651d1f1..b2fdd2f 100644 (file)
@@ -36,6 +36,7 @@ from webkitpy.common.net import bugzilla, buildbot, statusserver, web
 from webkitpy.common.net.buildbot.chromiumbuildbot import ChromiumBuildBot
 from webkitpy.common.net.irc import ircproxy
 from webkitpy.common.system import executive, filesystem, platforminfo, user, workspace
+from webkitpy.common.watchlist.watchlistloader import WatchListLoader
 from webkitpy.layout_tests.port.factory import PortFactory
 
 
@@ -76,6 +77,10 @@ class Host(object):
     def chromium_buildbot(self):
         return ChromiumBuildBot()
 
+    @memoized
+    def watch_list(self):
+        return WatchListLoader(self.filesystem).load()
+
     def ensure_irc_connected(self, irc_delegate):
         if not self._irc:
             self._irc = ircproxy.IRCProxy(irc_delegate)
index 59f1402..4a81039 100644 (file)
@@ -58,17 +58,18 @@ class WatchList(object):
         for rule in rules:
             if rule.match(matching_definitions):
                 instructions.update(rule.instructions())
-        return instructions
+        # Sort the results to make the order deterministic (for consistency and easier testing).
+        return sorted(instructions)
 
-    def determine_cc_set(self, matching_definitions):
+    def determine_cc_list(self, matching_definitions):
         return self._determine_instructions(matching_definitions, self.cc_rules)
 
     def determine_messages(self, matching_definitions):
         return self._determine_instructions(matching_definitions, self.message_rules)
 
-    def determine_cc_set_and_messages(self, diff):
+    def determine_cc_and_messages(self, diff):
         definitions = self.find_matching_definitions(diff)
         return {
-            'cc_set': self.determine_cc_set(definitions),
+            'cc_list': self.determine_cc_list(definitions),
             'messages':  self.determine_messages(definitions),
-            }
+        }
index b7fbd91..09010b2 100644 (file)
@@ -84,11 +84,11 @@ class WatchListTest(unittest.TestCase):
             '        ],'
            '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['levin@chromium.org']),
-                'messages': set(),
-                }, cc_set_and_messages)
+                'cc_list': ['levin@chromium.org'],
+                'messages': [],
+                }, cc_and_messages)
 
     def test_cc_rules_complex(self):
         watch_list = self._watch_list_parser.parse(
@@ -108,11 +108,11 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList2|WatchList1|WatchList3": [ "levin@chromium.org", ],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['levin@chromium.org']),
-                'messages': set(),
-                }, cc_set_and_messages)
+                'cc_list': ['levin@chromium.org'],
+                'messages': [],
+                }, cc_and_messages)
 
     def test_cc_and_message_rules_complex(self):
         watch_list = self._watch_list_parser.parse(
@@ -135,11 +135,11 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList2|WatchList1|WatchList3": [ "msg1", "msg2", ],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['levin@chromium.org']),
-                'messages': set(['msg1', 'msg2']),
-                }, cc_set_and_messages)
+                'cc_list': ['levin@chromium.org'],
+                'messages': ['msg1', 'msg2'],
+                }, cc_and_messages)
 
     def test_cc_and_message_rules_no_matches(self):
         watch_list = self._watch_list_parser.parse(
@@ -162,11 +162,11 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList2|WatchList1|WatchList3": [ "msg1", "msg2", ],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(),
-                'messages': set(),
-                }, cc_set_and_messages)
+                'cc_list': [],
+                'messages': [],
+                }, cc_and_messages)
 
     def test_added_match(self):
         watch_list = self._watch_list_parser.parse(
@@ -184,11 +184,11 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList2": [ "abarth@webkit.org", ],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['eric@webkit.org']),
-                'messages': set(),
-                }, cc_set_and_messages)
+                'cc_list': ['eric@webkit.org'],
+                'messages': [],
+                }, cc_and_messages)
 
     def test_deleted_match(self):
         watch_list = self._watch_list_parser.parse(
@@ -206,11 +206,11 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList2": [ "abarth@webkit.org", ],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['abarth@webkit.org']),
-                'messages': set(),
-                }, cc_set_and_messages)
+                'cc_list': ['abarth@webkit.org'],
+                'messages': [],
+                }, cc_and_messages)
 
     def test_more_and_less_match(self):
         watch_list = self._watch_list_parser.parse(
@@ -235,11 +235,11 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList3": ["Test message."],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['levin@chromium.org']),
-                'messages': set(["Test message."]),
-                }, cc_set_and_messages)
+                'cc_list': ['levin@chromium.org'],
+                'messages': ["Test message."],
+                }, cc_and_messages)
 
     def test_complex_match(self):
         watch_list = self._watch_list_parser.parse(
@@ -270,8 +270,8 @@ class WatchListTest(unittest.TestCase):
             '        "WatchList2": ["This is a test message."],'
             '    },'
             '}')
-        cc_set_and_messages = watch_list.determine_cc_set_and_messages(DIFF_TEST_DATA)
+        cc_and_messages = watch_list.determine_cc_and_messages(DIFF_TEST_DATA)
         self.assertEquals({
-                'cc_set': set(['eric@webkit.org']),
-                'messages': set(["This is a test message."]),
-                }, cc_set_and_messages)
+                'cc_list': ['eric@webkit.org'],
+                'messages': ["This is a test message."],
+                }, cc_and_messages)
index 6190f18..3836947 100644 (file)
@@ -1,6 +1,7 @@
 # Required for Python to search this directory for module files
 
 from webkitpy.tool.commands.adduserstogroups import AddUsersToGroups
+from webkitpy.tool.commands.applywatchlistlocal import ApplyWatchListLocal
 from webkitpy.tool.commands.bugfortest import BugForTest
 from webkitpy.tool.commands.bugsearch import BugSearch
 from webkitpy.tool.commands.download import *
diff --git a/Tools/Scripts/webkitpy/tool/commands/applywatchlistlocal.py b/Tools/Scripts/webkitpy/tool/commands/applywatchlistlocal.py
new file mode 100644 (file)
index 0000000..a656ab3
--- /dev/null
@@ -0,0 +1,40 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
+from webkitpy.tool import steps
+
+
+class ApplyWatchListLocal(AbstractSequencedCommand):
+    name = "apply-watchlist-local"
+    help_text = "Applies the watchlist to local changes."
+    steps = [
+        steps.ApplyWatchList,
+    ]
+    long_help = """"Applies the watchlist to local changes.
+The results is logged but not applied to any bug. This may be used to try out a watchlist change."""
diff --git a/Tools/Scripts/webkitpy/tool/commands/applywatchlistlocal_unittest.py b/Tools/Scripts/webkitpy/tool/commands/applywatchlistlocal_unittest.py
new file mode 100644 (file)
index 0000000..995bcd6
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.applywatchlistlocal import ApplyWatchListLocal
+
+
+class ApplyWatchListLocalTest(CommandsTest):
+    def test_args_parsing(self):
+        expected_stderr = "MockWatchList: determine_cc_and_messages\n"
+        self.assert_execute_outputs(ApplyWatchListLocal(), ["-g 2ed6f"], expected_stderr=expected_stderr)
index 18e2039..23ebf89 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (c) 2009, 2011 Google Inc. All rights reserved.
 # Copyright (c) 2009 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -250,6 +250,20 @@ class ApplyFromBug(AbstractPatchApplyingCommand, ProcessBugsMixin):
     show_in_main_help = True
 
 
+class ApplyWatchList(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
+    name = "apply-watchlist"
+    help_text = "Applies the watchlist to the specified attachments."
+    argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
+    main_steps = [
+        steps.CleanWorkingDirectory,
+        steps.Update,
+        steps.ApplyPatch,
+        steps.ApplyWatchList,
+    ]
+    long_help = """"Applies the watchlist to the specified attachments.
+Downloads the attachment, applies it locally, runs the watchlist against it, and updates the bug with the result."""
+
+
 class AbstractPatchLandingCommand(AbstractPatchSequencingCommand):
     main_steps = [
         steps.CleanWorkingDirectory,
index 5141937..6226208 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2009, 2011 Google Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
@@ -105,6 +105,14 @@ class DownloadCommandsTest(CommandsTest):
         expected_stderr = "Updating working directory\n2 reviewed patches found on bug 50000.\nProcessing 2 patches from 1 bug.\nProcessing patch 10000 from bug 50000.\nProcessing patch 10001 from bug 50000.\n"
         self.assert_execute_outputs(ApplyFromBug(), [50000], options=options, expected_stderr=expected_stderr)
 
+    def test_apply_watch_list(self):
+        expected_stderr = """Processing 1 patch from 1 bug.
+Updating working directory
+MOCK run_and_throw_if_fail: ['mock-update-webkit'], cwd=/mock-checkout\nProcessing patch 10000 from bug 50000.
+MockWatchList: determine_cc_and_messages
+"""
+        self.assert_execute_outputs(ApplyWatchList(), [10000], options=self._default_options(), expected_stderr=expected_stderr, tool=MockTool(log_executive=True))
+
     def test_land(self):
         expected_stderr = "Building WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning Bindings tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 50000\n"
         mock_tool = MockTool()
index 629dcbf..a03e127 100644 (file)
@@ -805,6 +805,12 @@ class MockPlatformInfo(object):
         return "MockPlatform 1.0"
 
 
+class MockWatchList(object):
+    def determine_cc_and_messages(self, diff):
+        log("MockWatchList: determine_cc_and_messages")
+        return {'cc_list': ['levin@chromium.org'], 'messages': ['Message1.', 'Message2.'], }
+
+
 class MockWorkspace(object):
     def find_unused_filename(self, directory, name, extension, search_limit=10):
         return "%s/%s.%s" % (directory, name, extension)
@@ -839,6 +845,7 @@ class MockTool(object):
         self.irc_password = "MOCK irc password"
         self.port_factory = MockPortFactory()
         self.platform = MockPlatformInfo()
+        self._watch_list = MockWatchList()
 
     def scm(self):
         return self._scm
@@ -849,6 +856,9 @@ class MockTool(object):
     def chromium_buildbot(self):
         return self._chromium_buildbot
 
+    def watch_list(self):
+        return self._watch_list
+
     def ensure_irc_connected(self, delegate):
         if not self._irc:
             self._irc = MockIRC()
index 203e694..27706af 100644 (file)
@@ -29,6 +29,7 @@
 # FIXME: Is this the right way to do this?
 from webkitpy.tool.steps.applypatch import ApplyPatch
 from webkitpy.tool.steps.applypatchwithlocalcommit import ApplyPatchWithLocalCommit
+from webkitpy.tool.steps.applywatchlist import ApplyWatchList
 from webkitpy.tool.steps.attachtobug import AttachToBug
 from webkitpy.tool.steps.build import Build
 from webkitpy.tool.steps.checkstyle import CheckStyle
diff --git a/Tools/Scripts/webkitpy/tool/steps/applywatchlist.py b/Tools/Scripts/webkitpy/tool/steps/applywatchlist.py
new file mode 100644 (file)
index 0000000..28c3649
--- /dev/null
@@ -0,0 +1,57 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system import logutils
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+
+
+_log = logutils.get_logger(__file__)
+
+
+class ApplyWatchList(AbstractStep):
+    @classmethod
+    def options(cls):
+        return AbstractStep.options() + [
+            Options.git_commit,
+        ]
+
+    def run(self, state):
+        diff = self.cached_lookup(state, 'diff')
+        bug_id = state.get("bug_id")
+
+        cc_and_messages = self._tool.watch_list().determine_cc_and_messages(diff)
+        cc_list = cc_and_messages['cc_list']
+        comment_text = '\n\n'.join(cc_and_messages['messages'])
+        if bug_id:
+            self._tool.bugs.post_comment_to_bug(bug_id, comment_text, cc_list)
+            log_result = _log.debug
+        else:
+            _log.info('No bug was updated because no id was given.')
+            log_result = _log.info
+        log_result('Result of watchlist: cc "%s" messages "%s"' % (', '.join(cc_list), comment_text))
diff --git a/Tools/Scripts/webkitpy/tool/steps/applywatchlist_unittest.py b/Tools/Scripts/webkitpy/tool/steps/applywatchlist_unittest.py
new file mode 100644 (file)
index 0000000..8e57a57
--- /dev/null
@@ -0,0 +1,53 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#    * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.applywatchlist import ApplyWatchList
+
+
+class ApplyWatchListTest(unittest.TestCase):
+    def test_apply_watch_list_local(self):
+        capture = OutputCapture()
+        step = ApplyWatchList(MockTool(log_executive=True), MockOptions())
+        state = {
+            'bug_id': '14397',
+            'diff': 'The diff',
+        }
+        expected_stderr = """MockWatchList: determine_cc_and_messages
+MOCK bug comment: bug_id=14397, cc=['levin@chromium.org']
+--- Begin comment ---
+Message1.
+
+Message2.
+--- End comment ---
+
+"""
+        capture.assert_outputs(self, step.run, [state], expected_stderr=expected_stderr)