Diff
Modified: trunk/Tools/ChangeLog (91239 => 91240)
--- trunk/Tools/ChangeLog 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/ChangeLog 2011-07-19 07:37:01 UTC (rev 91240)
@@ -1,3 +1,20 @@
+2011-07-19 Adam Barth <[email protected]>
+
+ garden-o-matic should live update as conditions change on the buildbot
+ https://bugs.webkit.org/show_bug.cgi?id=64646
+
+ Reviewed by Eric Seidel.
+
+ This patch causes the garden-o-matic display to update every 10 minutes
+ to show the latest failures. This patch required a moderately large
+ refactoring of main.js to make the display incremental instead of
+ all-at-once.
+
+ * Scripts/webkitpy/tool/servers/data/gardeningserver/base.js:
+ * Scripts/webkitpy/tool/servers/data/gardeningserver/main.css:
+ * Scripts/webkitpy/tool/servers/data/gardeningserver/main.js:
+ * Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js:
+
2011-07-18 Tab Atkins <[email protected]>
Tab Atkins is not in committers.py (as a non-committer)
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base.js (91239 => 91240)
--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base.js 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base.js 2011-07-19 07:37:01 UTC (rev 91240)
@@ -97,4 +97,18 @@
});
};
+base.RequestTracker = function(requestsInFlight, callback, args)
+{
+ this.m_requestsInFlight = requestsInFlight;
+ this.m_callback = callback;
+ this.m_args = args || [];
+};
+
+base.RequestTracker.prototype.requestComplete = function()
+{
+ --this.m_requestsInFlight;
+ if (!this.m_requestsInFlight)
+ this.m_callback.apply(null, this.m_args);
+};
+
})();
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base_unittests.js (91239 => 91240)
--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base_unittests.js 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/base_unittests.js 2011-07-19 07:37:01 UTC (rev 91240)
@@ -48,6 +48,30 @@
deepEqual(base.keys({"a": 1, "b": { "c" : 1}}), ["a", "b"]);
});
+test("RequestTracker", 3, function() {
+ var ready = false;
+ var tracker = new base.RequestTracker(1, function() {
+ ok(ready);
+ });
+ ready = true;
+ tracker.requestComplete();
+ ready = false;
+
+ tracker = new base.RequestTracker(2, function(parameter) {
+ ok(ready);
+ equals(parameter, 'argument');
+ }, ['argument']);
+ tracker.requestComplete();
+ ready = true;
+ tracker.requestComplete();
+ ready = false;
+
+ tracker = new base.RequestTracker(0, function() {
+ ok(false);
+ });
+ tracker.requestComplete();
+});
+
test("filterTree", 2, function() {
var tree = {
'path': {
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.css (91239 => 91240)
--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.css 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.css 2011-07-19 07:37:01 UTC (rev 91240)
@@ -87,6 +87,10 @@
padding: 4px;
}
+.results-summary tbody tr {
+ display: none;
+}
+
.results-summary ul {
margin: 0px;
padding: 0px;
@@ -159,13 +163,8 @@
border-radius: 4px;
}
-.results-summary .test[data-new-test="true"] .what a[draggable]::before {
- content: '(new)';
- margin: 0 3px;
-}
-
/* If we've only seen a given test failure once, we dim it so as not to distract the gardener. */
-.results-summary .test[data-failure-count="1"][data-new-test="false"] {
+.results-summary .test[data-failure-count="1"] {
-webkit-transition: 1s opacity;
opacity: 0.5;
}
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js (91239 => 91240)
--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/main.js 2011-07-19 07:37:01 UTC (rev 91240)
@@ -47,52 +47,103 @@
$('#favicon').attr('href', faviconURL);
}
-function showResults(onsuccess)
+function togglePartyTime(hasFailures)
{
+ if (!hasFailures) {
+ $('.results').text('No failures. Party time!');
+ var partyTime = $('<div class="partytime"><img src=""
+ $('.results').append(partyTime);
+ partyTime.fadeIn(1200).delay(7000).fadeOut();
+ return;
+ }
+ $('.results').empty();
+}
+
+function ensureResultsSummaryContainer()
+{
+ var container = $('.results-summary');
+ if (container.length)
+ return container;
+ container = ui.regressionsContainer();
+ $('.results').append(container);
+ return container;
+}
+
+function detachRepairedTestsAndPrepareTestMap(unexpectedFailures)
+{
+ var testMap = {};
+
+ $('.test').each(function() {
+ var testSummary = $(this);
+ var testName = testSummary.attr(config.kTestNameAttr);
+ if (!(testName in unexpectedFailures))
+ testSummary.slideUp(function() { testSummary.detach(); });
+ else
+ testMap[testName] = testSummary;
+ });
+
+ return testMap;
+}
+
+function prepareTestSummary(testName, resultNodesByBuilder, callback)
+{
+ var testSummary = ui.summarizeTest(testName, resultNodesByBuilder);
+ var builderNameList = base.keys(resultNodesByBuilder);
+
+ results.unifyRegressionRanges(builderNameList, testName, function(oldestFailingRevision, newestPassingRevision) {
+ $('.when', testSummary).append(ui.summarizeRegressionRange(oldestFailingRevision, newestPassingRevision));
+ });
+
+ results.countFailureOccurances(builderNameList, testName, function(failureCount) {
+ $(testSummary).attr(config.kFailureCountAttr, failureCount);
+ $('.how-many', testSummary).text(ui.failureCount(failureCount));
+ });
+
+ callback(testSummary);
+}
+
+function updateResultsSummary(callback)
+{
results.fetchResultsByBuilder(config.kBuilders, function(resultsByBuilder) {
var unexpectedFailures = results.unexpectedFailuresByTest(resultsByBuilder);
var hasFailures = !$.isEmptyObject(unexpectedFailures)
- if (!hasFailures) {
- $('.results').text('No failures. Party time!');
- var partyTime = $('<div class="partytime"><img src=""
- $('.results').append(partyTime);
- partyTime.fadeIn(1200).delay(7000).fadeOut();
- } else {
- var regressions = ui.regressionsContainer();
- $.each(unexpectedFailures, function(testName, resultNodesByBuilder) {
- var testSummary = ui.summarizeTest(testName, resultNodesByBuilder);
- $('tbody', regressions).append(testSummary);
+ togglePartyTime(hasFailures);
+ setIconState(hasFailures);
- var builderNameList = base.keys(resultNodesByBuilder);
- results.unifyRegressionRanges(builderNameList, testName, function(oldestFailingRevision, newestPassingRevision) {
- $('.when', testSummary).append(ui.summarizeRegressionRange(oldestFailingRevision, newestPassingRevision));
- if (!newestPassingRevision)
- return;
- checkout.existsAtRevision(checkout.subversionURLForTest(testName), newestPassingRevision, function(testExistedBeforeFailure) {
- $(testSummary).attr('data-new-test', !testExistedBeforeFailure);
- });
- });
- results.countFailureOccurances(builderNameList, testName, function(failureCount) {
- $(testSummary).attr(config.kFailureCountAttr, failureCount);
- $('.how-many', testSummary).text(ui.failureCount(failureCount));
- });
+ var container = ensureResultsSummaryContainer();
+ var testMap = detachRepairedTestsAndPrepareTestMap(unexpectedFailures);
+
+ var newTestSummaries = $();
+ var requestTracker = new base.RequestTracker(base.keys(unexpectedFailures).length, function() {
+ newTestSummaries.fadeIn();
+ callback()
+ });
+
+ $.each(unexpectedFailures, function(testName, resultNodesByBuilder) {
+ prepareTestSummary(testName, resultNodesByBuilder, function(testSummary) {
+ var existingElement = testMap[testName];
+ if (existingElement) {
+ existingElement.replaceWith(testSummary);
+ requestTracker.requestComplete();
+ return;
+ }
+ $('tbody', container).append(testSummary);
+ newTestSummaries = newTestSummaries.add(testSummary);
+ requestTracker.requestComplete();
});
- $('.results').append(regressions);
- }
- setIconState(hasFailures);
- onsuccess();
+ });
});
}
function showResultsDetail()
{
- var testBlock = $(this).parents('.test');
+ var testSummary = $(this).parents('.test');
var builderName = $(this).attr(config.kBuilderNameAttr);
- var testName = $('.what', testBlock).text();
+ var testName = testSummary.attr(config.kTestNameAttr);
// FIXME: It's lame that we have two different representations of multiple failure types.
- var failureTypes = testBlock.attr(config.kFailureTypesAttr);
+ var failureTypes = testSummary.attr(config.kFailureTypesAttr);
var failureTypeList = failureTypes.split(' ');
var content = $('.results-detail .content');
@@ -166,6 +217,8 @@
function update()
{
+ displayOnButterbar('Loading...');
+ updateResultsSummary(dismissButterbar);
checkBuilderStatuses();
}
@@ -174,9 +227,6 @@
$('.results-detail .actions .rebaseline').live('click', rebaselineResults);
$(document).ready(function() {
- showResults(function() {
- $('.butterbar').fadeOut();
- });
g_updateTimerId = window.setInterval(update, config.kUpdateFrequency);
update();
});
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js (91239 => 91240)
--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/results.js 2011-07-19 07:37:01 UTC (rev 91240)
@@ -177,7 +177,7 @@
// FIXME: Consider using setTimeout to make this method always asynchronous.
ResultsCache.prototype.get = function(key, callback)
{
- if (key in this._cache) {
+ if (this._cache[key]) {
callback(this._cache[key]);
return;
}
Modified: trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js (91239 => 91240)
--- trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js 2011-07-19 05:33:10 UTC (rev 91239)
+++ trunk/Tools/Scripts/webkitpy/tool/servers/data/gardeningserver/ui.js 2011-07-19 07:37:01 UTC (rev 91240)
@@ -54,6 +54,7 @@
'<td class="how-many"></td>' +
'</tr>');
$('.what a', block).text(testName).attr('href', ui.urlForTest(testName)).attr('class', unexpectedResults.join(' '));
+ block.attr(config.kTestNameAttr, testName);
block.attr(config.kFailureTypesAttr, unexpectedResults);
var where = $('.where', block);