Commit 03c8a837 authored by ap@apple.com's avatar ap@apple.com

build.webkit.org/dashboard should display information about patches in EWS

https://bugs.webkit.org/show_bug.cgi?id=127006

Reviewed by Ryosuke Niwa.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html:
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Bugzilla.js: Added.
(Bugzilla.prototype.detailsURLForAttachment):
Added a class for Bugzilla. So far, the only thing it can do is build patch URLs,
which is needed when one wants to do something with a patch EWS is stuck on.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js:
Create a Bugzilla instance.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/EWS.js:
(EWS.prototype.jsonQueueLengthURL):
(EWS.prototype.jsonQueueStatusURL):
Build JSON ULRs here, not in EWSQueue, as this is how other classes are structured.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/EWSQueue.js:
(EWSQueue.prototype.get statusPageURL): Changed to use a URL provided by EWS instead
of second guessing.
(EWSQueue.prototype.get chartsPageURL): Added.
(EWSQueue.prototype.get loadedDetailedStatus): Tells whether we currently have
additional data already loaded (it's reset with every update).
(EWSQueue.prototype.get patches): Get patch queue.
(EWSQueue.prototype.get bots): Get bots.
(EWSQueue.prototype.update): Changed to use a specialized cheaper URL.
(EWSQueue.prototype.loadDetailedStatus): Load and transform detailed status JSON.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/EWSQueueView.js:
(EWSQueueView.prototype.update.appendQueue): Add a popover is there are any patches
in the queue.
(EWSQueueView.prototype.addLinkToRow): A helper to build the popover.
(EWSQueueView.prototype.addTextToRow): Ditto.
(EWSQueueView.prototype._addQueueHeadingToPopover): Ditto.
(EWSQueueView.prototype._addBotsHeadingToPopover): Ditto.
(EWSQueueView.prototype._addDividerToPopover): Ditto.
(EWSQueueView.prototype._timeIntervalString): A helper to format a timestamp into a
relative string.
(EWSQueueView.prototype._popoverContentForEWSQueue): Build the popover.
(EWSQueueView.prototype._presentPopoverForEWSQueue): Start loading data, and present
it when done.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css:
Added rules for EWS popover. Removed a duplicate rule for build-logs-popover.
Changed a few difficult to read padding styles to padding-left.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@162373 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a5e72936
/*
* Copyright (C) 2014 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
*/
Bugzilla = function()
{
BaseObject.call(this);
this.baseURL = "https://bugs.webkit.org/";
};
BaseObject.addConstructorFunctions(Bugzilla);
Bugzilla.prototype = {
constructor: Bugzilla,
__proto__: BaseObject.prototype,
detailsURLForAttachment: function(attachmentID)
{
return this.baseURL + "attachment.cgi?id=" + encodeURIComponent(attachmentID) + "&action=edit";
},
};
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -49,4 +49,14 @@ BaseObject.addConstructorFunctions(EWS);
EWS.prototype = {
constructor: EWS,
__proto__: BaseObject.prototype,
jsonQueueLengthURL: function(queueID)
{
return this.baseURL + "queue-length-json/" + encodeURIComponent(queueID) + "-ews";
},
jsonQueueStatusURL: function(queueID)
{
return this.baseURL + "queue-status-json/" + encodeURIComponent(queueID) + "-ews";
},
};
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -49,14 +49,14 @@ EWSQueue.prototype = {
constructor: EWSQueue,
__proto__: BaseObject.prototype,
get baseURL()
get statusPageURL()
{
return this.ews.baseURL + "queue-status-json/" + encodeURIComponent(this.id) + "-ews";
return this._statusPageURL;
},
get statusPage()
get chartsPageURL()
{
return this.ews.baseURL + "queue-status/" + encodeURIComponent(this.id) + "-ews";
return this._chartsPageURL;
},
get patchCount()
......@@ -64,15 +64,81 @@ EWSQueue.prototype = {
return this._patchCount;
},
get loadedDetailedStatus()
{
return this._loadedDetailedStatus;
},
get patches()
{
console.assert(this._loadedDetailedStatus);
return this._queue;
},
get bots()
{
console.assert(this._loadedDetailedStatus);
return this._bots;
},
update: function()
{
JSON.load(this.baseURL, function(data) {
var newPatchCount = data.queue.length;
this._loadedDetailedStatus = false;
JSON.load(this.ews.jsonQueueLengthURL(this.id), function(data) {
var newPatchCount = data.queue_length;
if (this._patchCount == newPatchCount)
return;
this._patchCount = newPatchCount;
this.dispatchEventToListeners(EWSQueue.Event.Updated, null);
}.bind(this));
}
},
loadDetailedStatus: function(callback)
{
JSON.load(this.ews.jsonQueueStatusURL(this.id), function(data) {
this._queue = [];
for (var i = 0, end = data.queue.length; i < end; ++i) {
var patch = data.queue[i];
var activeSinceTime = patch.active_since ? Date.parse(patch.active_since) : 0;
this._queue.push({
attachmentID: patch.attachment_id,
statusPageURL: patch.status_page,
latestMessage: patch.latest_message,
latestMessageTime: patch.latest_message_time ? new Date(patch.latest_message_time) : null,
detailedResultsURLForLatestMessage: patch.latest_results,
messageCount: patch.message_count,
active: patch.active,
activeSince: new Date(activeSinceTime),
});
}
this._bots = [];
for (var i = 0, end = data.bots.length; i < end; ++i) {
var bot = data.bots[i];
var latestMessageTime = bot.latest_message_time ? Date.parse(bot.latest_message_time) : 0;
var oneDayInMilliseconds = 24 * 60 * 60 * 1000;
var botIsCurrentlyActive = Date.now() < latestMessageTime + oneDayInMilliseconds;
if (!botIsCurrentlyActive)
continue;
// Sometimes (rarely), there are status messages with an empty bot name added to the database.
if (!bot.bot_id.length)
bot.bot_id = "<empty name>";
this._bots.push({
id: bot.bot_id,
statusPageURL: bot.status_page,
latestMessageTime: new Date(latestMessageTime),
});
}
this._statusPageURL = data.status_page;
this._chartsPageURL = data.charts_page;
this._loadedDetailedStatus = true;
callback();
}.bind(this));
},
};
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
* Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -54,18 +54,21 @@ EWSQueueView.prototype = {
function appendQueue(queue)
{
var releaseLabel = document.createElement("a");
releaseLabel.classList.add("queueLabel");
releaseLabel.textContent = queue.title;
releaseLabel.href = queue.statusPage;
releaseLabel.target = "_blank";
this.element.appendChild(releaseLabel);
var queueLabel = document.createElement("a");
queueLabel.classList.add("queueLabel");
queueLabel.textContent = queue.title;
queueLabel.href = queue.statusPageURL;
queueLabel.target = "_blank";
this.element.appendChild(queueLabel);
var patchCount = queue.patchCount;
var message = patchCount === 1 ? "patch in queue" : "patches in queue";
var status = new StatusLineView(message, StatusLineView.Status.Neutral, null, patchCount || "0");
this.element.appendChild(status.element);
if (patchCount > 0)
new PopoverTracker(status.statusBubbleElement, this._presentPopoverForEWSQueue.bind(this), queue);
}
this.queues.forEach(function(queue) {
......@@ -73,6 +76,149 @@ EWSQueueView.prototype = {
}, this);
},
addLinkToRow: function(rowElement, className, text, url)
{
var linkElement = document.createElement("a");
linkElement.className = className;
linkElement.textContent = text;
linkElement.href = url;
linkElement.target = "_blank";
rowElement.appendChild(linkElement);
},
addTextToRow: function(rowElement, className, text)
{
var spanElement = document.createElement("span");
spanElement.className = className;
spanElement.textContent = text;
rowElement.appendChild(spanElement);
},
_addQueueHeadingToPopover: function(queue, content)
{
var title = document.createElement("div");
title.className = "popover-queue-heading";
this.addTextToRow(title, "queue-name", queue.id + " ews queue");
this.addLinkToRow(title, "queue-status-link", "status page", queue.statusPageURL);
this.addLinkToRow(title, "queue-charts-link", "charts", queue.chartsPageURL);
content.appendChild(title);
},
_addBotsHeadingToPopover: function(queue, content)
{
var title = document.createElement("div");
title.className = "popover-bots-heading";
title.textContent = "latest bot event";
content.appendChild(title);
},
_addDividerToPopover: function(content)
{
var divider = document.createElement("div");
divider.className = "divider";
content.appendChild(divider);
},
_timeIntervalString: function(time)
{
var secondsInHour = 60 * 60;
var timeDifference = (Date.now() - time.getTime()) / 1000;
var hours = Math.floor(timeDifference / secondsInHour);
var minutes = Math.floor((timeDifference - hours * secondsInHour) / 60);
var hoursPart = "";
if (hours === 1)
hoursPart = "1\xa0hour and ";
else if (hours > 0)
hoursPart = hours + "\xa0hours and ";
if (!minutes)
return "less than a minute";
if (minutes === 1)
return hoursPart + "1\xa0minute";
return hoursPart + minutes + "\xa0minutes";
},
_popoverContentForEWSQueue: function(queue)
{
var content = document.createElement("div");
content.className = "ews-popover";
this._addQueueHeadingToPopover(queue, content);
this._addDividerToPopover(content);
var patches = queue.patches;
for (var i = 0, end = patches.length; i < end; ++i) {
var patch = patches[i];
var rowElement = document.createElement("div");
this.addLinkToRow(rowElement, "patch-details-link", patch.attachmentID, patch.statusPageURL);
if (patch.messageCount)
this.addTextToRow(rowElement, "failure-count", patch.messageCount + "\xa0" + (patch.messageCount === 1 ? "attempt" : "attempts"));
if (patch.detailedResultsURLForLatestMessage)
this.addLinkToRow(rowElement, "latest-status-with-link", patch.latestMessage, patch.detailedResultsURLForLatestMessage);
else if (patch.latestMessage && patch.latestMessage.length)
this.addTextToRow(rowElement, "latest-status-no-link", patch.latestMessage);
else if (patch.active) {
this.addTextToRow(rowElement, "latest-status-no-link", "Started");
this.addTextToRow(rowElement, "time-since-message", this._timeIntervalString(patch.activeSince) + "\xa0ago");
} else
this.addTextToRow(rowElement, "latest-status-no-link", "Not started yet");
if (patch.latestMessageTime)
this.addTextToRow(rowElement, "time-since-message", this._timeIntervalString(patch.latestMessageTime) + "\xa0ago");
this.addLinkToRow(rowElement, "bugzilla-link", "bugzilla", bugzilla.detailsURLForAttachment(patch.attachmentID));
content.appendChild(rowElement);
}
this._addDividerToPopover(content);
this._addBotsHeadingToPopover(queue, content);
this._addDividerToPopover(content);
var bots = queue.bots;
for (var i = 0, end = bots.length; i < end; ++i) {
var bot = bots[i];
var rowElement = document.createElement("div");
this.addLinkToRow(rowElement, "bot-status-link", bot.id, bot.statusPageURL);
this.addTextToRow(rowElement, "bot-status-description", this._timeIntervalString(bot.latestMessageTime) + "\xa0ago");
content.appendChild(rowElement);
}
return content;
},
_presentPopoverForEWSQueue: function(element, popover, queue)
{
if (queue.loadedDetailedStatus)
var content = this._popoverContentForEWSQueue(queue);
else {
var content = document.createElement("div");
content.className = "ews-popover";
var loadingIndicator = document.createElement("div");
loadingIndicator.className = "loading-indicator";
loadingIndicator.textContent = "Loading\u2026";
content.appendChild(loadingIndicator);
queue.loadDetailedStatus(function() {
popover.content = this._popoverContentForEWSQueue(queue);
}.bind(this));
}
var rect = Dashboard.Rect.rectFromClientRect(element.getBoundingClientRect());
popover.content = content;
popover.present(rect, [Dashboard.RectEdge.MIN_Y, Dashboard.RectEdge.MAX_Y, Dashboard.RectEdge.MAX_X, Dashboard.RectEdge.MIN_X]);
return true;
},
_updateQueues: function()
{
this.queues.forEach(function(queue) { queue.update(); });
......
......@@ -26,5 +26,6 @@
var settings = new Settings;
var buildbot = new WebKitBuildbot;
var webkitTrac = new Trac("http://trac.webkit.org/");
var bugzilla = new Bugzilla;
var ews = new EWS;
var testHistory = new TestHistory;
......@@ -75,14 +75,6 @@
padding: 1px 6px 1px 6px;
}
.build-logs-popover {
font-family: "HelveticaNeue-Light", "Helvetica Neue", sans-serif;
color: rgb(145, 135, 95);
font-size: 12px;
text-align: left;
padding: 1px 6px 1px 6px;
}
.build-logs-popover .build-logs-heading {
display: inline;
}
......@@ -115,15 +107,42 @@
.test-results-popover .failure-kind-indicator {
color: rgb(191, 67, 41);
padding: 0px 0px 0px 7px;
padding-left: 7px;
}
.test-results-popover .test-history-link {
color: rgb(145, 135, 95);
padding: 0px 0px 0px 7px;
padding-left: 7px;
}
.test-results-popover .additional-link {
color: rgb(145, 135, 95);
padding: 0px 0px 0px 7px;
padding-left: 7px;
}
.ews-popover {
font-family: "HelveticaNeue-Light", "Helvetica Neue", sans-serif;
color: rgb(145, 135, 95);
font-size: 12px;
text-align: left;
padding: 1px 6px 1px 6px;
}
.ews-popover .popover-queue-heading .queue-status-link,
.ews-popover .popover-queue-heading .queue-charts-link {
color: rgb(145, 135, 95);
padding-left: 7px;
}
.ews-popover .latest-status-with-link,
.ews-popover .latest-status-no-link {
color: black;
padding-left: 7px;
}
.ews-popover .failure-count,
.ews-popover .time-since-message,
.ews-popover .bugzilla-link,
.ews-popover .bot-status-description {
padding-left: 7px;
}
......@@ -36,6 +36,7 @@ THE POSSIBILITY OF SUCH DAMAGE.
<script src="Scripts/BaseObject.js"></script>
<script src="Scripts/Dashboard.js"></script>
<script src="Scripts/Buildbot.js"></script>
<script src="Scripts/Bugzilla.js"></script>
<script src="Scripts/EWS.js"></script>
<script src="Scripts/WebKitBuildbot.js"></script>
<script src="Scripts/BuildbotQueue.js"></script>
......
2014-01-20 Alexey Proskuryakov <ap@apple.com>
build.webkit.org/dashboard should display information about patches in EWS
https://bugs.webkit.org/show_bug.cgi?id=127006
Reviewed by Ryosuke Niwa.
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html:
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Bugzilla.js: Added.
(Bugzilla.prototype.detailsURLForAttachment):
Added a class for Bugzilla. So far, the only thing it can do is build patch URLs,
which is needed when one wants to do something with a patch EWS is stuck on.
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js:
Create a Bugzilla instance.
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/EWS.js:
(EWS.prototype.jsonQueueLengthURL):
(EWS.prototype.jsonQueueStatusURL):
Build JSON ULRs here, not in EWSQueue, as this is how other classes are structured.
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/EWSQueue.js:
(EWSQueue.prototype.get statusPageURL): Changed to use a URL provided by EWS instead
of second guessing.
(EWSQueue.prototype.get chartsPageURL): Added.
(EWSQueue.prototype.get loadedDetailedStatus): Tells whether we currently have
additional data already loaded (it's reset with every update).
(EWSQueue.prototype.get patches): Get patch queue.
(EWSQueue.prototype.get bots): Get bots.
(EWSQueue.prototype.update): Changed to use a specialized cheaper URL.
(EWSQueue.prototype.loadDetailedStatus): Load and transform detailed status JSON.
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/EWSQueueView.js:
(EWSQueueView.prototype.update.appendQueue): Add a popover is there are any patches
in the queue.
(EWSQueueView.prototype.addLinkToRow): A helper to build the popover.
(EWSQueueView.prototype.addTextToRow): Ditto.
(EWSQueueView.prototype._addQueueHeadingToPopover): Ditto.
(EWSQueueView.prototype._addBotsHeadingToPopover): Ditto.
(EWSQueueView.prototype._addDividerToPopover): Ditto.
(EWSQueueView.prototype._timeIntervalString): A helper to format a timestamp into a
relative string.
(EWSQueueView.prototype._popoverContentForEWSQueue): Build the popover.
(EWSQueueView.prototype._presentPopoverForEWSQueue): Start loading data, and present
it when done.
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/QueueView.css:
Added rules for EWS popover. Removed a duplicate rule for build-logs-popover.
Changed a few difficult to read padding styles to padding-left.
2014-01-20 Alexey Proskuryakov <ap@apple.com>
Fix webkitpy tests.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment