1 # Copyright (c) 2009 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 from webkitpy.common.config.committers import CommitterList
30 from webkitpy.common.config.ports import WebKitPort
31 from webkitpy.common.system.deprecated_logging import error, log
32 from webkitpy.common.system.executive import ScriptError
33 from webkitpy.tool.bot.expectedfailures import ExpectedFailures
34 from webkitpy.tool.bot.layouttestresultsreader import LayoutTestResultsReader
35 from webkitpy.tool.bot.queueengine import QueueEngine
36 from webkitpy.tool.bot.earlywarningsystemtask import EarlyWarningSystemTask, EarlyWarningSystemTaskDelegate, UnableToApplyPatch
37 from webkitpy.tool.commands.queues import AbstractReviewQueue
40 class AbstractEarlyWarningSystem(AbstractReviewQueue, EarlyWarningSystemTaskDelegate):
41 _build_style = "release"
42 # FIXME: Switch _run_tests from opt-in to opt-out once more bots are ready to run tests.
46 AbstractReviewQueue.__init__(self)
47 self.port = WebKitPort.port(self.port_name)
49 def should_proceed_with_work_item(self, patch):
52 def begin_work_queue(self):
53 # FIXME: This violates abstraction
54 self._tool._port = self.port
55 AbstractReviewQueue.begin_work_queue(self)
56 self._expected_failures = ExpectedFailures()
57 self._layout_test_results_reader = LayoutTestResultsReader(self._tool, self._log_directory())
59 def _failing_tests_message(self, task, patch):
60 results = task.results_from_patch_test_run(patch)
61 unexpected_failures = self._expected_failures.unexpected_failures_observed(results)
62 if not unexpected_failures:
64 return "New failing tests:\n%s" % "\n".join(unexpected_failures)
66 def _post_reject_message_on_bug(self, tool, patch, status_id, extra_message_text=None):
67 results_link = tool.status_server.results_url_for_status(status_id)
68 message = "Attachment %s did not pass %s (%s):\nOutput: %s" % (patch.id(), self.name, self.port_name, results_link)
69 # FIXME: We might want to add some text about rejecting from the commit-queue in
70 # the case where patch.commit_queue() isn't already set to '-'.
72 tool.bugs.add_cc_to_bug(patch.bug_id(), self.watchers)
73 tool.bugs.set_flag_on_attachment(patch.id(), "commit-queue", "-", message, extra_message_text)
75 def review_patch(self, patch):
76 task = EarlyWarningSystemTask(self, patch, self._run_tests)
77 if not task.validate():
78 self._did_error(patch, "%s did not process patch." % self.name)
82 except UnableToApplyPatch, e:
83 self._did_error(patch, "%s unable to apply patch." % self.name)
85 except ScriptError, e:
86 self._post_reject_message_on_bug(self._tool, patch, task.failure_status_id, self._failing_tests_message(task, patch))
87 results_archive = task.results_archive_from_patch_test_run(patch)
89 self._upload_results_archive_for_patch(patch, results_archive)
91 # FIXME: We're supposed to be able to raise e again here and have
92 # one of our base classes mark the patch as fail, but there seems
93 # to be an issue with the exit_code.
96 # EarlyWarningSystemDelegate methods
98 def parent_command(self):
101 def run_command(self, command):
102 self.run_webkit_patch(command + [self.port.flag()])
104 def command_passed(self, message, patch):
107 def command_failed(self, message, script_error, patch):
108 failure_log = self._log_from_script_error_for_upload(script_error)
109 return self._update_status(message, patch=patch, results_file=failure_log)
111 def expected_failures(self):
112 return self._expected_failures
114 def layout_test_results(self):
115 return self._layout_test_results_reader.results()
117 def archive_last_layout_test_results(self, patch):
118 return self._layout_test_results_reader.archive(patch)
120 def build_style(self):
121 return self._build_style
123 def refetch_patch(self, patch):
124 return self._tool.bugs.fetch_attachment(patch.id())
126 def report_flaky_tests(self, patch, flaky_test_results, results_archive):
129 # StepSequenceErrorHandler methods
132 def handle_script_error(cls, tool, state, script_error):
133 # FIXME: Why does this not exit(1) like the superclass does?
134 log(script_error.message_with_output())
137 class GtkEWS(AbstractEarlyWarningSystem):
140 watchers = AbstractEarlyWarningSystem.watchers + [
142 "xan.lopez@gmail.com",
146 class EflEWS(AbstractEarlyWarningSystem):
149 watchers = AbstractEarlyWarningSystem.watchers + [
150 "leandro@profusion.mobi",
151 "antognolli@profusion.mobi",
152 "lucas.demarchi@profusion.mobi",
153 "gyuyoung.kim@samsung.com",
157 class QtEWS(AbstractEarlyWarningSystem):
162 class WinEWS(AbstractEarlyWarningSystem):
165 # Use debug, the Apple Win port fails to link Release on 32-bit Windows.
166 # https://bugs.webkit.org/show_bug.cgi?id=39197
167 _build_style = "debug"
170 class AbstractChromiumEWS(AbstractEarlyWarningSystem):
171 port_name = "chromium"
172 watchers = AbstractEarlyWarningSystem.watchers + [
173 "dglazkov@chromium.org",
177 class ChromiumLinuxEWS(AbstractChromiumEWS):
178 # FIXME: We should rename this command to cr-linux-ews, but that requires
179 # a database migration. :(
180 name = "chromium-ews"
181 port_name = "chromium-xvfb"
185 class ChromiumWindowsEWS(AbstractChromiumEWS):
189 # For platforms that we can't run inside a VM (like Mac OS X), we require
190 # patches to be uploaded by committers, who are generally trustworthy folk. :)
191 class AbstractCommitterOnlyEWS(AbstractEarlyWarningSystem):
192 def process_work_item(self, patch):
193 if not patch.attacher() or not patch.attacher().can_commit:
194 self._did_error(patch, "%s cannot process patches from non-committers :(" % self.name)
196 return AbstractEarlyWarningSystem.process_work_item(self, patch)
199 # FIXME: Inheriting from AbstractCommitterOnlyEWS is kinda a hack, but it
200 # happens to work because AbstractChromiumEWS and AbstractCommitterOnlyEWS
201 # provide disjoint sets of functionality, and Python is otherwise smart
202 # enough to handle the diamond inheritance.
203 class ChromiumMacEWS(AbstractChromiumEWS, AbstractCommitterOnlyEWS):
207 class MacEWS(AbstractCommitterOnlyEWS):