Adding "has-landed" command to webkit-patch which compares a

committed patch to the changes which exist locally (ignoring the
ChangeLog file).

https://bugs.webkit.org/show_bug.cgi?id=106402

Patch by Tim 'mithro' Ansell <mithro@mithis.com> on 2013-01-24
Reviewed by Eric Seidel.

* Scripts/webkitpy/common/checkout/diff_parser.py:
(git_diff_to_svn_diff):
* Scripts/webkitpy/common/net/bugzilla/bug.py:
(Bug.commit_revision):
* Scripts/webkitpy/common/net/bugzilla/bug_unittest.py:
(BugTest.test_is_in_comments):
(BugTest):
(BugTest.test_commit_revision):
* Scripts/webkitpy/tool/commands/upload.py:
(HasLanded):
* Scripts/webkitpy/tool/steps/__init__.py:
* Scripts/webkitpy/tool/steps/haslanded.py: Added.
(HasLanded):
(HasLanded.convert_to_svn):
(HasLanded.strip_change_log):
(run):

* Scripts/webkitpy/common/net/bugzilla/bug.py:
(Bug.commit_revision):
* Scripts/webkitpy/common/net/bugzilla/bug_unittest.py:
(BugTest.test_is_in_comments):
(BugTest):
(BugTest.test_commit_revision):
* Scripts/webkitpy/tool/commands/upload.py:
(HasLanded):
* Scripts/webkitpy/tool/steps/__init__.py:
* Scripts/webkitpy/tool/steps/haslanded.py: Added.
(HasLanded):
(HasLanded.convert_to_svn):
(HasLanded.strip_change_log):
(HasLanded.diff_diff):
(HasLanded.run):
* Scripts/webkitpy/tool/steps/haslanded_unittest.py: Added.
(HasLandedTest):
(HasLandedTest.test_run):
(test_convert_to_svn_and_strip_change_log):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@140674 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a129f181
2013-01-24 Tim 'mithro' Ansell <mithro@mithis.com>
Adding "has-landed" command to webkit-patch which compares a
committed patch to the changes which exist locally (ignoring the
ChangeLog file).
https://bugs.webkit.org/show_bug.cgi?id=106402
Reviewed by Eric Seidel.
* Scripts/webkitpy/common/checkout/diff_parser.py:
(git_diff_to_svn_diff):
* Scripts/webkitpy/common/net/bugzilla/bug.py:
(Bug.commit_revision):
* Scripts/webkitpy/common/net/bugzilla/bug_unittest.py:
(BugTest.test_is_in_comments):
(BugTest):
(BugTest.test_commit_revision):
* Scripts/webkitpy/tool/commands/upload.py:
(HasLanded):
* Scripts/webkitpy/tool/steps/__init__.py:
* Scripts/webkitpy/tool/steps/haslanded.py: Added.
(HasLanded):
(HasLanded.convert_to_svn):
(HasLanded.strip_change_log):
(run):
* Scripts/webkitpy/common/net/bugzilla/bug.py:
(Bug.commit_revision):
* Scripts/webkitpy/common/net/bugzilla/bug_unittest.py:
(BugTest.test_is_in_comments):
(BugTest):
(BugTest.test_commit_revision):
* Scripts/webkitpy/tool/commands/upload.py:
(HasLanded):
* Scripts/webkitpy/tool/steps/__init__.py:
* Scripts/webkitpy/tool/steps/haslanded.py: Added.
(HasLanded):
(HasLanded.convert_to_svn):
(HasLanded.strip_change_log):
(HasLanded.diff_diff):
(HasLanded.run):
* Scripts/webkitpy/tool/steps/haslanded_unittest.py: Added.
(HasLandedTest):
(HasLandedTest.test_run):
(test_convert_to_svn_and_strip_change_log):
2013-01-24 Dan Carney <dcarney@google.com>
[chromium] move most WebViewHost printf calls to WebTestProxy
......
......@@ -28,6 +28,8 @@
# (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 re
from .attachment import Attachment
......@@ -123,3 +125,12 @@ class Bug(object):
return True
return False
def commit_revision(self):
# Sort the comments in reverse order as we want the latest committed revision.
r = re.compile("Committed r(?P<svn_revision>\d+)")
for comment in sorted(self.comments(), reverse=True):
rev = r.search(comment['text'])
if rev:
return int(rev.group('svn_revision'))
return None
......@@ -45,3 +45,39 @@ class BugTest(unittest.TestCase):
bugzilla=None)
self.assertTrue(bug.is_in_comments("Message3."))
self.assertFalse(bug.is_in_comments("Message."))
def test_commit_revision(self):
bug = Bug({"comments": []}, bugzilla=None)
self.assertEqual(bug.commit_revision(), None)
bug = Bug({"comments": [
{"text": "Comment 1"},
{"text": "Comment 2"},
]}, bugzilla=None)
self.assertEqual(bug.commit_revision(), None)
bug = Bug({"comments": [
{"text": "Committed r138776: <http://trac.webkit.org/changeset/138776>"},
]}, bugzilla=None)
self.assertEqual(bug.commit_revision(), 138776)
bug = Bug({"comments": [
{"text": "(From update of attachment 181269) Clearing flags on attachment: 181269 Committed r138776: <http://trac.webkit.org/changeset/138776>"},
]}, bugzilla=None)
self.assertEqual(bug.commit_revision(), 138776)
bug = Bug({"comments": [
{"text": "Comment before"},
{"text": "(From update of attachment 181269) Clearing flags on attachment: 181269 Committed r138776: <http://trac.webkit.org/changeset/138776>"},
{"text": "Comment after"},
]}, bugzilla=None)
self.assertEqual(bug.commit_revision(), 138776)
bug = Bug({"comments": [
{"text": "Comment before"},
{"text": "(From update of attachment 181269) Clearing flags on attachment: 181269 Committed r138776: <http://trac.webkit.org/changeset/138776>"},
{"text": "Comment Middle"},
{"text": "(From update of attachment 181280) Clearing flags on attachment: 181280 Committed r138976: <http://trac.webkit.org/changeset/138976>"},
{"text": "Comment After"},
]}, bugzilla=None)
self.assertEqual(bug.commit_revision(), 138976)
......@@ -241,6 +241,15 @@ class LandSafely(AbstractPatchUploadingCommand):
]
class HasLanded(AbstractPatchUploadingCommand):
name = "has-landed"
help_text = "Check that the current code was successfully landed and no changes remain."
argument_names = "[BUGID]"
steps = [
steps.HasLanded,
]
class Prepare(AbstractSequencedCommand):
name = "prepare"
help_text = "Creates a bug (or prompts for an existing bug) and prepares the ChangeLogs"
......
......@@ -45,6 +45,7 @@ from webkitpy.tool.steps.discardlocalchanges import DiscardLocalChanges
from webkitpy.tool.steps.editchangelog import EditChangeLog
from webkitpy.tool.steps.ensurebugisopenandassigned import EnsureBugIsOpenAndAssigned
from webkitpy.tool.steps.ensurelocalcommitifneeded import EnsureLocalCommitIfNeeded
from webkitpy.tool.steps.haslanded import HasLanded
from webkitpy.tool.steps.obsoletepatches import ObsoletePatches
from webkitpy.tool.steps.options import Options
from webkitpy.tool.steps.postdiff import PostDiff
......
# Copyright (C) 2010 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 cStringIO as StringIO
import logging
import sys
import re
import tempfile
from webkitpy.tool.steps.abstractstep import AbstractStep
from webkitpy.common.system.executive import Executive, ScriptError
from webkitpy.common.checkout import diff_parser
from webkitpy.tool.steps import confirmdiff
_log = logging.getLogger(__name__)
class HasLanded(confirmdiff.ConfirmDiff):
@classmethod
def convert_to_svn(cls, diff):
lines = StringIO.StringIO(diff).readlines()
convert = diff_parser.get_diff_converter(lines[0])
return "".join(convert(x) for x in lines)
@classmethod
def strip_change_log(cls, diff):
output = []
skipping = False
for line in StringIO.StringIO(diff).readlines():
indexline = re.match("^Index: ([^\\n]*/)?([^/\\n]*)$", line)
if skipping and indexline:
skipping = False
if indexline and indexline.group(2) == "ChangeLog":
skipping = True
if not skipping:
output.append(line)
return "".join(output)
@classmethod
def diff_diff(cls, diff1, diff2, diff1_suffix, diff2_suffix, executive=None):
# Now this is where it gets complicated, we need to compare our diff to the diff at landed_revision.
diff1_patch = tempfile.NamedTemporaryFile(suffix=diff1_suffix + '.patch')
diff1_patch.write(diff1)
diff1_patch.flush()
# Check if there are any differences in the patch that don't happen
diff2_patch = tempfile.NamedTemporaryFile(suffix=diff2_suffix + '.patch')
diff2_patch.write(diff2)
diff2_patch.flush()
# Diff the two diff's together...
if not executive:
executive = Executive()
try:
return executive.run_command(
["interdiff", diff1_patch.name, diff2_patch.name], decode_output=False)
except ScriptError, e:
_log.warning("Unable to find interdiff util (part of GNU difftools package) which is required.")
raise
def run(self, state):
# Check if there are changes first
if not self._tool.scm().local_changes_exist():
_log.warn("No local changes found, exiting.")
return True
# Check if there is a SVN revision in the bug from the commit queue
landed_revision = self.cached_lookup(state, "bug").commit_revision()
if not landed_revision:
raise ScriptError("Unable to find landed message in associated bug.")
# Now this is there it gets complicated, we need to compare our diff to the diff at landed_revision.
landed_diff_bin = self._tool.scm().diff_for_revision(landed_revision)
landed_diff_trimmed = self.strip_change_log(self.convert_to_svn(landed_diff_bin))
# Check if there are any differences in the patch that don't happen
local_diff_bin = self._tool.scm().create_patch()
local_diff_trimmed = self.strip_change_log(self.convert_to_svn(local_diff_bin))
# Diff the two diff's together...
diff_diff = self.diff_diff(landed_diff_trimmed, local_diff_trimmed,
'-landed', '-local',
executive=self._tool.executive)
with self._show_pretty_diff(diff_diff) as pretty_diff_file:
if not pretty_diff_file:
self._tool.user.page(diff_diff)
if self._tool.user.confirm("May I discard local changes?"):
# Discard changes if the user confirmed we should
_log.warn("Discarding changes as requested.")
self._tool.scm().discard_local_changes()
# Copyright (C) 2009 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 unittest2 as unittest
from webkitpy.tool.steps.haslanded import HasLanded
class HasLandedTest(unittest.TestCase):
maxDiff = None
def test_run(self):
# These patches require trailing whitespace to remain valid patches.
diff1 = """\
Index: a.py
===================================================================
--- a.py
+++ a.py
@@ -1,3 +1,5 @@
A
B
C
+D
+E
Index: b.py
===================================================================
--- b.py 2013-01-21 15:20:59.693887185 +1100
+++ b.py 2013-01-21 15:22:24.382555711 +1100
@@ -1,3 +1,5 @@
1
2
3
+4
+5
"""
diff1_add_line = """\
Index: a.py
===================================================================
--- a.py
+++ a.py
@@ -1,3 +1,6 @@
A
B
C
+D
+E
+F
Index: b.py
===================================================================
--- b.py
+++ b.py
@@ -1,3 +1,5 @@
1
2
3
+4
+5
"""
diff1_remove_line = """\
Index: a.py
===================================================================
--- a.py
+++ a.py
@@ -1,3 +1,4 @@
A
B
C
+D
Index: b.py
===================================================================
--- b.py
+++ b.py
@@ -1,3 +1,5 @@
1
2
3
+4
+5
"""
diff1_add_file = diff1 + """\
Index: c.py
===================================================================
--- c.py
+++ c.py
@@ -1,3 +1,5 @@
1
2
3
+4
+5
"""
diff1_remove_file = """\
Index: a.py
===================================================================
--- a.py
+++ a.py
@@ -1,3 +1,5 @@
A
B
C
+D
+E
"""
self.assertMultiLineEqual(
HasLanded.diff_diff(diff1, diff1_add_line, '', 'add-line'),
"""\
diff -u a.py a.py
--- a.py
+++ a.py
@@ -5,0 +6 @@
+F
""")
self.assertMultiLineEqual(
HasLanded.diff_diff(diff1, diff1_remove_line, '', 'remove-line'),
"""\
diff -u a.py a.py
--- a.py
+++ a.py
@@ -5 +4,0 @@
-E
""")
self.assertMultiLineEqual(
HasLanded.diff_diff(diff1, diff1_add_file, '', 'add-file'),
"""\
only in patch2:
unchanged:
--- c.py
+++ c.py
@@ -1,3 +1,5 @@
1
2
3
+4
+5
""")
self.assertMultiLineEqual(
HasLanded.diff_diff(diff1, diff1_remove_file, '', 'remove-file'),
"""\
reverted:
--- b.py 2013-01-21 15:22:24.382555711 +1100
+++ b.py 2013-01-21 15:20:59.693887185 +1100
@@ -1,5 +1,3 @@
1
2
3
-4
-5
""")
def test_convert_to_svn_and_strip_change_log(self):
# These patches require trailing whitespace to remain valid patches.
testbefore1 = HasLanded.convert_to_svn("""\
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 219ba72..0390b73 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,32 @@
+2013-01-17 Tim 'mithro' Ansell <mithro@mithis.com>
+
+ Adding "has-landed" command to webkit-patch which allows a person to
+ Reviewed by NOBODY (OOPS!).
+
2013-01-20 Tim 'mithro' Ansell <mithro@mithis.com>
Extend diff_parser to support the --full-index output.
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
index 4bf8ec6..3a128cb 100644
--- a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
""")
testafter1 = HasLanded.convert_to_svn("""\
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
index 4bf8ec6..3a128cb 100644
--- a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 219ba72..0390b73 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,32 @@
+2013-01-17 Tim 'mithro' Ansell <mithro@mithis.com>
+
+ Adding "has-landed" command to webkit-patch which allows a person to
+ Reviewed by NOBODY (OOPS!).
+
2013-01-20 Tim 'mithro' Ansell <mithro@mithis.com>
Extend diff_parser to support the --full-index output.
""")
testexpected1 = """\
Index: Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
===================================================================
--- Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
+++ Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
"""
testmiddle1 = HasLanded.convert_to_svn("""\
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
index 4bf8ec6..3a128cb 100644
--- a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
diff --git a/ChangeLog b/ChangeLog
index 219ba72..0390b73 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2013-01-17 Tim 'mithro' Ansell <mithro@mithis.com>
+
+ Adding "has-landed" command to webkit-patch which allows a person to
+ Reviewed by NOBODY (OOPS!).
+
2013-01-20 Tim 'mithro' Ansell <mithro@mithis.com>
Extend diff_parser to support the --full-index output.
diff --git a/Tools/Scripts/webkitpy/common/other.py b/Tools/Scripts/webkitpy/common/other.py
index 4bf8ec6..3a128cb 100644
--- a/Tools/Scripts/webkitpy/common/other.py
+++ b/Tools/Scripts/webkitpy/common/other.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
""")
testexpected2 = """\
Index: Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
===================================================================
--- Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
+++ Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
Index: Tools/Scripts/webkitpy/common/other.py
===================================================================
--- Tools/Scripts/webkitpy/common/other.py
+++ Tools/Scripts/webkitpy/common/other.py
@@ -28,6 +28,8 @@
+import re
+
from .attachment import Attachment
"""
self.assertMultiLineEqual(testexpected1, HasLanded.strip_change_log(testbefore1))
self.assertMultiLineEqual(testexpected1, HasLanded.strip_change_log(testafter1))
self.assertMultiLineEqual(testexpected2, HasLanded.strip_change_log(testmiddle1))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment