diff options
Diffstat (limited to 'Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py')
-rw-r--r-- | Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py new file mode 100644 index 000000000..338149b6d --- /dev/null +++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py @@ -0,0 +1,209 @@ +# 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.common.config.committers import CommitterList +from webkitpy.common.config.ports import WebKitPort +from webkitpy.common.system.deprecated_logging import error, log +from webkitpy.common.system.executive import ScriptError +from webkitpy.tool.bot.expectedfailures import ExpectedFailures +from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader +from webkitpy.tool.bot.queueengine import QueueEngine +from webkitpy.tool.bot.earlywarningsystemtask import EarlyWarningSystemTask, EarlyWarningSystemTaskDelegate, UnableToApplyPatch +from webkitpy.tool.commands.queues import AbstractReviewQueue + + +class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDelegate): + _build_style = "release" + # FIXME: Switch _run_tests from opt-in to opt-out once more bots are ready to run tests. + _run_tests = False + + def __init__(self): + AbstractReviewQueue.__init__(self) + self.port = WebKitPort.port(self.port_name) + + def should_proceed_with_work_item(self, patch): + return True + + def begin_work_queue(self): + # FIXME: This violates abstraction + self._tool._deprecated_port = self.port + AbstractReviewQueue.begin_work_queue(self) + self._expected_failures = ExpectedFailures() + self._layout_test_results_reader = LayoutTestResultsReader(self._tool, self._log_directory()) + + def _failing_tests_message(self, task, patch): + results = task.results_from_patch_test_run(patch) + unexpected_failures = self._expected_failures.unexpected_failures_observed(results) + if not unexpected_failures: + return None + return "New failing tests:\n%s" % "\n".join(unexpected_failures) + + def _post_reject_message_on_bug(self, tool, patch, status_id, extra_message_text=None): + results_link = tool.status_server.results_url_for_status(status_id) + message = "Attachment %s did not pass %s (%s):\nOutput: %s" % (patch.id(), self.name, self.port_name, results_link) + # FIXME: We might want to add some text about rejecting from the commit-queue in + # the case where patch.commit_queue() isn't already set to '-'. + if self.watchers: + tool.bugs.add_cc_to_bug(patch.bug_id(), self.watchers) + tool.bugs.set_flag_on_attachment(patch.id(), "commit-queue", "-", message, extra_message_text) + + def review_patch(self, patch): + task = EarlyWarningSystemTask(self, patch, self._run_tests) + if not task.validate(): + self._did_error(patch, "%s did not process patch." % self.name) + return False + try: + return task.run() + except UnableToApplyPatch, e: + self._did_error(patch, "%s unable to apply patch." % self.name) + return False + except ScriptError, e: + self._post_reject_message_on_bug(self._tool, patch, task.failure_status_id, self._failing_tests_message(task, patch)) + results_archive = task.results_archive_from_patch_test_run(patch) + if results_archive: + self._upload_results_archive_for_patch(patch, results_archive) + self._did_fail(patch) + # FIXME: We're supposed to be able to raise e again here and have + # one of our base classes mark the patch as fail, but there seems + # to be an issue with the exit_code. + return False + + # EarlyWarningSystemDelegate methods + + def parent_command(self): + return self.name + + def run_command(self, command): + self.run_webkit_patch(command + [self.port.flag()]) + + def command_passed(self, message, patch): + pass + + def command_failed(self, message, script_error, patch): + failure_log = self._log_from_script_error_for_upload(script_error) + return self._update_status(message, patch=patch, results_file=failure_log) + + def expected_failures(self): + return self._expected_failures + + def layout_test_results(self): + return self._layout_test_results_reader.results() + + def archive_last_layout_test_results(self, patch): + return self._layout_test_results_reader.archive(patch) + + def build_style(self): + return self._build_style + + def refetch_patch(self, patch): + return self._tool.bugs.fetch_attachment(patch.id()) + + def report_flaky_tests(self, patch, flaky_test_results, results_archive): + pass + + # StepSequenceErrorHandler methods + + @classmethod + def handle_script_error(cls, tool, state, script_error): + # FIXME: Why does this not exit(1) like the superclass does? + log(script_error.message_with_output()) + + +class GtkEWS(AbstractEarlyWarningSystem): + name = "gtk-ews" + port_name = "gtk" + watchers = AbstractEarlyWarningSystem.watchers + [ + "gns@gnome.org", + "xan.lopez@gmail.com", + ] + + +class EflEWS(AbstractEarlyWarningSystem): + name = "efl-ews" + port_name = "efl" + watchers = AbstractEarlyWarningSystem.watchers + [ + "leandro@profusion.mobi", + "antognolli@profusion.mobi", + "lucas.demarchi@profusion.mobi", + "gyuyoung.kim@samsung.com", + ] + + +class QtEWS(AbstractEarlyWarningSystem): + name = "qt-ews" + port_name = "qt" + + +class WinEWS(AbstractEarlyWarningSystem): + name = "win-ews" + port_name = "win" + # Use debug, the Apple Win port fails to link Release on 32-bit Windows. + # https://bugs.webkit.org/show_bug.cgi?id=39197 + _build_style = "debug" + + +class AbstractChromiumEWS(AbstractEarlyWarningSystem): + port_name = "chromium" + watchers = AbstractEarlyWarningSystem.watchers + [ + "dglazkov@chromium.org", + ] + + +class ChromiumLinuxEWS(AbstractChromiumEWS): + # FIXME: We should rename this command to cr-linux-ews, but that requires + # a database migration. :( + name = "chromium-ews" + port_name = "chromium-xvfb" + _run_tests = True + + +class ChromiumWindowsEWS(AbstractChromiumEWS): + name = "cr-win-ews" + + +# 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 process_work_item(self, patch): + if not patch.attacher() or not patch.attacher().can_commit: + self._did_error(patch, "%s cannot process patches from non-committers :(" % self.name) + return False + return AbstractEarlyWarningSystem.process_work_item(self, patch) + + +# FIXME: Inheriting from AbstractCommitterOnlyEWS is kinda a hack, but it +# happens to work because AbstractChromiumEWS and AbstractCommitterOnlyEWS +# provide disjoint sets of functionality, and Python is otherwise smart +# enough to handle the diamond inheritance. +class ChromiumMacEWS(AbstractChromiumEWS, AbstractCommitterOnlyEWS): + name = "cr-mac-ews" + + +class MacEWS(AbstractCommitterOnlyEWS): + name = "mac-ews" + port_name = "mac" |