diff options
author | Steve Block <steveblock@google.com> | 2010-04-27 16:31:00 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-05-11 14:42:12 +0100 |
commit | dcc8cf2e65d1aa555cce12431a16547e66b469ee (patch) | |
tree | 92a8d65cd5383bca9749f5327fb5e440563926e6 /WebKitTools/Scripts/webkitpy/commands | |
parent | ccac38a6b48843126402088a309597e682f40fe6 (diff) | |
download | external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2 |
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/commands')
16 files changed, 0 insertions, 1999 deletions
diff --git a/WebKitTools/Scripts/webkitpy/commands/__init__.py b/WebKitTools/Scripts/webkitpy/commands/__init__.py deleted file mode 100644 index ef65bee..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Required for Python to search this directory for module files diff --git a/WebKitTools/Scripts/webkitpy/commands/abstractsequencedcommand.py b/WebKitTools/Scripts/webkitpy/commands/abstractsequencedcommand.py deleted file mode 100644 index 53af5b1..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/abstractsequencedcommand.py +++ /dev/null @@ -1,43 +0,0 @@ -# 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. - -from webkitpy.multicommandtool import AbstractDeclarativeCommand -from webkitpy.stepsequence import StepSequence - - -class AbstractSequencedCommand(AbstractDeclarativeCommand): - steps = None - def __init__(self): - self._sequence = StepSequence(self.steps) - AbstractDeclarativeCommand.__init__(self, self._sequence.options()) - - def _prepare_state(self, options, args, tool): - return None - - def execute(self, options, args, tool): - self._sequence.run_and_handle_errors(tool, options, self._prepare_state(options, args, tool)) diff --git a/WebKitTools/Scripts/webkitpy/commands/commandtest.py b/WebKitTools/Scripts/webkitpy/commands/commandtest.py deleted file mode 100644 index a56cb05..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/commandtest.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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 unittest - -from webkitpy.mock import Mock -from webkitpy.mock_bugzillatool import MockBugzillaTool -from webkitpy.outputcapture import OutputCapture - -class CommandsTest(unittest.TestCase): - def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", options=Mock(), tool=MockBugzillaTool()): - command.bind_to_tool(tool) - OutputCapture().assert_outputs(self, command.execute, [options, args, tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr) diff --git a/WebKitTools/Scripts/webkitpy/commands/download.py b/WebKitTools/Scripts/webkitpy/commands/download.py deleted file mode 100644 index 49a6862..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/download.py +++ /dev/null @@ -1,284 +0,0 @@ -# Copyright (c) 2009, Google Inc. All rights reserved. -# Copyright (c) 2009 Apple 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 optparse import make_option - -import webkitpy.steps as steps - -from webkitpy.bugzilla import parse_bug_id -# We could instead use from modules import buildsteps and then prefix every buildstep with "buildsteps." -from webkitpy.changelogs import ChangeLog -from webkitpy.commands.abstractsequencedcommand import AbstractSequencedCommand -from webkitpy.comments import bug_comment_from_commit_text -from webkitpy.executive import ScriptError -from webkitpy.grammar import pluralize -from webkitpy.webkit_logging import error, log -from webkitpy.multicommandtool import AbstractDeclarativeCommand -from webkitpy.stepsequence import StepSequence - - -class Build(AbstractSequencedCommand): - name = "build" - help_text = "Update working copy and build" - steps = [ - steps.CleanWorkingDirectory, - steps.Update, - steps.Build, - ] - - -class BuildAndTest(AbstractSequencedCommand): - name = "build-and-test" - help_text = "Update working copy, build, and run the tests" - steps = [ - steps.CleanWorkingDirectory, - steps.Update, - steps.Build, - steps.RunTests, - ] - - -class Land(AbstractSequencedCommand): - name = "land" - help_text = "Land the current working directory diff and updates the associated bug if any" - argument_names = "[BUGID]" - show_in_main_help = True - steps = [ - steps.EnsureBuildersAreGreen, - steps.UpdateChangeLogsWithReviewer, - steps.EnsureBuildersAreGreen, - steps.Build, - steps.RunTests, - steps.Commit, - steps.CloseBugForLandDiff, - ] - long_help = """land commits the current working copy diff (just as svn or git commit would). -land will build and run the tests before committing. -If a bug id is provided, or one can be found in the ChangeLog land will update the bug after committing.""" - - def _prepare_state(self, options, args, tool): - return { - "bug_id" : (args and args[0]) or parse_bug_id(tool.scm().create_patch()), - } - - -class AbstractPatchProcessingCommand(AbstractDeclarativeCommand): - # Subclasses must implement the methods below. We don't declare them here - # because we want to be able to implement them with mix-ins. - # - # def _fetch_list_of_patches_to_process(self, options, args, tool): - # def _prepare_to_process(self, options, args, tool): - - @staticmethod - def _collect_patches_by_bug(patches): - bugs_to_patches = {} - for patch in patches: - bugs_to_patches[patch.bug_id()] = bugs_to_patches.get(patch.bug_id(), []) + [patch] - return bugs_to_patches - - def execute(self, options, args, tool): - self._prepare_to_process(options, args, tool) - patches = self._fetch_list_of_patches_to_process(options, args, tool) - - # It's nice to print out total statistics. - bugs_to_patches = self._collect_patches_by_bug(patches) - log("Processing %s from %s." % (pluralize("patch", len(patches)), pluralize("bug", len(bugs_to_patches)))) - - for patch in patches: - self._process_patch(patch, options, args, tool) - - -class AbstractPatchSequencingCommand(AbstractPatchProcessingCommand): - prepare_steps = None - main_steps = None - - def __init__(self): - options = [] - self._prepare_sequence = StepSequence(self.prepare_steps) - self._main_sequence = StepSequence(self.main_steps) - options = sorted(set(self._prepare_sequence.options() + self._main_sequence.options())) - AbstractPatchProcessingCommand.__init__(self, options) - - def _prepare_to_process(self, options, args, tool): - self._prepare_sequence.run_and_handle_errors(tool, options) - - def _process_patch(self, patch, options, args, tool): - state = { "patch" : patch } - self._main_sequence.run_and_handle_errors(tool, options, state) - - -class ProcessAttachmentsMixin(object): - def _fetch_list_of_patches_to_process(self, options, args, tool): - return map(lambda patch_id: tool.bugs.fetch_attachment(patch_id), args) - - -class ProcessBugsMixin(object): - def _fetch_list_of_patches_to_process(self, options, args, tool): - all_patches = [] - for bug_id in args: - patches = tool.bugs.fetch_bug(bug_id).reviewed_patches() - log("%s found on bug %s." % (pluralize("reviewed patch", len(patches)), bug_id)) - all_patches += patches - return all_patches - - -class CheckStyle(AbstractPatchSequencingCommand, ProcessAttachmentsMixin): - name = "check-style" - help_text = "Run check-webkit-style on the specified attachments" - argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]" - main_steps = [ - steps.CleanWorkingDirectory, - steps.Update, - steps.ApplyPatch, - steps.CheckStyle, - ] - - -class BuildAttachment(AbstractPatchSequencingCommand, ProcessAttachmentsMixin): - name = "build-attachment" - help_text = "Apply and build patches from bugzilla" - argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]" - main_steps = [ - steps.CleanWorkingDirectory, - steps.Update, - steps.ApplyPatch, - steps.Build, - ] - - -class AbstractPatchApplyingCommand(AbstractPatchSequencingCommand): - prepare_steps = [ - steps.EnsureLocalCommitIfNeeded, - steps.CleanWorkingDirectoryWithLocalCommits, - steps.Update, - ] - main_steps = [ - steps.ApplyPatchWithLocalCommit, - ] - long_help = """Updates the working copy. -Downloads and applies the patches, creating local commits if necessary.""" - - -class ApplyAttachment(AbstractPatchApplyingCommand, ProcessAttachmentsMixin): - name = "apply-attachment" - help_text = "Apply an attachment to the local working directory" - argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]" - show_in_main_help = True - - -class ApplyFromBug(AbstractPatchApplyingCommand, ProcessBugsMixin): - name = "apply-from-bug" - help_text = "Apply reviewed patches from provided bugs to the local working directory" - argument_names = "BUGID [BUGIDS]" - show_in_main_help = True - - -class AbstractPatchLandingCommand(AbstractPatchSequencingCommand): - prepare_steps = [ - steps.EnsureBuildersAreGreen, - ] - main_steps = [ - steps.CleanWorkingDirectory, - steps.Update, - steps.ApplyPatch, - steps.EnsureBuildersAreGreen, - steps.Build, - steps.RunTests, - steps.Commit, - steps.ClosePatch, - steps.CloseBug, - ] - long_help = """Checks to make sure builders are green. -Updates the working copy. -Applies the patch. -Builds. -Runs the layout tests. -Commits the patch. -Clears the flags on the patch. -Closes the bug if no patches are marked for review.""" - - -class LandAttachment(AbstractPatchLandingCommand, ProcessAttachmentsMixin): - name = "land-attachment" - help_text = "Land patches from bugzilla, optionally building and testing them first" - argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]" - show_in_main_help = True - - -class LandFromBug(AbstractPatchLandingCommand, ProcessBugsMixin): - name = "land-from-bug" - help_text = "Land all patches on the given bugs, optionally building and testing them first" - argument_names = "BUGID [BUGIDS]" - show_in_main_help = True - - -class Rollout(AbstractSequencedCommand): - name = "rollout" - show_in_main_help = True - help_text = "Revert the given revision in the working copy and optionally commit the revert and re-open the original bug" - argument_names = "REVISION REASON" - long_help = """Updates the working copy. -Applies the inverse diff for the provided revision. -Creates an appropriate rollout ChangeLog, including a trac link and bug link. -Opens the generated ChangeLogs in $EDITOR. -Shows the prepared diff for confirmation. -Commits the revert and updates the bug (including re-opening the bug if necessary).""" - steps = [ - steps.CleanWorkingDirectory, - steps.Update, - steps.RevertRevision, - steps.PrepareChangeLogForRevert, - steps.EditChangeLog, - steps.ConfirmDiff, - steps.CompleteRollout, - ] - - @staticmethod - def _parse_bug_id_from_revision_diff(tool, revision): - original_diff = tool.scm().diff_for_revision(revision) - return parse_bug_id(original_diff) - - def execute(self, options, args, tool): - revision = args[0] - reason = args[1] - bug_id = self._parse_bug_id_from_revision_diff(tool, revision) - if options.complete_rollout: - if bug_id: - log("Will re-open bug %s after rollout." % bug_id) - else: - log("Failed to parse bug number from diff. No bugs will be updated/reopened after the rollout.") - - state = { - "revision" : revision, - "bug_id" : bug_id, - "reason" : reason, - } - self._sequence.run_and_handle_errors(tool, options, state) diff --git a/WebKitTools/Scripts/webkitpy/commands/download_unittest.py b/WebKitTools/Scripts/webkitpy/commands/download_unittest.py deleted file mode 100644 index f60c5b8..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/download_unittest.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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. - -from webkitpy.commands.commandtest import CommandsTest -from webkitpy.commands.download import * -from webkitpy.mock import Mock - -class DownloadCommandsTest(CommandsTest): - def _default_options(self): - options = Mock() - options.force_clean = False - options.clean = True - options.check_builders = True - options.quiet = False - options.non_interactive = False - options.update = True - options.build = True - options.test = True - options.close_bug = True - options.complete_rollout = False - return options - - def test_build(self): - expected_stderr = "Updating working directory\nBuilding WebKit\n" - self.assert_execute_outputs(Build(), [], options=self._default_options(), expected_stderr=expected_stderr) - - def test_build_and_test(self): - expected_stderr = "Updating working directory\nBuilding WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\n" - self.assert_execute_outputs(BuildAndTest(), [], options=self._default_options(), expected_stderr=expected_stderr) - - def test_apply_attachment(self): - options = self._default_options() - options.update = True - options.local_commit = True - expected_stderr = "Updating working directory\nProcessing 1 patch from 1 bug.\nProcessing patch 197 from bug 42.\n" - self.assert_execute_outputs(ApplyAttachment(), [197], options=options, expected_stderr=expected_stderr) - - def test_apply_patches(self): - options = self._default_options() - options.update = True - options.local_commit = True - expected_stderr = "Updating working directory\n2 reviewed patches found on bug 42.\nProcessing 2 patches from 1 bug.\nProcessing patch 197 from bug 42.\nProcessing patch 128 from bug 42.\n" - self.assert_execute_outputs(ApplyFromBug(), [42], options=options, expected_stderr=expected_stderr) - - def test_land_diff(self): - expected_stderr = "Building WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nUpdating bug 42\n" - self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr) - - def test_check_style(self): - expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nRunning check-webkit-style\n" - self.assert_execute_outputs(CheckStyle(), [197], options=self._default_options(), expected_stderr=expected_stderr) - - def test_build_attachment(self): - expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nBuilding WebKit\n" - self.assert_execute_outputs(BuildAttachment(), [197], options=self._default_options(), expected_stderr=expected_stderr) - - def test_land_attachment(self): - # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags. - expected_stderr = """Processing 1 patch from 1 bug. -Updating working directory -Processing patch 197 from bug 42. -Building WebKit -Running Python unit tests -Running Perl unit tests -Running JavaScriptCore tests -Running run-webkit-tests -Not closing bug 42 as attachment 197 has review=+. Assuming there are more patches to land from this bug. -""" - self.assert_execute_outputs(LandAttachment(), [197], options=self._default_options(), expected_stderr=expected_stderr) - - def test_land_patches(self): - # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags. - expected_stderr = """2 reviewed patches found on bug 42. -Processing 2 patches from 1 bug. -Updating working directory -Processing patch 197 from bug 42. -Building WebKit -Running Python unit tests -Running Perl unit tests -Running JavaScriptCore tests -Running run-webkit-tests -Not closing bug 42 as attachment 197 has review=+. Assuming there are more patches to land from this bug. -Updating working directory -Processing patch 128 from bug 42. -Building WebKit -Running Python unit tests -Running Perl unit tests -Running JavaScriptCore tests -Running run-webkit-tests -Not closing bug 42 as attachment 197 has review=+. Assuming there are more patches to land from this bug. -""" - self.assert_execute_outputs(LandFromBug(), [42], options=self._default_options(), expected_stderr=expected_stderr) - - def test_rollout(self): - expected_stderr = "Updating working directory\nRunning prepare-ChangeLog\n\nNOTE: Rollout support is experimental.\nPlease verify the rollout diff and use \"webkit-patch land 12345\" to commit the rollout.\n" - self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr) - - def test_complete_rollout(self): - options = self._default_options() - options.complete_rollout = True - expected_stderr = "Will re-open bug 12345 after rollout.\nUpdating working directory\nRunning prepare-ChangeLog\nBuilding WebKit\n" - self.assert_execute_outputs(Rollout(), [852, "Reason"], options=options, expected_stderr=expected_stderr) diff --git a/WebKitTools/Scripts/webkitpy/commands/early_warning_system.py b/WebKitTools/Scripts/webkitpy/commands/early_warning_system.py deleted file mode 100644 index e3e14dd..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/early_warning_system.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -# 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. - -from StringIO import StringIO - -from webkitpy.commands.queues import AbstractReviewQueue -from webkitpy.committers import CommitterList -from webkitpy.executive import ScriptError -from webkitpy.webkitport import WebKitPort -from webkitpy.queueengine import QueueEngine - - -class AbstractEarlyWarningSystem(AbstractReviewQueue): - _build_style = "release" - - def __init__(self): - AbstractReviewQueue.__init__(self) - self.port = WebKitPort.port(self.port_name) - - def should_proceed_with_work_item(self, patch): - try: - self.run_webkit_patch([ - "build", - self.port.flag(), - "--build-style=%s" % self._build_style, - "--force-clean", - "--quiet"]) - self._update_status("Building", patch) - except ScriptError, e: - self._update_status("Unable to perform a build") - return False - return True - - def _review_patch(self, patch): - self.run_webkit_patch([ - "build-attachment", - self.port.flag(), - "--build-style=%s" % self._build_style, - "--force-clean", - "--quiet", - "--non-interactive", - "--parent-command=%s" % self.name, - "--no-update", - patch.id()]) - - @classmethod - def handle_script_error(cls, tool, state, script_error): - is_svn_apply = script_error.command_name() == "svn-apply" - status_id = cls._update_status_for_script_error(tool, state, script_error, is_error=is_svn_apply) - if is_svn_apply: - QueueEngine.exit_after_handled_error(script_error) - results_link = tool.status_server.results_url_for_status(status_id) - message = "Attachment %s did not build on %s:\nBuild output: %s" % (state["patch"].id(), cls.port_name, results_link) - tool.bugs.post_comment_to_bug(state["patch"].bug_id(), message, cc=cls.watchers) - exit(1) - - -class GtkEWS(AbstractEarlyWarningSystem): - name = "gtk-ews" - port_name = "gtk" - watchers = AbstractEarlyWarningSystem.watchers + [ - "gns@gnome.org", - "xan.lopez@gmail.com", - ] - - -class QtEWS(AbstractEarlyWarningSystem): - name = "qt-ews" - port_name = "qt" - - -class ChromiumEWS(AbstractEarlyWarningSystem): - name = "chromium-ews" - port_name = "chromium" - watchers = AbstractEarlyWarningSystem.watchers + [ - "dglazkov@chromium.org", - ] - - -# For platforms that we can't run inside a VM (like Mac OS X), we require -# patches to be uploaded by committers, who are generally trustworthy folk. :) -class AbstractCommitterOnlyEWS(AbstractEarlyWarningSystem): - def __init__(self, committers=CommitterList()): - AbstractEarlyWarningSystem.__init__(self) - self._committers = committers - - def process_work_item(self, patch): - if not self._committers.committer_by_email(patch.attacher_email()): - self._did_error(patch, "%s cannot process patches from non-committers :(" % self.name) - return - AbstractEarlyWarningSystem.process_work_item(self, patch) - - -class MacEWS(AbstractCommitterOnlyEWS): - name = "mac-ews" - port_name = "mac" diff --git a/WebKitTools/Scripts/webkitpy/commands/early_warning_system_unittest.py b/WebKitTools/Scripts/webkitpy/commands/early_warning_system_unittest.py deleted file mode 100644 index d516b84..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/early_warning_system_unittest.py +++ /dev/null @@ -1,62 +0,0 @@ -# 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 os - -from webkitpy.commands.early_warning_system import * -from webkitpy.commands.queuestest import QueuesTest -from webkitpy.mock import Mock - -class EarlyWarningSytemTest(QueuesTest): - def test_chromium_ews(self): - expected_stderr = { - "begin_work_queue" : "CAUTION: chromium-ews will discard all local changes in \"%s\"\nRunning WebKit chromium-ews.\n" % os.getcwd(), - "handle_unexpected_error" : "Mock error message\n", - } - self.assert_queue_outputs(ChromiumEWS(), expected_stderr=expected_stderr) - - def test_qt_ews(self): - expected_stderr = { - "begin_work_queue" : "CAUTION: qt-ews will discard all local changes in \"%s\"\nRunning WebKit qt-ews.\n" % os.getcwd(), - "handle_unexpected_error" : "Mock error message\n", - } - self.assert_queue_outputs(QtEWS(), expected_stderr=expected_stderr) - - def test_gtk_ews(self): - expected_stderr = { - "begin_work_queue" : "CAUTION: gtk-ews will discard all local changes in \"%s\"\nRunning WebKit gtk-ews.\n" % os.getcwd(), - "handle_unexpected_error" : "Mock error message\n", - } - self.assert_queue_outputs(GtkEWS(), expected_stderr=expected_stderr) - - def test_mac_ews(self): - expected_stderr = { - "begin_work_queue" : "CAUTION: mac-ews will discard all local changes in \"%s\"\nRunning WebKit mac-ews.\n" % os.getcwd(), - "handle_unexpected_error" : "Mock error message\n", - } - self.assert_queue_outputs(MacEWS(), expected_stderr=expected_stderr) diff --git a/WebKitTools/Scripts/webkitpy/commands/openbugs.py b/WebKitTools/Scripts/webkitpy/commands/openbugs.py deleted file mode 100644 index 25bdefc..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/openbugs.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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 re -import sys - -from webkitpy.multicommandtool import AbstractDeclarativeCommand -from webkitpy.webkit_logging import log - - -class OpenBugs(AbstractDeclarativeCommand): - name = "open-bugs" - help_text = "Finds all bug numbers passed in arguments (or stdin if no args provided) and opens them in a web browser" - - bug_number_regexp = re.compile(r"\b\d{4,6}\b") - - def _open_bugs(self, bug_ids): - for bug_id in bug_ids: - bug_url = self.tool.bugs.bug_url_for_bug_id(bug_id) - self.tool.user.open_url(bug_url) - - # _find_bugs_in_string mostly exists for easy unit testing. - def _find_bugs_in_string(self, string): - return self.bug_number_regexp.findall(string) - - def _find_bugs_in_iterable(self, iterable): - return sum([self._find_bugs_in_string(string) for string in iterable], []) - - def execute(self, options, args, tool): - if args: - bug_ids = self._find_bugs_in_iterable(args) - else: - # This won't open bugs until stdin is closed but could be made to easily. That would just make unit testing slightly harder. - bug_ids = self._find_bugs_in_iterable(sys.stdin) - - log("%s bugs found in input." % len(bug_ids)) - - self._open_bugs(bug_ids) diff --git a/WebKitTools/Scripts/webkitpy/commands/openbugs_unittest.py b/WebKitTools/Scripts/webkitpy/commands/openbugs_unittest.py deleted file mode 100644 index 71fefd2..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/openbugs_unittest.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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. - -from webkitpy.commands.commandtest import CommandsTest -from webkitpy.commands.openbugs import OpenBugs - -class OpenBugsTest(CommandsTest): - - find_bugs_in_string_expectations = [ - ["123", []], - ["1234", ["1234"]], - ["12345", ["12345"]], - ["123456", ["123456"]], - ["1234567", []], - [" 123456 234567", ["123456", "234567"]], - ] - - def test_find_bugs_in_string(self): - openbugs = OpenBugs() - for expectation in self.find_bugs_in_string_expectations: - self.assertEquals(openbugs._find_bugs_in_string(expectation[0]), expectation[1]) - - def test_args_parsing(self): - expected_stderr = "2 bugs found in input.\nMOCK: user.open_url: http://example.com/12345\nMOCK: user.open_url: http://example.com/23456\n" - self.assert_execute_outputs(OpenBugs(), ["12345\n23456"], expected_stderr=expected_stderr) diff --git a/WebKitTools/Scripts/webkitpy/commands/queries.py b/WebKitTools/Scripts/webkitpy/commands/queries.py deleted file mode 100644 index 3ca4f42..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/queries.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2009, Google Inc. All rights reserved. -# Copyright (c) 2009 Apple 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 optparse import make_option - -from webkitpy.buildbot import BuildBot -from webkitpy.committers import CommitterList -from webkitpy.webkit_logging import log -from webkitpy.multicommandtool import AbstractDeclarativeCommand - - -class BugsToCommit(AbstractDeclarativeCommand): - name = "bugs-to-commit" - help_text = "List bugs in the commit-queue" - - def execute(self, options, args, tool): - # FIXME: This command is poorly named. It's fetching the commit-queue list here. The name implies it's fetching pending-commit (all r+'d patches). - bug_ids = tool.bugs.queries.fetch_bug_ids_from_commit_queue() - for bug_id in bug_ids: - print "%s" % bug_id - - -class PatchesInCommitQueue(AbstractDeclarativeCommand): - name = "patches-in-commit-queue" - help_text = "List patches in the commit-queue" - - def execute(self, options, args, tool): - patches = tool.bugs.queries.fetch_patches_from_commit_queue() - log("Patches in commit queue:") - for patch in patches: - print patch.url() - - -class PatchesToCommitQueue(AbstractDeclarativeCommand): - name = "patches-to-commit-queue" - help_text = "Patches which should be added to the commit queue" - def __init__(self): - options = [ - make_option("--bugs", action="store_true", dest="bugs", help="Output bug links instead of patch links"), - ] - AbstractDeclarativeCommand.__init__(self, options=options) - - @staticmethod - def _needs_commit_queue(patch): - if patch.commit_queue() == "+": # If it's already cq+, ignore the patch. - log("%s already has cq=%s" % (patch.id(), patch.commit_queue())) - return False - - # We only need to worry about patches from contributers who are not yet committers. - committer_record = CommitterList().committer_by_email(patch.attacher_email()) - if committer_record: - log("%s committer = %s" % (patch.id(), committer_record)) - return not committer_record - - def execute(self, options, args, tool): - patches = tool.bugs.queries.fetch_patches_from_pending_commit_list() - patches_needing_cq = filter(self._needs_commit_queue, patches) - if options.bugs: - bugs_needing_cq = map(lambda patch: patch.bug_id(), patches_needing_cq) - bugs_needing_cq = sorted(set(bugs_needing_cq)) - for bug_id in bugs_needing_cq: - print "%s" % tool.bugs.bug_url_for_bug_id(bug_id) - else: - for patch in patches_needing_cq: - print "%s" % tool.bugs.attachment_url_for_id(patch.id(), action="edit") - - -class PatchesToReview(AbstractDeclarativeCommand): - name = "patches-to-review" - help_text = "List patches that are pending review" - - def execute(self, options, args, tool): - patch_ids = tool.bugs.queries.fetch_attachment_ids_from_review_queue() - log("Patches pending review:") - for patch_id in patch_ids: - print patch_id - - -class TreeStatus(AbstractDeclarativeCommand): - name = "tree-status" - help_text = "Print the status of the %s buildbots" % BuildBot.default_host - long_help = """Fetches build status from http://build.webkit.org/one_box_per_builder -and displayes the status of each builder.""" - - def execute(self, options, args, tool): - for builder in tool.buildbot.builder_statuses(): - status_string = "ok" if builder["is_green"] else "FAIL" - print "%s : %s" % (status_string.ljust(4), builder["name"]) diff --git a/WebKitTools/Scripts/webkitpy/commands/queries_unittest.py b/WebKitTools/Scripts/webkitpy/commands/queries_unittest.py deleted file mode 100644 index b858777..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/queries_unittest.py +++ /dev/null @@ -1,63 +0,0 @@ -# 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. - -from webkitpy.bugzilla import Bugzilla -from webkitpy.commands.commandtest import CommandsTest -from webkitpy.commands.queries import * -from webkitpy.mock import Mock -from webkitpy.mock_bugzillatool import MockBugzillaTool - -class QueryCommandsTest(CommandsTest): - def test_bugs_to_commit(self): - expected_stderr = "Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)\n" - self.assert_execute_outputs(BugsToCommit(), None, "42\n77\n", expected_stderr) - - def test_patches_in_commit_queue(self): - expected_stdout = "http://example.com/197\nhttp://example.com/103\n" - expected_stderr = "Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)\nPatches in commit queue:\n" - self.assert_execute_outputs(PatchesInCommitQueue(), None, expected_stdout, expected_stderr) - - def test_patches_to_commit_queue(self): - expected_stdout = "http://example.com/104&action=edit\n" - expected_stderr = "197 already has cq=+\n128 already has cq=+\n105 committer = \"Eric Seidel\" <eric@webkit.org>\n" - options = Mock() - options.bugs = False - self.assert_execute_outputs(PatchesToCommitQueue(), None, expected_stdout, expected_stderr, options=options) - - expected_stdout = "http://example.com/77\n" - options.bugs = True - self.assert_execute_outputs(PatchesToCommitQueue(), None, expected_stdout, expected_stderr, options=options) - - def test_patches_to_review(self): - expected_stdout = "103\n" - expected_stderr = "Patches pending review:\n" - self.assert_execute_outputs(PatchesToReview(), None, expected_stdout, expected_stderr) - - def test_tree_status(self): - expected_stdout = "ok : Builder1\nok : Builder2\n" - self.assert_execute_outputs(TreeStatus(), None, expected_stdout) diff --git a/WebKitTools/Scripts/webkitpy/commands/queues.py b/WebKitTools/Scripts/webkitpy/commands/queues.py deleted file mode 100644 index 6ea1c48..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/queues.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2009, Google Inc. All rights reserved. -# Copyright (c) 2009 Apple 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 traceback -import os - -from datetime import datetime -from optparse import make_option -from StringIO import StringIO - -from webkitpy.bugzilla import CommitterValidator -from webkitpy.executive import ScriptError -from webkitpy.grammar import pluralize -from webkitpy.webkit_logging import error, log -from webkitpy.multicommandtool import Command -from webkitpy.patchcollection import PersistentPatchCollection, PersistentPatchCollectionDelegate -from webkitpy.statusserver import StatusServer -from webkitpy.stepsequence import StepSequenceErrorHandler -from webkitpy.queueengine import QueueEngine, QueueEngineDelegate - -class AbstractQueue(Command, QueueEngineDelegate): - watchers = [ - "webkit-bot-watchers@googlegroups.com", - ] - - _pass_status = "Pass" - _fail_status = "Fail" - _error_status = "Error" - - def __init__(self, options=None): # Default values should never be collections (like []) as default values are shared between invocations - options_list = (options or []) + [ - make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Do not ask the user for confirmation before running the queue. Dangerous!"), - ] - Command.__init__(self, "Run the %s" % self.name, options=options_list) - - def _cc_watchers(self, bug_id): - try: - self.tool.bugs.add_cc_to_bug(bug_id, self.watchers) - except Exception, e: - traceback.print_exc() - log("Failed to CC watchers.") - - def _update_status(self, message, patch=None, results_file=None): - self.tool.status_server.update_status(self.name, message, patch, results_file) - - def _did_pass(self, patch): - self._update_status(self._pass_status, patch) - - def _did_fail(self, patch): - self._update_status(self._fail_status, patch) - - def _did_error(self, patch, reason): - message = "%s: %s" % (self._error_status, reason) - self._update_status(message, patch) - - def queue_log_path(self): - return "%s.log" % self.name - - def work_item_log_path(self, patch): - return os.path.join("%s-logs" % self.name, "%s.log" % patch.bug_id()) - - def begin_work_queue(self): - log("CAUTION: %s will discard all local changes in \"%s\"" % (self.name, self.tool.scm().checkout_root)) - if self.options.confirm: - response = self.tool.user.prompt("Are you sure? Type \"yes\" to continue: ") - if (response != "yes"): - error("User declined.") - log("Running WebKit %s." % self.name) - - def should_continue_work_queue(self): - return True - - def next_work_item(self): - raise NotImplementedError, "subclasses must implement" - - def should_proceed_with_work_item(self, work_item): - raise NotImplementedError, "subclasses must implement" - - def process_work_item(self, work_item): - raise NotImplementedError, "subclasses must implement" - - def handle_unexpected_error(self, work_item, message): - raise NotImplementedError, "subclasses must implement" - - def run_webkit_patch(self, args): - webkit_patch_args = [self.tool.path()] - # FIXME: This is a hack, we should have a more general way to pass global options. - webkit_patch_args += ["--status-host=%s" % self.tool.status_server.host] - webkit_patch_args += map(str, args) - self.tool.executive.run_and_throw_if_fail(webkit_patch_args) - - def log_progress(self, patch_ids): - log("%s in %s [%s]" % (pluralize("patch", len(patch_ids)), self.name, ", ".join(map(str, patch_ids)))) - - def execute(self, options, args, tool, engine=QueueEngine): - self.options = options - self.tool = tool - return engine(self.name, self).run() - - @classmethod - def _update_status_for_script_error(cls, tool, state, script_error, is_error=False): - message = script_error.message - if is_error: - message = "Error: %s" % message - output = script_error.message_with_output(output_limit=5*1024*1024) # 5MB - return tool.status_server.update_status(cls.name, message, state["patch"], StringIO(output)) - - -class CommitQueue(AbstractQueue, StepSequenceErrorHandler): - name = "commit-queue" - def __init__(self): - AbstractQueue.__init__(self) - - # AbstractQueue methods - - def begin_work_queue(self): - AbstractQueue.begin_work_queue(self) - self.committer_validator = CommitterValidator(self.tool.bugs) - - def _validate_patches_in_commit_queue(self): - # Not using BugzillaQueries.fetch_patches_from_commit_queue() so we can reject patches with invalid committers/reviewers. - bug_ids = self.tool.bugs.queries.fetch_bug_ids_from_commit_queue() - all_patches = sum([self.tool.bugs.fetch_bug(bug_id).commit_queued_patches(include_invalid=True) for bug_id in bug_ids], []) - return self.committer_validator.patches_after_rejecting_invalid_commiters_and_reviewers(all_patches) - - def next_work_item(self): - patches = self._validate_patches_in_commit_queue() - # FIXME: We could sort the patches in a specific order here, was suggested by https://bugs.webkit.org/show_bug.cgi?id=33395 - if not patches: - self._update_status("Empty queue") - return None - # Only bother logging if we have patches in the queue. - self.log_progress([patch.id() for patch in patches]) - return patches[0] - - def _can_build_and_test(self): - try: - self.run_webkit_patch(["build-and-test", "--force-clean", "--non-interactive", "--build-style=both", "--quiet"]) - except ScriptError, e: - self._update_status("Unabled to successfully build and test", None) - return False - return True - - def _builders_are_green(self): - red_builders_names = self.tool.buildbot.red_core_builders_names() - if red_builders_names: - red_builders_names = map(lambda name: "\"%s\"" % name, red_builders_names) # Add quotes around the names. - self._update_status("Builders [%s] are red. See http://build.webkit.org" % ", ".join(red_builders_names), None) - return False - return True - - def should_proceed_with_work_item(self, patch): - if not self._builders_are_green(): - return False - if not self._can_build_and_test(): - return False - if not self._builders_are_green(): - return False - self._update_status("Landing patch", patch) - return True - - def process_work_item(self, patch): - try: - self._cc_watchers(patch.bug_id()) - # We pass --no-update here because we've already validated - # that the current revision actually builds and passes the tests. - # If we update, we risk moving to a revision that doesn't! - self.run_webkit_patch(["land-attachment", "--force-clean", "--non-interactive", "--no-update", "--parent-command=commit-queue", "--build-style=both", "--quiet", patch.id()]) - self._did_pass(patch) - except ScriptError, e: - self._did_fail(patch) - raise e - - def handle_unexpected_error(self, patch, message): - self.committer_validator.reject_patch_from_commit_queue(patch.id(), message) - - # StepSequenceErrorHandler methods - - @staticmethod - def _error_message_for_bug(tool, status_id, script_error): - if not script_error.output: - return script_error.message_with_output() - results_link = tool.status_server.results_url_for_status(status_id) - return "%s\nFull output: %s" % (script_error.message_with_output(), results_link) - - @classmethod - def handle_script_error(cls, tool, state, script_error): - status_id = cls._update_status_for_script_error(tool, state, script_error) - validator = CommitterValidator(tool.bugs) - validator.reject_patch_from_commit_queue(state["patch"].id(), cls._error_message_for_bug(tool, status_id, script_error)) - - -class AbstractReviewQueue(AbstractQueue, PersistentPatchCollectionDelegate, StepSequenceErrorHandler): - def __init__(self, options=None): - AbstractQueue.__init__(self, options) - - def _review_patch(self, patch): - raise NotImplementedError, "subclasses must implement" - - # PersistentPatchCollectionDelegate methods - - def collection_name(self): - return self.name - - def fetch_potential_patch_ids(self): - return self.tool.bugs.queries.fetch_attachment_ids_from_review_queue() - - def status_server(self): - return self.tool.status_server - - def is_terminal_status(self, status): - return status == "Pass" or status == "Fail" or status.startswith("Error:") - - # AbstractQueue methods - - def begin_work_queue(self): - AbstractQueue.begin_work_queue(self) - self._patches = PersistentPatchCollection(self) - - def next_work_item(self): - patch_id = self._patches.next() - if patch_id: - return self.tool.bugs.fetch_attachment(patch_id) - self._update_status("Empty queue") - - def should_proceed_with_work_item(self, patch): - raise NotImplementedError, "subclasses must implement" - - def process_work_item(self, patch): - try: - self._review_patch(patch) - self._did_pass(patch) - except ScriptError, e: - if e.exit_code != QueueEngine.handled_error_code: - self._did_fail(patch) - raise e - - def handle_unexpected_error(self, patch, message): - log(message) - - # StepSequenceErrorHandler methods - - @classmethod - def handle_script_error(cls, tool, state, script_error): - log(script_error.message_with_output()) - - -class StyleQueue(AbstractReviewQueue): - name = "style-queue" - def __init__(self): - AbstractReviewQueue.__init__(self) - - def should_proceed_with_work_item(self, patch): - self._update_status("Checking style", patch) - return True - - def _review_patch(self, patch): - self.run_webkit_patch(["check-style", "--force-clean", "--non-interactive", "--parent-command=style-queue", patch.id()]) - - @classmethod - def handle_script_error(cls, tool, state, script_error): - is_svn_apply = script_error.command_name() == "svn-apply" - status_id = cls._update_status_for_script_error(tool, state, script_error, is_error=is_svn_apply) - if is_svn_apply: - QueueEngine.exit_after_handled_error(script_error) - message = "Attachment %s did not pass %s:\n\n%s\n\nIf any of these errors are false positives, please file a bug against check-webkit-style." % (state["patch"].id(), cls.name, script_error.message_with_output(output_limit=3*1024)) - tool.bugs.post_comment_to_bug(state["patch"].bug_id(), message, cc=cls.watchers) - exit(1) diff --git a/WebKitTools/Scripts/webkitpy/commands/queues_unittest.py b/WebKitTools/Scripts/webkitpy/commands/queues_unittest.py deleted file mode 100644 index 87cd645..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/queues_unittest.py +++ /dev/null @@ -1,102 +0,0 @@ -# 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 os - -from webkitpy.commands.commandtest import CommandsTest -from webkitpy.commands.queues import * -from webkitpy.commands.queuestest import QueuesTest -from webkitpy.mock_bugzillatool import MockBugzillaTool -from webkitpy.outputcapture import OutputCapture - - -class TestQueue(AbstractQueue): - name = "test-queue" - - -class TestReviewQueue(AbstractReviewQueue): - name = "test-review-queue" - - -class AbstractQueueTest(CommandsTest): - def _assert_log_progress_output(self, patch_ids, progress_output): - OutputCapture().assert_outputs(self, TestQueue().log_progress, [patch_ids], expected_stderr=progress_output) - - def test_log_progress(self): - self._assert_log_progress_output([1,2,3], "3 patches in test-queue [1, 2, 3]\n") - self._assert_log_progress_output(["1","2","3"], "3 patches in test-queue [1, 2, 3]\n") - self._assert_log_progress_output([1], "1 patch in test-queue [1]\n") - - def _assert_run_webkit_patch(self, run_args): - queue = TestQueue() - tool = MockBugzillaTool() - queue.bind_to_tool(tool) - - queue.run_webkit_patch(run_args) - expected_run_args = ["echo", "--status-host=example.com"] + map(str, run_args) - tool.executive.run_and_throw_if_fail.assert_called_with(expected_run_args) - - def test_run_webkit_patch(self): - self._assert_run_webkit_patch([1]) - self._assert_run_webkit_patch(["one", 2]) - - -class AbstractReviewQueueTest(CommandsTest): - def test_patch_collection_delegate_methods(self): - queue = TestReviewQueue() - tool = MockBugzillaTool() - queue.bind_to_tool(tool) - self.assertEquals(queue.collection_name(), "test-review-queue") - self.assertEquals(queue.fetch_potential_patch_ids(), [103]) - queue.status_server() - self.assertTrue(queue.is_terminal_status("Pass")) - self.assertTrue(queue.is_terminal_status("Fail")) - self.assertTrue(queue.is_terminal_status("Error: Your patch exploded")) - self.assertFalse(queue.is_terminal_status("Foo")) - - -class CommitQueueTest(QueuesTest): - def test_commit_queue(self): - expected_stderr = { - "begin_work_queue" : "CAUTION: commit-queue will discard all local changes in \"%s\"\nRunning WebKit commit-queue.\n" % os.getcwd(), - # FIXME: The commit-queue warns about bad committers twice. This is due to the fact that we access Attachment.reviewer() twice and it logs each time. - "next_work_item" : """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) -Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) -2 patches in commit-queue [197, 106] -""", - } - self.assert_queue_outputs(CommitQueue(), expected_stderr=expected_stderr) - - -class StyleQueueTest(QueuesTest): - def test_style_queue(self): - expected_stderr = { - "begin_work_queue" : "CAUTION: style-queue will discard all local changes in \"%s\"\nRunning WebKit style-queue.\n" % os.getcwd(), - "handle_unexpected_error" : "Mock error message\n", - } - self.assert_queue_outputs(StyleQueue(), expected_stderr=expected_stderr) diff --git a/WebKitTools/Scripts/webkitpy/commands/queuestest.py b/WebKitTools/Scripts/webkitpy/commands/queuestest.py deleted file mode 100644 index 09d1c26..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/queuestest.py +++ /dev/null @@ -1,99 +0,0 @@ -# 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 unittest - -from webkitpy.bugzilla import Attachment -from webkitpy.mock import Mock -from webkitpy.mock_bugzillatool import MockBugzillaTool -from webkitpy.outputcapture import OutputCapture - - -class MockQueueEngine(object): - def __init__(self, name, queue): - pass - - def run(self): - pass - - -class QueuesTest(unittest.TestCase): - mock_work_item = Attachment({ - "id" : 1234, - "bug_id" : 345, - "attacher_email": "adam@example.com", - }, None) - - def assert_queue_outputs(self, queue, args=None, work_item=None, expected_stdout=None, expected_stderr=None, options=Mock(), tool=MockBugzillaTool()): - if not expected_stdout: - expected_stdout = {} - if not expected_stderr: - expected_stderr = {} - if not args: - args = [] - if not work_item: - work_item = self.mock_work_item - tool.user.prompt = lambda message: "yes" - - queue.execute(options, args, tool, engine=MockQueueEngine) - - OutputCapture().assert_outputs(self, - queue.queue_log_path, - expected_stdout=expected_stdout.get("queue_log_path", ""), - expected_stderr=expected_stderr.get("queue_log_path", "")) - OutputCapture().assert_outputs(self, - queue.work_item_log_path, - args=[work_item], - expected_stdout=expected_stdout.get("work_item_log_path", ""), - expected_stderr=expected_stderr.get("work_item_log_path", "")) - OutputCapture().assert_outputs(self, - queue.begin_work_queue, - expected_stdout=expected_stdout.get("begin_work_queue", ""), - expected_stderr=expected_stderr.get("begin_work_queue", "")) - OutputCapture().assert_outputs(self, - queue.should_continue_work_queue, - expected_stdout=expected_stdout.get("should_continue_work_queue", ""), expected_stderr=expected_stderr.get("should_continue_work_queue", "")) - OutputCapture().assert_outputs(self, - queue.next_work_item, - expected_stdout=expected_stdout.get("next_work_item", ""), - expected_stderr=expected_stderr.get("next_work_item", "")) - OutputCapture().assert_outputs(self, - queue.should_proceed_with_work_item, - args=[work_item], - expected_stdout=expected_stdout.get("should_proceed_with_work_item", ""), - expected_stderr=expected_stderr.get("should_proceed_with_work_item", "")) - OutputCapture().assert_outputs(self, - queue.process_work_item, - args=[work_item], - expected_stdout=expected_stdout.get("process_work_item", ""), - expected_stderr=expected_stderr.get("process_work_item", "")) - OutputCapture().assert_outputs(self, - queue.handle_unexpected_error, - args=[work_item, "Mock error message"], - expected_stdout=expected_stdout.get("handle_unexpected_error", ""), - expected_stderr=expected_stderr.get("handle_unexpected_error", "")) diff --git a/WebKitTools/Scripts/webkitpy/commands/upload.py b/WebKitTools/Scripts/webkitpy/commands/upload.py deleted file mode 100644 index 15bdfbb..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/upload.py +++ /dev/null @@ -1,447 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2009, Google Inc. All rights reserved. -# Copyright (c) 2009 Apple 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 -import re -import StringIO -import sys - -from optparse import make_option - -import webkitpy.steps as steps - -from webkitpy.bugzilla import parse_bug_id -from webkitpy.commands.abstractsequencedcommand import AbstractSequencedCommand -from webkitpy.comments import bug_comment_from_svn_revision -from webkitpy.committers import CommitterList -from webkitpy.grammar import pluralize, join_with_separators -from webkitpy.webkit_logging import error, log -from webkitpy.mock import Mock -from webkitpy.multicommandtool import AbstractDeclarativeCommand -from webkitpy.user import User - -class CommitMessageForCurrentDiff(AbstractDeclarativeCommand): - name = "commit-message" - help_text = "Print a commit message suitable for the uncommitted changes" - - def execute(self, options, args, tool): - os.chdir(tool.scm().checkout_root) - print "%s" % tool.scm().commit_message_for_this_commit().message() - -class CleanPendingCommit(AbstractDeclarativeCommand): - name = "clean-pending-commit" - help_text = "Clear r+ on obsolete patches so they do not appear in the pending-commit list." - - # NOTE: This was designed to be generic, but right now we're only processing patches from the pending-commit list, so only r+ matters. - def _flags_to_clear_on_patch(self, patch): - if not patch.is_obsolete(): - return None - what_was_cleared = [] - if patch.review() == "+": - if patch.reviewer(): - what_was_cleared.append("%s's review+" % patch.reviewer().full_name) - else: - what_was_cleared.append("review+") - return join_with_separators(what_was_cleared) - - def execute(self, options, args, tool): - committers = CommitterList() - for bug_id in tool.bugs.queries.fetch_bug_ids_from_pending_commit_list(): - bug = self.tool.bugs.fetch_bug(bug_id) - patches = bug.patches(include_obsolete=True) - for patch in patches: - flags_to_clear = self._flags_to_clear_on_patch(patch) - if not flags_to_clear: - continue - message = "Cleared %s from obsolete attachment %s so that this bug does not appear in http://webkit.org/pending-commit." % (flags_to_clear, patch.id()) - self.tool.bugs.obsolete_attachment(patch.id(), message) - - -class AssignToCommitter(AbstractDeclarativeCommand): - name = "assign-to-committer" - help_text = "Assign bug to whoever attached the most recent r+'d patch" - - def _patches_have_commiters(self, reviewed_patches): - for patch in reviewed_patches: - if not patch.committer(): - return False - return True - - def _assign_bug_to_last_patch_attacher(self, bug_id): - committers = CommitterList() - bug = self.tool.bugs.fetch_bug(bug_id) - assigned_to_email = bug.assigned_to_email() - if assigned_to_email != self.tool.bugs.unassigned_email: - log("Bug %s is already assigned to %s (%s)." % (bug_id, assigned_to_email, committers.committer_by_email(assigned_to_email))) - return - - reviewed_patches = bug.reviewed_patches() - if not reviewed_patches: - log("Bug %s has no non-obsolete patches, ignoring." % bug_id) - return - - # We only need to do anything with this bug if one of the r+'d patches does not have a valid committer (cq+ set). - if self._patches_have_commiters(reviewed_patches): - log("All reviewed patches on bug %s already have commit-queue+, ignoring." % bug_id) - return - - latest_patch = reviewed_patches[-1] - attacher_email = latest_patch.attacher_email() - committer = committers.committer_by_email(attacher_email) - if not committer: - log("Attacher %s is not a committer. Bug %s likely needs commit-queue+." % (attacher_email, bug_id)) - return - - reassign_message = "Attachment %s was posted by a committer and has review+, assigning to %s for commit." % (latest_patch.id(), committer.full_name) - self.tool.bugs.reassign_bug(bug_id, committer.bugzilla_email(), reassign_message) - - def execute(self, options, args, tool): - for bug_id in tool.bugs.queries.fetch_bug_ids_from_pending_commit_list(): - self._assign_bug_to_last_patch_attacher(bug_id) - - -class ObsoleteAttachments(AbstractSequencedCommand): - name = "obsolete-attachments" - help_text = "Mark all attachments on a bug as obsolete" - argument_names = "BUGID" - steps = [ - steps.ObsoletePatches, - ] - - def _prepare_state(self, options, args, tool): - return { "bug_id" : args[0] } - - -class AbstractPatchUploadingCommand(AbstractSequencedCommand): - def _bug_id(self, args, tool, state): - # Perfer a bug id passed as an argument over a bug url in the diff (i.e. ChangeLogs). - bug_id = args and args[0] - if not bug_id: - state["diff"] = tool.scm().create_patch() - bug_id = parse_bug_id(state["diff"]) - return bug_id - - def _prepare_state(self, options, args, tool): - state = {} - state["bug_id"] = self._bug_id(args, tool, state) - if not state["bug_id"]: - error("No bug id passed and no bug url found in diff.") - return state - - -class Post(AbstractPatchUploadingCommand): - name = "post" - help_text = "Attach the current working directory diff to a bug as a patch file" - argument_names = "[BUGID]" - show_in_main_help = True - steps = [ - steps.CheckStyle, - steps.ConfirmDiff, - steps.ObsoletePatches, - steps.PostDiff, - ] - - -class LandSafely(AbstractPatchUploadingCommand): - name = "land-safely" - help_text = "Land the current diff via the commit-queue (Experimental)" - argument_names = "[BUGID]" - steps = [ - steps.UpdateChangeLogsWithReviewer, - steps.ObsoletePatches, - steps.PostDiffForCommit, - ] - - -class Prepare(AbstractSequencedCommand): - name = "prepare" - help_text = "Creates a bug (or prompts for an existing bug) and prepares the ChangeLogs" - argument_names = "[BUGID]" - show_in_main_help = True - steps = [ - steps.PromptForBugOrTitle, - steps.CreateBug, - steps.PrepareChangeLog, - ] - - def _prepare_state(self, options, args, tool): - bug_id = args and args[0] - return { "bug_id" : bug_id } - - -class Upload(AbstractPatchUploadingCommand): - name = "upload" - help_text = "Automates the process of uploading a patch for review" - argument_names = "[BUGID]" - show_in_main_help = True - steps = [ - steps.CheckStyle, - steps.PromptForBugOrTitle, - steps.CreateBug, - steps.PrepareChangeLog, - steps.EditChangeLog, - steps.ConfirmDiff, - steps.ObsoletePatches, - steps.PostDiff, - ] - long_help = """upload uploads the current diff to bugs.webkit.org. - If no bug id is provided, upload will create a bug. - If the current diff does not have a ChangeLog, upload - will prepare a ChangeLog. Once a patch is read, upload - will open the ChangeLogs for editing using the command in the - EDITOR environment variable and will display the diff using the - command in the PAGER environment variable.""" - - def _prepare_state(self, options, args, tool): - state = {} - state["bug_id"] = self._bug_id(args, tool, state) - return state - - -class EditChangeLogs(AbstractSequencedCommand): - name = "edit-changelogs" - help_text = "Opens modified ChangeLogs in $EDITOR" - show_in_main_help = True - steps = [ - steps.EditChangeLog, - ] - - -class PostCommits(AbstractDeclarativeCommand): - name = "post-commits" - help_text = "Attach a range of local commits to bugs as patch files" - argument_names = "COMMITISH" - - def __init__(self): - options = [ - make_option("-b", "--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."), - make_option("--add-log-as-comment", action="store_true", dest="add_log_as_comment", default=False, help="Add commit log message as a comment when uploading the patch."), - make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: description from commit message)"), - steps.Options.obsolete_patches, - steps.Options.review, - steps.Options.request_commit, - ] - AbstractDeclarativeCommand.__init__(self, options=options, requires_local_commits=True) - - def _comment_text_for_commit(self, options, commit_message, tool, commit_id): - comment_text = None - if (options.add_log_as_comment): - comment_text = commit_message.body(lstrip=True) - comment_text += "---\n" - comment_text += tool.scm().files_changed_summary_for_commit(commit_id) - return comment_text - - def _diff_file_for_commit(self, tool, commit_id): - diff = tool.scm().create_patch_from_local_commit(commit_id) - return StringIO.StringIO(diff) # add_patch_to_bug expects a file-like object - - def execute(self, options, args, tool): - commit_ids = tool.scm().commit_ids_from_commitish_arguments(args) - if len(commit_ids) > 10: # We could lower this limit, 10 is too many for one bug as-is. - error("webkit-patch does not support attaching %s at once. Are you sure you passed the right commit range?" % (pluralize("patch", len(commit_ids)))) - - have_obsoleted_patches = set() - for commit_id in commit_ids: - commit_message = tool.scm().commit_message_for_local_commit(commit_id) - - # Prefer --bug-id=, then a bug url in the commit message, then a bug url in the entire commit diff (i.e. ChangeLogs). - bug_id = options.bug_id or parse_bug_id(commit_message.message()) or parse_bug_id(tool.scm().create_patch_from_local_commit(commit_id)) - if not bug_id: - log("Skipping %s: No bug id found in commit or specified with --bug-id." % commit_id) - continue - - if options.obsolete_patches and bug_id not in have_obsoleted_patches: - state = { "bug_id": bug_id } - steps.ObsoletePatches(tool, options).run(state) - have_obsoleted_patches.add(bug_id) - - diff_file = self._diff_file_for_commit(tool, commit_id) - description = options.description or commit_message.description(lstrip=True, strip_url=True) - comment_text = self._comment_text_for_commit(options, commit_message, tool, commit_id) - tool.bugs.add_patch_to_bug(bug_id, diff_file, description, comment_text, mark_for_review=options.review, mark_for_commit_queue=options.request_commit) - - -class MarkBugFixed(AbstractDeclarativeCommand): - name = "mark-bug-fixed" - help_text = "Mark the specified bug as fixed" - argument_names = "[SVN_REVISION]" - def __init__(self): - options = [ - make_option("--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."), - make_option("--comment", action="store", type="string", dest="comment", help="Text to include in bug comment."), - make_option("--open", action="store_true", default=False, dest="open_bug", help="Open bug in default web browser (Mac only)."), - make_option("--update-only", action="store_true", default=False, dest="update_only", help="Add comment to the bug, but do not close it."), - ] - AbstractDeclarativeCommand.__init__(self, options=options) - - def _fetch_commit_log(self, tool, svn_revision): - if not svn_revision: - return tool.scm().last_svn_commit_log() - return tool.scm().svn_commit_log(svn_revision) - - def _determine_bug_id_and_svn_revision(self, tool, bug_id, svn_revision): - commit_log = self._fetch_commit_log(tool, svn_revision) - - if not bug_id: - bug_id = parse_bug_id(commit_log) - - if not svn_revision: - match = re.search("^r(?P<svn_revision>\d+) \|", commit_log, re.MULTILINE) - if match: - svn_revision = match.group('svn_revision') - - if not bug_id or not svn_revision: - not_found = [] - if not bug_id: - not_found.append("bug id") - if not svn_revision: - not_found.append("svn revision") - error("Could not find %s on command-line or in %s." - % (" or ".join(not_found), "r%s" % svn_revision if svn_revision else "last commit")) - - return (bug_id, svn_revision) - - def execute(self, options, args, tool): - bug_id = options.bug_id - - svn_revision = args and args[0] - if svn_revision: - if re.match("^r[0-9]+$", svn_revision, re.IGNORECASE): - svn_revision = svn_revision[1:] - if not re.match("^[0-9]+$", svn_revision): - error("Invalid svn revision: '%s'" % svn_revision) - - needs_prompt = False - if not bug_id or not svn_revision: - needs_prompt = True - (bug_id, svn_revision) = self._determine_bug_id_and_svn_revision(tool, bug_id, svn_revision) - - log("Bug: <%s> %s" % (tool.bugs.bug_url_for_bug_id(bug_id), tool.bugs.fetch_bug_dictionary(bug_id)["title"])) - log("Revision: %s" % svn_revision) - - if options.open_bug: - tool.user.open_url(tool.bugs.bug_url_for_bug_id(bug_id)) - - if needs_prompt: - if not tool.user.confirm("Is this correct?"): - exit(1) - - bug_comment = bug_comment_from_svn_revision(svn_revision) - if options.comment: - bug_comment = "%s\n\n%s" % (options.comment, bug_comment) - - if options.update_only: - log("Adding comment to Bug %s." % bug_id) - tool.bugs.post_comment_to_bug(bug_id, bug_comment) - else: - log("Adding comment to Bug %s and marking as Resolved/Fixed." % bug_id) - tool.bugs.close_bug_as_fixed(bug_id, bug_comment) - - -# FIXME: Requires unit test. Blocking issue: too complex for now. -class CreateBug(AbstractDeclarativeCommand): - name = "create-bug" - help_text = "Create a bug from local changes or local commits" - argument_names = "[COMMITISH]" - - def __init__(self): - options = [ - steps.Options.cc, - steps.Options.component, - make_option("--no-prompt", action="store_false", dest="prompt", default=True, help="Do not prompt for bug title and comment; use commit log instead."), - make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."), - make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."), - ] - AbstractDeclarativeCommand.__init__(self, options=options) - - def create_bug_from_commit(self, options, args, tool): - commit_ids = tool.scm().commit_ids_from_commitish_arguments(args) - if len(commit_ids) > 3: - error("Are you sure you want to create one bug with %s patches?" % len(commit_ids)) - - commit_id = commit_ids[0] - - bug_title = "" - comment_text = "" - if options.prompt: - (bug_title, comment_text) = self.prompt_for_bug_title_and_comment() - else: - commit_message = tool.scm().commit_message_for_local_commit(commit_id) - bug_title = commit_message.description(lstrip=True, strip_url=True) - comment_text = commit_message.body(lstrip=True) - comment_text += "---\n" - comment_text += tool.scm().files_changed_summary_for_commit(commit_id) - - diff = tool.scm().create_patch_from_local_commit(commit_id) - diff_file = StringIO.StringIO(diff) # create_bug expects a file-like object - bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff_file, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit) - - if bug_id and len(commit_ids) > 1: - options.bug_id = bug_id - options.obsolete_patches = False - # FIXME: We should pass through --no-comment switch as well. - PostCommits.execute(self, options, commit_ids[1:], tool) - - def create_bug_from_patch(self, options, args, tool): - bug_title = "" - comment_text = "" - if options.prompt: - (bug_title, comment_text) = self.prompt_for_bug_title_and_comment() - else: - commit_message = tool.scm().commit_message_for_this_commit() - bug_title = commit_message.description(lstrip=True, strip_url=True) - comment_text = commit_message.body(lstrip=True) - - diff = tool.scm().create_patch() - diff_file = StringIO.StringIO(diff) # create_bug expects a file-like object - bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff_file, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit) - - def prompt_for_bug_title_and_comment(self): - bug_title = User.prompt("Bug title: ") - print "Bug comment (hit ^D on blank line to end):" - lines = sys.stdin.readlines() - try: - sys.stdin.seek(0, os.SEEK_END) - except IOError: - # Cygwin raises an Illegal Seek (errno 29) exception when the above - # seek() call is made. Ignoring it seems to cause no harm. - # FIXME: Figure out a way to get avoid the exception in the first - # place. - pass - comment_text = "".join(lines) - return (bug_title, comment_text) - - def execute(self, options, args, tool): - if len(args): - if (not tool.scm().supports_local_commits()): - error("Extra arguments not supported; patch is taken from working directory.") - self.create_bug_from_commit(options, args, tool) - else: - self.create_bug_from_patch(options, args, tool) diff --git a/WebKitTools/Scripts/webkitpy/commands/upload_unittest.py b/WebKitTools/Scripts/webkitpy/commands/upload_unittest.py deleted file mode 100644 index 7fa8797..0000000 --- a/WebKitTools/Scripts/webkitpy/commands/upload_unittest.py +++ /dev/null @@ -1,87 +0,0 @@ -# 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. - -from webkitpy.commands.commandtest import CommandsTest -from webkitpy.commands.upload import * -from webkitpy.mock import Mock -from webkitpy.mock_bugzillatool import MockBugzillaTool - -class UploadCommandsTest(CommandsTest): - def test_commit_message_for_current_diff(self): - tool = MockBugzillaTool() - mock_commit_message_for_this_commit = Mock() - mock_commit_message_for_this_commit.message = lambda: "Mock message" - tool._scm.commit_message_for_this_commit = lambda: mock_commit_message_for_this_commit - expected_stdout = "Mock message\n" - self.assert_execute_outputs(CommitMessageForCurrentDiff(), [], expected_stdout=expected_stdout, tool=tool) - - def test_clean_pending_commit(self): - self.assert_execute_outputs(CleanPendingCommit(), []) - - def test_assign_to_committer(self): - tool = MockBugzillaTool() - expected_stderr = "Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)\nBug 77 is already assigned to foo@foo.com (None).\nBug 76 has no non-obsolete patches, ignoring.\n" - self.assert_execute_outputs(AssignToCommitter(), [], expected_stderr=expected_stderr, tool=tool) - tool.bugs.reassign_bug.assert_called_with(42, "eric@webkit.org", "Attachment 128 was posted by a committer and has review+, assigning to Eric Seidel for commit.") - - def test_obsolete_attachments(self): - expected_stderr = "Obsoleting 2 old patches on bug 42\n" - self.assert_execute_outputs(ObsoleteAttachments(), [42], expected_stderr=expected_stderr) - - def test_post(self): - expected_stderr = "Running check-webkit-style\nObsoleting 2 old patches on bug 42\n" - self.assert_execute_outputs(Post(), [42], expected_stderr=expected_stderr) - - def test_post(self): - expected_stderr = "Obsoleting 2 old patches on bug 42\n" - self.assert_execute_outputs(LandSafely(), [42], expected_stderr=expected_stderr) - - def test_prepare_diff_with_arg(self): - self.assert_execute_outputs(Prepare(), [42]) - - def test_prepare(self): - self.assert_execute_outputs(Prepare(), []) - - def test_upload(self): - expected_stderr = "Running check-webkit-style\nObsoleting 2 old patches on bug 42\nMOCK: user.open_url: http://example.com/42\n" - self.assert_execute_outputs(Upload(), [42], expected_stderr=expected_stderr) - - def test_mark_bug_fixed(self): - tool = MockBugzillaTool() - tool._scm.last_svn_commit_log = lambda: "r9876 |" - options = Mock() - options.bug_id = 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 -Adding comment to Bug 42. -""" - self.assert_execute_outputs(MarkBugFixed(), [], expected_stderr=expected_stderr, tool=tool, options=options) - - def test_edit_changelog(self): - self.assert_execute_outputs(EditChangeLogs(), []) |