2011-01-28 Adam Barth <abarth@webkit.org>
authorabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Jan 2011 10:14:13 +0000 (10:14 +0000)
committerabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Jan 2011 10:14:13 +0000 (10:14 +0000)
        Reviewed by Eric Seidel.

        Add webkit-patch roll-chromium-deps
        https://bugs.webkit.org/show_bug.cgi?id=53288

        This command updates the Source/WebKit/chromium/DEPS file with the
        last-known good revision of Chromium (or a revision specified on the
        command line).  I'd eventually like to turn this into a SheriffBot
        command, but this is the first step.

        This patch somewhat sprawled because I needed to move a bunch of code
        out of ChangeLog that should never have been there in the first place.
        Also, I had to fix a bug in MockUser in order to test the new command.

        * Scripts/webkitpy/common/checkout/api.py:
        * Scripts/webkitpy/common/checkout/changelog.py:
        * Scripts/webkitpy/common/checkout/changelog_unittest.py:
        * Scripts/webkitpy/common/checkout/deps.py: Added.
        * Scripts/webkitpy/common/config/urls.py:
        * Scripts/webkitpy/tool/commands/__init__.py:
        * Scripts/webkitpy/tool/commands/download_unittest.py:
        * Scripts/webkitpy/tool/commands/roll.py: Added.
        * Scripts/webkitpy/tool/commands/roll_unittest.py: Added.
        * Scripts/webkitpy/tool/commands/upload_unittest.py:
        * Scripts/webkitpy/tool/mocktool.py:
        * Scripts/webkitpy/tool/steps/__init__.py:
        * Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py: Added.
        * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
        * Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py: Added.
        * Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py:
        * Scripts/webkitpy/tool/steps/updatechromiumdeps.py: Added.
        * Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py:

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

20 files changed:
Tools/ChangeLog
Tools/Scripts/webkitpy/common/checkout/api.py
Tools/Scripts/webkitpy/common/checkout/changelog.py
Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py
Tools/Scripts/webkitpy/common/checkout/deps.py [new file with mode: 0644]
Tools/Scripts/webkitpy/common/config/urls.py
Tools/Scripts/webkitpy/tool/commands/__init__.py
Tools/Scripts/webkitpy/tool/commands/commandtest.py
Tools/Scripts/webkitpy/tool/commands/download_unittest.py
Tools/Scripts/webkitpy/tool/commands/roll.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/commands/roll_unittest.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/commands/upload_unittest.py
Tools/Scripts/webkitpy/tool/mocktool.py
Tools/Scripts/webkitpy/tool/steps/__init__.py
Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py
Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py
Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py [new file with mode: 0644]
Tools/Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py

index 31c3af623fbc117e45f0f42ad631e220bc9a6519..a29308598d520c54c1a31965e75747312c591a9d 100644 (file)
@@ -1,3 +1,38 @@
+2011-01-28  Adam Barth  <abarth@webkit.org>
+
+        Reviewed by Eric Seidel.
+
+        Add webkit-patch roll-chromium-deps
+        https://bugs.webkit.org/show_bug.cgi?id=53288
+
+        This command updates the Source/WebKit/chromium/DEPS file with the
+        last-known good revision of Chromium (or a revision specified on the
+        command line).  I'd eventually like to turn this into a SheriffBot
+        command, but this is the first step.
+
+        This patch somewhat sprawled because I needed to move a bunch of code
+        out of ChangeLog that should never have been there in the first place.
+        Also, I had to fix a bug in MockUser in order to test the new command.
+
+        * Scripts/webkitpy/common/checkout/api.py:
+        * Scripts/webkitpy/common/checkout/changelog.py:
+        * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+        * Scripts/webkitpy/common/checkout/deps.py: Added.
+        * Scripts/webkitpy/common/config/urls.py:
+        * Scripts/webkitpy/tool/commands/__init__.py:
+        * Scripts/webkitpy/tool/commands/download_unittest.py:
+        * Scripts/webkitpy/tool/commands/roll.py: Added.
+        * Scripts/webkitpy/tool/commands/roll_unittest.py: Added.
+        * Scripts/webkitpy/tool/commands/upload_unittest.py:
+        * Scripts/webkitpy/tool/mocktool.py:
+        * Scripts/webkitpy/tool/steps/__init__.py:
+        * Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py: Added.
+        * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+        * Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py: Added.
+        * Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py:
+        * Scripts/webkitpy/tool/steps/updatechromiumdeps.py: Added.
+        * Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py:
+
 2011-01-27  Greg Coletta  <greg.coletta@nokia.com>
 
         Reviewed by Laszlo Gombos.
index a87bb5a528a8ee7e9a839af97106d1ae80645421..170b82256fec19a6bfbaf16dba91bba68d85df72 100644 (file)
@@ -33,6 +33,7 @@ from webkitpy.common.config import urls
 from webkitpy.common.checkout.changelog import ChangeLog
 from webkitpy.common.checkout.commitinfo import CommitInfo
 from webkitpy.common.checkout.scm import CommitMessage
+from webkitpy.common.checkout.deps import DEPS
 from webkitpy.common.memoized import memoized
 from webkitpy.common.net.bugzilla import parse_bug_id
 from webkitpy.common.system.executive import Executive, run_command, ScriptError
@@ -148,6 +149,9 @@ class Checkout(object):
         except ScriptError, e:
             pass # We might not have ChangeLogs.
 
+    def chromium_deps(self):
+        return DEPS(os.path.join(self._scm.checkout_root, "Source", "WebKit", "chromium", "DEPS"))
+
     def apply_patch(self, patch, force=False):
         # It's possible that the patch was not made from the root directory.
         # We should detect and handle that case.
index 07f905dd2818e19d9c36345f81d20d7aa02e1e51..c81318c2ffcf60f0313514348ffb85ed21785cd2 100644 (file)
@@ -36,9 +36,7 @@ import textwrap
 
 from webkitpy.common.system.deprecated_logging import log
 from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.config import urls
 from webkitpy.common.net.bugzilla import parse_bug_id
-from webkitpy.tool.grammar import join_with_separators
 
 
 class ChangeLogEntry(object):
@@ -145,29 +143,14 @@ class ChangeLog(object):
         lines = [self._wrap_line(line) for line in message.splitlines()]
         return "\n".join(lines)
 
-    # This probably does not belong in changelogs.py
-    def _message_for_revert(self, revision_list, reason, bug_url):
-        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 self._wrap_lines(message)
-
-    def update_for_revert(self, revision_list, reason, bug_url=None):
+    def update_with_unreviewed_message(self, message):
         reviewed_by_regexp = re.compile(
                 "%sReviewed by NOBODY \(OOPS!\)\." % self._changelog_indent)
         removing_boilerplate = False
         # inplace=1 creates a backup file and re-directs stdout to the file
         for line in fileinput.FileInput(self.path, inplace=1):
             if reviewed_by_regexp.search(line):
-                message_lines = self._message_for_revert(revision_list,
-                                                         reason,
-                                                         bug_url)
+                message_lines = self._wrap_lines(message)
                 print reviewed_by_regexp.sub(message_lines, line),
                 # Remove all the ChangeLog boilerplate between the Reviewed by
                 # line and the first changed file.
index 20c6cfaae0f27da8a2a1b5b53b8aabe1ffcee98a..299d509aa0d0fe21780a065891c5bff8519fed38 100644 (file)
@@ -142,89 +142,3 @@ class ChangeLogTest(unittest.TestCase):
         expected_contents = changelog_contents.replace("Need a short description and bug URL (OOPS!)", expected_message)
         os.remove(changelog_path)
         self.assertEquals(actual_contents, expected_contents)
