Please clarify "pending" reporting at build.webkit.org/dashboard
authorap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Dec 2013 18:01:50 +0000 (18:01 +0000)
committerap@apple.com <ap@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Dec 2013 18:01:50 +0000 (18:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=122191

Reviewed by Timothy Hatcher.

Reporting the count of pending runs didn't make a lot of sense - first, runs are
coalesced and sometimes even out of order, and second, buildbot's notion of pending
run was confusingly different from dashboard's.

Let's display how many SVN revisions are pending. This can be somewhat misleading
too, because some revisions (like those for other platforms) don't trigger builds,
but it's better than what we had.

This patch also lays the groundwork for displaying detailed information about
pending revisions.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotBuilderQueueView.js:
(BuildbotBuilderQueueView.prototype.update.appendBuilderQueueStatus): Instead of
building pending status line directly, call newly added base class method.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js:
(BuildbotTesterQueueView.prototype.update.appendBuilderQueueStatus): Ditto.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js:
(BuildbotQueueView): Listen for events when new SVN revisions are landed, and update the view.
(BuildbotQueueView.prototype._appendPendingRevisionCount): Add a line for pending
SVN revisions. It uses a new style, StatusLineView.Status.NoBubble, because this
information is secondary, and doesn't need as much attention.
(BuildbotQueueView.prototype.revisionLinksForIteration): Build revisionURL through
Trac, not through Buildbot.
(BuildbotQueueView.prototype._newCommitsRecorded): Schedule an update, just like when
iterations are updated.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js:
Initialize a global webkitTrac object.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js:
* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/StatusLineView.css:
Added a new style for messages without a bubble.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Trac.js:
Added a model class for Trac, which keeps track of SVN timeline, and notifies
listeners of changes. It uses an RSS interface to Trac, because there is no JSON one.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js:
(loadXML): Added a function to load XML asynchronouly, just like existing JSON.load.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js:
Removed tracRevisionURL() function. Now that we have a Trac object, it just makes
more sense to build trac URLs through it.

* BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html:
Load Trac.js.

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

Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotBuilderQueueView.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Trac.js [new file with mode: 0644]
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/StatusLineView.css
Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html
Tools/ChangeLog

index 9ae537a..1b0a4c9 100644 (file)
@@ -60,12 +60,7 @@ BuildbotBuilderQueueView.prototype = {
 
         function appendBuilderQueueStatus(queue)
         {
-            var pendingBuildCount = queue.pendingIterationsCount;
-            if (pendingBuildCount) {
-                var message = pendingBuildCount === 1 ? "pending build" : "pending builds";
-                var status = new StatusLineView(message, StatusLineView.Status.Neutral, null, pendingBuildCount);
-                this.element.appendChild(status.element);
-            }
+            this._appendPendingRevisionCount(queue)
 
             var firstRecentFailedIteration = queue.firstRecentFailedIteration;
             if (firstRecentFailedIteration && firstRecentFailedIteration.loaded) {
index 72b9bb5..c7d04b3 100644 (file)
@@ -50,6 +50,10 @@ BuildbotQueueView = function(debugQueues, releaseQueues)
         queue.addEventListener(BuildbotQueue.Event.IterationsAdded, this._queueIterationsAdded, this);
     }.bind(this));
 
+    webkitTrac.addEventListener(Trac.Event.NewCommitsRecorded, this._newCommitsRecorded, this);
+    if (typeof internalTrac != "undefined")
+        internalTrac.addEventListener(Trac.Event.NewCommitsRecorded, this._newCommitsRecorded, this);
+
     this.updateTimer = null;
     this._updateHiddenState();
     settings.addSettingListener("hiddenPlatforms", this._updateHiddenState.bind(this));
@@ -81,12 +85,50 @@ BuildbotQueueView.prototype = {
         // Implemented by subclasses.
     },
 
+    _appendPendingRevisionCount: function(queue)
+    {
+        for (var i = 0; i < queue.iterations.length; ++i) {
+            var iteration = queue.iterations[i];
+            if (!iteration.loaded || !iteration.finished)
+                continue;
+
+            var latestRecordedOpenSourceRevisionNumber = webkitTrac.latestRecordedRevisionNumber;
+            if (!latestRecordedOpenSourceRevisionNumber)
+                return;
+
+            var openSourceRevisionsBehind = latestRecordedOpenSourceRevisionNumber - iteration.openSourceRevision;
+            if (openSourceRevisionsBehind < 0)
+                openSourceRevisionsBehind = 0;
+
+            if (iteration.internalRevision) {
+                var latestRecordedInternalRevisionNumber = internalTrac.latestRecordedRevisionNumber;
+                if (!latestRecordedInternalRevisionNumber)
+                    return;
+
+                var internalRevisionsBehind = latestRecordedInternalRevisionNumber - iteration.internalRevision;
+                if (internalRevisionsBehind < 0)
+                    internalRevisionsBehind = 0;
+                if (openSourceRevisionsBehind || internalRevisionsBehind) {
+                    var message = openSourceRevisionsBehind + " \uff0b " + internalRevisionsBehind + " revisions behind";
+                    var status = new StatusLineView(message, StatusLineView.Status.NoBubble);
+                    this.element.appendChild(status.element);
+                }
+            } else if (openSourceRevisionsBehind) {
+                var message = openSourceRevisionsBehind + " " + (openSourceRevisionsBehind === 1 ? "revision behind" : "revisions behind");
+                var status = new StatusLineView(message, StatusLineView.Status.NoBubble);
+                this.element.appendChild(status.element);
+            }
+
+            return;
+        }
+    },
+
     revisionLinksForIteration: function(iteration)
     {
-        function linkForRevision(revision, internal)
+        function linkForRevision(revision, trac)
         {
             var linkElement = document.createElement("a");
-            linkElement.href = iteration.queue.buildbot.tracRevisionURL(revision, internal);
+            linkElement.href = trac.revisionURL(revision);
             linkElement.target = "_blank";
             linkElement.textContent = "r" + revision;
             linkElement.classList.add("selectable");
@@ -95,12 +137,12 @@ BuildbotQueueView.prototype = {
         }
 
         console.assert(iteration.openSourceRevision);
-        var openSourceLink = linkForRevision(iteration.openSourceRevision, false);
+        var openSourceLink = linkForRevision(iteration.openSourceRevision, webkitTrac);
 
         if (!iteration.internalRevision)
             return openSourceLink;
 
-        var internalLink = linkForRevision(iteration.internalRevision, true);
+        var internalLink = linkForRevision(iteration.internalRevision, internalTrac);
 
         var fragment = document.createDocumentFragment();
         fragment.appendChild(openSourceLink);
@@ -141,5 +183,10 @@ BuildbotQueueView.prototype = {
     _iterationUpdated: function(event)
     {
         this.updateSoon();
+    },
+    
+    _newCommitsRecorded: function(event)
+    {
+        this.updateSoon();
     }
 };
index a0ca296..cbc2886 100644 (file)
@@ -44,12 +44,7 @@ BuildbotTesterQueueView.prototype = {
 
         function appendBuilderQueueStatus(queue)
         {
-            var pendingRunsCount = queue.pendingIterationsCount;
-            if (pendingRunsCount) {
-                var message = pendingRunsCount === 1 ? "pending test run" : "pending test runs";
-                var status = new StatusLineView(message, StatusLineView.Status.Neutral, null, pendingRunsCount);
-                this.element.appendChild(status.element);
-            }
+            this._appendPendingRevisionCount(queue);
 
             var appendedStatus = false;
 
index 732f909..b0a8a64 100644 (file)
@@ -35,7 +35,8 @@ StatusLineView = function(message, status, label, repeatCount, url)
 
     this._statusBubbleElement = document.createElement("div");
     this._statusBubbleElement.classList.add("bubble");
-    this.element.appendChild(this._statusBubbleElement);
+    if (status != StatusLineView.Status.NoBubble)
+        this.element.appendChild(this._statusBubbleElement);
 
     this._labelElement = document.createElement("div");
     this._labelElement.classList.add("label");
@@ -57,6 +58,7 @@ StatusLineView = function(message, status, label, repeatCount, url)
 };
 
 StatusLineView.Status = {
+    NoBubble: "no-bubble",
     Neutral: "neutral",
     Good: "good",
     Danger: "danger",
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Trac.js b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Trac.js
new file mode 100644 (file)
index 0000000..7fbbec0
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+Trac = function(baseURL)
+{
+    BaseObject.call(this);
+
+    console.assert(baseURL);
+
+    this.baseURL = baseURL;
+    this.recordedCommits = []; // Will be sorted in ascending order.
+
+    this.update();
+    this.updateTimer = setInterval(this.update.bind(this), Trac.UpdateInterval);
+};
+
+BaseObject.addConstructorFunctions(Trac);
+
+Trac.UpdateInterval = 45000; // 45 seconds
+
+Trac.Event = {
+    NewCommitsRecorded: "new-commits-recorded"
+};
+
+Trac.prototype = {
+    constructor: Trac,
+    __proto__: BaseObject.prototype,
+
+    get latestRecordedRevisionNumber()
+    {
+        if (!this.recordedCommits.length)
+            return undefined;
+        return this.recordedCommits[this.recordedCommits.length - 1].revisionNumber;
+    },
+
+    revisionURL: function(revision)
+    {
+        return this.baseURL + "changeset/" + encodeURIComponent(revision);
+    },
+
+    _xmlTimelineURL: function()
+    {
+        return this.baseURL + "timeline?changeset=on&max=50&format=rss";
+    },
+
+    _convertCommitInfoElementToObject: function(doc, commitElement)
+    {
+        var link = doc.evaluate("./link", commitElement, null, XPathResult.STRING_TYPE).stringValue;
+        var revisionNumber = parseInt(/\d+$/.exec(link))
+
+        var title = doc.evaluate("./title", commitElement, null, XPathResult.STRING_TYPE).stringValue;
+        title = title.replace(/^Changeset \[\d+\]: /, "");
+        var author = doc.evaluate("./author", commitElement, null, XPathResult.STRING_TYPE).stringValue;
+        var date = doc.evaluate("./pubDate", commitElement, null, XPathResult.STRING_TYPE).stringValue;
+        date = new Date(Date.parse(date));
+        var description = doc.evaluate("./description", commitElement, null, XPathResult.STRING_TYPE).stringValue;
+
+        return {
+            revisionNumber: revisionNumber,
+            link: link,
+            title: title,
+            author: author,
+            date: date,
+            description: description
+        };
+    },
+
+    update: function()
+    {
+        loadXML(this._xmlTimelineURL(), function(dataDocument) {
+            var latestKnownRevision = 0;
+            if (this.recordedCommits.length)
+                latestKnownRevision = this.recordedCommits[this.recordedCommits.length - 1].revisionNumber;
+
+            var newCommits = [];
+
+            var commitInfoElements = dataDocument.evaluate("/rss/channel/item", dataDocument, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
+            var commitInfoElement = undefined;
+            while (commitInfoElement = commitInfoElements.iterateNext()) {
+                var commit = this._convertCommitInfoElementToObject(dataDocument, commitInfoElement);
+                if (commit.revisionNumber == latestKnownRevision)
+                    break;
+                newCommits.push(commit);
+            }
+            
+            if (!newCommits.length)
+                return;
+
+            this.recordedCommits = this.recordedCommits.concat(newCommits.reverse());
+
+            this.dispatchEventToListeners(Trac.Event.NewCommitsRecorded, {newCommits: newCommits});
+        }.bind(this));
+    }
+};
index 286f434..05495cb 100644 (file)
@@ -50,6 +50,26 @@ JSON.load = function(url, callback)
     request.send();
 };
 
+function loadXML(url, callback) {
+    console.assert(url);
+
+    if (!(callback instanceof Function))
+        return;
+
+    var request = new XMLHttpRequest;
+    request.onreadystatechange = function() {
+        if (this.readyState !== 4)
+            return;
+
+        // Allow a status of 0 for easier testing with local files.
+        if (!this.status || this.status === 200)
+            callback(request.responseXML);
+    };
+
+    request.open("GET", url);
+    request.send();
+};
+
 Element.prototype.removeChildren = function()
 {
     // This has been tested to be the fastest removal method.
index 98c9ead..ab5bc6b 100644 (file)
@@ -59,11 +59,6 @@ WebKitBuildbot.prototype = {
     constructor: WebKitBuildbot,
     __proto__: Buildbot.prototype,
 
-    tracRevisionURL: function(revision)
-    {
-        return "http://trac.webkit.org/changeset/" + revision;
-    },
-
     buildLogURLForIteration: function(iteration)
     {
         return this.baseURL + "builders/" + encodeURIComponent(iteration.queue.id) + "/builds/" + iteration.id + "/steps/compile-webkit/logs/stdio/text";
index 888c3eb..f2a6fb3 100644 (file)
 }
 
 .status-line.neutral .label,
-.status-line.neutral .message {
+.status-line.neutral .message,
+.status-line.no-bubble .label,
+.status-line.no-bubble .message {
     color: rgb(145, 135, 95);
 }
 
index ed34ba1..5a1b976 100644 (file)
@@ -45,6 +45,7 @@ THE POSSIBILITY OF SUCH DAMAGE.
     <script src="Scripts/BuildbotTesterQueueView.js"></script>
     <script src="Scripts/StatusLineView.js"></script>
     <script src="Scripts/Settings.js"></script>
+    <script src="Scripts/Trac.js"></script>
     <script src="Scripts/Initialization.js"></script>
     <script src="Scripts/Main.js"></script>
 </head>
index f62ffcc..eddfb80 100644 (file)
@@ -1,3 +1,59 @@
+2013-12-25  Alexey Proskuryakov  <ap@apple.com>
+
+        Please clarify "pending" reporting at build.webkit.org/dashboard
+        https://bugs.webkit.org/show_bug.cgi?id=122191
+
+        Reviewed by Timothy Hatcher.
+
+        Reporting the count of pending runs didn't make a lot of sense - first, runs are
+        coalesced and sometimes even out of order, and second, buildbot's notion of pending
+        run was confusingly different from dashboard's.
+
+        Let's display how many SVN revisions are pending. This can be somewhat misleading
+        too, because some revisions (like those for other platforms) don't trigger builds,
+        but it's better than what we had.
+
+        This patch also lays the groundwork for displaying detailed information about
+        pending revisions.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotBuilderQueueView.js:
+        (BuildbotBuilderQueueView.prototype.update.appendBuilderQueueStatus): Instead of
+        building pending status line directly, call newly added base class method.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotTesterQueueView.js:
+        (BuildbotTesterQueueView.prototype.update.appendBuilderQueueStatus): Ditto.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/BuildbotQueueView.js:
+        (BuildbotQueueView): Listen for events when new SVN revisions are landed, and update the view.
+        (BuildbotQueueView.prototype._appendPendingRevisionCount): Add a line for pending
+        SVN revisions. It uses a new style, StatusLineView.Status.NoBubble, because this
+        information is secondary, and doesn't need as much attention.
+        (BuildbotQueueView.prototype.revisionLinksForIteration): Build revisionURL through
+        Trac, not through Buildbot.
+        (BuildbotQueueView.prototype._newCommitsRecorded): Schedule an update, just like when
+        iterations are updated.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Initialization.js:
+        Initialize a global webkitTrac object.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/StatusLineView.js:
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Styles/StatusLineView.css:
+        Added a new style for messages without a bubble.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Trac.js:
+        Added a model class for Trac, which keeps track of SVN timeline, and notifies
+        listeners of changes. It uses an RSS interface to Trac, because there is no JSON one.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/Utilities.js:
+        (loadXML): Added a function to load XML asynchronouly, just like existing JSON.load.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/Scripts/WebKitBuildbot.js:
+        Removed tracRevisionURL() function. Now that we have a Trac object, it just makes
+        more sense to build trac URLs through it.
+
+        * BuildSlaveSupport/build.webkit.org-config/public_html/dashboard/index.html:
+        Load Trac.js.
+
 2013-12-25  Jongwoo Choi  <jw0330.choi@samsung.com>
 
         [EFL] Activate keyboard homepage shortcut on efl minibrowser.