| # 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 codecs |
| import os |
| import shutil |
| import tempfile |
| import unittest |
| |
| from .checkout import Checkout |
| from .changelog import ChangeLogEntry |
| from .scm import CommitMessage, SCMDetector |
| from .scm.scm_mock import MockSCM |
| from webkitpy.common.webkit_finder import WebKitFinder |
| from webkitpy.common.system.executive import Executive, ScriptError |
| from webkitpy.common.system.filesystem import FileSystem # FIXME: This should not be needed. |
| from webkitpy.common.system.filesystem_mock import MockFileSystem |
| from webkitpy.common.system.executive_mock import MockExecutive |
| from webkitpy.common.system.outputcapture import OutputCapture |
| from webkitpy.thirdparty.mock import Mock |
| |
| |
| _changelog1entry1 = u"""2010-03-25 Fr\u00e9d\u00e9ric Wang <fred.wang@free.fr> |
| |
| Unreviewed build fix to un-break webkit-patch land. |
| |
| Move commit_message_for_this_commit from scm to checkout |
| https://bugs.webkit.org/show_bug.cgi?id=36629 |
| |
| * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage |
| """ |
| _changelog1entry2 = u"""2010-03-25 Adam Barth <abarth@webkit.org> |
| |
| Reviewed by Eric Seidel. |
| |
| Move commit_message_for_this_commit from scm to checkout |
| https://bugs.webkit.org/show_bug.cgi?id=36629 |
| |
| * Scripts/webkitpy/common/checkout/api.py: |
| """ |
| _changelog1 = u"\n".join([_changelog1entry1, _changelog1entry2]) |
| _changelog2 = u"""2010-03-25 Fr\u00e9d\u00e9ric Wang <fred.wang@free.fr> |
| |
| Unreviewed build fix to un-break webkit-patch land. |
| |
| Second part of this complicated change by me, Fr\u00e9d\u00e9ric Wang! |
| |
| * Path/To/Complicated/File: Added. |
| |
| 2010-03-25 Adam Barth <abarth@webkit.org> |
| |
| Reviewed by Eric Seidel. |
| |
| Filler change. |
| """ |
| |
| _changelog3 = u"""2014-07-17 David Kilzer <ddkilzer@apple.com> |
| |
| SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig |
| <http://webkit.org/b/135006> |
| |
| Reviewed by Darin Adler. |
| |
| * WebKit.xcodeproj/project.pbxproj: Remove references to unused |
| WebKit.xcconfig file. |
| """ |
| |
| _changelog4 = u"""2014-07-17 David Kilzer <ddkilzer@apple.com> |
| |
| SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig |
| <http://webkit.org/b/135006> |
| |
| Reviewed by Darin Adler. |
| |
| * Path/To/Complicated/File: Added. |
| """ |
| |
| _changelog5 = u"""2014-07-17 David Kilzer <ddkilzer@apple.com> |
| |
| SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig |
| <http://webkit.org/b/135006> |
| |
| Reviewed by Darin Adler. |
| |
| Filler change. |
| |
| * Path/To/Complicated/File: Added. |
| """ |
| |
| _changelog6 = u"""2014-06-23 Daniel Bates <dabates@apple.com> |
| |
| Rolling out r170340 and r170339. |
| |
| Changeset r170339 broke the Apple Windows Debug and Release builds. |
| |
| Reverted changesets: |
| |
| "[Win] Build fix after r134209" |
| https://trac.webkit.org/changeset/170340 |
| |
| "[Win] Clean up and refactor WinLauncher" |
| https://bugs.webkit.org/show_bug.cgi?id=134209 |
| https://trac.webkit.org/changeset/170339 |
| """ |
| |
| |
| class CommitMessageForThisCommitTest(unittest.TestCase): |
| def setUp(self): |
| # FIXME: This should not need to touch the filesystem, however |
| # ChangeLog is difficult to mock at current. |
| self.filesystem = FileSystem() |
| self.temp_dir = str(self.filesystem.mkdtemp(suffix="changelogs")) |
| self.old_cwd = self.filesystem.getcwd() |
| self.filesystem.chdir(self.temp_dir) |
| self.webkit_base = WebKitFinder(self.filesystem).webkit_base() |
| |
| # Trick commit-log-editor into thinking we're in a Subversion working copy so it won't |
| # complain about not being able to figure out what SCM is in use. |
| # FIXME: VCSTools.pm is no longer so easily fooled. It logs because "svn info" doesn't |
| # treat a bare .svn directory being part of an svn checkout. |
| self.filesystem.maybe_make_directory(".svn") |
| |
| def mock_changelog(self, changelogs): |
| for path, contents in zip(self.changelog_paths, changelogs): |
| self.filesystem.maybe_make_directory(self.filesystem.dirname(path)) |
| self.filesystem.write_text_file(path, contents) |
| |
| def tearDown(self): |
| self.filesystem.rmtree(self.temp_dir) |
| self.filesystem.chdir(self.old_cwd) |
| |
| def mock_checkout_for_test(self): |
| executive = Executive() |
| |
| def mock_run(*args, **kwargs): |
| # Note that we use a real Executive here, not a MockExecutive, so we can test that we're |
| # invoking commit-log-editor correctly. |
| env = os.environ.copy() |
| env['CHANGE_LOG_EMAIL_ADDRESS'] = 'fred.wang@free.fr' |
| kwargs['env'] = env |
| return executive.run_command(*args, **kwargs) |
| |
| detector = SCMDetector(self.filesystem, executive) |
| real_scm = detector.detect_scm_system(self.webkit_base) |
| |
| mock_scm = MockSCM() |
| mock_scm.run = mock_run |
| |
| real_checkout = Checkout(real_scm) |
| checkout = Checkout(mock_scm) |
| checkout.script_path = real_checkout.script_path |
| checkout.modified_changelogs = lambda git_commit, changed_files=None: self.changelog_paths |
| |
| return checkout |
| |
| def test_commit_message_for_unreviewed_changelogs_with_different_messages(self): |
| expected_commit_message = u"""Unreviewed build fix to un-break webkit-patch land. |
| |
| Tools: |
| |
| Move commit_message_for_this_commit from scm to checkout |
| https://bugs.webkit.org/show_bug.cgi?id=36629 |
| |
| * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage |
| |
| LayoutTests: |
| |
| Second part of this complicated change by me, Fr\u00e9d\u00e9ric Wang! |
| |
| * Path/To/Complicated/File: Added. |
| """ |
| |
| self.changelog_paths = map(self.filesystem.abspath, (self.filesystem.join("Tools", "ChangeLog"), self.filesystem.join("LayoutTests", "ChangeLog"))) |
| |
| self.mock_changelog((_changelog1, _changelog2)) |
| checkout = self.mock_checkout_for_test() |
| commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) |
| # Throw away the first line - a warning about unknown VCS root. |
| commit_message.message_lines = commit_message.message_lines[1:] |
| self.assertMultiLineEqual(commit_message.message(), expected_commit_message) |
| |
| def test_commit_message_for_one_reviewed_changelog(self): |
| expected_commit_message = u"""SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig |
| <http://webkit.org/b/135006> |
| |
| Patch by David Kilzer <ddkilzer@apple.com> on 2014-07-17 |
| Reviewed by Darin Adler. |
| |
| * WebKit.xcodeproj/project.pbxproj: Remove references to unused |
| WebKit.xcconfig file. |
| """ |
| |
| self.changelog_paths = map(self.filesystem.abspath, [self.filesystem.join("Source/WebKitLegacy", "ChangeLog")]) |
| |
| self.mock_changelog([_changelog3]) |
| checkout = self.mock_checkout_for_test() |
| commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) |
| # Throw away the first line - a warning about unknown VCS root. |
| commit_message.message_lines = commit_message.message_lines[1:] |
| self.assertMultiLineEqual(commit_message.message(), expected_commit_message) |
| |
| def test_commit_message_for_changelogs_with_same_messages(self): |
| expected_commit_message = u"""SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig |
| <http://webkit.org/b/135006> |
| |
| Patch by David Kilzer <ddkilzer@apple.com> on 2014-07-17 |
| Reviewed by Darin Adler. |
| |
| Source/WebKitLegacy: |
| |
| * WebKit.xcodeproj/project.pbxproj: Remove references to unused |
| WebKit.xcconfig file. |
| |
| LayoutTests: |
| |
| * Path/To/Complicated/File: Added. |
| """ |
| |
| self.changelog_paths = map(self.filesystem.abspath, (self.filesystem.join("Source/WebKitLegacy", "ChangeLog"), self.filesystem.join("LayoutTests", "ChangeLog"))) |
| |
| self.mock_changelog((_changelog3, _changelog4)) |
| checkout = self.mock_checkout_for_test() |
| commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) |
| # Throw away the first line - a warning about unknown VCS root. |
| commit_message.message_lines = commit_message.message_lines[1:] |
| self.assertMultiLineEqual(commit_message.message(), expected_commit_message) |
| |
| def test_commit_message_for_changelogs_with_different_messages(self): |
| expected_commit_message = u"""SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig |
| <http://webkit.org/b/135006> |
| |
| Patch by David Kilzer <ddkilzer@apple.com> on 2014-07-17 |
| Reviewed by Darin Adler. |
| |
| Source/WebKitLegacy: |
| |
| * WebKit.xcodeproj/project.pbxproj: Remove references to unused |
| WebKit.xcconfig file. |
| |
| LayoutTests: |
| |
| Filler change. |
| |
| * Path/To/Complicated/File: Added. |
| """ |
| |
| self.changelog_paths = map(self.filesystem.abspath, (self.filesystem.join("Source/WebKitLegacy", "ChangeLog"), self.filesystem.join("LayoutTests", "ChangeLog"))) |
| |
| self.mock_changelog((_changelog3, _changelog5)) |
| checkout = self.mock_checkout_for_test() |
| commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) |
| # Throw away the first line - a warning about unknown VCS root. |
| commit_message.message_lines = commit_message.message_lines[1:] |
| self.assertMultiLineEqual(commit_message.message(), expected_commit_message) |
| |
| def test_commit_message_for_one_rollout_changelog(self): |
| expected_commit_message = u"""Rolling out r170340 and r170339. |
| |
| Changeset r170339 broke the Apple Windows Debug and Release builds. |
| |
| Reverted changesets: |
| |
| "[Win] Build fix after r134209" |
| https://trac.webkit.org/changeset/170340 |
| |
| "[Win] Clean up and refactor WinLauncher" |
| https://bugs.webkit.org/show_bug.cgi?id=134209 |
| https://trac.webkit.org/changeset/170339 |
| |
| Patch by Daniel Bates <dabates@apple.com> on 2014-06-23 |
| """ |
| |
| self.changelog_paths = map(self.filesystem.abspath, [self.filesystem.join("Tools", "ChangeLog")]) |
| |
| self.mock_changelog([_changelog6]) |
| checkout = self.mock_checkout_for_test() |
| commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) |
| # Throw away the first line - a warning about unknown VCS root. |
| commit_message.message_lines = commit_message.message_lines[1:] |
| self.assertMultiLineEqual(commit_message.message(), expected_commit_message) |
| |
| def test_commit_message_for_rollout_changelogs_with_different_directories(self): |
| expected_commit_message = u"""Rolling out r170340 and r170339. |
| |
| Changeset r170339 broke the Apple Windows Debug and Release builds. |
| |
| Reverted changesets: |
| |
| "[Win] Build fix after r134209" |
| https://trac.webkit.org/changeset/170340 |
| |
| "[Win] Clean up and refactor WinLauncher" |
| https://bugs.webkit.org/show_bug.cgi?id=134209 |
| https://trac.webkit.org/changeset/170339 |
| |
| Patch by Daniel Bates <dabates@apple.com> on 2014-06-23 |
| """ |
| |
| self.changelog_paths = map(self.filesystem.abspath, (self.filesystem.join("Tools", "ChangeLog"), self.filesystem.join("Source/WebCore", "ChangeLog"))) |
| |
| self.mock_changelog((_changelog6, _changelog6)) |
| checkout = self.mock_checkout_for_test() |
| commit_message = checkout.commit_message_for_this_commit(git_commit=None, return_stderr=True) |
| # Throw away the first line - a warning about unknown VCS root. |
| commit_message.message_lines = commit_message.message_lines[1:] |
| self.assertMultiLineEqual(commit_message.message(), expected_commit_message) |
| |
| |
| class CheckoutTest(unittest.TestCase): |
| def _make_checkout(self): |
| return Checkout(scm=MockSCM(), filesystem=MockFileSystem(), executive=MockExecutive()) |
| |
| def test_latest_entry_for_changelog_at_revision(self): |
| def mock_contents_at_revision(changelog_path, revision): |
| self.assertEqual(changelog_path, "foo") |
| self.assertEqual(revision, "bar") |
| # contents_at_revision is expected to return a byte array (str) |
| # so we encode our unicode ChangeLog down to a utf-8 stream. |
| # The ChangeLog utf-8 decoding should ignore invalid codepoints. |
| invalid_utf8 = "\255" |
| return _changelog1.encode("utf-8") + invalid_utf8 |
| checkout = self._make_checkout() |
| checkout._scm.contents_at_revision = mock_contents_at_revision |
| entry = checkout._latest_entry_for_changelog_at_revision("foo", "bar") |
| self.assertMultiLineEqual(entry.contents(), _changelog1entry1) # Pylint is confused about this line, pylint: disable=E1101 |
| |
| # FIXME: This tests a hack around our current changed_files handling. |
| # Right now changelog_entries_for_revision tries to fetch deleted files |
| # from revisions, resulting in a ScriptError exception. Test that we |
| # recover from those and still return the other ChangeLog entries. |
| def test_changelog_entries_for_revision(self): |
| checkout = self._make_checkout() |
| checkout._scm.changed_files_for_revision = lambda revision: ['foo/ChangeLog', 'bar/ChangeLog'] |
| |
| def mock_latest_entry_for_changelog_at_revision(path, revision): |
| if path == "foo/ChangeLog": |
| return 'foo' |
| raise ScriptError() |
| |
| checkout._latest_entry_for_changelog_at_revision = mock_latest_entry_for_changelog_at_revision |
| |
| # Even though fetching one of the entries failed, the other should succeed. |
| entries = checkout.changelog_entries_for_revision(1) |
| self.assertEqual(len(entries), 1) |
| self.assertEqual(entries[0], 'foo') |
| |
| def test_commit_info_for_revision(self): |
| checkout = self._make_checkout() |
| checkout._scm.changed_files_for_revision = lambda revision: ['path/to/file', 'another/file'] |
| checkout._scm.committer_email_for_revision = lambda revision, changed_files=None: "committer@example.com" |
| checkout.changelog_entries_for_revision = lambda revision, changed_files=None: [ChangeLogEntry(_changelog1entry1)] |
| commitinfo = checkout.commit_info_for_revision(4) |
| self.assertEqual(commitinfo.bug_id(), 36629) |
| self.assertEqual(commitinfo.bug_description(), "Unreviewed build fix to un-break webkit-patch land.") |
| self.assertEqual(commitinfo.author_name(), u"Fr\u00e9d\u00e9ric Wang") |
| self.assertEqual(commitinfo.author_email(), "fred.wang@free.fr") |
| self.assertIsNone(commitinfo.reviewer_text()) |
| self.assertIsNone(commitinfo.reviewer()) |
| self.assertEqual(commitinfo.committer_email(), "committer@example.com") |
| self.assertIsNone(commitinfo.committer()) |
| self.assertEqual(commitinfo.to_json(), { |
| 'bug_id': 36629, |
| 'author_email': 'fred.wang@free.fr', |
| 'changed_files': [ |
| 'path/to/file', |
| 'another/file', |
| ], |
| 'reviewer_text': None, |
| 'author_name': u'Fr\u00e9d\u00e9ric Wang', |
| 'bug_description': 'Unreviewed build fix to un-break webkit-patch land.', |
| }) |
| |
| checkout.changelog_entries_for_revision = lambda revision, changed_files=None: [] |
| self.assertIsNone(checkout.commit_info_for_revision(1)) |
| |
| def test_bug_id_for_revision(self): |
| checkout = self._make_checkout() |
| checkout._scm.committer_email_for_revision = lambda revision: "committer@example.com" |
| checkout.changelog_entries_for_revision = lambda revision, changed_files=None: [ChangeLogEntry(_changelog1entry1)] |
| self.assertEqual(checkout.bug_id_for_revision(4), 36629) |
| |
| def test_bug_id_for_this_commit(self): |
| checkout = self._make_checkout() |
| checkout.commit_message_for_this_commit = lambda git_commit, changed_files=None, return_stderr=False: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines()) |
| self.assertEqual(checkout.bug_id_for_this_commit(git_commit=None), 36629) |
| |
| def test_modified_changelogs(self): |
| checkout = self._make_checkout() |
| checkout._scm.checkout_root = "/foo/bar" |
| checkout._scm.changed_files = lambda git_commit: ["file1", "ChangeLog", "relative/path/ChangeLog"] |
| expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"] |
| self.assertEqual(checkout.modified_changelogs(git_commit=None), expected_changlogs) |
| |
| def test_suggested_reviewers(self): |
| def mock_changelog_entries_for_revision(revision, changed_files=None): |
| if revision == 27: |
| return [] |
| if revision % 2 == 0: |
| return [ChangeLogEntry(_changelog1entry1)] |
| return [ChangeLogEntry(_changelog1entry2)] |
| |
| def mock_revisions_changing_file(path, limit=5): |
| if path.endswith('ChangeLog'): |
| return [3] |
| if path.endswith('file_with_empty_changelog'): |
| return [27] |
| return [4, 8] |
| |
| checkout = self._make_checkout() |
| checkout._scm.checkout_root = '/foo/bar' |
| checkout._scm.changed_files = lambda git_commit: ['file1', 'file2', 'relative/path/ChangeLog', 'file_with_empty_changelog'] |
| checkout._scm.revisions_changing_file = mock_revisions_changing_file |
| checkout.changelog_entries_for_revision = mock_changelog_entries_for_revision |
| reviewers = checkout.suggested_reviewers(git_commit=None) |
| reviewer_names = [reviewer.full_name for reviewer in reviewers] |
| self.assertEqual(reviewer_names, [u'Fr\u00e9d\u00e9ric Wang']) |
| |
| def test_apply_patch(self): |
| checkout = self._make_checkout() |
| checkout._executive = MockExecutive(should_log=True) |
| checkout.script_path = lambda script: script |
| mock_patch = Mock() |
| mock_patch.contents = lambda: "foo" |
| mock_patch.reviewer = lambda: None |
| expected_logs = "MOCK run_command: ['svn-apply', '--force'], cwd=/mock-checkout, input=foo\n" |
| OutputCapture().assert_outputs(self, checkout.apply_patch, [mock_patch], expected_logs=expected_logs) |