-
-    _revert_message = """        Unreviewed, rolling out r12345.
-        http://trac.webkit.org/changeset/12345
-        http://example.com/123
-
-        This is a very long reason which should be long enough so that
-        _message_for_revert will need to wrap it.  We'll also include
-        a
-        https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354
-        link so that we can make sure we wrap that right too.
-"""
-
-    def test_message_for_revert(self):
-        changelog = ChangeLog("/fake/path")
-        long_reason = "This is a very long reason which should be long enough so that _message_for_revert will need to wrap it.  We'll also include a https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354 link so that we can make sure we wrap that right too."
-        message = changelog._message_for_revert([12345], long_reason, "http://example.com/123")
-        self.assertEquals(message, self._revert_message)
-
-    _revert_entry_with_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
-
-        Unreviewed, rolling out r12345.
-        http://trac.webkit.org/changeset/12345
-        http://example.com/123
-
-        Reason
-
-        * Scripts/bugzilla-tool:
-'''
-
-    _revert_entry_without_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
-
-        Unreviewed, rolling out r12345.
-        http://trac.webkit.org/changeset/12345
-
-        Reason
-
-        * Scripts/bugzilla-tool:
-'''
-
-    _multiple_revert_entry_with_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
-
-        Unreviewed, rolling out r12345, r12346, and r12347.
-        http://trac.webkit.org/changeset/12345
-        http://trac.webkit.org/changeset/12346
-        http://trac.webkit.org/changeset/12347
-        http://example.com/123
-
-        Reason
-
-        * Scripts/bugzilla-tool:
-'''
-
-    _multiple_revert_entry_without_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
-
-        Unreviewed, rolling out r12345, r12346, and r12347.
-        http://trac.webkit.org/changeset/12345
-        http://trac.webkit.org/changeset/12346
-        http://trac.webkit.org/changeset/12347
-
-        Reason
-
-        * Scripts/bugzilla-tool:
-'''
-
-    def _assert_update_for_revert_output(self, args, expected_entry):
-        changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
-        changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
-        changelog = ChangeLog(changelog_path)
-        changelog.update_for_revert(*args)
-        actual_entry = changelog.latest_entry()
-        os.remove(changelog_path)
-        self.assertEquals(actual_entry.contents(), expected_entry)
-        self.assertEquals(actual_entry.reviewer_text(), None)
-        # These checks could be removed to allow this to work on other entries:
-        self.assertEquals(actual_entry.author_name(), "Eric Seidel")
-        self.assertEquals(actual_entry.author_email(), "eric@webkit.org")
-
-    def test_update_for_revert(self):
-        self._assert_update_for_revert_output([[12345], "Reason"], self._revert_entry_without_bug_url)
-        self._assert_update_for_revert_output([[12345], "Reason", "http://example.com/123"], self._revert_entry_with_bug_url)
-        self._assert_update_for_revert_output([[12345, 12346, 12347], "Reason"], self._multiple_revert_entry_without_bug_url)
-        self._assert_update_for_revert_output([[12345, 12346, 12347], "Reason", "http://example.com/123"], self._multiple_revert_entry_with_bug_url)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/checkout/deps.py b/Tools/Scripts/webkitpy/common/checkout/deps.py
new file mode 100644 (file)
index 0000000..6b87ff1
--- /dev/null
@@ -0,0 +1,61 @@
+# 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.
+#
+# WebKit's Python module for parsing and modifying ChangeLog files
+
+import codecs
+import fileinput
+import os.path
+import re
+import textwrap
+
+
+class DEPS(object):
+
+    _variable_regexp = r"\s+'%s':\s+'(?P<value>\d+)'"
+
+    def __init__(self, path):
+        self._path = path
+
+    def read_variable(self, name):
+        pattern = re.compile(self._variable_regexp % name)
+        for line in fileinput.FileInput(self._path):
+            match = pattern.match(line)
+            if match:
+                return int(match.group("value"))
+
+    def write_variable(self, name, value):
+        pattern = re.compile(self._variable_regexp % name)
+        replacement_line = "  '%s': '%s'" % (name, value)
+        # inplace=1 creates a backup file and re-directs stdout to the file
+        for line in fileinput.FileInput(self._path, inplace=1):
+            if pattern.match(line):
+                print replacement_line
+                continue
+            # Trailing comma suppresses printing newline
+            print line,
index dfa6d6983c22ff30b5ffb6a0cfc77f05631645b9..ddaef97b78a550f1278fe79d6b7020ae88516b36 100644 (file)
@@ -34,5 +34,6 @@ def view_source_url(local_path):
 def view_revision_url(revision_number):
     return "http://trac.webkit.org/changeset/%s" % revision_number
 
+chromium_lkgr_url = "http://chromium-status.appspot.com/lkgr"
 
 contribution_guidelines = "http://webkit.org/coding/contributing.html"
index a974b672aaad72cea7e9f96195ca3b8eb043f6b5..26bd1956a55d878a53612189f9c560f891ded7ec 100644 (file)
@@ -10,5 +10,6 @@ from webkitpy.tool.commands.queries import *
 from webkitpy.tool.commands.queues import *
 from webkitpy.tool.commands.rebaseline import Rebaseline
 from webkitpy.tool.commands.rebaselineserver import RebaselineServer
+from webkitpy.tool.commands.roll import *
 from webkitpy.tool.commands.sheriffbot import *
 from webkitpy.tool.commands.upload import *
index c0efa50b01eae8a9ab1bada441790d907f91b767..e3357104dcbbe336d6cc8d36c66c154c970a4f82 100644 (file)
@@ -32,7 +32,7 @@ from webkitpy.common.system.outputcapture import OutputCapture
 from webkitpy.tool.mocktool import MockOptions, MockTool
 
 class CommandsTest(unittest.TestCase):
-    def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", options=MockOptions(), tool=MockTool()):
+    def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", expected_exception=None, options=MockOptions(), tool=MockTool()):
         options.blocks = None
         options.cc = 'MOCK cc'
         options.component = 'MOCK component'
@@ -45,4 +45,4 @@ class CommandsTest(unittest.TestCase):
         options.quiet = True
         options.reviewer = 'MOCK reviewer'
         command.bind_to_tool(tool)
