1# Copyright (c) 2009 Google Inc. All rights reserved. 2# 3# Redistribution and use in source and binary forms, with or without 4# modification, are permitted provided that the following conditions are 5# met: 6# 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 12# distribution. 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. 16# 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. 28 29from webkitpy.tool.commands.queues import AbstractReviewQueue 30from webkitpy.common.config.committers import CommitterList 31from webkitpy.common.config.ports import WebKitPort 32from webkitpy.common.system.executive import ScriptError 33from webkitpy.tool.bot.queueengine import QueueEngine 34 35 36class AbstractEarlyWarningSystem(AbstractReviewQueue): 37 _build_style = "release" 38 39 def __init__(self): 40 AbstractReviewQueue.__init__(self) 41 self.port = WebKitPort.port(self.port_name) 42 43 def should_proceed_with_work_item(self, patch): 44 return True 45 46 def _can_build(self): 47 try: 48 self.run_webkit_patch([ 49 "build", 50 self.port.flag(), 51 "--build-style=%s" % self._build_style, 52 "--force-clean", 53 "--no-update"]) 54 return True 55 except ScriptError, e: 56 failure_log = self._log_from_script_error_for_upload(e) 57 self._update_status("Unable to perform a build", results_file=failure_log) 58 return False 59 60 def _build(self, patch, first_run=False): 61 try: 62 args = [ 63 "build-attachment", 64 self.port.flag(), 65 "--build", 66 "--build-style=%s" % self._build_style, 67 "--force-clean", 68 "--quiet", 69 "--non-interactive", 70 patch.id()] 71 if not first_run: 72 # See commit-queue for an explanation of what we're doing here. 73 args.append("--no-update") 74 args.append("--parent-command=%s" % self.name) 75 self.run_webkit_patch(args) 76 return True 77 except ScriptError, e: 78 if first_run: 79 return False 80 raise 81 82 def review_patch(self, patch): 83 if patch.is_obsolete(): 84 self._did_error(patch, "%s does not process obsolete patches." % self.name) 85 return False 86 87 if patch.bug().is_closed(): 88 self._did_error(patch, "%s does not process patches on closed bugs." % self.name) 89 return False 90 91 if not self._build(patch, first_run=True): 92 if not self._can_build(): 93 return False 94 self._build(patch) 95 return True 96 97 @classmethod 98 def handle_script_error(cls, tool, state, script_error): 99 is_svn_apply = script_error.command_name() == "svn-apply" 100 status_id = cls._update_status_for_script_error(tool, state, script_error, is_error=is_svn_apply) 101 if is_svn_apply: 102 QueueEngine.exit_after_handled_error(script_error) 103 results_link = tool.status_server.results_url_for_status(status_id) 104 message = "Attachment %s did not build on %s:\nBuild output: %s" % (state["patch"].id(), cls.port_name, results_link) 105 tool.bugs.post_comment_to_bug(state["patch"].bug_id(), message, cc=cls.watchers) 106 exit(1) 107 108 109class GtkEWS(AbstractEarlyWarningSystem): 110 name = "gtk-ews" 111 port_name = "gtk" 112 watchers = AbstractEarlyWarningSystem.watchers + [ 113 "gns@gnome.org", 114 "xan.lopez@gmail.com", 115 ] 116 117 118class EflEWS(AbstractEarlyWarningSystem): 119 name = "efl-ews" 120 port_name = "efl" 121 watchers = AbstractEarlyWarningSystem.watchers + [ 122 "leandro@profusion.mobi", 123 "antognolli@profusion.mobi", 124 "lucas.demarchi@profusion.mobi", 125 "gyuyoung.kim@samsung.com", 126 ] 127 128 129class QtEWS(AbstractEarlyWarningSystem): 130 name = "qt-ews" 131 port_name = "qt" 132 133 134class WinEWS(AbstractEarlyWarningSystem): 135 name = "win-ews" 136 port_name = "win" 137 # Use debug, the Apple Win port fails to link Release on 32-bit Windows. 138 # https://bugs.webkit.org/show_bug.cgi?id=39197 139 _build_style = "debug" 140 141 142class AbstractChromiumEWS(AbstractEarlyWarningSystem): 143 port_name = "chromium" 144 watchers = AbstractEarlyWarningSystem.watchers + [ 145 "dglazkov@chromium.org", 146 ] 147 148 149class ChromiumLinuxEWS(AbstractChromiumEWS): 150 # FIXME: We should rename this command to cr-linux-ews, but that requires 151 # a database migration. :( 152 name = "chromium-ews" 153 154 155class ChromiumWindowsEWS(AbstractChromiumEWS): 156 name = "cr-win-ews" 157 158 159# For platforms that we can't run inside a VM (like Mac OS X), we require 160# patches to be uploaded by committers, who are generally trustworthy folk. :) 161class AbstractCommitterOnlyEWS(AbstractEarlyWarningSystem): 162 def __init__(self, committers=CommitterList()): 163 AbstractEarlyWarningSystem.__init__(self) 164 self._committers = committers 165 166 def process_work_item(self, patch): 167 if not self._committers.committer_by_email(patch.attacher_email()): 168 self._did_error(patch, "%s cannot process patches from non-committers :(" % self.name) 169 return False 170 return AbstractEarlyWarningSystem.process_work_item(self, patch) 171 172 173# FIXME: Inheriting from AbstractCommitterOnlyEWS is kinda a hack, but it 174# happens to work because AbstractChromiumEWS and AbstractCommitterOnlyEWS 175# provide disjoint sets of functionality, and Python is otherwise smart 176# enough to handle the diamond inheritance. 177class ChromiumMacEWS(AbstractChromiumEWS, AbstractCommitterOnlyEWS): 178 name = "cr-mac-ews" 179 180 181class MacEWS(AbstractCommitterOnlyEWS): 182 name = "mac-ews" 183 port_name = "mac" 184