garden-o-matic should have a "rebaseline" button
authorabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jul 2011 02:06:28 +0000 (02:06 +0000)
committerabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jul 2011 02:06:28 +0000 (02:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=64446

Reviewed by Ojan Vafai.

This patch adds a basic Rebaseline button that copies the baselines
displayed in the results pane into the appropriate directory in your
working copy.

There are two main limitations:

1) There is no UI for actually committing the baselines.

2) The baselines are not optimized for redundancy (meaning you can have
   identical baselines in both chromium-mac and chromium-win).

* Scripts/webkitpy/tool/commands/rebaseline.py:
    - Turns out we need to create the directory for the baseline if it doesn't exist yet.
* Scripts/webkitpy/tool/servers/data/gardeningserver/checkout.js:
    - Add an programatic API to call the server.
* Scripts/webkitpy/tool/servers/data/gardeningserver/index.html:
    - Add the rebaseline button itself.
* Scripts/webkitpy/tool/servers/data/gardeningserver/main.css:
    - Change the CSS so that the Rebaseline and Close buttons can
      appear in the normal order in the DOM.
* Scripts/webkitpy/tool/servers/data/gardeningserver/main.js:
    - Bind the event and translate the parameters.
    - Hide/show the rebaseline button, as appropriate.
* Scripts/webkitpy/tool/servers/data/gardeningserver/results.js:
    - Add some helpful utility functions for manipulating failure types.
* Scripts/webkitpy/tool/servers/data/gardeningserver/results_unittests.js:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@91042 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/Scripts/webkitpy/tool/commands/rebaseline.py
Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/checkout.js
Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/index.html
Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.css
Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js
Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js
Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results_unittests.js

index 3e8ac56..43b7340 100644 (file)
@@ -1,3 +1,37 @@
+2011-07-14  Adam Barth  <abarth@webkit.org>
+
+        garden-o-matic should have a "rebaseline" button
+        https://bugs.webkit.org/show_bug.cgi?id=64446
+
+        Reviewed by Ojan Vafai.
+
+        This patch adds a basic Rebaseline button that copies the baselines
+        displayed in the results pane into the appropriate directory in your
+        working copy.
+
+        There are two main limitations:
+
+        1) There is no UI for actually committing the baselines.
+
+        2) The baselines are not optimized for redundancy (meaning you can have
+           identical baselines in both chromium-mac and chromium-win).
+
+        * Scripts/webkitpy/tool/commands/rebaseline.py:
+            - Turns out we need to create the directory for the baseline if it doesn't exist yet.
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/checkout.js:
+            - Add an programatic API to call the server.
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/index.html:
+            - Add the rebaseline button itself.
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/main.css:
+            - Change the CSS so that the Rebaseline and Close buttons can
+              appear in the normal order in the DOM.
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/main.js:
+            - Bind the event and translate the parameters.
+            - Hide/show the rebaseline button, as appropriate.
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/results.js:
+            - Add some helpful utility functions for manipulating failure types.
+        * Scripts/webkitpy/tool/servers/data/gardeningserver/results_unittests.js:
+
 2011-07-14  Ryosuke Niwa  <rniwa@webkit.org>
 
         REGRESSION: webkit-patch roll-chromium-deps is broken
index e5c58bf..a3c9cf4 100644 (file)
@@ -101,7 +101,9 @@ class RebaselineTest(AbstractDeclarativeCommand):
         return port.baseline_path()
 
     def _save_baseline(self, data, target_baseline):
-        self._tool.filesystem.write_binary_file(target_baseline, data)
+        filesystem = self._tool.filesystem
+        filesystem.maybe_make_directory(filesystem.dirname(target_baseline))
+        filesystem.write_binary_file(target_baseline, data)
         if not self._tool.scm().exists(target_baseline):
             self._tool.scm().add(target_baseline)
 
index bdefb1d..143475e 100644 (file)
@@ -28,4 +28,31 @@ checkout.existsAtRevision = function (subversionURL, revision, callback)
     });
 };
 
+checkout.rebaseline = function(builderName, testName, failureTypeList, callback)
+{
+    var extensionList = [];
+
+    $.each(failureTypeList, function(index, failureType) {
+        extensionList = extensionList.concat(results.failureTypeToExtensionList(failureType));
+    });
+
+    var requestsInFlight = extensionList.length;
+
+    if (!requestsInFlight)
+        callback();
+
+    $.each(extensionList, function(index, extension) {
+        $.post('/rebaseline?' + $.param({
+            'builder': builderName,
+            'test': testName,
+            // FIXME: Rename "suffix" query parameter to "extension".
+            'suffix': extension
+        }), function() {
+            --requestsInFlight;
+            if (!requestsInFlight)
+                callback();
+        });
+    });
+};
+
 })();
index 3ad3add..72a1cb9 100644 (file)
 <div class="butterbar"><span class="status">Loading...</span></div>
 <div class="results"></div>
 <div class="results-detail">
-<div class="toolbar"><span class="status"></span> <a class="dismiss" href="#">Close</a></div><div class="content"></div></div>
+    <div class="toolbar">
+        <div class="actions">
+            <a class="rebaseline" href="#">Rebaseline</a>
+            <a class="dismiss" href="#">Close</a>
+        </div>
+        <div class="status"></div>
+    </div>
+    <div class="content"></div>
+</div>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 
 <script src="config.js"></script>
 <script src="base.js"></script>
index 0f099e6..3f1e98c 100644 (file)
@@ -177,10 +177,13 @@ td:last-of-type {
     padding: 5px;
 }
 
-.results-detail .toolbar .dismiss {
+.results-detail .toolbar .actions {
     float: right;
+}
+
+.results-detail .toolbar .actions a {
     display: inline-block;
-    padding: 5px;
+    padding: 5px 5px 5px 0px;
 }
 
 .results-detail .toolbar {
index 319ae78..72f7aec 100644 (file)
@@ -80,6 +80,7 @@ function showResultsDetail()
             status.text(testName + ' [' + builderName + ']');
             content.empty();
             content.append(ui.failureDetails(resultsURLs));
+            $('.results-detail .actions .rebaseline').toggle(results.canRebaseline(failureTypeList));
             $('.failure-details', content).attr(config.kBuilderNameAttr, builderName);
             $('.failure-details', content).attr(config.kTestNameAttr, testName);
             $('.failure-details', content).attr(config.kFailureTypesAttr, failureTypes);
@@ -108,8 +109,22 @@ function hideResultsDetail()
     });
 }
 
+function rebaselineResults()
+{
+    var failureDetails = $('.failure-details', $(this).parents('.results-detail'));
+
+    var builderName = failureDetails.attr(config.kBuilderNameAttr);
+    var testName = failureDetails.attr(config.kTestNameAttr);
+    var failureTypes = failureDetails.attr(config.kFailureTypesAttr);
+    var failureTypeList = failureTypes.split(' ');
+
+    displayOnButterbar('Rebaselining...');
+    checkout.rebaseline(builderName, testName, failureTypeList, dismissButterbar);
+}
+
 $('.regression .where a').live('click', showResultsDetail);
-$('.results-detail .dismiss').live('click', hideResultsDetail);
+$('.results-detail .actions .dismiss').live('click', hideResultsDetail);
+$('.results-detail .actions .rebaseline').live('click', rebaselineResults);
 
 $(document).ready(function() {
     showResults(function() {
index 7056662..66d2b45 100644 (file)
@@ -26,6 +26,9 @@ var kImageDiffSuffix = '-diff.png';
 var kTextDiffSuffix = '-diff.txt';
 var kCrashLogSuffix = '-crash-log.txt';
 
+var kPNGExtension = 'png';
+var kTXTExtension = 'txt';
+
 var kPreferredSuffixOrder = [
     kExpectedImageSuffix,
     kActualImageSuffix,
@@ -88,33 +91,60 @@ function possibleSuffixListFor(failureTypeList)
 
     $.each(failureTypeList, function(index, failureType) {
         switch(failureType) {
-            case IMAGE:
-                pushImageSuffixes();
-                break;
-            case TEXT:
-                pushTextSuffixes();
-                break;
-            case IMAGE_TEXT:
-                pushImageSuffixes();
-                pushTextSuffixes();
-                break;
-            case CRASH:
-                suffixList.push(kCrashLogSuffix);
-                break;
-            default:
-                // FIXME: Add support for the rest of the result types.
-                // '-expected.html',
-                // '-expected-mismatch.html',
-                // '-expected.wav',
-                // '-actual.wav',
-                // ... and possibly more.
-                break;
+        case IMAGE:
+            pushImageSuffixes();
+            break;
+        case TEXT:
+            pushTextSuffixes();
+            break;
+        case IMAGE_TEXT:
+            pushImageSuffixes();
+            pushTextSuffixes();
+            break;
+        case CRASH:
+            suffixList.push(kCrashLogSuffix);
+            break;
+        default:
+            // FIXME: Add support for the rest of the result types.
+            // '-expected.html',
+            // '-expected-mismatch.html',
+            // '-expected.wav',
+            // '-actual.wav',
+            // ... and possibly more.
+            break;
         }
     });
 
     return suffixList;
 }
 
+results.failureTypeToExtensionList = function(failureType)
+{
+    switch(failureType) {
+    case IMAGE:
+        return [kPNGExtension];
+    case TEXT:
+        return [kTXTExtension];
+    case IMAGE_TEXT:
+        return [kTXTExtension, kPNGExtension];
+    default:
+        // FIXME: Add support for the rest of the result types.
+        // '-expected.html',
+        // '-expected-mismatch.html',
+        // '-expected.wav',
+        // '-actual.wav',
+        // ... and possibly more.
+        return [];
+    }
+};
+
+results.canRebaseline = function(failureTypeList)
+{
+    return failureTypeList.some(function(element) {
+        return results.failureTypeToExtensionList(element).length > 0;
+    });
+};
+
 function resultsSummaryURL(builderName, testName)
 {
     return kTestResultsQuery + $.param(resultsParameters(builderName, testName));
index 5444c52..7172c7c 100644 (file)
@@ -326,6 +326,23 @@ test("collectUnexpectedResults", 1, function() {
     deepEqual(collectedResults, ["TEXT", "IMAGE"]);
 });
 
+test("failureTypeToExtensionList", 5, function() {
+    deepEqual(results.failureTypeToExtensionList('TEXT'), ['txt']);
+    deepEqual(results.failureTypeToExtensionList('IMAGE+TEXT'), ['txt', 'png']);
+    deepEqual(results.failureTypeToExtensionList('IMAGE'), ['png']);
+    deepEqual(results.failureTypeToExtensionList('CRASH'), []);
+    deepEqual(results.failureTypeToExtensionList('TIMEOUT'), []);
+});
+
+test("canRebaseline", 6, function() {
+    ok(results.canRebaseline(['TEXT']));
+    ok(results.canRebaseline(['IMAGE+TEXT', 'CRASH']));
+    ok(results.canRebaseline(['IMAGE']));
+    ok(!results.canRebaseline(['CRASH']));
+    ok(!results.canRebaseline(['TIMEOUT']));
+    ok(!results.canRebaseline([]));
+});
+
 test("fetchResultsURLs", 4, function() {
     var simulator = new NetworkSimulator();