-        OutputCapture().assert_outputs(self, command.execute, [options, args, tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+        OutputCapture().assert_outputs(self, command.execute, [options, args, tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr, expected_exception=expected_exception)
index ba23ab98f52eb9c5e30be807b2645806fd8a8e67..ced5b2f1f42d9d694d99d801703e38c56a80e826 100644 (file)
@@ -200,7 +200,13 @@ where ATTACHMENT_ID is the ID of this attachment.
         self.assert_execute_outputs(CreateRollout(), ["855 852 854", "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
 
     def test_rollout(self):
-        expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\nMOCK: user.open_url: file://...\nBuilding WebKit\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\n"
-        expected_stdout = "Was that diff correct?\n"
-        self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+        expected_stderr = """Preparing rollout for bug 42.
+Updating working directory
+Running prepare-ChangeLog
+MOCK: user.open_url: file://...
+Was that diff correct?
+Building WebKit
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+"""
+        self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
 
diff --git a/Tools/Scripts/webkitpy/tool/commands/roll.py b/Tools/Scripts/webkitpy/tool/commands/roll.py
new file mode 100644 (file)
index 0000000..74f198f
--- /dev/null
@@ -0,0 +1,48 @@
+# 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
+
+import webkitpy.tool.steps as steps
+
+
+class RollChromiumDEPS(AbstractSequencedCommand):
+    name = "roll-chromium-deps"
+    help_text = "Updates Chromium DEPS (defaults to the last-known good revision of Chromium)"
+    argument_names = "[CHROMIUM_REVISION]"
+    steps = [
+        steps.UpdateChromiumDEPS,
+        steps.PrepareChangeLogForDEPSRoll,
+        steps.ConfirmDiff,
+        steps.Commit,
+    ]
+
+    def _prepare_state(self, options, args, tool):
+        return {
+            "chromium_revision": (args and args[0]),
+        }
diff --git a/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py b/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py
new file mode 100644 (file)
index 0000000..b6f69ea
--- /dev/null
@@ -0,0 +1,50 @@
+# 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.thirdparty.mock import Mock
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.roll import *
+from webkitpy.tool.mocktool import MockOptions, MockTool
+
+
+class RollCommandsTest(CommandsTest):
+    def test_update_chromium_deps(self):
+        expected_stderr = """Updating Chromium DEPS to 6764
+MOCK: MockDEPS.write_variable(chromium_rev, 6764)
+Running prepare-ChangeLog
+MOCK: user.open_url: file://...
+Was that diff correct?
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+"""
+        self.assert_execute_outputs(RollChromiumDEPS(), [6764], expected_stderr=expected_stderr)
+
+    def test_update_chromium_deps_older_revision(self):
+        expected_stderr = """Current Chromium DEPS revision 6564 is newer than 5764.
+ERROR: Unable to update Chromium DEPS
+"""
+        self.assert_execute_outputs(RollChromiumDEPS(), [5764], expected_stderr=expected_stderr, expected_exception=SystemExit)
index a347b00718fa92967fbe43f8e2de29e63f645d91..b5f5ae9bb2f6e2e7075dde53311843eafac9145b 100644 (file)
@@ -61,12 +61,12 @@ class UploadCommandsTest(CommandsTest):
         options.suggest_reviewers = False
         expected_stderr = """Running check-webkit-style
 MOCK: user.open_url: file://...
+Was that diff correct?
 Obsoleting 2 old patches on bug 42
 MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
 MOCK: user.open_url: http://example.com/42
 """
-        expected_stdout = "Was that diff correct?\n"
-        self.assert_execute_outputs(Post(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+        self.assert_execute_outputs(Post(), [42], options=options, expected_stderr=expected_stderr)
 
     def test_land_safely(self):
         expected_stderr = "Obsoleting 2 old patches on bug 42\nMOCK add_patch_to_bug: bug_id=42, description=Patch for landing, mark_for_review=False, mark_for_commit_queue=False, mark_for_landing=True\n"
@@ -90,12 +90,12 @@ MOCK: user.open_url: http://example.com/42
         options.suggest_reviewers = False
         expected_stderr = """Running check-webkit-style
 MOCK: user.open_url: file://...
+Was that diff correct?
 Obsoleting 2 old patches on bug 42
 MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
 MOCK: user.open_url: http://example.com/42
 """
-        expected_stdout = "Was that diff correct?\n"
-        self.assert_execute_outputs(Upload(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+        self.assert_execute_outputs(Upload(), [42], options=options, expected_stderr=expected_stderr)
 
     def test_mark_bug_fixed(self):
         tool = MockTool()
@@ -106,6 +106,7 @@ MOCK: user.open_url: http://example.com/42
         expected_stderr = """Bug: <http://example.com/42> Bug with two r+'d and cq+'d patches, one of which has an invalid commit-queue setter.
 Revision: 9876
 MOCK: user.open_url: http://example.com/42
+Is this correct?
 Adding comment to Bug 42.
 MOCK bug comment: bug_id=42, cc=None
 --- Begin comment ---
@@ -115,8 +116,7 @@ Committed r9876: <http://trac.webkit.org/changeset/9876>
 --- End comment ---
 
 """
-        expected_stdout = "Is this correct?\n"
-        self.assert_execute_outputs(MarkBugFixed(), [], expected_stdout=expected_stdout, expected_stderr=expected_stderr, tool=tool, options=options)
+        self.assert_execute_outputs(MarkBugFixed(), [], expected_stderr=expected_stderr, tool=tool, options=options)
 
     def test_edit_changelog(self):
         self.assert_execute_outputs(EditChangeLogs(), [])
index 3680d4cef84e6137fdba9046ce2f83e418e01f47..05782841c3f61e76289801db112da51ab4422aee 100644 (file)
@@ -495,6 +495,14 @@ class MockSCM(Mock):
             return 0
 
 
+class MockDEPS(object):
+    def read_variable(self, name):
+        return 6564
+
+    def write_variable(self, name, value):
+        log("MOCK: MockDEPS.write_variable(%s, %s)" % (name, value))
+
+
 class MockCheckout(object):
 
     _committer_list = CommitterList()
@@ -528,6 +536,9 @@ class MockCheckout(object):
         commit_message.message = lambda:"This is a fake commit message that is at least 50 characters."
         return commit_message
 
+    def chromium_deps(self):
+        return MockDEPS()
+
     def apply_patch(self, patch, force=False):
         pass
 
@@ -561,7 +572,7 @@ class MockUser(object):
         pass
 
     def confirm(self, message=None, default='y'):
-        print message
+        log(message)
         return default == 'y'
 
     def can_open_url(self):
index f426f177d5b6ccd7dcedd975bc3c5fe75df34fca..d5d7bb4c248df5e1efa08804ff6adb4c718dc12e 100644 (file)
@@ -47,6 +47,7 @@ from webkitpy.tool.steps.options import Options
 from webkitpy.tool.steps.postdiff import PostDiff
 from webkitpy.tool.steps.postdiffforcommit import PostDiffForCommit
 from webkitpy.tool.steps.postdiffforrevert import PostDiffForRevert
+from webkitpy.tool.steps.preparechangelogfordepsroll import PrepareChangeLogForDEPSRoll
 from webkitpy.tool.steps.preparechangelogforrevert import PrepareChangeLogForRevert
 from webkitpy.tool.steps.preparechangelog import PrepareChangeLog
 from webkitpy.tool.steps.promptforbugortitle import PromptForBugOrTitle
@@ -55,6 +56,7 @@ from webkitpy.tool.steps.revertrevision import RevertRevision
 from webkitpy.tool.steps.runtests import RunTests
 from webkitpy.tool.steps.suggestreviewers import SuggestReviewers
 from webkitpy.tool.steps.updatechangelogswithreviewer import UpdateChangeLogsWithReviewer
+from webkitpy.tool.steps.updatechromiumdeps import UpdateChromiumDEPS
 from webkitpy.tool.steps.update import Update
 from webkitpy.tool.steps.validatechangelogs import ValidateChangeLogs
 from webkitpy.tool.steps.validatereviewer import ValidateReviewer
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py
new file mode 100644 (file)
index 0000000..39c9a9a
--- /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.
+
+import os
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class PrepareChangeLogForDEPSRoll(AbstractStep):
+    def run(self, state):
+        self._run_script("prepare-ChangeLog")
+        changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None)
+        for changelog_path in changelog_paths:
+            ChangeLog(changelog_path).update_with_unreviewed_message("Rolled DEPS.\n\n")
index 1e47a6a932d7408972c506b8a58b7d0c103ced62..dcd4b9393c22f675c505fecf6d268dbfc5477d7c 100644 (file)
 import os
 
 from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.config import urls
+from webkitpy.tool.grammar import join_with_separators
 from webkitpy.tool.steps.abstractstep import AbstractStep
 
 
 class PrepareChangeLogForRevert(AbstractStep):
+    @classmethod
+    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 run(self, state):
         # This could move to prepare-ChangeLog by adding a --revert= option.
         self._run_script("prepare-ChangeLog")
         changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None)
         bug_url = self._tool.bugs.bug_url_for_bug_id(state["bug_id"]) if state["bug_id"] else None
+        message = self._message_for_revert(state["revision_list"], state["reason"], bug_url)
         for changelog_path in changelog_paths:
             # FIXME: Seems we should prepare the message outside of changelogs.py and then just pass in
             # text that we want to use to replace the reviewed by line.
-            ChangeLog(changelog_path).update_for_revert(state["revision_list"], state["reason"], bug_url)
+            ChangeLog(changelog_path).update_with_unreviewed_message(message)
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py
new file mode 100644 (file)
index 0000000..aa9d5e9
--- /dev/null
@@ -0,0 +1,130 @@
+# 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 __future__ import with_statement
+
+import codecs
+import os
+import tempfile
+import unittest
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.checkout.changelog_unittest import ChangeLogTest
+from webkitpy.tool.steps.preparechangelogforrevert import *
+
+
+class UpdateChangeLogsForRevertTest(unittest.TestCase):
+    @staticmethod
+    def _write_tmp_file_with_contents(byte_array):
+        assert(isinstance(byte_array, str))
+        (file_descriptor, file_path) = tempfile.mkstemp()  # NamedTemporaryFile always deletes the file on close in python < 2.6
+        with os.fdopen(file_descriptor, "w") as file:
+            file.write(byte_array)
+        return file_path
+
+    _revert_entry_with_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
+
+        Unreviewed, rolling out r12345.
+        http://trac.webkit.org/changeset/12345
+        http://example.com/123
+
+        Reason
+
+        * Scripts/bugzilla-tool:
+'''
+
+    _revert_entry_without_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
+
+        Unreviewed, rolling out r12345.
+        http://trac.webkit.org/changeset/12345
+
+        Reason
+
+        * Scripts/bugzilla-tool:
+'''
+
+    _multiple_revert_entry_with_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
+
+        Unreviewed, rolling out r12345, r12346, and r12347.
+        http://trac.webkit.org/changeset/12345
+        http://trac.webkit.org/changeset/12346
+        http://trac.webkit.org/changeset/12347
+        http://example.com/123
+
+        Reason
+
+        * Scripts/bugzilla-tool:
+'''
+
+    _multiple_revert_entry_without_bug_url = '''2009-08-19  Eric Seidel  <eric@webkit.org>
+
+        Unreviewed, rolling out r12345, r12346, and r12347.
+        http://trac.webkit.org/changeset/12345
+        http://trac.webkit.org/changeset/12346
+        http://trac.webkit.org/changeset/12347
+
+        Reason
+
+        * Scripts/bugzilla-tool:
+'''
+
+    _revert_with_log_reason = """2009-08-19  Eric Seidel  <eric@webkit.org>
+
+        Unreviewed, rolling out r12345.
+        http://trac.webkit.org/changeset/12345
+        http://example.com/123
+
+        This is a very long reason which should be long enough so that
+        _message_for_revert will need to wrap it.  We'll also include
+        a
+        https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354
+        link so that we can make sure we wrap that right too.
+
+        * Scripts/bugzilla-tool:
+"""
+
+    def _assert_message_for_revert_output(self, args, expected_entry):
+        changelog_contents = u"%s\n%s" % (ChangeLogTest._new_entry_boilerplate, ChangeLogTest._example_changelog)
+        changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
+        changelog = ChangeLog(changelog_path)
+        changelog.update_with_unreviewed_message(PrepareChangeLogForRevert._message_for_revert(*args))
+        actual_entry = changelog.latest_entry()
+        os.remove(changelog_path)
+        self.assertEquals(actual_entry.contents(), expected_entry)
+        self.assertEquals(actual_entry.reviewer_text(), None)
+        # These checks could be removed to allow this to work on other entries:
+        self.assertEquals(actual_entry.author_name(), "Eric Seidel")
+        self.assertEquals(actual_entry.author_email(), "eric@webkit.org")
+
+    def test_message_for_revert(self):
+        self._assert_message_for_revert_output([[12345], "Reason"], self._revert_entry_without_bug_url)
+        self._assert_message_for_revert_output([[12345], "Reason", "http://example.com/123"], self._revert_entry_with_bug_url)
+        self._assert_message_for_revert_output([[12345, 12346, 12347], "Reason"], self._multiple_revert_entry_without_bug_url)
+        self._assert_message_for_revert_output([[12345, 12346, 12347], "Reason", "http://example.com/123"], self._multiple_revert_entry_with_bug_url)
+        long_reason = "This is a very long reason which should be long enough so that _message_for_revert will need to wrap it.  We'll also include a https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354 link so that we can make sure we wrap that right too."
+        self._assert_message_for_revert_output([[12345], long_reason, "http://example.com/123"], self._revert_with_log_reason)
index 0c86535b68338376d79eb132ef7102dc0a3374ac..e99566326bf398c60a4646a9f2b1074537624cd5 100644 (file)
@@ -41,5 +41,6 @@ class SuggestReviewersTest(unittest.TestCase):
     def test_basic(self):
         capture = OutputCapture()
         step = SuggestReviewers(MockTool(), MockOptions(suggest_reviewers=True, git_commit=None))
-        expected_stdout = "The following reviewers have recently modified files in your patch:\nFoo Bar\nWould you like to CC them?\n"
-        capture.assert_outputs(self, step.run, [{"bug_id": "123"}], expected_stdout=expected_stdout)
+        expected_stdout = "The following reviewers have recently modified files in your patch:\nFoo Bar\n"
+        expected_stderr = "Would you like to CC them?\n"
+        capture.assert_outputs(self, step.run, [{"bug_id": "123"}], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py b/Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py
new file mode 100644 (file)
index 0000000..315bbac
--- /dev/null
@@ -0,0 +1,64 @@
+# 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 urllib2
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.config import urls
+from webkitpy.common.system.deprecated_logging import log, error
+
+
+class UpdateChromiumDEPS(AbstractStep):
+    # Notice that this method throws lots of exciting exceptions!
+    def _fetch_last_known_good_revision(self):
+        return int(urllib2.urlopen(urls.chromium_lkgr_url).read())
+
+    def _validate_revisions(self, current_chromium_revision, new_chromium_revision):
+        if new_chromium_revision < current_chromium_revision:
+            log("Current Chromium DEPS revision %s is newer than %s." % (current_chromium_revision, new_chromium_revision))
+            new_chromium_revision = self._tool.user.prompt("Enter new chromium revision (enter nothing to cancel):\n")
+            try:
+                new_chromium_revision = int(new_chromium_revision)
+            except ValueError, TypeError:
+                new_chromium_revision = None
+            if not new_chromium_revision:
+                error("Unable to update Chromium DEPS")
+
+
+    def run(self, state):
+        # Note that state["chromium_revision"] must be defined, but can be None.
+        new_chromium_revision = state["chromium_revision"]
+        if not new_chromium_revision:
+            new_chromium_revision = self._fetch_last_known_good_revision()
+
+        deps = self._tool.checkout().chromium_deps()
+        current_chromium_revision = deps.read_variable("chromium_rev")
+        self._validate_revisions(current_chromium_revision, new_chromium_revision)
+        log("Updating Chromium DEPS to %s" % new_chromium_revision)
+        deps.write_variable("chromium_rev", new_chromium_revision)
index db35a5857e61f8b45b3b5243886568322168f7ac..96bae9fa819fbed6dbbc7ae52bc6abaacf5a3ba1 100644 (file)
@@ -45,9 +45,8 @@ class ValidateChangeLogsTest(unittest.TestCase):
         diff_file.lines = [(start_line, start_line, "foo")]
         expected_stdout = expected_stderr = ""
         if should_fail and not non_interactive:
-            expected_stdout = "OK to continue?\n"
-            expected_stderr = "The diff to mock/ChangeLog looks wrong.  Are you sure your ChangeLog entry is at the top of the file?\n"
-        result = OutputCapture().assert_outputs(self, step._check_changelog_diff, [diff_file], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+            expected_stderr = "The diff to mock/ChangeLog looks wrong.  Are you sure your ChangeLog entry is at the top of the file?\nOK to continue?\n"
+        result = OutputCapture().assert_outputs(self, step._check_changelog_diff, [diff_file], expected_stderr=expected_stderr)
         self.assertEqual(not result, should_fail)
 
     def test_check_changelog_diff(self):