summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/webkitpy/tool/commands
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-05 14:36:32 +0100
committerBen Murdoch <benm@google.com>2011-05-10 15:38:30 +0100
commitf05b935882198ccf7d81675736e3aeb089c5113a (patch)
tree4ea0ca838d9ef1b15cf17ddb3928efb427c7e5a1 /WebKitTools/Scripts/webkitpy/tool/commands
parent60fbdcc62bced8db2cb1fd233cc4d1e4ea17db1b (diff)
downloadexternal_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.zip
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.gz
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.bz2
Merge WebKit at r74534: Initial merge by git.
Change-Id: I6ccd1154fa1b19c2ec2a66878eb675738735f1eb
Diffstat (limited to 'WebKitTools/Scripts/webkitpy/tool/commands')
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/__init__.py12
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py43
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/commandtest.py48
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html180
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js144
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css292
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js498
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js158
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js94
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/download.py394
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/download_unittest.py190
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py182
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py132
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/openbugs.py63
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/openbugs_unittest.py50
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/prettydiff.py38
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/queries.py393
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py90
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/queues.py417
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py378
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/queuestest.py95
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/rebaseline.py114
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py38
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py268
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py88
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot.py106
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py57
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/stepsequence.py83
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/upload.py483
-rw-r--r--WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py117
30 files changed, 0 insertions, 5245 deletions
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py b/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py
deleted file mode 100644
index d2aa503..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Required for Python to search this directory for module files
-
-from webkitpy.tool.commands.download import *
-from webkitpy.tool.commands.earlywarningsystem import *
-from webkitpy.tool.commands.openbugs import OpenBugs
-from webkitpy.tool.commands.prettydiff import PrettyDiff
-from webkitpy.tool.commands.queries import *
-from webkitpy.tool.commands.queues import *
-from webkitpy.tool.commands.rebaseline import Rebaseline
-from webkitpy.tool.commands.rebaselineserver import RebaselineServer
-from webkitpy.tool.commands.sheriffbot import *
-from webkitpy.tool.commands.upload import *
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py b/WebKitTools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py
deleted file mode 100644
index fc5a794..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/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.tool.commands.stepsequence import StepSequence
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-
-
-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/tool/commands/commandtest.py b/WebKitTools/Scripts/webkitpy/tool/commands/commandtest.py
deleted file mode 100644
index adc6d81..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/commandtest.py
+++ /dev/null
@@ -1,48 +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.common.system.outputcapture import OutputCapture
-from webkitpy.tool.mocktool import MockOptions, MockTool
-
-class CommandsTest(unittest.TestCase):
- def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", options=MockOptions(), tool=MockTool()):
- options.blocks = True
- options.cc = 'MOCK cc'
- options.component = 'MOCK component'
- options.confirm = True
- options.email = 'MOCK email'
- options.git_commit = 'MOCK git commit'
- options.obsolete_patches = True
- options.open_bug = True
- options.port = 'MOCK port'
- options.quiet = True
- options.reviewer = 'MOCK reviewer'
- 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/tool/commands/data/rebaselineserver/index.html b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
deleted file mode 100644
index 5b58301..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
+++ /dev/null
@@ -1,180 +0,0 @@
-<!DOCTYPE html>
-<!--
- 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.
--->
-<html>
-<head>
- <title>Layout Test Rebaseline Server</title>
- <link rel="stylesheet" href="/main.css" type="text/css">
- <script src="/util.js"></script>
- <script src="/loupe.js"></script>
- <script src="/main.js"></script>
- <script src="/queue.js"></script>
-</head>
-<body class="loading">
-
-<pre id="log" style="display: none"></pre>
-<div id="queue" style="display: none">
- Queue:
- <select id="queue-select" size="10"></select>
- <button id="remove-queue-selection">Remove selection</button>
- <button id="rebaseline-queue">Rebaseline queue</button>
-</div>
-
-<div id="header">
- <div id="controls">
- <!-- Add a dummy <select> node so that this lines up with the text on the left -->
- <select style="visibility: hidden"></select>
- <span id="toggle-log" class="link">Log</span>
- <span class="divider">|</span>
- <a href="/quitquitquit">Exit</a>
- </div>
-
- <span id="selectors">
- <label>
- Failure type:
- <select id="failure-type-selector"></select>
- </label>
-
- <label>
- Directory:
- <select id="directory-selector"></select>
- </label>
-
- <label>
- Test:
- <select id="test-selector"></select>
- </label>
- </span>
-
- <a id="test-link" target="_blank">View test</a>
-
- <span id="nav-buttons">
- <button id="previous-test">&laquo;</button>
- <span id="test-index"></span> of <span id="test-count"></span>
- <button id="next-test">&raquo;</button>
- </span>
-</div>
-
-<table id="test-output">
- <thead id="labels">
- <tr>
- <th>Expected</th>
- <th>Actual</th>
- <th>Diff</th>
- </tr>
- </thead>
- <tbody id="image-outputs" style="display: none">
- <tr>
- <td colspan="3"><h2>Image</h2></td>
- </tr>
- <tr>
- <td><img id="expected-image"></td>
- <td><img id="actual-image"></td>
- <td>
- <canvas id="diff-canvas" width="800" height="600"></canvas>
- <div id="diff-checksum" style="display: none">
- <h3>Checksum mismatch</h3>
- Expected: <span id="expected-checksum"></span><br>
- Actual: <span id="actual-checksum"></span>
- </div>
- </td>
- </tr>
- </tbody>
- <tbody id="text-outputs" style="display: none">
- <tr>
- <td colspan="3"><h2>Text</h2></td>
- </tr>
- <tr>
- <td><pre id="expected-text"></pre></td>
- <td><pre id="actual-text"></pre></td>
- <td><pre id="diff-text"><pre></td>
- </tr>
- </tbody>
-</table>
-
-<div id="footer">
- <label>State: <span id="state"></span></label>
- <label>Existing baselines: <span id="current-baselines"></span></label>
- <label>
- Baseline target:
- <select id="baseline-target"></select>
- </label>
- <label>
- Move current baselines to:
- <select id="baseline-move-to">
- <option value="none">Nowhere (replace)</option>
- </select>
- </label>
-
- <!-- Add a dummy <button> node so that this lines up with the text on the right -->
- <button style="visibility: hidden; padding-left: 0; padding-right: 0;"></button>
-
- <div id="action-buttons">
- <span id="toggle-queue" class="link">Queue</span>
- <button id="add-to-rebaseline-queue">Add to rebaseline queue</button>
- </div>
-</div>
-
-<table id="loupe" style="display: none">
- <tr>
- <td colspan="3" id="loupe-info">
- <span id="loupe-close" class="link">Close</span>
- <label>Coordinate: <span id="loupe-coordinate"></span></label>
- </td>
- </tr>
- <tr>
- <td>
- <div class="loupe-container">
- <canvas id="expected-loupe" width="210" height="210"></canvas>
- <div class="center-highlight"></div>
- </div>
- </td>
- <td>
- <div class="loupe-container">
- <canvas id="actual-loupe" width="210" height="210"></canvas>
- <div class="center-highlight"></div>
- </div>
- </td>
- <td>
- <div class="loupe-container">
- <canvas id="diff-loupe" width="210" height="210"></canvas>
- <div class="center-highlight"></div>
- </div>
- </td>
- </tr>
- <tr id="loupe-colors">
- <td><label>Exp. color: <span id="expected-loupe-color"></span></label></td>
- <td><label>Actual color: <span id="actual-loupe-color"></span></label></td>
- <td><label>Diff color: <span id="diff-loupe-color"></span></label></td>
- </tr>
-</table>
-
-</body>
-</html>
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js
deleted file mode 100644
index 41f977a..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js
+++ /dev/null
@@ -1,144 +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.
- */
-
-var LOUPE_MAGNIFICATION_FACTOR = 10;
-
-function Loupe()
-{
- this._node = $('loupe');
- this._currentCornerX = -1;
- this._currentCornerY = -1;
-
- var self = this;
-
- function handleOutputClick(event) { self._handleOutputClick(event); }
- $('expected-image').addEventListener('click', handleOutputClick);
- $('actual-image').addEventListener('click', handleOutputClick);
- $('diff-canvas').addEventListener('click', handleOutputClick);
-
- function handleLoupeClick(event) { self._handleLoupeClick(event); }
- $('expected-loupe').addEventListener('click', handleLoupeClick);
- $('actual-loupe').addEventListener('click', handleLoupeClick);
- $('diff-loupe').addEventListener('click', handleLoupeClick);
-
- function hide(event) { self.hide(); }
- $('loupe-close').addEventListener('click', hide);
-}
-
-Loupe.prototype._handleOutputClick = function(event)
-{
- // The -1 compensates for the border around the image/canvas.
- this._showFor(event.offsetX - 1, event.offsetY - 1);
-};
-
-Loupe.prototype._handleLoupeClick = function(event)
-{
- var deltaX = Math.floor(event.offsetX/LOUPE_MAGNIFICATION_FACTOR);
- var deltaY = Math.floor(event.offsetY/LOUPE_MAGNIFICATION_FACTOR);
-
- this._showFor(
- this._currentCornerX + deltaX, this._currentCornerY + deltaY);
-}
-
-Loupe.prototype.hide = function()
-{
- this._node.style.display = 'none';
-};
-
-Loupe.prototype._showFor = function(x, y)
-{
- this._fillFromImage(x, y, 'expected', $('expected-image'));
- this._fillFromImage(x, y, 'actual', $('actual-image'));
- this._fillFromCanvas(x, y, 'diff', $('diff-canvas'));
-
- this._node.style.display = '';
-};
-
-Loupe.prototype._fillFromImage = function(x, y, type, sourceImage)
-{
- var tempCanvas = document.createElement('canvas');
- tempCanvas.width = sourceImage.width;
- tempCanvas.height = sourceImage.height;
- var tempContext = tempCanvas.getContext('2d');
-
- tempContext.drawImage(sourceImage, 0, 0);
-
- this._fillFromCanvas(x, y, type, tempCanvas);
-};
-
-Loupe.prototype._fillFromCanvas = function(x, y, type, canvas)
-{
- var context = canvas.getContext('2d');
- var sourceImageData =
- context.getImageData(0, 0, canvas.width, canvas.height);
-
- var targetCanvas = $(type + '-loupe');
- var targetContext = targetCanvas.getContext('2d');
- targetContext.fillStyle = 'rgba(255, 255, 255, 1)';
- targetContext.fillRect(0, 0, targetCanvas.width, targetCanvas.height);
-
- var sourceXOffset = (targetCanvas.width/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
- var sourceYOffset = (targetCanvas.height/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
-
- function readPixelComponent(x, y, component) {
- var offset = (y * sourceImageData.width + x) * 4 + component;
- return sourceImageData.data[offset];
- }
-
- for (var i = -sourceXOffset; i <= sourceXOffset; i++) {
- for (var j = -sourceYOffset; j <= sourceYOffset; j++) {
- var sourceX = x + i;
- var sourceY = y + j;
-
- var sourceR = readPixelComponent(sourceX, sourceY, 0);
- var sourceG = readPixelComponent(sourceX, sourceY, 1);
- var sourceB = readPixelComponent(sourceX, sourceY, 2);
- var sourceA = readPixelComponent(sourceX, sourceY, 3)/255;
- sourceA = Math.round(sourceA * 10)/10;
-
- var targetX = (i + sourceXOffset) * LOUPE_MAGNIFICATION_FACTOR;
- var targetY = (j + sourceYOffset) * LOUPE_MAGNIFICATION_FACTOR;
- var colorString =
- sourceR + ', ' + sourceG + ', ' + sourceB + ', ' + sourceA;
- targetContext.fillStyle = 'rgba(' + colorString + ')';
- targetContext.fillRect(
- targetX, targetY,
- LOUPE_MAGNIFICATION_FACTOR, LOUPE_MAGNIFICATION_FACTOR);
-
- if (i == 0 && j == 0) {
- $('loupe-coordinate').textContent = sourceX + ', ' + sourceY;
- $(type + '-loupe-color').textContent = colorString;
- }
- }
- }
-
- this._currentCornerX = x - sourceXOffset;
- this._currentCornerY = y - sourceYOffset;
-};
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
deleted file mode 100644
index 62afda6..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
+++ /dev/null
@@ -1,292 +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.
- */
-
-body {
- font-size: 12px;
- font-family: Helvetica, Arial, sans-serif;
- padding: 0;
- margin: 0;
-}
-
-.loading {
- opacity: 0.5;
-}
-
-div {
- margin: 0;
-}
-
-a, .link {
- color: #aaf;
- text-decoration: underline;
- cursor: pointer;
-}
-
-.link.selected {
- color: #fff;
- font-weight: bold;
- text-decoration: none;
-}
-
-#log,
-#queue {
- padding: .25em 0 0 .25em;
- position: absolute;
- right: 0;
- height: 200px;
- overflow: auto;
- background: #fff;
- -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .5);
-}
-
-#log {
- top: 2em;
- width: 500px;
-}
-
-#queue {
- bottom: 3em;
- width: 400px;
-}
-
-#queue-select {
- display: block;
- width: 390px;
-}
-
-#header,
-#footer {
- padding: .5em 1em;
- background: #333;
- color: #fff;
- -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
-}
-
-#header {
- margin-bottom: 1em;
-}
-
-#header .divider,
-#footer .divider {
- opacity: .3;
- padding: 0 .5em;
-}
-
-#header label,
-#footer label {
- padding-right: 1em;
- color: #ccc;
-}
-
-#test-link {
- margin-right: 1em;
-}
-
-#header label span,
-#footer label span {
- color: #fff;
- font-weight: bold;
-}
-
-#nav-buttons {
- white-space: nowrap;
-}
-
-#nav-buttons button {
- background: #fff;
- border: 0;
- border-radius: 10px;
-}
-
-#nav-buttons button:active {
- -webkit-box-shadow: 0 0 5px #33f inset;
- background: #aaa;
-}
-
-#nav-buttons button[disabled] {
- opacity: .5;
-}
-
-#controls {
- float: right;
-}
-
-#test-output {
- border-spacing: 0;
- border-collapse: collapse;
- margin: 0 auto;
- width: 100%;
-}
-
-#test-output td,
-#test-output th {
- padding: 0;
- vertical-align: top;
-}
-
-#image-outputs img,
-#image-outputs canvas,
-#image-outputs #diff-checksum {
- width: 800px;
- height: 600px;
- border: solid 1px #ddd;
- -webkit-user-select: none;
- -webkit-user-drag: none;
-}
-
-#image-outputs img,
-#image-outputs canvas {
- cursor: crosshair;
-}
-
-#image-outputs img.loading,
-#image-outputs canvas.loading {
- opacity: .5;
-}
-
-#image-outputs #actual-image {
- margin: 0 1em;
-}
-
-#test-output #labels th {
- text-align: center;
- color: #666;
-}
-
-#text-outputs pre {
- height: 600px;
- width: 800px;
- overflow: auto;
-}
-
-#test-output h2 {
- border-bottom: solid 1px #ccc;
- font-weight: bold;
- margin: 0;
- background: #eee;
-}
-
-#footer {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- margin-top: 1em;
-}
-
-#state.needs_rebaseline {
- color: yellow;
-}
-
-#state.rebaseline_failed {
- color: red;
-}
-
-#state.rebaseline_succeeded {
- color: green;
-}
-
-#state.in_queue {
- color: gray;
-}
-
-#action-buttons {
- float: right;
-}
-
-#action-buttons .link {
- margin-right: 1em;
-}
-
-#footer button {
- padding: 1em;
-}
-
-#loupe {
- -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, .5);
- position: absolute;
- width: 634px;
- top: 50%;
- left: 50%;
- margin-left: -151px;
- margin-top: -50px;
- background: #fff;
- border-spacing: 0;
- border-collapse: collapse;
-}
-
-#loupe td {
- padding: 0;
- border: solid 1px #ccc;
-}
-
-#loupe label {
- color: #999;
- padding-right: 1em;
-}
-
-#loupe span {
- color: #000;
- font-weight: bold;
-}
-
-#loupe canvas {
- cursor: crosshair;
-}
-
-#loupe #loupe-close {
- float: right;
-}
-
-#loupe #loupe-info {
- background: #eee;
- padding: .3em .5em;
-}
-
-#loupe #loupe-colors td {
- text-align: center;
-}
-
-#loupe .loupe-container {
- position: relative;
- width: 210px;
- height: 210px;
-}
-
-#loupe .center-highlight {
- position: absolute;
- width: 10px;
- height: 10px;
- top: 50%;
- left: 50%;
- margin-left: -5px;
- margin-top: -5px;
- outline: solid 1px #999;
-}
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
deleted file mode 100644
index 25f9146..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
+++ /dev/null
@@ -1,498 +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.
- */
-
-var ALL_DIRECTORY_PATH = '[all]';
-
-var STATE_NEEDS_REBASELINE = 'needs_rebaseline';
-var STATE_REBASELINE_FAILED = 'rebaseline_failed';
-var STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded';
-var STATE_IN_QUEUE = 'in_queue';
-var STATE_TO_DISPLAY_STATE = {};
-STATE_TO_DISPLAY_STATE[STATE_NEEDS_REBASELINE] = 'Needs rebaseline';
-STATE_TO_DISPLAY_STATE[STATE_REBASELINE_FAILED] = 'Rebaseline failed';
-STATE_TO_DISPLAY_STATE[STATE_REBASELINE_SUCCEEDED] = 'Rebaseline succeeded';
-STATE_TO_DISPLAY_STATE[STATE_IN_QUEUE] = 'In queue';
-
-var results;
-var testsByFailureType = {};
-var testsByDirectory = {};
-var selectedTests = [];
-var loupe;
-var queue;
-
-function main()
-{
- $('failure-type-selector').addEventListener('change', selectFailureType);
- $('directory-selector').addEventListener('change', selectDirectory);
- $('test-selector').addEventListener('change', selectTest);
- $('next-test').addEventListener('click', nextTest);
- $('previous-test').addEventListener('click', previousTest);
-
- $('toggle-log').addEventListener('click', function() { toggle('log'); });
-
- loupe = new Loupe();
- queue = new RebaselineQueue();
-
- document.addEventListener('keydown', function(event) {
- if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
- return;
- }
-
- switch (event.keyIdentifier) {
- case 'Left':
- event.preventDefault();
- previousTest();
- break;
- case 'Right':
- event.preventDefault();
- nextTest();
- break;
- case 'U+0051': // q
- queue.addCurrentTest();
- break;
- case 'U+0058': // x
- queue.removeCurrentTest();
- break;
- case 'U+0052': // r
- queue.rebaseline();
- break;
- }
- });
-
- loadText('/platforms.json', function(text) {
- var platforms = JSON.parse(text);
- platforms.platforms.forEach(function(platform) {
- var platformOption = document.createElement('option');
- platformOption.value = platform;
- platformOption.textContent = platform;
-
- var targetOption = platformOption.cloneNode(true);
- targetOption.selected = platform == platforms.defaultPlatform;
- $('baseline-target').appendChild(targetOption);
- $('baseline-move-to').appendChild(platformOption.cloneNode(true));
- });
- });
-
- loadText('/results.json', function(text) {
- results = JSON.parse(text);
- displayResults();
- });
-}
-
-/**
- * Groups test results by failure type.
- */
-function displayResults()
-{
- var failureTypeSelector = $('failure-type-selector');
- var failureTypes = [];
-
- for (var testName in results.tests) {
- var test = results.tests[testName];
- if (test.actual == 'PASS') {
- continue;
- }
- var failureType = test.actual + ' (expected ' + test.expected + ')';
- if (!(failureType in testsByFailureType)) {
- testsByFailureType[failureType] = [];
- failureTypes.push(failureType);
- }
- testsByFailureType[failureType].push(testName);
- }
-
- // Sort by number of failures
- failureTypes.sort(function(a, b) {
- return testsByFailureType[b].length - testsByFailureType[a].length;
- });
-
- for (var i = 0, failureType; failureType = failureTypes[i]; i++) {
- var failureTypeOption = document.createElement('option');
- failureTypeOption.value = failureType;
- failureTypeOption.textContent = failureType + ' - ' + testsByFailureType[failureType].length + ' tests';
- failureTypeSelector.appendChild(failureTypeOption);
- }
-
- selectFailureType();
-
- document.body.classList.remove('loading');
-}
-
-/**
- * For a given failure type, gets all the tests and groups them by directory
- * (populating the directory selector with them).
- */
-function selectFailureType()
-{
- var selectedFailureType = getSelectValue('failure-type-selector');
- var tests = testsByFailureType[selectedFailureType];
-
- testsByDirectory = {}
- var displayDirectoryNamesByDirectory = {};
- var directories = [];
-
- // Include a special option for all tests
- testsByDirectory[ALL_DIRECTORY_PATH] = tests;
- displayDirectoryNamesByDirectory[ALL_DIRECTORY_PATH] = 'all';
- directories.push(ALL_DIRECTORY_PATH);
-
- // Roll up tests by ancestor directories
- tests.forEach(function(test) {
- var pathPieces = test.split('/');
- var pathDirectories = pathPieces.slice(0, pathPieces.length -1);
- var ancestorDirectory = '';
-
- pathDirectories.forEach(function(pathDirectory, index) {
- ancestorDirectory += pathDirectory + '/';
- if (!(ancestorDirectory in testsByDirectory)) {
- testsByDirectory[ancestorDirectory] = [];
- var displayDirectoryName = new Array(index * 6).join('&nbsp;') + pathDirectory;
- displayDirectoryNamesByDirectory[ancestorDirectory] = displayDirectoryName;
- directories.push(ancestorDirectory);
- }
-
- testsByDirectory[ancestorDirectory].push(test);
- });
- });
-
- directories.sort();
-
- var directorySelector = $('directory-selector');
- directorySelector.innerHTML = '';
-
- directories.forEach(function(directory) {
- var directoryOption = document.createElement('option');
- directoryOption.value = directory;
- directoryOption.innerHTML =
- displayDirectoryNamesByDirectory[directory] + ' - ' +
- testsByDirectory[directory].length + ' tests';
- directorySelector.appendChild(directoryOption);
- });
-
- selectDirectory();
-}
-
-/**
- * For a given failure type and directory and failure type, gets all the tests
- * in that directory and populatest the test selector with them.
- */
-function selectDirectory()
-{
- var selectedDirectory = getSelectValue('directory-selector');
- selectedTests = testsByDirectory[selectedDirectory];
-
- selectedTests.sort();
-
- var testSelector = $('test-selector');
- testSelector.innerHTML = '';
-
- selectedTests.forEach(function(testName) {
- var testOption = document.createElement('option');
- testOption.value = testName;
- var testDisplayName = testName;
- if (testName.lastIndexOf(selectedDirectory) == 0) {
- testDisplayName = testName.substring(selectedDirectory.length);
- }
- testOption.innerHTML = '&nbsp;&nbsp;' + testDisplayName;
- testSelector.appendChild(testOption);
- });
-
- selectTest();
-}
-
-function getSelectedTest()
-{
- return getSelectValue('test-selector');
-}
-
-function selectTest()
-{
- var selectedTest = getSelectedTest();
-
- if (results.tests[selectedTest].actual.indexOf('IMAGE') != -1) {
- $('image-outputs').style.display = '';
- displayImageResults(selectedTest);
- } else {
- $('image-outputs').style.display = 'none';
- }
-
- if (results.tests[selectedTest].actual.indexOf('TEXT') != -1) {
- $('text-outputs').style.display = '';
- displayTextResults(selectedTest);
- } else {
- $('text-outputs').style.display = 'none';
- }
-
- var currentBaselines = $('current-baselines');
- currentBaselines.textContent = '';
- var baselines = results.tests[selectedTest].baselines;
- var testName = selectedTest.split('.').slice(0, -1).join('.');
- for (var platform in baselines) {
- if (currentBaselines.firstChild) {
- currentBaselines.appendChild(document.createTextNode('; '));
- }
- currentBaselines.appendChild(document.createTextNode(platform + ' ('));
- for (var i = 0, extension; extension = baselines[platform][i]; i++) {
- if (i != 0) {
- currentBaselines.appendChild(document.createTextNode(', '));
- }
- var link = document.createElement('a');
- var baselinePath = '';
- if (platform != 'base') {
- baselinePath += 'platform/' + platform + '/';
- }
- baselinePath += testName + '-expected' + extension;
- link.href = getTracUrl(baselinePath);
- if (extension == '.checksum') {
- link.textContent = 'chk';
- } else {
- link.textContent = extension.substring(1);
- }
- link.target = '_blank';
- currentBaselines.appendChild(link);
- }
- currentBaselines.appendChild(document.createTextNode(')'));
- }
-
- updateState();
- loupe.hide();
-
- prefetchNextImageTest();
-}
-
-function prefetchNextImageTest()
-{
- var testSelector = $('test-selector');
- if (testSelector.selectedIndex == testSelector.options.length - 1) {
- return;
- }
- var nextTest = testSelector.options[testSelector.selectedIndex + 1].value;
- if (results.tests[nextTest].actual.indexOf('IMAGE') != -1) {
- new Image().src = getTestResultUrl(nextTest, 'expected-image');
- new Image().src = getTestResultUrl(nextTest, 'actual-image');
- }
-}
-
-function updateState()
-{
- var testName = getSelectedTest();
- var testIndex = selectedTests.indexOf(testName);
- var testCount = selectedTests.length
- $('test-index').textContent = testIndex + 1;
- $('test-count').textContent = testCount;
-
- $('next-test').disabled = testIndex == testCount - 1;
- $('previous-test').disabled = testIndex == 0;
-
- $('test-link').href = getTracUrl(testName);
-
- var state = results.tests[testName].state;
- $('state').className = state;
- $('state').innerHTML = STATE_TO_DISPLAY_STATE[state];
-
- queue.updateState();
-}
-
-function getTestResultUrl(testName, mode)
-{
- return '/test_result?test=' + testName + '&mode=' + mode;
-}
-
-var currentExpectedImageTest;
-var currentActualImageTest;
-
-function displayImageResults(testName)
-{
- if (currentExpectedImageTest == currentActualImageTest
- && currentExpectedImageTest == testName) {
- return;
- }
-
- function displayImageResult(mode, callback) {
- var image = $(mode);
- image.className = 'loading';
- image.src = getTestResultUrl(testName, mode);
- image.onload = function() {
- image.className = '';
- callback();
- updateImageDiff();
- };
- }
-
- displayImageResult(
- 'expected-image',
- function() { currentExpectedImageTest = testName; });
- displayImageResult(
- 'actual-image',
- function() { currentActualImageTest = testName; });
-
- $('diff-canvas').className = 'loading';
- $('diff-canvas').style.display = '';
- $('diff-checksum').style.display = 'none';
-}
-
-/**
- * Computes a graphical a diff between the expected and actual images by
- * rendering each to a canvas, getting the image data, and comparing the RGBA
- * components of each pixel. The output is put into the diff canvas, with
- * identical pixels appearing at 12.5% opacity and different pixels being
- * highlighted in red.
- */
-function updateImageDiff() {
- if (currentExpectedImageTest != currentActualImageTest)
- return;
-
- var expectedImage = $('expected-image');
- var actualImage = $('actual-image');
-
- function getImageData(image) {
- var imageCanvas = document.createElement('canvas');
- imageCanvas.width = image.width;
- imageCanvas.height = image.height;
- imageCanvasContext = imageCanvas.getContext('2d');
-
- imageCanvasContext.fillStyle = 'rgba(255, 255, 255, 1)';
- imageCanvasContext.fillRect(
- 0, 0, image.width, image.height);
-
- imageCanvasContext.drawImage(image, 0, 0);
- return imageCanvasContext.getImageData(
- 0, 0, image.width, image.height);
- }
-
- var expectedImageData = getImageData(expectedImage);
- var actualImageData = getImageData(actualImage);
-
- var diffCanvas = $('diff-canvas');
- var diffCanvasContext = diffCanvas.getContext('2d');
- var diffImageData =
- diffCanvasContext.createImageData(diffCanvas.width, diffCanvas.height);
-
- // Avoiding property lookups for all these during the per-pixel loop below
- // provides a significant performance benefit.
- var expectedWidth = expectedImage.width;
- var expectedHeight = expectedImage.height;
- var expected = expectedImageData.data;
-
- var actualWidth = actualImage.width;
- var actual = actualImageData.data;
-
- var diffWidth = diffImageData.width;
- var diff = diffImageData.data;
-
- var hadDiff = false;
- for (var x = 0; x < expectedWidth; x++) {
- for (var y = 0; y < expectedHeight; y++) {
- var expectedOffset = (y * expectedWidth + x) * 4;
- var actualOffset = (y * actualWidth + x) * 4;
- var diffOffset = (y * diffWidth + x) * 4;
- if (expected[expectedOffset] != actual[actualOffset] ||
- expected[expectedOffset + 1] != actual[actualOffset + 1] ||
- expected[expectedOffset + 2] != actual[actualOffset + 2] ||
- expected[expectedOffset + 3] != actual[actualOffset + 3]) {
- hadDiff = true;
- diff[diffOffset] = 255;
- diff[diffOffset + 1] = 0;
- diff[diffOffset + 2] = 0;
- diff[diffOffset + 3] = 255;
- } else {
- diff[diffOffset] = expected[expectedOffset];
- diff[diffOffset + 1] = expected[expectedOffset + 1];
- diff[diffOffset + 2] = expected[expectedOffset + 2];
- diff[diffOffset + 3] = 32;
- }
- }
- }
-
- diffCanvasContext.putImageData(
- diffImageData,
- 0, 0,
- 0, 0,
- diffImageData.width, diffImageData.height);
- diffCanvas.className = '';
-
- if (!hadDiff) {
- diffCanvas.style.display = 'none';
- $('diff-checksum').style.display = '';
- loadTextResult(currentExpectedImageTest, 'expected-checksum');
- loadTextResult(currentExpectedImageTest, 'actual-checksum');
- }
-}
-
-function loadTextResult(testName, mode)
-{
- loadText(getTestResultUrl(testName, mode), function(text) {
- $(mode).textContent = text;
- });
-}
-
-function displayTextResults(testName)
-{
- loadTextResult(testName, 'expected-text');
- loadTextResult(testName, 'actual-text');
- loadTextResult(testName, 'diff-text');
-}
-
-function nextTest()
-{
- var testSelector = $('test-selector');
- var nextTestIndex = testSelector.selectedIndex + 1;
- while (true) {
- if (nextTestIndex == testSelector.options.length) {
- return;
- }
- if (testSelector.options[nextTestIndex].disabled) {
- nextTestIndex++;
- } else {
- testSelector.selectedIndex = nextTestIndex;
- selectTest();
- return;
- }
- }
-}
-
-function previousTest()
-{
- var testSelector = $('test-selector');
- var previousTestIndex = testSelector.selectedIndex - 1;
- while (true) {
- if (previousTestIndex == -1) {
- return;
- }
- if (testSelector.options[previousTestIndex].disabled) {
- previousTestIndex--;
- } else {
- testSelector.selectedIndex = previousTestIndex;
- selectTest();
- return
- }
- }
-}
-
-window.addEventListener('DOMContentLoaded', main);
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js
deleted file mode 100644
index f57c919..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js
+++ /dev/null
@@ -1,158 +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.
- */
-
-function RebaselineQueue()
-{
- this._selectNode = $('queue-select');
- this._rebaselineButtonNode = $('rebaseline-queue');
- this._toggleNode = $('toggle-queue');
- this._removeSelectionButtonNode = $('remove-queue-selection');
-
- this._inProgressRebaselineCount = 0;
-
- var self = this;
- $('add-to-rebaseline-queue').addEventListener(
- 'click', function() { self.addCurentTest(); });
- this._selectNode.addEventListener('change', updateState);
- this._removeSelectionButtonNode.addEventListener(
- 'click', function() { self._removeSelection(); });
- this._rebaselineButtonNode.addEventListener(
- 'click', function() { self.rebaseline(); });
- this._toggleNode.addEventListener(
- 'click', function() { toggle('queue'); });
-}
-
-RebaselineQueue.prototype.updateState = function()
-{
- var testName = getSelectedTest();
-
- var state = results.tests[testName].state;
- $('add-to-rebaseline-queue').disabled = state != STATE_NEEDS_REBASELINE;
-
- var queueLength = this._selectNode.options.length;
- if (this._inProgressRebaselineCount > 0) {
- this._rebaselineButtonNode.disabled = true;
- this._rebaselineButtonNode.textContent =
- 'Rebaseline in progress (' + this._inProgressRebaselineCount +
- ' tests left)';
- } else if (queueLength == 0) {
- this._rebaselineButtonNode.disabled = true;
- this._rebaselineButtonNode.textContent = 'Rebaseline queue';
- this._toggleNode.textContent = 'Queue';
- } else {
- this._rebaselineButtonNode.disabled = false;
- this._rebaselineButtonNode.textContent =
- 'Rebaseline queue (' + queueLength + ' tests)';
- this._toggleNode.textContent = 'Queue (' + queueLength + ' tests)';
- }
- this._removeSelectionButtonNode.disabled =
- this._selectNode.selectedIndex == -1;
-};
-
-RebaselineQueue.prototype.addCurrentTest = function()
-{
- var testName = getSelectedTest();
- var test = results.tests[testName];
-
- if (test.state != STATE_NEEDS_REBASELINE) {
- log('Cannot add test with state "' + test.state + '" to queue.',
- log.WARNING);
- return;
- }
-
- var queueOption = document.createElement('option');
- queueOption.value = testName;
- queueOption.textContent = testName;
- this._selectNode.appendChild(queueOption);
- test.state = STATE_IN_QUEUE;
- updateState();
-};
-
-RebaselineQueue.prototype.removeCurrentTest = function()
-{
- this._removeTest(getSelectedTest());
-};
-
-RebaselineQueue.prototype._removeSelection = function()
-{
- if (this._selectNode.selectedIndex == -1)
- return;
-
- this._removeTest(
- this._selectNode.options[this._selectNode.selectedIndex].value);
-};
-
-RebaselineQueue.prototype._removeTest = function(testName)
-{
- var queueOption = this._selectNode.firstChild;
-
- while (queueOption && queueOption.value != testName) {
- queueOption = queueOption.nextSibling;
- }
-
- if (!queueOption)
- return;
-
- this._selectNode.removeChild(queueOption);
- var test = results.tests[testName];
- test.state = STATE_NEEDS_REBASELINE;
- updateState();
-};
-
-RebaselineQueue.prototype.rebaseline = function()
-{
- var testNames = [];
- for (var queueOption = this._selectNode.firstChild;
- queueOption;
- queueOption = queueOption.nextSibling) {
- testNames.push(queueOption.value);
- }
-
- this._inProgressRebaselineCount = testNames.length;
- updateState();
-
- testNames.forEach(this._rebaselineTest, this);
-};
-
-RebaselineQueue.prototype._rebaselineTest = function(testName)
-{
- var baselineTarget = getSelectValue('baseline-target');
- var baselineMoveTo = getSelectValue('baseline-move-to');
-
- // FIXME: actually rebaseline
- log('Rebaselining ' + testName + ' for platform ' + baselineTarget + '...');
- var test = results.tests[testName];
- this._removeTest(testName);
- this._inProgressRebaselineCount--;
- test.state = STATE_REBASELINE_SUCCEEDED;
- updateState();
- log('Rebaselined add test with state ' + test.state + ' to queue',
- log.SUCCESS);
-};
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js
deleted file mode 100644
index b348462..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js
+++ /dev/null
@@ -1,94 +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.
- */
-
-var results;
-var testsByFailureType = {};
-var testsByDirectory = {};
-var selectedTests = [];
-
-function $(id)
-{
- return document.getElementById(id);
-}
-
-function getSelectValue(id)
-{
- var select = $(id);
- if (select.selectedIndex == -1) {
- return null;
- } else {
- return select.options[select.selectedIndex].value;
- }
-}
-
-function loadText(url, callback)
-{
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url);
- xhr.addEventListener('load', function() { callback(xhr.responseText); });
- xhr.send();
-}
-
-function log(text, type)
-{
- var node = $('log');
-
- if (type) {
- var typeNode = document.createElement('span');
- typeNode.textContent = type.text;
- typeNode.style.color = type.color;
- node.appendChild(typeNode);
- }
-
- node.appendChild(document.createTextNode(text + '\n'));
- node.scrollTop = node.scrollHeight;
-}
-
-log.WARNING = {text: 'Warning: ', color: '#aa3'};
-log.SUCCESS = {text: 'Success: ', color: 'green'};
-log.ERROR = {text: 'Error: ', color: 'red'};
-
-function toggle(id)
-{
- var element = $(id);
- var toggler = $('toggle-' + id);
- if (element.style.display == 'none') {
- element.style.display = '';
- toggler.className = 'link selected';
- } else {
- element.style.display = 'none';
- toggler.className = 'link';
- }
-}
-
-function getTracUrl(layoutTestPath)
-{
- return 'http://trac.webkit.org/browser/trunk/LayoutTests/' + layoutTestPath;
-} \ No newline at end of file
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/download.py b/WebKitTools/Scripts/webkitpy/tool/commands/download.py
deleted file mode 100644
index 457c050..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/download.py
+++ /dev/null
@@ -1,394 +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
-
-import webkitpy.tool.steps as steps
-
-from webkitpy.common.checkout.changelog import ChangeLog, view_source_url
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
-from webkitpy.tool.commands.stepsequence import StepSequence
-from webkitpy.tool.comments import bug_comment_from_commit_text
-from webkitpy.tool.grammar import pluralize
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.common.system.deprecated_logging import error, log
-
-
-class Clean(AbstractSequencedCommand):
- name = "clean"
- help_text = "Clean the working copy"
- steps = [
- steps.CleanWorkingDirectory,
- ]
-
- def _prepare_state(self, options, args, tool):
- options.force_clean = True
-
-
-class Update(AbstractSequencedCommand):
- name = "update"
- help_text = "Update working copy (used internally)"
- steps = [
- steps.CleanWorkingDirectory,
- steps.Update,
- ]
-
-
-class Build(AbstractSequencedCommand):
- name = "build"
- help_text = "Update working copy and build"
- steps = [
- steps.CleanWorkingDirectory,
- steps.Update,
- steps.Build,
- ]
-
- def _prepare_state(self, options, args, tool):
- options.build = True
-
-
-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.ValidateReviewer,
- 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 NOT build and run the tests before committing, but you can use the --build option for that.
-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):
- changed_files = self._tool.scm().changed_files(options.git_commit)
- return {
- "changed_files": changed_files,
- "bug_id": (args and args[0]) or tool.checkout().bug_id_for_this_commit(options.git_commit, changed_files),
- }
-
-
-class LandCowboy(AbstractSequencedCommand):
- name = "land-cowboy"
- help_text = "Prepares a ChangeLog and lands the current working directory diff."
- steps = [
- steps.PrepareChangeLog,
- steps.EditChangeLog,
- steps.ConfirmDiff,
- steps.Build,
- steps.RunTests,
- steps.Commit,
- ]
-
-
-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 BuildAndTestAttachment(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
- name = "build-and-test-attachment"
- help_text = "Apply, build, and test patches from bugzilla"
- argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
- main_steps = [
- steps.CleanWorkingDirectory,
- steps.Update,
- steps.ApplyPatch,
- steps.Build,
- steps.RunTests,
- ]
-
-
-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.ValidateReviewer,
- 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 AbstractRolloutPrepCommand(AbstractSequencedCommand):
- argument_names = "REVISION REASON"
-
- def _commit_info(self, revision):
- commit_info = self._tool.checkout().commit_info_for_revision(revision)
- if commit_info and commit_info.bug_id():
- # Note: Don't print a bug URL here because it will confuse the
- # SheriffBot because the SheriffBot just greps the output
- # of create-rollout for bug URLs. It should do better
- # parsing instead.
- log("Preparing rollout for bug %s." % commit_info.bug_id())
- else:
- log("Unable to parse bug number from diff.")
- return commit_info
-
- def _prepare_state(self, options, args, tool):
- revision = args[0]
- commit_info = self._commit_info(revision)
- cc_list = sorted([party.bugzilla_email()
- for party in commit_info.responsible_parties()
- if party.bugzilla_email()])
- return {
- "revision": revision,
- "bug_id": commit_info.bug_id(),
- # FIXME: We should used the list as the canonical representation.
- "bug_cc": ",".join(cc_list),
- "reason": args[1],
- }
-
-
-class PrepareRollout(AbstractRolloutPrepCommand):
- name = "prepare-rollout"
- help_text = "Revert the given revision in the working copy and prepare ChangeLogs with revert 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.
-"""
- steps = [
- steps.CleanWorkingDirectory,
- steps.Update,
- steps.RevertRevision,
- steps.PrepareChangeLogForRevert,
- ]
-
-
-class CreateRollout(AbstractRolloutPrepCommand):
- name = "create-rollout"
- help_text = "Creates a bug to track a broken SVN revision and uploads a rollout patch."
- steps = [
- steps.CleanWorkingDirectory,
- steps.Update,
- steps.RevertRevision,
- steps.CreateBug,
- steps.PrepareChangeLogForRevert,
- steps.PostDiffForRevert,
- ]
-
- def _prepare_state(self, options, args, tool):
- state = AbstractRolloutPrepCommand._prepare_state(self, options, args, tool)
- # Currently, state["bug_id"] points to the bug that caused the
- # regression. We want to create a new bug that blocks the old bug
- # so we move state["bug_id"] to state["bug_blocked"] and delete the
- # old state["bug_id"] so that steps.CreateBug will actually create
- # the new bug that we want (and subsequently store its bug id into
- # state["bug_id"])
- state["bug_blocked"] = state["bug_id"]
- del state["bug_id"]
- state["bug_title"] = "REGRESSION(r%s): %s" % (state["revision"], state["reason"])
- state["bug_description"] = "%s broke the build:\n%s" % (view_source_url(state["revision"]), state["reason"])
- # FIXME: If we had more context here, we could link to other open bugs
- # that mention the test that regressed.
- if options.parent_command == "sheriff-bot":
- state["bug_description"] += """
-
-This is an automatic bug report generated by the sheriff-bot. If this bug
-report was created because of a flaky test, please file a bug for the flaky
-test (if we don't already have one on file) and dup this bug against that bug
-so that we can track how often these flaky tests case pain.
-
-"Only you can prevent forest fires." -- Smokey the Bear
-"""
- return state
-
-
-class Rollout(AbstractRolloutPrepCommand):
- 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"
- 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.Build,
- steps.Commit,
- steps.ReopenBugAfterRollout,
- ]
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/download_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/download_unittest.py
deleted file mode 100644
index 9ca343b..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/download_unittest.py
+++ /dev/null
@@ -1,190 +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.common.system.outputcapture import OutputCapture
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.download import *
-from webkitpy.tool.mocktool import MockOptions, MockTool
-
-
-class AbstractRolloutPrepCommandTest(unittest.TestCase):
- def test_commit_info(self):
- command = AbstractRolloutPrepCommand()
- tool = MockTool()
- command.bind_to_tool(tool)
- output = OutputCapture()
-
- expected_stderr = "Preparing rollout for bug 42.\n"
- commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_stderr=expected_stderr)
- self.assertTrue(commit_info)
-
- mock_commit_info = Mock()
- mock_commit_info.bug_id = lambda: None
- tool._checkout.commit_info_for_revision = lambda revision: mock_commit_info
- expected_stderr = "Unable to parse bug number from diff.\n"
- commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_stderr=expected_stderr)
- self.assertEqual(commit_info, mock_commit_info)
-
-
-class DownloadCommandsTest(CommandsTest):
- def _default_options(self):
- options = MockOptions()
- options.build = True
- options.build_style = True
- options.check_builders = True
- options.check_style = True
- options.clean = True
- options.close_bug = True
- options.force_clean = False
- options.force_patch = True
- options.non_interactive = False
- options.parent_command = 'MOCK parent command'
- options.quiet = False
- options.test = True
- options.update = True
- 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\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 42\n"
- mock_tool = MockTool()
- mock_tool.scm().create_patch = Mock()
- mock_tool.checkout().modified_changelogs = Mock(return_value=[])
- self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool)
- # Make sure we're not calling expensive calls too often.
- self.assertEqual(mock_tool.scm().create_patch.call_count, 0)
- self.assertEqual(mock_tool.checkout().modified_changelogs.call_count, 1)
-
- def test_land_red_builders(self):
- expected_stderr = '\nWARNING: Builders ["Builder2"] are red, please watch your commit carefully.\nSee http://dummy_buildbot_host/console?category=core\n\nBuilding WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 42\n'
- mock_tool = MockTool()
- mock_tool.buildbot.light_tree_on_fire()
- self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool)
-
- 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
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-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
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-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
-Committed r49824: <http://trac.webkit.org/changeset/49824>
-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_prepare_rollout(self):
- expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\n"
- self.assert_execute_outputs(PrepareRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
-
- def test_create_rollout(self):
- expected_stderr = """Preparing rollout for bug 42.
-Updating working directory
-MOCK create_bug
-bug_title: REGRESSION(r852): Reason
-bug_description: http://trac.webkit.org/changeset/852 broke the build:
-Reason
-Running prepare-ChangeLog
-MOCK add_patch_to_bug: bug_id=None, description=ROLLOUT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
--- Begin comment --
-Any committer can land this patch automatically by marking it commit-queue+. The commit-queue will build and test the patch before landing to ensure that the rollout will be successful. This process takes approximately 15 minutes.
-
-If you would like to land the rollout faster, you can use the following command:
-
- webkit-patch land-attachment ATTACHMENT_ID --ignore-builders
-
-where ATTACHMENT_ID is the ID of this attachment.
--- End comment --
-"""
- self.assert_execute_outputs(CreateRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
-
- def test_rollout(self):
- expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\nMOCK: user.open_url: file://...\nBuilding WebKit\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\n"
- expected_stdout = "Was that diff correct?\n"
- self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stdout=expected_stdout, expected_stderr=expected_stderr)
-
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
deleted file mode 100644
index 3b53d1a..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
+++ /dev/null
@@ -1,182 +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.tool.commands.queues import AbstractReviewQueue
-from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.config.ports import WebKitPort
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.tool.bot.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):
- return True
-
- def _can_build(self):
- try:
- self.run_webkit_patch([
- "build",
- self.port.flag(),
- "--build-style=%s" % self._build_style,
- "--force-clean",
- "--no-update"])
- return True
- except ScriptError, e:
- failure_log = self._log_from_script_error_for_upload(e)
- self._update_status("Unable to perform a build", results_file=failure_log)
- return False
-
- def _build(self, patch, first_run=False):
- try:
- args = [
- "build-attachment",
- self.port.flag(),
- "--build",
- "--build-style=%s" % self._build_style,
- "--force-clean",
- "--quiet",
- "--non-interactive",
- patch.id()]
- if not first_run:
- # See commit-queue for an explanation of what we're doing here.
- args.append("--no-update")
- args.append("--parent-command=%s" % self.name)
- self.run_webkit_patch(args)
- return True
- except ScriptError, e:
- if first_run:
- return False
- raise
-
- def review_patch(self, patch):
- if patch.is_obsolete():
- self._did_error(patch, "%s does not process obsolete patches." % self.name)
- return False
-
- if patch.bug().is_closed():
- self._did_error(patch, "%s does not process patches on closed bugs." % self.name)
- return False
-
- if not self._build(patch, first_run=True):
- if not self._can_build():
- return False
- self._build(patch)
- return True
-
- @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 EflEWS(AbstractEarlyWarningSystem):
- name = "efl-ews"
- port_name = "efl"
- watchers = AbstractEarlyWarningSystem.watchers + [
- "leandro@profusion.mobi",
- "antognolli@profusion.mobi",
- "lucas.demarchi@profusion.mobi",
- ]
-
-
-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"
-
-
-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 __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 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"
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py
deleted file mode 100644
index 830e11c..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py
+++ /dev/null
@@ -1,132 +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.thirdparty.mock import Mock
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.tool.bot.queueengine import QueueEngine
-from webkitpy.tool.commands.earlywarningsystem import *
-from webkitpy.tool.commands.queuestest import QueuesTest
-from webkitpy.tool.mocktool import MockTool, MockOptions
-
-
-class AbstractEarlyWarningSystemTest(QueuesTest):
- def test_can_build(self):
- # Needed to define port_name, used in AbstractEarlyWarningSystem.__init__
- class TestEWS(AbstractEarlyWarningSystem):
- port_name = "win" # Needs to be a port which port/factory understands.
-
- queue = TestEWS()
- queue.bind_to_tool(MockTool(log_executive=True))
- queue._options = MockOptions(port=None)
- expected_stderr = "MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build', '--port=win', '--build-style=release', '--force-clean', '--no-update']\n"
- OutputCapture().assert_outputs(self, queue._can_build, [], expected_stderr=expected_stderr)
-
- def mock_run_webkit_patch(args):
- raise ScriptError("MOCK script error")
-
- queue.run_webkit_patch = mock_run_webkit_patch
- expected_stderr = "MOCK: update_status: None Unable to perform a build\n"
- OutputCapture().assert_outputs(self, queue._can_build, [], expected_stderr=expected_stderr)
-
- # FIXME: This belongs on an AbstractReviewQueueTest object in queues_unittest.py
- def test_subprocess_handled_error(self):
- queue = AbstractReviewQueue()
- queue.bind_to_tool(MockTool())
-
- def mock_review_patch(patch):
- raise ScriptError('MOCK script error', exit_code=QueueEngine.handled_error_code)
-
- queue.review_patch = mock_review_patch
- mock_patch = queue._tool.bugs.fetch_attachment(197)
- expected_stderr = "MOCK: release_work_item: None 197\n"
- OutputCapture().assert_outputs(self, queue.process_work_item, [mock_patch], expected_stderr=expected_stderr, expected_exception=ScriptError)
-
-
-class EarlyWarningSytemTest(QueuesTest):
- def test_failed_builds(self):
- ews = ChromiumLinuxEWS()
- ews.bind_to_tool(MockTool())
- ews._build = lambda patch, first_run=False: False
- ews._can_build = lambda: True
- mock_patch = ews._tool.bugs.fetch_attachment(197)
- ews.review_patch(mock_patch)
-
- def _default_expected_stderr(self, ews):
- string_replacemnts = {
- "name": ews.name,
- "port": ews.port_name,
- "watchers": ews.watchers,
- }
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr(ews.name, ews._tool.scm().checkout_root),
- "handle_unexpected_error": "Mock error message\n",
- "next_work_item": "",
- "process_work_item": "MOCK: update_status: %(name)s Pass\nMOCK: release_work_item: %(name)s 197\n" % string_replacemnts,
- "handle_script_error": "MOCK: update_status: %(name)s ScriptError error message\nMOCK bug comment: bug_id=42, cc=%(watchers)s\n--- Begin comment ---\nAttachment 197 did not build on %(port)s:\nBuild output: http://dummy_url\n--- End comment ---\n\n" % string_replacemnts,
- }
- return expected_stderr
-
- def _test_ews(self, ews):
- ews.bind_to_tool(MockTool())
- expected_exceptions = {
- "handle_script_error": SystemExit,
- }
- self.assert_queue_outputs(ews, expected_stderr=self._default_expected_stderr(ews), expected_exceptions=expected_exceptions)
-
- def _test_committer_only_ews(self, ews):
- ews.bind_to_tool(MockTool())
- expected_stderr = self._default_expected_stderr(ews)
- string_replacemnts = {"name": ews.name}
- expected_stderr["process_work_item"] = "MOCK: update_status: %(name)s Error: %(name)s cannot process patches from non-committers :(\nMOCK: release_work_item: %(name)s 197\n" % string_replacemnts
- expected_exceptions = {"handle_script_error": SystemExit}
- self.assert_queue_outputs(ews, expected_stderr=expected_stderr, expected_exceptions=expected_exceptions)
-
- # FIXME: If all EWSes are going to output the same text, we
- # could test them all in one method with a for loop over an array.
- def test_chromium_linux_ews(self):
- self._test_ews(ChromiumLinuxEWS())
-
- def test_chromium_windows_ews(self):
- self._test_ews(ChromiumWindowsEWS())
-
- def test_qt_ews(self):
- self._test_ews(QtEWS())
-
- def test_gtk_ews(self):
- self._test_ews(GtkEWS())
-
- def test_efl_ews(self):
- self._test_ews(EflEWS())
-
- def test_mac_ews(self):
- self._test_committer_only_ews(MacEWS())
-
- def test_chromium_mac_ews(self):
- self._test_committer_only_ews(ChromiumMacEWS())
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/openbugs.py b/WebKitTools/Scripts/webkitpy/tool/commands/openbugs.py
deleted file mode 100644
index 1b51c9f..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/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.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.common.system.deprecated_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/tool/commands/openbugs_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/openbugs_unittest.py
deleted file mode 100644
index 40a6e1b..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/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.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.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/tool/commands/prettydiff.py b/WebKitTools/Scripts/webkitpy/tool/commands/prettydiff.py
deleted file mode 100644
index e3fc00c..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/prettydiff.py
+++ /dev/null
@@ -1,38 +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.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
-import webkitpy.tool.steps as steps
-
-
-class PrettyDiff(AbstractSequencedCommand):
- name = "pretty-diff"
- help_text = "Shows the pretty diff in the default browser"
- steps = [
- steps.ConfirmDiff,
- ]
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queries.py b/WebKitTools/Scripts/webkitpy/tool/commands/queries.py
deleted file mode 100644
index 16ddc2c..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/queries.py
+++ /dev/null
@@ -1,393 +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.
-
-
-from optparse import make_option
-
-import webkitpy.tool.steps as steps
-
-from webkitpy.common.checkout.commitinfo import CommitInfo
-from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.net.buildbot import BuildBot
-from webkitpy.common.net.regressionwindow import RegressionWindow
-from webkitpy.common.system.user import User
-from webkitpy.tool.grammar import pluralize
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.common.system.deprecated_logging import log
-from webkitpy.layout_tests import port
-
-
-class SuggestReviewers(AbstractDeclarativeCommand):
- name = "suggest-reviewers"
- help_text = "Suggest reviewers for a patch based on recent changes to the modified files."
-
- def __init__(self):
- options = [
- steps.Options.git_commit,
- ]
- AbstractDeclarativeCommand.__init__(self, options=options)
-
- def execute(self, options, args, tool):
- reviewers = tool.checkout().suggested_reviewers(options.git_commit)
- print "\n".join([reviewer.full_name for reviewer in reviewers])
-
-
-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 LastGreenRevision(AbstractDeclarativeCommand):
- name = "last-green-revision"
- help_text = "Prints the last known good revision"
-
- def execute(self, options, args, tool):
- print self._tool.buildbot.last_green_revision()
-
-
-class WhatBroke(AbstractDeclarativeCommand):
- name = "what-broke"
- help_text = "Print failing buildbots (%s) and what revisions broke them" % BuildBot.default_host
-
- def _print_builder_line(self, builder_name, max_name_width, status_message):
- print "%s : %s" % (builder_name.ljust(max_name_width), status_message)
-
- def _print_blame_information_for_builder(self, builder_status, name_width, avoid_flakey_tests=True):
- builder = self._tool.buildbot.builder_with_name(builder_status["name"])
- red_build = builder.build(builder_status["build_number"])
- regression_window = builder.find_regression_window(red_build)
- if not regression_window.failing_build():
- self._print_builder_line(builder.name(), name_width, "FAIL (error loading build information)")
- return
- if not regression_window.build_before_failure():
- self._print_builder_line(builder.name(), name_width, "FAIL (blame-list: sometime before %s?)" % regression_window.failing_build().revision())
- return
-
- revisions = regression_window.revisions()
- first_failure_message = ""
- if (regression_window.failing_build() == builder.build(builder_status["build_number"])):
- first_failure_message = " FIRST FAILURE, possibly a flaky test"
- self._print_builder_line(builder.name(), name_width, "FAIL (blame-list: %s%s)" % (revisions, first_failure_message))
- for revision in revisions:
- commit_info = self._tool.checkout().commit_info_for_revision(revision)
- if commit_info:
- print commit_info.blame_string(self._tool.bugs)
- else:
- print "FAILED to fetch CommitInfo for r%s, likely missing ChangeLog" % revision
-
- def execute(self, options, args, tool):
- builder_statuses = tool.buildbot.builder_statuses()
- longest_builder_name = max(map(len, map(lambda builder: builder["name"], builder_statuses)))
- failing_builders = 0
- for builder_status in builder_statuses:
- # If the builder is green, print OK, exit.
- if builder_status["is_green"]:
- continue
- self._print_blame_information_for_builder(builder_status, name_width=longest_builder_name)
- failing_builders += 1
- if failing_builders:
- print "%s of %s are failing" % (failing_builders, pluralize("builder", len(builder_statuses)))
- else:
- print "All builders are passing!"
-
-
-class ResultsFor(AbstractDeclarativeCommand):
- name = "results-for"
- help_text = "Print a list of failures for the passed revision from bots on %s" % BuildBot.default_host
- argument_names = "REVISION"
-
- def _print_layout_test_results(self, results):
- if not results:
- print " No results."
- return
- for title, files in results.parsed_results().items():
- print " %s" % title
- for filename in files:
- print " %s" % filename
-
- def execute(self, options, args, tool):
- builders = self._tool.buildbot.builders()
- for builder in builders:
- print "%s:" % builder.name()
- build = builder.build_for_revision(args[0], allow_failed_lookups=True)
- self._print_layout_test_results(build.layout_test_results())
-
-
-class FailureReason(AbstractDeclarativeCommand):
- name = "failure-reason"
- help_text = "Lists revisions where individual test failures started at %s" % BuildBot.default_host
-
- def _blame_line_for_revision(self, revision):
- try:
- commit_info = self._tool.checkout().commit_info_for_revision(revision)
- except Exception, e:
- return "FAILED to fetch CommitInfo for r%s, exception: %s" % (revision, e)
- if not commit_info:
- return "FAILED to fetch CommitInfo for r%s, likely missing ChangeLog" % revision
- return commit_info.blame_string(self._tool.bugs)
-
- def _print_blame_information_for_transition(self, regression_window, failing_tests):
- red_build = regression_window.failing_build()
- print "SUCCESS: Build %s (r%s) was the first to show failures: %s" % (red_build._number, red_build.revision(), failing_tests)
- print "Suspect revisions:"
- for revision in regression_window.revisions():
- print self._blame_line_for_revision(revision)
-
- def _explain_failures_for_builder(self, builder, start_revision):
- print "Examining failures for \"%s\", starting at r%s" % (builder.name(), start_revision)
- revision_to_test = start_revision
- build = builder.build_for_revision(revision_to_test, allow_failed_lookups=True)
- layout_test_results = build.layout_test_results()
- if not layout_test_results:
- # FIXME: This could be made more user friendly.
- print "Failed to load layout test results; can't continue. (start revision = r%s)" % start_revision
- return 1
-
- results_to_explain = set(layout_test_results.failing_tests())
- last_build_with_results = build
- print "Starting at %s" % revision_to_test
- while results_to_explain:
- revision_to_test -= 1
- new_build = builder.build_for_revision(revision_to_test, allow_failed_lookups=True)
- if not new_build:
- print "No build for %s" % revision_to_test
- continue
- build = new_build
- latest_results = build.layout_test_results()
- if not latest_results:
- print "No results build %s (r%s)" % (build._number, build.revision())
- continue
- failures = set(latest_results.failing_tests())
- if len(failures) >= 20:
- # FIXME: We may need to move this logic into the LayoutTestResults class.
- # The buildbot stops runs after 20 failures so we don't have full results to work with here.
- print "Too many failures in build %s (r%s), ignoring." % (build._number, build.revision())
- continue
- fixed_results = results_to_explain - failures
- if not fixed_results:
- print "No change in build %s (r%s), %s unexplained failures (%s in this build)" % (build._number, build.revision(), len(results_to_explain), len(failures))
- last_build_with_results = build
- continue
- regression_window = RegressionWindow(build, last_build_with_results)
- self._print_blame_information_for_transition(regression_window, fixed_results)
- last_build_with_results = build
- results_to_explain -= fixed_results
- if results_to_explain:
- print "Failed to explain failures: %s" % results_to_explain
- return 1
- print "Explained all results for %s" % builder.name()
- return 0
-
- def _builder_to_explain(self):
- builder_statuses = self._tool.buildbot.builder_statuses()
- red_statuses = [status for status in builder_statuses if not status["is_green"]]
- print "%s failing" % (pluralize("builder", len(red_statuses)))
- builder_choices = [status["name"] for status in red_statuses]
- # We could offer an "All" choice here.
- chosen_name = User.prompt_with_list("Which builder to diagnose:", builder_choices)
- # FIXME: prompt_with_list should really take a set of objects and a set of names and then return the object.
- for status in red_statuses:
- if status["name"] == chosen_name:
- return (self._tool.buildbot.builder_with_name(chosen_name), status["built_revision"])
-
- def execute(self, options, args, tool):
- (builder, latest_revision) = self._builder_to_explain()
- start_revision = self._tool.user.prompt("Revision to walk backwards from? [%s] " % latest_revision) or latest_revision
- if not start_revision:
- print "Revision required."
- return 1
- return self._explain_failures_for_builder(builder, start_revision=int(start_revision))
-
-
-class FindFlakyTests(AbstractDeclarativeCommand):
- name = "find-flaky-tests"
- help_text = "Lists tests that often fail for a single build at %s" % BuildBot.default_host
-
- def _find_failures(self, builder, revision):
- build = builder.build_for_revision(revision, allow_failed_lookups=True)
- if not build:
- print "No build for %s" % revision
- return (None, None)
- results = build.layout_test_results()
- if not results:
- print "No results build %s (r%s)" % (build._number, build.revision())
- return (None, None)
- failures = set(results.failing_tests())
- if len(failures) >= 20:
- # FIXME: We may need to move this logic into the LayoutTestResults class.
- # The buildbot stops runs after 20 failures so we don't have full results to work with here.
- print "Too many failures in build %s (r%s), ignoring." % (build._number, build.revision())
- return (None, None)
- return (build, failures)
-
- def _increment_statistics(self, flaky_tests, flaky_test_statistics):
- for test in flaky_tests:
- count = flaky_test_statistics.get(test, 0)
- flaky_test_statistics[test] = count + 1
-
- def _print_statistics(self, statistics):
- print "=== Results ==="
- print "Occurances Test name"
- for value, key in sorted([(value, key) for key, value in statistics.items()]):
- print "%10d %s" % (value, key)
-
- def _walk_backwards_from(self, builder, start_revision, limit):
- flaky_test_statistics = {}
- all_previous_failures = set([])
- one_time_previous_failures = set([])
- previous_build = None
- for i in range(limit):
- revision = start_revision - i
- print "Analyzing %s ... " % revision,
- (build, failures) = self._find_failures(builder, revision)
- if failures == None:
- # Notice that we don't loop on the empty set!
- continue
- print "has %s failures" % len(failures)
- flaky_tests = one_time_previous_failures - failures
- if flaky_tests:
- print "Flaky tests: %s %s" % (sorted(flaky_tests),
- previous_build.results_url())
- self._increment_statistics(flaky_tests, flaky_test_statistics)
- one_time_previous_failures = failures - all_previous_failures
- all_previous_failures = failures
- previous_build = build
- self._print_statistics(flaky_test_statistics)
-
- def _builder_to_analyze(self):
- statuses = self._tool.buildbot.builder_statuses()
- choices = [status["name"] for status in statuses]
- chosen_name = User.prompt_with_list("Which builder to analyze:", choices)
- for status in statuses:
- if status["name"] == chosen_name:
- return (self._tool.buildbot.builder_with_name(chosen_name), status["built_revision"])
-
- def execute(self, options, args, tool):
- (builder, latest_revision) = self._builder_to_analyze()
- limit = self._tool.user.prompt("How many revisions to look through? [10000] ") or 10000
- return self._walk_backwards_from(builder, latest_revision, limit=int(limit))
-
-
-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"])
-
-
-class SkippedPorts(AbstractDeclarativeCommand):
- name = "skipped-ports"
- help_text = "Print the list of ports skipping the given layout test(s)"
- long_help = """Scans the the Skipped file of each port and figure
-out what ports are skipping the test(s). Categories are taken in account too."""
- argument_names = "TEST_NAME"
-
- def execute(self, options, args, tool):
- class Options:
- # Required for chromium port.
- use_drt = True
-
- results = dict([(test_name, []) for test_name in args])
- for port_name, port_object in tool.port_factory.get_all(options=Options).iteritems():
- for test_name in args:
- if port_object.skips_layout_test(test_name):
- results[test_name].append(port_name)
-
- for test_name, ports in results.iteritems():
- if ports:
- print "Ports skipping test %r: %s" % (test_name, ', '.join(ports))
- else:
- print "Test %r is not skipped by any port." % test_name
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py
deleted file mode 100644
index 05a4a5c..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/queries_unittest.py
+++ /dev/null
@@ -1,90 +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.common.net.bugzilla import Bugzilla
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.queries import *
-from webkitpy.tool.mocktool import MockTool
-
-
-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)
-
- def test_skipped_ports(self):
- expected_stdout = "Ports skipping test 'media/foo/bar.html': test_port1, test_port2\n"
- self.assert_execute_outputs(SkippedPorts(), ("media/foo/bar.html",), expected_stdout)
-
- expected_stdout = "Ports skipping test 'foo': test_port1\n"
- self.assert_execute_outputs(SkippedPorts(), ("foo",), expected_stdout)
-
- expected_stdout = "Test 'media' is not skipped by any port.\n"
- self.assert_execute_outputs(SkippedPorts(), ("media",), expected_stdout)
-
-
-class FailureReasonTest(unittest.TestCase):
- def test_blame_line_for_revision(self):
- tool = MockTool()
- command = FailureReason()
- command.bind_to_tool(tool)
- # This is an artificial example, mostly to test the CommitInfo lookup failure case.
- self.assertEquals(command._blame_line_for_revision(None), "FAILED to fetch CommitInfo for rNone, likely missing ChangeLog")
-
- def raising_mock(self):
- raise Exception("MESSAGE")
- tool.checkout().commit_info_for_revision = raising_mock
- self.assertEquals(command._blame_line_for_revision(None), "FAILED to fetch CommitInfo for rNone, exception: MESSAGE")
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queues.py b/WebKitTools/Scripts/webkitpy/tool/commands/queues.py
deleted file mode 100644
index bfaeb08..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/queues.py
+++ /dev/null
@@ -1,417 +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.
-
-from __future__ import with_statement
-
-import codecs
-import time
-import traceback
-import os
-
-from datetime import datetime
-from optparse import make_option
-from StringIO import StringIO
-
-from webkitpy.common.config.committervalidator import CommitterValidator
-from webkitpy.common.net.bugzilla import Attachment
-from webkitpy.common.net.layouttestresults import path_for_layout_test, LayoutTestResults
-from webkitpy.common.net.statusserver import StatusServer
-from webkitpy.common.system.deprecated_logging import error, log
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.tool.bot.commitqueuetask import CommitQueueTask, CommitQueueTaskDelegate
-from webkitpy.tool.bot.feeders import CommitQueueFeeder, EWSFeeder
-from webkitpy.tool.bot.queueengine import QueueEngine, QueueEngineDelegate
-from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
-from webkitpy.tool.grammar import pluralize, join_with_separators
-from webkitpy.tool.multicommandtool import Command, TryAgain
-
-
-class AbstractQueue(Command, QueueEngineDelegate):
- watchers = [
- ]
-
- _pass_status = "Pass"
- _fail_status = "Fail"
- _retry_status = "Retry"
- _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!"),
- make_option("--exit-after-iteration", action="store", type="int", dest="iterations", default=None, help="Stop running the queue after iterating this number of times."),
- ]
- Command.__init__(self, "Run the %s" % self.name, options=options_list)
- self._iteration_count = 0
-
- 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 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.
- # FIXME: We must always pass global options and their value in one argument
- # because our global option code looks for the first argument which does
- # not begin with "-" and assumes that is the command name.
- webkit_patch_args += ["--status-host=%s" % self._tool.status_server.host]
- if self._tool.status_server.bot_id:
- webkit_patch_args += ["--bot-id=%s" % self._tool.status_server.bot_id]
- if self._options.port:
- webkit_patch_args += ["--port=%s" % self._options.port]
- webkit_patch_args.extend(args)
- # FIXME: There is probably no reason to use run_and_throw_if_fail anymore.
- # run_and_throw_if_fail was invented to support tee'd output
- # (where we write both to a log file and to the console at once),
- # but the queues don't need live-progress, a dump-of-output at the
- # end should be sufficient.
- return self._tool.executive.run_and_throw_if_fail(webkit_patch_args)
-
- def _log_directory(self):
- return "%s-logs" % self.name
-
- # QueueEngineDelegate methods
-
- def queue_log_path(self):
- return os.path.join(self._log_directory(), "%s.log" % self.name)
-
- def work_item_log_path(self, work_item):
- raise NotImplementedError, "subclasses must implement"
-
- 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)
- self._tool.status_server.update_status(self.name, "Starting Queue")
-
- def stop_work_queue(self, reason):
- self._tool.status_server.update_status(self.name, "Stopping Queue, reason: %s" % reason)
-
- def should_continue_work_queue(self):
- self._iteration_count += 1
- return not self._options.iterations or self._iteration_count <= self._options.iterations
-
- 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"
-
- # Command methods
-
- def execute(self, options, args, tool, engine=QueueEngine):
- self._options = options # FIXME: This code is wrong. Command.options is a list, this assumes an Options element!
- self._tool = tool # FIXME: This code is wrong too! Command.bind_to_tool handles this!
- return engine(self.name, self, self._tool.wakeup_event).run()
-
- @classmethod
- def _log_from_script_error_for_upload(cls, script_error, output_limit=None):
- # We have seen request timeouts with app engine due to large
- # log uploads. Trying only the last 512k.
- if not output_limit:
- output_limit = 512 * 1024 # 512k
- output = script_error.message_with_output(output_limit=output_limit)
- # We pre-encode the string to a byte array before passing it
- # to status_server, because ClientForm (part of mechanize)
- # wants a file-like object with pre-encoded data.
- return StringIO(output.encode("utf-8"))
-
- @classmethod
- def _update_status_for_script_error(cls, tool, state, script_error, is_error=False):
- message = str(script_error)
- if is_error:
- message = "Error: %s" % message
- failure_log = cls._log_from_script_error_for_upload(script_error)
- return tool.status_server.update_status(cls.name, message, state["patch"], failure_log)
-
-
-class FeederQueue(AbstractQueue):
- name = "feeder-queue"
-
- _sleep_duration = 30 # seconds
-
- # AbstractPatchQueue methods
-
- def begin_work_queue(self):
- AbstractQueue.begin_work_queue(self)
- self.feeders = [
- CommitQueueFeeder(self._tool),
- EWSFeeder(self._tool),
- ]
-
- def next_work_item(self):
- # This really show inherit from some more basic class that doesn't
- # understand work items, but the base class in the heirarchy currently
- # understands work items.
- return "synthetic-work-item"
-
- def should_proceed_with_work_item(self, work_item):
- return True
-
- def process_work_item(self, work_item):
- for feeder in self.feeders:
- feeder.feed()
- time.sleep(self._sleep_duration)
- return True
-
- def work_item_log_path(self, work_item):
- return None
-
- def handle_unexpected_error(self, work_item, message):
- log(message)
-
-
-class AbstractPatchQueue(AbstractQueue):
- def _update_status(self, message, patch=None, results_file=None):
- return self._tool.status_server.update_status(self.name, message, patch, results_file)
-
- def _next_patch(self):
- patch_id = self._tool.status_server.next_work_item(self.name)
- if not patch_id:
- return None
- patch = self._tool.bugs.fetch_attachment(patch_id)
- if not patch:
- # FIXME: Using a fake patch because release_work_item has the wrong API.
- # We also don't really need to release the lock (although that's fine),
- # mostly we just need to remove this bogus patch from our queue.
- # If for some reason bugzilla is just down, then it will be re-fed later.
- patch = Attachment({'id': patch_id}, None)
- self._release_work_item(patch)
- return None
- return patch
-
- def _release_work_item(self, patch):
- self._tool.status_server.release_work_item(self.name, patch)
-
- def _did_pass(self, patch):
- self._update_status(self._pass_status, patch)
- self._release_work_item(patch)
-
- def _did_fail(self, patch):
- self._update_status(self._fail_status, patch)
- self._release_work_item(patch)
-
- def _did_retry(self, patch):
- self._update_status(self._retry_status, patch)
- self._release_work_item(patch)
-
- def _did_error(self, patch, reason):
- message = "%s: %s" % (self._error_status, reason)
- self._update_status(message, patch)
- self._release_work_item(patch)
-
- def work_item_log_path(self, patch):
- return os.path.join(self._log_directory(), "%s.log" % patch.bug_id())
-
-
-class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskDelegate):
- name = "commit-queue"
-
- # AbstractPatchQueue methods
-
- def begin_work_queue(self):
- AbstractPatchQueue.begin_work_queue(self)
- self.committer_validator = CommitterValidator(self._tool.bugs)
-
- def next_work_item(self):
- return self._next_patch()
-
- def should_proceed_with_work_item(self, patch):
- patch_text = "rollout patch" if patch.is_rollout() else "patch"
- self._update_status("Processing %s" % patch_text, patch)
- return True
-
- def process_work_item(self, patch):
- self._cc_watchers(patch.bug_id())
- task = CommitQueueTask(self, patch)
- try:
- if task.run():
- self._did_pass(patch)
- return True
- self._did_retry(patch)
- except ScriptError, e:
- validator = CommitterValidator(self._tool.bugs)
- validator.reject_patch_from_commit_queue(patch.id(), self._error_message_for_bug(task.failure_status_id, e))
- self._did_fail(patch)
-
- def _error_message_for_bug(self, status_id, script_error):
- if not script_error.output:
- return script_error.message_with_output()
- results_link = self._tool.status_server.results_url_for_status(status_id)
- return "%s\nFull output: %s" % (script_error.message_with_output(), results_link)
-
- def handle_unexpected_error(self, patch, message):
- self.committer_validator.reject_patch_from_commit_queue(patch.id(), message)
-
- # CommitQueueTaskDelegate methods
-
- def run_command(self, command):
- self.run_webkit_patch(command)
-
- def command_passed(self, message, patch):
- self._update_status(message, patch=patch)
-
- 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)
-
- # FIXME: This exists for mocking, but should instead be mocked via
- # some sort of tool.filesystem() object.
- def _read_file_contents(self, path):
- try:
- with codecs.open(path, "r", "utf-8") as open_file:
- return open_file.read()
- except OSError, e: # File does not exist or can't be read.
- return None
-
- # FIXME: This may belong on the Port object.
- def layout_test_results(self):
- results_path = self._tool.port().layout_tests_results_path()
- results_html = self._read_file_contents(results_path)
- if not results_html:
- return None
- return LayoutTestResults.results_from_string(results_html)
-
- def refetch_patch(self, patch):
- return self._tool.bugs.fetch_attachment(patch.id())
-
- def _author_emails_for_tests(self, flaky_tests):
- test_paths = map(path_for_layout_test, flaky_tests)
- commit_infos = self._tool.checkout().recent_commit_infos_for_files(test_paths)
- return set([commit_info.author().bugzilla_email() for commit_info in commit_infos if commit_info.author()])
-
- def report_flaky_tests(self, patch, flaky_tests):
- message = "The %s encountered the following flaky tests while processing attachment %s:" % (self.name, patch.id())
- message += "\n\n%s\n\n" % ("\n".join(flaky_tests))
- message += "Please file bugs against the tests. "
- author_emails = self._author_emails_for_tests(flaky_tests)
- if author_emails:
- message += "These tests were authored by %s. " % (join_with_separators(sorted(author_emails)))
- message += "The commit-queue is continuing to process your patch."
- self._tool.bugs.post_comment_to_bug(patch.bug_id(), message)
-
- # StepSequenceErrorHandler methods
-
- def handle_script_error(cls, tool, state, script_error):
- # Hitting this error handler should be pretty rare. It does occur,
- # however, when a patch no longer applies to top-of-tree in the final
- # land step.
- log(script_error.message_with_output())
-
- @classmethod
- def handle_checkout_needs_update(cls, tool, state, options, error):
- message = "Tests passed, but commit failed (checkout out of date). Updating, then landing without building or re-running tests."
- tool.status_server.update_status(cls.name, message, state["patch"])
- # The only time when we find out that out checkout needs update is
- # when we were ready to actually pull the trigger and land the patch.
- # Rather than spinning in the master process, we retry without
- # building or testing, which is much faster.
- options.build = False
- options.test = False
- options.update = True
- raise TryAgain()
-
-
-class AbstractReviewQueue(AbstractPatchQueue, StepSequenceErrorHandler):
- """This is the base-class for the EWS queues and the style-queue."""
- def __init__(self, options=None):
- AbstractPatchQueue.__init__(self, options)
-
- def review_patch(self, patch):
- raise NotImplementedError("subclasses must implement")
-
- # AbstractPatchQueue methods
-
- def begin_work_queue(self):
- AbstractPatchQueue.begin_work_queue(self)
-
- def next_work_item(self):
- return self._next_patch()
-
- def should_proceed_with_work_item(self, patch):
- raise NotImplementedError("subclasses must implement")
-
- def process_work_item(self, patch):
- try:
- if not self.review_patch(patch):
- return False
- self._did_pass(patch)
- return True
- except ScriptError, e:
- if e.exit_code != QueueEngine.handled_error_code:
- self._did_fail(patch)
- else:
- # The subprocess handled the error, but won't have released the patch, so we do.
- # FIXME: We need to simplify the rules by which _release_work_item is called.
- self._release_work_item(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()])
- return True
-
- @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/tool/commands/queues_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py
deleted file mode 100644
index b45db7b..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py
+++ /dev/null
@@ -1,378 +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.common.checkout.scm import CheckoutNeedsUpdate
-from webkitpy.common.config.committers import Committer
-from webkitpy.common.net.bugzilla import Attachment
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.queues import *
-from webkitpy.tool.commands.queuestest import QueuesTest
-from webkitpy.tool.commands.stepsequence import StepSequence
-from webkitpy.tool.mocktool import MockTool, MockSCM, MockStatusServer
-
-
-class TestQueue(AbstractPatchQueue):
- name = "test-queue"
-
-
-class TestReviewQueue(AbstractReviewQueue):
- name = "test-review-queue"
-
-
-class TestFeederQueue(FeederQueue):
- _sleep_duration = 0
-
-
-class AbstractQueueTest(CommandsTest):
- def test_log_directory(self):
- self.assertEquals(TestQueue()._log_directory(), "test-queue-logs")
-
- def _assert_run_webkit_patch(self, run_args, port=None):
- queue = TestQueue()
- tool = MockTool()
- tool.status_server.bot_id = "gort"
- tool.executive = Mock()
- queue.bind_to_tool(tool)
- queue._options = Mock()
- queue._options.port = port
-
- queue.run_webkit_patch(run_args)
- expected_run_args = ["echo", "--status-host=example.com", "--bot-id=gort"]
- if port:
- expected_run_args.append("--port=%s" % port)
- expected_run_args.extend(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])
- self._assert_run_webkit_patch([1], port="mockport")
-
- def test_iteration_count(self):
- queue = TestQueue()
- queue._options = Mock()
- queue._options.iterations = 3
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertFalse(queue.should_continue_work_queue())
-
- def test_no_iteration_count(self):
- queue = TestQueue()
- queue._options = Mock()
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
- self.assertTrue(queue.should_continue_work_queue())
-
- def _assert_log_message(self, script_error, log_message):
- failure_log = AbstractQueue._log_from_script_error_for_upload(script_error, output_limit=10)
- self.assertTrue(failure_log.read(), log_message)
-
- def test_log_from_script_error_for_upload(self):
- self._assert_log_message(ScriptError("test"), "test")
- # In python 2.5 unicode(Exception) is busted. See:
- # http://bugs.python.org/issue2517
- # With no good workaround, we just ignore these tests.
- if not hasattr(Exception, "__unicode__"):
- return
-
- unicode_tor = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
- utf8_tor = unicode_tor.encode("utf-8")
- self._assert_log_message(ScriptError(unicode_tor), utf8_tor)
- script_error = ScriptError(unicode_tor, output=unicode_tor)
- expected_output = "%s\nLast %s characters of output:\n%s" % (utf8_tor, 10, utf8_tor[-10:])
- self._assert_log_message(script_error, expected_output)
-
-
-class FeederQueueTest(QueuesTest):
- def test_feeder_queue(self):
- queue = TestFeederQueue()
- tool = MockTool(log_executive=True)
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("feeder-queue", MockSCM.fake_checkout_root),
- "should_proceed_with_work_item": "",
- "next_work_item": "",
- "process_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)
-MOCK setting flag 'commit-queue' to '-' on attachment '128' with comment 'Rejecting patch 128 from commit-queue.' and additional comment 'non-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/WebKitTools/Scripts/webkitpy/common/config/committers.py.
-
-- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.
-
-- If you have committer rights please correct the error in WebKitTools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed). The commit-queue restarts itself every 2 hours. After restart the commit-queue will correctly respect your committer rights.'
-MOCK: update_work_items: commit-queue [106, 197]
-Feeding commit-queue items [106, 197]
-Feeding EWS (1 r? patch, 1 new)
-MOCK: submit_to_ews: 103
-""",
- "handle_unexpected_error": "Mock error message\n",
- }
- self.assert_queue_outputs(queue, tool=tool, expected_stderr=expected_stderr)
-
-
-class AbstractPatchQueueTest(CommandsTest):
- def test_next_patch(self):
- queue = AbstractPatchQueue()
- tool = MockTool()
- queue.bind_to_tool(tool)
- queue._options = Mock()
- queue._options.port = None
- self.assertEquals(queue._next_patch(), None)
- tool.status_server = MockStatusServer(work_items=[2, 197])
- expected_stdout = "MOCK: fetch_attachment: 2 is not a known attachment id\n" # A mock-only message to prevent us from making mistakes.
- expected_stderr = "MOCK: release_work_item: None 2\n"
- patch_id = OutputCapture().assert_outputs(self, queue._next_patch, [], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
- self.assertEquals(patch_id, None) # 2 is an invalid patch id
- self.assertEquals(queue._next_patch().id(), 197)
-
-
-class NeedsUpdateSequence(StepSequence):
- def _run(self, tool, options, state):
- raise CheckoutNeedsUpdate([], 1, "", None)
-
-
-class AlwaysCommitQueueTool(object):
- def __init__(self):
- self.status_server = MockStatusServer()
-
- def command_by_name(self, name):
- return CommitQueue
-
-
-class SecondThoughtsCommitQueue(CommitQueue):
- def __init__(self):
- self._reject_patch = False
- CommitQueue.__init__(self)
-
- def run_command(self, command):
- # We want to reject the patch after the first validation,
- # so wait to reject it until after some other command has run.
- self._reject_patch = True
- return CommitQueue.run_command(self, command)
-
- def refetch_patch(self, patch):
- if not self._reject_patch:
- return self._tool.bugs.fetch_attachment(patch.id())
-
- attachment_dictionary = {
- "id": patch.id(),
- "bug_id": patch.bug_id(),
- "name": "Rejected",
- "is_obsolete": True,
- "is_patch": False,
- "review": "-",
- "reviewer_email": "foo@bar.com",
- "commit-queue": "-",
- "committer_email": "foo@bar.com",
- "attacher_email": "Contributer1",
- }
- return Attachment(attachment_dictionary, None)
-
-
-# Creating fake CommitInfos is a pain, so we use a mock one here.
-class MockCommitInfo(object):
- def __init__(self, author_email):
- self._author_email = author_email
-
- def author(self):
- # It's definitely possible to have commits with authors who
- # are not in our committers.py list.
- if not self._author_email:
- return None
- return Committer("Mock Committer", self._author_email)
-
-
-class CommitQueueTest(QueuesTest):
- def test_commit_queue(self):
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
- "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing patch\n",
- "next_work_item": "",
- "process_work_item": """MOCK: update_status: commit-queue Applied patch
-MOCK: update_status: commit-queue Built patch
-MOCK: update_status: commit-queue Passed tests
-MOCK: update_status: commit-queue Landed patch
-MOCK: update_status: commit-queue Pass
-MOCK: release_work_item: commit-queue 197
-""",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting patch 197 from commit-queue.' and additional comment 'Mock error message'\n",
- "handle_script_error": "ScriptError error message\n",
- }
- self.assert_queue_outputs(CommitQueue(), expected_stderr=expected_stderr)
-
- def test_commit_queue_failure(self):
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
- "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing patch\n",
- "next_work_item": "",
- "process_work_item": """MOCK: update_status: commit-queue Patch does not apply
-MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting patch 197 from commit-queue.' and additional comment 'MOCK script error'
-MOCK: update_status: commit-queue Fail
-MOCK: release_work_item: commit-queue 197
-""",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting patch 197 from commit-queue.' and additional comment 'Mock error message'\n",
- "handle_script_error": "ScriptError error message\n",
- }
- queue = CommitQueue()
-
- def mock_run_webkit_patch(command):
- raise ScriptError('MOCK script error')
-
- queue.run_webkit_patch = mock_run_webkit_patch
- self.assert_queue_outputs(queue, expected_stderr=expected_stderr)
-
- def test_rollout(self):
- tool = MockTool(log_executive=True)
- tool.buildbot.light_tree_on_fire()
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
- "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing patch\n",
- "next_work_item": "",
- "process_work_item": """MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'apply-attachment', '--force-clean', '--non-interactive', 197]
-MOCK: update_status: commit-queue Applied patch
-MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build', '--no-clean', '--no-update', '--build-style=both']
-MOCK: update_status: commit-queue Built patch
-MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
-MOCK: update_status: commit-queue Passed tests
-MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197]
-MOCK: update_status: commit-queue Landed patch
-MOCK: update_status: commit-queue Pass
-MOCK: release_work_item: commit-queue 197
-""",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting patch 197 from commit-queue.' and additional comment 'Mock error message'\n",
- "handle_script_error": "ScriptError error message\n",
- }
- self.assert_queue_outputs(CommitQueue(), tool=tool, expected_stderr=expected_stderr)
-
- def test_rollout_lands(self):
- tool = MockTool(log_executive=True)
- tool.buildbot.light_tree_on_fire()
- rollout_patch = tool.bugs.fetch_attachment(106) # _patch6, a rollout patch.
- assert(rollout_patch.is_rollout())
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
- "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing rollout patch\n",
- "next_work_item": "",
- "process_work_item": """MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'apply-attachment', '--force-clean', '--non-interactive', 106]
-MOCK: update_status: commit-queue Applied patch
-MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build', '--no-clean', '--no-update', '--build-style=both']
-MOCK: update_status: commit-queue Built patch
-MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 106]
-MOCK: update_status: commit-queue Landed patch
-MOCK: update_status: commit-queue Pass
-MOCK: release_work_item: commit-queue 106
-""",
- "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '106' with comment 'Rejecting patch 106 from commit-queue.' and additional comment 'Mock error message'\n",
- "handle_script_error": "ScriptError error message\n",
- }
- self.assert_queue_outputs(CommitQueue(), tool=tool, work_item=rollout_patch, expected_stderr=expected_stderr)
-
- def test_auto_retry(self):
- queue = CommitQueue()
- options = Mock()
- options.parent_command = "commit-queue"
- tool = AlwaysCommitQueueTool()
- sequence = NeedsUpdateSequence(None)
-
- expected_stderr = "Commit failed because the checkout is out of date. Please update and try again.\nMOCK: update_status: commit-queue Tests passed, but commit failed (checkout out of date). Updating, then landing without building or re-running tests.\n"
- state = {'patch': None}
- OutputCapture().assert_outputs(self, sequence.run_and_handle_errors, [tool, options, state], expected_exception=TryAgain, expected_stderr=expected_stderr)
-
- self.assertEquals(options.update, True)
- self.assertEquals(options.build, False)
- self.assertEquals(options.test, False)
-
- def test_manual_reject_during_processing(self):
- queue = SecondThoughtsCommitQueue()
- queue.bind_to_tool(MockTool())
- queue._options = Mock()
- queue._options.port = None
- expected_stderr = """MOCK: update_status: commit-queue Applied patch
-MOCK: update_status: commit-queue Built patch
-MOCK: update_status: commit-queue Passed tests
-MOCK: update_status: commit-queue Retry
-MOCK: release_work_item: commit-queue 197
-"""
- OutputCapture().assert_outputs(self, queue.process_work_item, [QueuesTest.mock_work_item], expected_stderr=expected_stderr)
-
- def _assert_emails_for_tests(self, emails):
- queue = CommitQueue()
- tool = MockTool()
- queue.bind_to_tool(tool)
- commit_infos = [MockCommitInfo(email) for email in emails]
- tool.checkout().recent_commit_infos_for_files = lambda paths: set(commit_infos)
- self.assertEqual(queue._author_emails_for_tests([]), set(emails))
-
- def test_author_emails_for_tests(self):
- self._assert_emails_for_tests([])
- self._assert_emails_for_tests(["test1@test.com", "test1@test.com"])
- self._assert_emails_for_tests(["test1@test.com", "test2@test.com"])
-
- def test_report_flaky_tests(self):
- queue = CommitQueue()
- queue.bind_to_tool(MockTool())
- expected_stderr = """MOCK bug comment: bug_id=42, cc=None
---- Begin comment ---
-The commit-queue encountered the following flaky tests while processing attachment 197:
-
-foo/bar.html
-bar/baz.html
-
-Please file bugs against the tests. These tests were authored by abarth@webkit.org. The commit-queue is continuing to process your patch.
---- End comment ---
-
-"""
- OutputCapture().assert_outputs(self, queue.report_flaky_tests, [QueuesTest.mock_work_item, ["foo/bar.html", "bar/baz.html"]], expected_stderr=expected_stderr)
-
- def test_layout_test_results(self):
- queue = CommitQueue()
- queue.bind_to_tool(MockTool())
- queue._read_file_contents = lambda path: None
- self.assertEquals(queue.layout_test_results(), None)
- queue._read_file_contents = lambda path: ""
- self.assertEquals(queue.layout_test_results(), None)
-
-
-class StyleQueueTest(QueuesTest):
- def test_style_queue(self):
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("style-queue", MockSCM.fake_checkout_root),
- "next_work_item": "",
- "should_proceed_with_work_item": "MOCK: update_status: style-queue Checking style\n",
- "process_work_item": "MOCK: update_status: style-queue Pass\nMOCK: release_work_item: style-queue 197\n",
- "handle_unexpected_error": "Mock error message\n",
- "handle_script_error": "MOCK: update_status: style-queue ScriptError error message\nMOCK bug comment: bug_id=42, cc=[]\n--- Begin comment ---\nAttachment 197 did not pass style-queue:\n\nScriptError error message\n\nIf any of these errors are false positives, please file a bug against check-webkit-style.\n--- End comment ---\n\n",
- }
- expected_exceptions = {
- "handle_script_error": SystemExit,
- }
- self.assert_queue_outputs(StyleQueue(), expected_stderr=expected_stderr, expected_exceptions=expected_exceptions)
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queuestest.py b/WebKitTools/Scripts/webkitpy/tool/commands/queuestest.py
deleted file mode 100644
index 6455617..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/queuestest.py
+++ /dev/null
@@ -1,95 +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.common.net.bugzilla import Attachment
-from webkitpy.common.system.outputcapture import OutputCapture
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
-from webkitpy.tool.mocktool import MockTool
-
-
-class MockQueueEngine(object):
- def __init__(self, name, queue, wakeup_event):
- pass
-
- def run(self):
- pass
-
-
-class QueuesTest(unittest.TestCase):
- # This is _patch1 in mocktool.py
- mock_work_item = MockTool().bugs.fetch_attachment(197)
-
- def assert_outputs(self, func, func_name, args, expected_stdout, expected_stderr, expected_exceptions):
- exception = None
- if expected_exceptions and func_name in expected_exceptions:
- exception = expected_exceptions[func_name]
-
- OutputCapture().assert_outputs(self,
- func,
- args=args,
- expected_stdout=expected_stdout.get(func_name, ""),
- expected_stderr=expected_stderr.get(func_name, ""),
- expected_exception=exception)
-
- def _default_begin_work_queue_stderr(self, name, checkout_dir):
- string_replacements = {"name": name, 'checkout_dir': checkout_dir}
- return "CAUTION: %(name)s will discard all local changes in \"%(checkout_dir)s\"\nRunning WebKit %(name)s.\nMOCK: update_status: %(name)s Starting Queue\n" % string_replacements
-
- def assert_queue_outputs(self, queue, args=None, work_item=None, expected_stdout=None, expected_stderr=None, expected_exceptions=None, options=None, tool=None):
- if not tool:
- tool = MockTool()
- if not expected_stdout:
- expected_stdout = {}
- if not expected_stderr:
- expected_stderr = {}
- if not args:
- args = []
- if not options:
- options = Mock()
- options.port = None
- if not work_item:
- work_item = self.mock_work_item
- tool.user.prompt = lambda message: "yes"
-
- queue.execute(options, args, tool, engine=MockQueueEngine)
-
- self.assert_outputs(queue.queue_log_path, "queue_log_path", [], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.work_item_log_path, "work_item_log_path", [work_item], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.begin_work_queue, "begin_work_queue", [], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.should_continue_work_queue, "should_continue_work_queue", [], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.next_work_item, "next_work_item", [], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.should_proceed_with_work_item, "should_proceed_with_work_item", [work_item], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.process_work_item, "process_work_item", [work_item], expected_stdout, expected_stderr, expected_exceptions)
- self.assert_outputs(queue.handle_unexpected_error, "handle_unexpected_error", [work_item, "Mock error message"], expected_stdout, expected_stderr, expected_exceptions)
- # Should we have a different function for testing StepSequenceErrorHandlers?
- if isinstance(queue, StepSequenceErrorHandler):
- self.assert_outputs(queue.handle_script_error, "handle_script_error", [tool, {"patch": self.mock_work_item}, ScriptError(message="ScriptError error message", script_args="MockErrorCommand")], expected_stdout, expected_stderr, expected_exceptions)
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaseline.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaseline.py
deleted file mode 100644
index abfa850..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/rebaseline.py
+++ /dev/null
@@ -1,114 +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 os.path
-import re
-import shutil
-import urllib
-
-from webkitpy.common.net.buildbot import BuildBot, LayoutTestResults
-from webkitpy.common.system.user import User
-from webkitpy.layout_tests.port import factory
-from webkitpy.tool.grammar import pluralize
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-
-
-# FIXME: I'm not sure where this logic should go in the end.
-# For now it's here, until we have a second need for it.
-class BuilderToPort(object):
- _builder_name_to_port_name = {
- r"SnowLeopard": "mac-snowleopard",
- r"Leopard": "mac-leopard",
- r"Tiger": "mac-tiger",
- r"Windows": "win",
- r"GTK": "gtk",
- r"Qt": "qt",
- r"Chromium Mac": "chromium-mac",
- r"Chromium Linux": "chromium-linux",
- r"Chromium Win": "chromium-win",
- }
-
- def _port_name_for_builder_name(self, builder_name):
- for regexp, port_name in self._builder_name_to_port_name.items():
- if re.match(regexp, builder_name):
- return port_name
-
- def port_for_builder(self, builder_name):
- port_name = self._port_name_for_builder_name(builder_name)
- assert(port_name) # Need to update _builder_name_to_port_name
- port = factory.get(port_name)
- assert(port) # Need to update _builder_name_to_port_name
- return port
-
-
-class Rebaseline(AbstractDeclarativeCommand):
- name = "rebaseline"
- help_text = "Replaces local expected.txt files with new results from build bots"
-
- # FIXME: This should share more code with FailureReason._builder_to_explain
- def _builder_to_pull_from(self):
- builder_statuses = self._tool.buildbot.builder_statuses()
- red_statuses = [status for status in builder_statuses if not status["is_green"]]
- print "%s failing" % (pluralize("builder", len(red_statuses)))
- builder_choices = [status["name"] for status in red_statuses]
- chosen_name = self._tool.user.prompt_with_list("Which builder to pull results from:", builder_choices)
- # FIXME: prompt_with_list should really take a set of objects and a set of names and then return the object.
- for status in red_statuses:
- if status["name"] == chosen_name:
- return (self._tool.buildbot.builder_with_name(chosen_name), status["build_number"])
-
- def _replace_expectation_with_remote_result(self, local_file, remote_file):
- (downloaded_file, headers) = urllib.urlretrieve(remote_file)
- shutil.move(downloaded_file, local_file)
-
- def _tests_to_update(self, build):
- parsed_results = build.layout_test_results().parsed_results()
- # FIXME: This probably belongs as API on LayoutTestResults
- # but .failing_tests() already means something else.
- failing_tests = parsed_results[LayoutTestResults.fail_key]
- return self._tool.user.prompt_with_list("Which test(s) to rebaseline:", failing_tests, can_choose_multiple=True)
-
- def _results_url_for_test(self, build, test):
- test_base = os.path.splitext(test)[0]
- actual_path = test_base + "-actual.txt"
- return build.results_url() + "/" + actual_path
-
- def execute(self, options, args, tool):
- builder, build_number = self._builder_to_pull_from()
- build = builder.build(build_number)
- port = BuilderToPort().port_for_builder(builder.name())
-
- for test in self._tests_to_update(build):
- results_url = self._results_url_for_test(build, test)
- # Port operates with absolute paths.
- absolute_path = os.path.join(port.layout_tests_dir(), test)
- expected_file = port.expected_filename(absolute_path, ".txt")
- print test
- self._replace_expectation_with_remote_result(expected_file, results_url)
-
- # FIXME: We should handle new results too.
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
deleted file mode 100644
index d6582a7..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ /dev/null
@@ -1,38 +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 unittest
-
-from webkitpy.tool.commands.rebaseline import BuilderToPort
-
-
-class BuilderToPortTest(unittest.TestCase):
- def test_port_for_builder(self):
- converter = BuilderToPort()
- port = converter.port_for_builder("Leopard Intel Debug (Tests)")
- self.assertEqual(port.name(), "mac-leopard")
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
deleted file mode 100644
index 2924a6f..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py
+++ /dev/null
@@ -1,268 +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.
-
-"""Starts a local HTTP server which displays layout test failures (given a test
-results directory), provides comparisons of expected and actual results (both
-images and text) and allows one-click rebaselining of tests."""
-from __future__ import with_statement
-
-import codecs
-import datetime
-import mimetypes
-import os
-import os.path
-import shutil
-import threading
-import time
-import urlparse
-import BaseHTTPServer
-
-from optparse import make_option
-from wsgiref.handlers import format_date_time
-
-from webkitpy.common import system
-from webkitpy.layout_tests.port import factory
-from webkitpy.layout_tests.port.webkit import WebKitPort
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.thirdparty import simplejson
-
-STATE_NEEDS_REBASELINE = 'needs_rebaseline'
-STATE_REBASELINE_FAILED = 'rebaseline_failed'
-STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded'
-
-class RebaselineHTTPServer(BaseHTTPServer.HTTPServer):
- def __init__(self, httpd_port, results_directory, results_json, platforms_json):
- BaseHTTPServer.HTTPServer.__init__(self, ("", httpd_port), RebaselineHTTPRequestHandler)
- self.results_directory = results_directory
- self.results_json = results_json
- self.platforms_json = platforms_json
-
-
-class RebaselineHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- STATIC_FILE_NAMES = frozenset([
- "index.html",
- "loupe.js",
- "main.js",
- "main.css",
- "queue.js",
- "util.js",
- ])
-
- STATIC_FILE_DIRECTORY = os.path.join(
- os.path.dirname(__file__), "data", "rebaselineserver")
-
- def do_GET(self):
- self._handle_request()
-
- def do_POST(self):
- self._handle_request()
-
- def _handle_request(self):
- # Parse input.
- if "?" in self.path:
- path, query_string = self.path.split("?", 1)
- self.query = urlparse.parse_qs(query_string)
- else:
- path = self.path
- self.query = {}
- function_or_file_name = path[1:] or "index.html"
-
- # See if a static file matches.
- if function_or_file_name in RebaselineHTTPRequestHandler.STATIC_FILE_NAMES:
- self._serve_static_file(function_or_file_name)
- return
-
- # See if a class method matches.
- function_name = function_or_file_name.replace(".", "_")
- if not hasattr(self, function_name):
- self.send_error(404, "Unknown function %s" % function_name)
- return
- if function_name[0] == "_":
- self.send_error(
- 401, "Not allowed to invoke private or protected methods")
- return
- function = getattr(self, function_name)
- function()
-
- def _serve_static_file(self, static_path):
- self._serve_file(os.path.join(
- RebaselineHTTPRequestHandler.STATIC_FILE_DIRECTORY, static_path))
-
- def quitquitquit(self):
- self.send_response(200)
- self.send_header("Content-type", "text/plain")
- self.end_headers()
- self.wfile.write("Quit.\n")
-
- # Shutdown has to happen on another thread from the server's thread,
- # otherwise there's a deadlock
- threading.Thread(target=lambda: self.server.shutdown()).start()
-
- def test_result(self):
- test_name, _ = os.path.splitext(self.query['test'][0])
- mode = self.query['mode'][0]
- if mode == 'expected-image':
- file_name = test_name + '-expected.png'
- elif mode == 'actual-image':
- file_name = test_name + '-actual.png'
- if mode == 'expected-checksum':
- file_name = test_name + '-expected.checksum'
- elif mode == 'actual-checksum':
- file_name = test_name + '-actual.checksum'
- elif mode == 'diff-image':
- file_name = test_name + '-diff.png'
- if mode == 'expected-text':
- file_name = test_name + '-expected.txt'
- elif mode == 'actual-text':
- file_name = test_name + '-actual.txt'
- elif mode == 'diff-text':
- file_name = test_name + '-diff.txt'
-
- file_path = os.path.join(self.server.results_directory, file_name)
-
- # Let results be cached for 60 seconds, so that they can be pre-fetched
- # by the UI
- self._serve_file(file_path, cacheable_seconds=60)
-
- def results_json(self):
- self._serve_json(self.server.results_json)
-
- def platforms_json(self):
- self._serve_json(self.server.platforms_json)
-
- def _serve_json(self, json):
- self.send_response(200)
- self.send_header('Content-type', 'application/json')
- self.end_headers()
- simplejson.dump(json, self.wfile)
-
- def _serve_file(self, file_path, cacheable_seconds=0):
- if not os.path.exists(file_path):
- self.send_error(404, "File not found")
- return
- with codecs.open(file_path, "rb") as static_file:
- self.send_response(200)
- self.send_header("Content-Length", os.path.getsize(file_path))
- mime_type, encoding = mimetypes.guess_type(file_path)
- if mime_type:
- self.send_header("Content-type", mime_type)
-
- if cacheable_seconds:
- expires_time = (datetime.datetime.now() +
- datetime.timedelta(0, cacheable_seconds))
- expires_formatted = format_date_time(
- time.mktime(expires_time.timetuple()))
- self.send_header("Expires", expires_formatted)
- self.end_headers()
-
- shutil.copyfileobj(static_file, self.wfile)
-
-
-def _get_test_baselines(test_file, layout_tests_directory, platforms, filesystem):
- class AllPlatformsPort(WebKitPort):
- def __init__(self):
- WebKitPort.__init__(self, filesystem=filesystem)
- self._platforms_by_directory = dict(
- [(self._webkit_baseline_path(p), p) for p in platforms])
-
- def baseline_search_path(self):
- return self._platforms_by_directory.keys()
-
- def platform_from_directory(self, directory):
- return self._platforms_by_directory[directory]
-
- all_platforms_port = AllPlatformsPort()
-
- test_baselines = {}
- for baseline_extension in ('.txt', '.checksum', '.png'):
- test_path = filesystem.join(layout_tests_directory, test_file)
- baselines = all_platforms_port.expected_baselines(
- test_path, baseline_extension, all_baselines=True)
- for platform_directory, expected_filename in baselines:
- if not platform_directory:
- continue
- if platform_directory == layout_tests_directory:
- platform = 'base'
- else:
- platform = all_platforms_port.platform_from_directory(
- platform_directory)
- if platform not in test_baselines:
- test_baselines[platform] = []
- test_baselines[platform].append(baseline_extension)
-
- for platform, extensions in test_baselines.items():
- test_baselines[platform] = tuple(extensions)
-
- return test_baselines
-
-class RebaselineServer(AbstractDeclarativeCommand):
- name = "rebaseline-server"
- help_text = __doc__
- argument_names = "/path/to/results/directory"
-
- def __init__(self):
- options = [
- make_option("--httpd-port", action="store", type="int", default=8127, help="Port to use for the the rebaseline HTTP server"),
- ]
- AbstractDeclarativeCommand.__init__(self, options=options)
-
- def execute(self, options, args, tool):
- results_directory = args[0]
- filesystem = system.filesystem.FileSystem()
-
- print 'Parsing unexpected_results.json...'
- results_json_path = filesystem.join(
- results_directory, 'unexpected_results.json')
- with codecs.open(results_json_path, "r") as results_json_file:
- results_json_file = file(results_json_path)
- results_json = simplejson.load(results_json_file)
-
- port = factory.get()
- layout_tests_directory = port.layout_tests_dir()
- platforms = filesystem.listdir(
- filesystem.join(layout_tests_directory, 'platform'))
-
- print 'Gathering current baselines...'
- for test_file, test_json in results_json['tests'].items():
- test_json['state'] = STATE_NEEDS_REBASELINE
- test_json['baselines'] = _get_test_baselines(
- test_file, layout_tests_directory, platforms, filesystem)
-
- print "Starting server at http://localhost:%d/" % options.httpd_port
- print ("Use the 'Exit' link in the UI, http://localhost:%d/"
- "quitquitquit or Ctrl-C to stop") % options.httpd_port
-
- httpd = RebaselineHTTPServer(
- httpd_port=options.httpd_port,
- results_directory=results_directory,
- results_json=results_json,
- platforms_json={
- 'platforms': platforms,
- 'defaultPlatform': port.name(),
- })
- httpd.serve_forever()
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py
deleted file mode 100644
index ea52902..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py
+++ /dev/null
@@ -1,88 +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 unittest
-
-from webkitpy.common.system import filesystem_mock
-from webkitpy.layout_tests.port import base
-from webkitpy.tool.commands import rebaselineserver
-
-
-class GetBaselinesTest(unittest.TestCase):
- def test_no_baselines(self):
- self._assertBaselines(
- test_files=(),
- test='fast/missing.html',
- expected_baselines={})
-
- def test_text_baselines(self):
- self._assertBaselines(
- test_files=(
- 'fast/text-expected.txt',
- 'platform/mac/fast/text-expected.txt',
- ),
- test='fast/text.html',
- expected_baselines={'mac': ('.txt',), 'base': ('.txt',)})
-
- def test_image_and_text_baselines(self):
- self._assertBaselines(
- test_files=(
- 'fast/image-expected.txt',
- 'platform/mac/fast/image-expected.png',
- 'platform/mac/fast/image-expected.checksum',
- 'platform/win/fast/image-expected.png',
- 'platform/win/fast/image-expected.checksum',
- ),
- test='fast/image.html',
- expected_baselines={
- 'base': ('.txt',),
- 'mac': ('.checksum', '.png'),
- 'win': ('.checksum', '.png'),
- })
-
- def test_extra_baselines(self):
- self._assertBaselines(
- test_files=(
- 'fast/text-expected.txt',
- 'platform/nosuchplatform/fast/text-expected.txt',
- ),
- test='fast/text.html',
- expected_baselines={'base': ('.txt',)})
-
- def _assertBaselines(self, test_files, test, expected_baselines):
- layout_tests_directory = base.Port().layout_tests_dir()
- mock_filesystem = filesystem_mock.MockFileSystem()
- for file in test_files + (test,):
- file_path = mock_filesystem.join(layout_tests_directory, file)
- mock_filesystem.files[file_path] = ''
- actual_baselines = rebaselineserver._get_test_baselines(
- test,
- layout_tests_directory,
- ('mac', 'win', 'linux'),
- mock_filesystem)
- self.assertEqual(actual_baselines, expected_baselines)
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot.py b/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot.py
deleted file mode 100644
index 145f485..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot.py
+++ /dev/null
@@ -1,106 +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.common.system.deprecated_logging import log
-from webkitpy.common.config.ports import WebKitPort
-from webkitpy.tool.bot.sheriff import Sheriff
-from webkitpy.tool.bot.sheriffircbot import SheriffIRCBot
-from webkitpy.tool.commands.queues import AbstractQueue
-from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
-
-
-class SheriffBot(AbstractQueue, StepSequenceErrorHandler):
- name = "sheriff-bot"
- watchers = AbstractQueue.watchers + [
- "abarth@webkit.org",
- "eric@webkit.org",
- ]
-
- def _update(self):
- self.run_webkit_patch(["update", "--force-clean", "--quiet"])
-
- # AbstractQueue methods
-
- def begin_work_queue(self):
- AbstractQueue.begin_work_queue(self)
- self._sheriff = Sheriff(self._tool, self)
- self._irc_bot = SheriffIRCBot(self._tool, self._sheriff)
- self._tool.ensure_irc_connected(self._irc_bot.irc_delegate())
-
- def work_item_log_path(self, failure_map):
- return None
-
- def _is_old_failure(self, revision):
- return self._tool.status_server.svn_revision(revision)
-
- def next_work_item(self):
- self._irc_bot.process_pending_messages()
- self._update()
-
- # FIXME: We need to figure out how to provoke_flaky_builders.
-
- failure_map = self._tool.buildbot.failure_map()
- failure_map.filter_out_old_failures(self._is_old_failure)
- if failure_map.is_empty():
- return None
- return failure_map
-
- def should_proceed_with_work_item(self, failure_map):
- # Currently, we don't have any reasons not to proceed with work items.
- return True
-
- def process_work_item(self, failure_map):
- failing_revisions = failure_map.failing_revisions()
- for revision in failing_revisions:
- builders = failure_map.builders_failing_for(revision)
- tests = failure_map.tests_failing_for(revision)
- try:
- commit_info = self._tool.checkout().commit_info_for_revision(revision)
- if not commit_info:
- print "FAILED to fetch CommitInfo for r%s, likely missing ChangeLog" % revision
- continue
- self._sheriff.post_irc_warning(commit_info, builders)
- self._sheriff.post_blame_comment_on_bug(commit_info, builders, tests)
-
- finally:
- for builder in builders:
- self._tool.status_server.update_svn_revision(revision, builder.name())
- return True
-
- def handle_unexpected_error(self, failure_map, message):
- log(message)
-
- # StepSequenceErrorHandler methods
-
- @classmethod
- def handle_script_error(cls, tool, state, script_error):
- # Ideally we would post some information to IRC about what went wrong
- # here, but we don't have the IRC password in the child process.
- pass
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py
deleted file mode 100644
index 4db463e..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py
+++ /dev/null
@@ -1,57 +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 os
-
-from webkitpy.tool.commands.queuestest import QueuesTest
-from webkitpy.tool.commands.sheriffbot import SheriffBot
-from webkitpy.tool.mocktool import *
-
-
-class SheriffBotTest(QueuesTest):
- builder1 = MockBuilder("Builder1")
- builder2 = MockBuilder("Builder2")
-
- def test_sheriff_bot(self):
- tool = MockTool()
- mock_work_item = MockFailureMap(tool.buildbot)
- expected_stderr = {
- "begin_work_queue": self._default_begin_work_queue_stderr("sheriff-bot", tool.scm().checkout_root),
- "next_work_item": "",
- "process_work_item": """MOCK: irc.post: abarth, darin, eseidel: http://trac.webkit.org/changeset/29837 might have broken Builder1
-MOCK bug comment: bug_id=42, cc=['abarth@webkit.org', 'eric@webkit.org']
---- Begin comment ---
-http://trac.webkit.org/changeset/29837 might have broken Builder1
-The following tests are not passing:
-mock-test-1
---- End comment ---
-
-""",
- "handle_unexpected_error": "Mock error message\n"
- }
- self.assert_queue_outputs(SheriffBot(), work_item=mock_work_item, expected_stderr=expected_stderr)
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/stepsequence.py b/WebKitTools/Scripts/webkitpy/tool/commands/stepsequence.py
deleted file mode 100644
index be2ed4c..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/stepsequence.py
+++ /dev/null
@@ -1,83 +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 webkitpy.tool.steps as steps
-
-from webkitpy.common.system.executive import ScriptError
-from webkitpy.common.checkout.scm import CheckoutNeedsUpdate
-from webkitpy.tool.bot.queueengine import QueueEngine
-from webkitpy.common.system.deprecated_logging import log
-
-
-class StepSequenceErrorHandler():
- @classmethod
- def handle_script_error(cls, tool, patch, script_error):
- raise NotImplementedError, "subclasses must implement"
-
- @classmethod
- def handle_checkout_needs_update(cls, tool, state, options, error):
- raise NotImplementedError, "subclasses must implement"
-
-
-class StepSequence(object):
- def __init__(self, steps):
- self._steps = steps or []
-
- def options(self):
- collected_options = [
- steps.Options.parent_command,
- steps.Options.quiet,
- ]
- for step in self._steps:
- collected_options = collected_options + step.options()
- # Remove duplicates.
- collected_options = sorted(set(collected_options))
- return collected_options
-
- def _run(self, tool, options, state):
- for step in self._steps:
- step(tool, options).run(state)
-
- def run_and_handle_errors(self, tool, options, state=None):
- if not state:
- state = {}
- try:
- self._run(tool, options, state)
- except CheckoutNeedsUpdate, e:
- log("Commit failed because the checkout is out of date. Please update and try again.")
- if options.parent_command:
- command = tool.command_by_name(options.parent_command)
- command.handle_checkout_needs_update(tool, state, options, e)
- QueueEngine.exit_after_handled_error(e)
- except ScriptError, e:
- if not options.quiet:
- log(e.message_with_output())
- if options.parent_command:
- command = tool.command_by_name(options.parent_command)
- command.handle_script_error(tool, state, e)
- QueueEngine.exit_after_handled_error(e)
diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/upload.py b/WebKitTools/Scripts/webkitpy/tool/commands/upload.py
deleted file mode 100644
index e12c8e2..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/upload.py
+++ /dev/null
@@ -1,483 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2009, 2010 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 sys
-
-from optparse import make_option
-
-import webkitpy.tool.steps as steps
-
-from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.net.bugzilla import parse_bug_id
-from webkitpy.common.system.user import User
-from webkitpy.thirdparty.mock import Mock
-from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
-from webkitpy.tool.grammar import pluralize, join_with_separators
-from webkitpy.tool.comments import bug_comment_from_svn_revision
-from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.common.system.deprecated_logging import error, log
-
-
-class CommitMessageForCurrentDiff(AbstractDeclarativeCommand):
- name = "commit-message"
- help_text = "Print a commit message suitable for the uncommitted changes"
-
- def __init__(self):
- options = [
- steps.Options.git_commit,
- ]
- AbstractDeclarativeCommand.__init__(self, options=options)
-
- def execute(self, options, args, tool):
- # This command is a useful test to make sure commit_message_for_this_commit
- # always returns the right value regardless of the current working directory.
- print "%s" % tool.checkout().commit_message_for_this_commit(options.git_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)
-
-
-# FIXME: This should be share more logic with AssignToCommitter and CleanPendingCommit
-class CleanReviewQueue(AbstractDeclarativeCommand):
- name = "clean-review-queue"
- help_text = "Clear r? on obsolete patches so they do not appear in the pending-commit list."
-
- def execute(self, options, args, tool):
- queue_url = "http://webkit.org/pending-review"
- # We do this inefficient dance to be more like webkit.org/pending-review
- # bugs.queries.fetch_bug_ids_from_review_queue() doesn't return
- # closed bugs, but folks using /pending-review will see them. :(
- for patch_id in tool.bugs.queries.fetch_attachment_ids_from_review_queue():
- patch = self._tool.bugs.fetch_attachment(patch_id)
- if not patch.review() == "?":
- continue
- attachment_obsolete_modifier = ""
- if patch.is_obsolete():
- attachment_obsolete_modifier = "obsolete "
- elif patch.bug().is_closed():
- bug_closed_explanation = " If you would like this patch reviewed, please attach it to a new bug (or re-open this bug before marking it for review again)."
- else:
- # Neither the patch was obsolete or the bug was closed, next patch...
- continue
- message = "Cleared review? from %sattachment %s so that this bug does not appear in %s.%s" % (attachment_obsolete_modifier, patch.id(), queue_url, bug_closed_explanation)
- 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)
- if not bug.is_unassigned():
- assigned_to_email = bug.assigned_to_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, options, 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:
- changed_files = self._tool.scm().changed_files(options.git_commit)
- state["changed_files"] = changed_files
- bug_id = tool.checkout().bug_id_for_this_commit(options.git_commit, changed_files)
- return bug_id
-
- def _prepare_state(self, options, args, tool):
- state = {}
- state["bug_id"] = self._bug_id(options, args, tool, state)
- if not state["bug_id"]:
- error("No bug id passed and no bug url found in ChangeLogs.")
- 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]"
- steps = [
- steps.CheckStyle,
- steps.ConfirmDiff,
- steps.ObsoletePatches,
- steps.SuggestReviewers,
- steps.PostDiff,
- ]
-
-
-class LandSafely(AbstractPatchUploadingCommand):
- name = "land-safely"
- help_text = "Land the current diff via the commit-queue"
- argument_names = "[BUGID]"
- long_help = """land-safely updates the ChangeLog with the reviewer listed
- in bugs.webkit.org for BUGID (or the bug ID detected from the ChangeLog).
- The command then uploads the current diff to the bug and marks it for
- commit by the commit-queue."""
- show_in_main_help = True
- 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]"
- 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.SuggestReviewers,
- 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(options, 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 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(git_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 = tool.scm().create_patch(git_commit=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, description, comment_text, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
-
-
-# FIXME: This command needs to be brought into the modern age with steps and CommitInfo.
-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)
-
- # FIXME: We should be using checkout().changelog_entries_for_revision(...) instead here.
- 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(git_commit=commit_id)
- bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff, "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.checkout().commit_message_for_this_commit(options.git_commit)
- bug_title = commit_message.description(lstrip=True, strip_url=True)
- comment_text = commit_message.body(lstrip=True)
-
- diff = tool.scm().create_patch(options.git_commit)
- bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff, "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/tool/commands/upload_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py
deleted file mode 100644
index bd1fbd6..0000000
--- a/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py
+++ /dev/null
@@ -1,117 +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.thirdparty.mock import Mock
-from webkitpy.tool.commands.commandtest import CommandsTest
-from webkitpy.tool.commands.upload import *
-from webkitpy.tool.mocktool import MockOptions, MockTool
-
-class UploadCommandsTest(CommandsTest):
- def test_commit_message_for_current_diff(self):
- tool = MockTool()
- expected_stdout = "This is a fake commit message that is at least 50 characters.\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 = MockTool()
- 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):
- options = MockOptions()
- options.cc = None
- options.check_style = True
- options.comment = None
- options.description = "MOCK description"
- options.request_commit = False
- options.review = True
- options.suggest_reviewers = False
- expected_stderr = """Running check-webkit-style
-MOCK: user.open_url: file://...
-Obsoleting 2 old patches on bug 42
-MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
--- Begin comment --
-None
--- End comment --
-MOCK: user.open_url: http://example.com/42
-"""
- expected_stdout = "Was that diff correct?\n"
- self.assert_execute_outputs(Post(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
-
- def test_land_safely(self):
- expected_stderr = "Obsoleting 2 old patches on bug 42\nMOCK add_patch_to_bug: bug_id=42, description=Patch for landing, mark_for_review=False, mark_for_commit_queue=False, mark_for_landing=True\n-- Begin comment --\nNone\n-- End comment --\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):
- expected_stderr = "MOCK create_bug\nbug_title: Mock user response\nbug_description: Mock user response\n"
- self.assert_execute_outputs(Prepare(), [], expected_stderr=expected_stderr)
-
- def test_upload(self):
- options = MockOptions()
- options.cc = None
- options.check_style = True
- options.comment = None
- options.description = "MOCK description"
- options.request_commit = False
- options.review = True
- options.suggest_reviewers = False
- expected_stderr = """Running check-webkit-style
-MOCK: user.open_url: file://...
-Obsoleting 2 old patches on bug 42
-MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
--- Begin comment --
-None
--- End comment --
-MOCK: user.open_url: http://example.com/42
-"""
- expected_stdout = "Was that diff correct?\n"
- self.assert_execute_outputs(Upload(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
-
- def test_mark_bug_fixed(self):
- tool = MockTool()
- tool._scm.last_svn_commit_log = lambda: "r9876 |"
- options = Mock()
- options.bug_id = 42
- options.comment = "MOCK comment"
- 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.\nRevision: 9876\nMOCK: user.open_url: http://example.com/42\nAdding comment to Bug 42.\nMOCK bug comment: bug_id=42, cc=None\n--- Begin comment ---\nMOCK comment\n\nCommitted r9876: <http://trac.webkit.org/changeset/9876>\n--- End comment ---\n\n"
- expected_stdout = "Is this correct?\n"
- self.assert_execute_outputs(MarkBugFixed(), [], expected_stdout=expected_stdout, expected_stderr=expected_stderr, tool=tool, options=options)
-
- def test_edit_changelog(self):
- self.assert_execute_outputs(EditChangeLogs(), [])