Support Trac 1.0.x XML timeline link format
[WebKit-https.git] / Tools / BuildSlaveSupport / build.webkit.org-config / public_html / dashboard / Scripts / Trac.js
index 7fbd1b3..77bad79 100644 (file)
@@ -49,6 +49,13 @@ Trac.prototype = {
     constructor: Trac,
     __proto__: BaseObject.prototype,
 
+    get oldestRecordedRevisionNumber()
+    {
+        if (!this.recordedCommits.length)
+            return undefined;
+        return this.recordedCommits[0].revisionNumber;
+    },
+
     get latestRecordedRevisionNumber()
     {
         if (!this.recordedCommits.length)
@@ -56,6 +63,13 @@ Trac.prototype = {
         return this.recordedCommits[this.recordedCommits.length - 1].revisionNumber;
     },
 
+    commitsOnBranch: function(branch, filter)
+    {
+        return this.recordedCommits.filter(function(commit) {
+            return (!commit.containsBranchLocation || commit.branch === branch) && filter(commit);
+        });
+    },
+
     revisionURL: function(revision)
     {
         return this.baseURL + "changeset/" + encodeURIComponent(revision);
@@ -63,14 +77,6 @@ Trac.prototype = {
 
     _xmlTimelineURL: function(fromDate, toDate)
     {
-        if (typeof fromDate === "undefined") {
-            fromDate = new Date();
-            toDate = new Date(fromDate);
-            // By default, get at least one full day of changesets, as the current day may have only begun.
-            fromDate.setDate(fromDate.getDate() - 1);
-        } else if (typeof toDate === "undefined")
-            toDate = fromDate;
-
         console.assert(fromDate <= toDate);
 
         var fromDay = new Date(fromDate.getFullYear(), fromDate.getMonth(), fromDate.getDate());
@@ -84,7 +90,14 @@ Trac.prototype = {
     _convertCommitInfoElementToObject: function(doc, commitElement)
     {
         var link = doc.evaluate("./link", commitElement, null, XPathResult.STRING_TYPE).stringValue;
-        var revisionNumber = parseInt(/\d+$/.exec(link))
+
+        // There are multiple link formats for Trac that we support:
+        // https://trac.webkit.org/changeset/190497
+        // http://trac.foobar.com/repository/changeset/75388/project
+        var linkComponents = link.split("/");
+        var revisionNumber = parseInt(linkComponents.pop());
+        if (!revisionNumber)
+            var revisionNumber = parseInt(linkComponents.pop());
 
         function tracNSResolver(prefix)
         {
@@ -98,11 +111,19 @@ Trac.prototype = {
         date = new Date(Date.parse(date));
         var description = doc.evaluate("./description", commitElement, null, XPathResult.STRING_TYPE).stringValue;
 
-        // The feed contains a <title>, but it's not parsed as well as what we are getting from description.
         var parsedDescription = document.createElement("div");
         parsedDescription.innerHTML = description;
+
+        var location = "";
+        if (parsedDescription.firstChild && parsedDescription.firstChild.className === "changes") {
+            // We can extract branch information when trac.ini contains "changeset_show_files=location".
+            location = doc.evaluate("//strong", parsedDescription.firstChild, null, XPathResult.STRING_TYPE).stringValue
+            parsedDescription.removeChild(parsedDescription.firstChild);
+        }
+
+        // The feed contains a <title>, but it's not parsed as well as what we are getting from description.
         var title = document.createElement("div");
-        var node = parsedDescription.firstChild.firstChild;
+        var node = parsedDescription.firstChild ? parsedDescription.firstChild.firstChild : null;
         while (node && node.tagName != "BR") {
             title.appendChild(node.cloneNode(true));
             node = node.nextSibling;
@@ -112,18 +133,44 @@ Trac.prototype = {
         if (title.firstChild && title.firstChild.nodeType == Node.TEXT_NODE && title.firstChild.textContent.length > 0 && title.firstChild.textContent[0] == "\n")
             title.firstChild.textContent = title.firstChild.textContent.substring(1);
 
-        return {
+        var result = {
             revisionNumber: revisionNumber,
             link: link,
             title: title,
             author: author,
             date: date,
-            description: description
+            description: parsedDescription.innerHTML,
+            containsBranchLocation: location !== ""
         };
+
+        if (result.containsBranchLocation) {
+            console.assert(location[location.length - 1] !== "/");
+            location = location += "/";
+            if (location.startsWith("tags/"))
+                result.tag = location.substr(5, location.indexOf("/", 5) - 5);
+            else if (location.startsWith("branches/"))
+                result.branch = location.substr(9, location.indexOf("/", 9) - 9);
+            else if (location.startsWith("releases/"))
+                result.release = location.substr(9, location.indexOf("/", 9) - 9);
+            else if (location.startsWith("trunk/"))
+                result.branch = "trunk";
+            else if (location.startsWith("submissions/"))
+                ; // These changes are never relevant to the dashboard.
+            else {
+                // result.containsBranchLocation remains true, because this commit does
+                // not match any explicitly specified branches.
+                console.assert(false);
+            }
+        }
+
+        return result;
     },
 
     _loaded: function(dataDocument)
     {
+        if (!dataDocument)
+            return;
+
         var recordedRevisionNumbers = this.recordedCommits.reduce(function(previousResult, commit) {
             previousResult[commit.revisionNumber] = commit;
             return previousResult;
@@ -162,14 +209,52 @@ Trac.prototype = {
         }.bind(this), this._needsAuthentication ? { withCredentials: true } : {});
     },
 
-    update: function()
+    _update: function()
     {
-        loadXML(this._xmlTimelineURL(), this._loaded.bind(this), this._needsAuthentication ? { withCredentials: true } : {});
+        var fromDate = new Date(this._latestLoadedDate);
+        var toDate = new Date();
+
+        this._latestLoadedDate = toDate;
+
+        loadXML(this._xmlTimelineURL(fromDate, toDate), this._loaded.bind(this), this._needsAuthentication ? { withCredentials: true } : {});
     },
 
     startPeriodicUpdates: function()
     {
-        this.update();
-        this.updateTimer = setInterval(this.update.bind(this), Trac.UpdateInterval);
-    }
+        console.assert(!this._oldestHistoricalDate);
+
+        var today = new Date();
+
+        this._oldestHistoricalDate = today;
+        this._latestLoadedDate = today;
+
+        this._loadingHistoricalData = true;
+        loadXML(this._xmlTimelineURL(today, today), function(dataDocument) {
+            this._loadingHistoricalData = false;
+            this._loaded(dataDocument);
+        }.bind(this), this._needsAuthentication ? { withCredentials: true } : {});
+
+        this.updateTimer = setInterval(this._update.bind(this), Trac.UpdateInterval);
+    },
+
+    loadMoreHistoricalData: function()
+    {
+        console.assert(this._oldestHistoricalDate);
+
+        if (this._loadingHistoricalData)
+            return;
+
+        // Load one more day of historical data.
+        var fromDate = new Date(this._oldestHistoricalDate);
+        fromDate.setDate(fromDate.getDate() - 1);
+        var toDate = new Date(fromDate);
+
+        this._oldestHistoricalDate = fromDate;
+
+        this._loadingHistoricalData = true;
+        loadXML(this._xmlTimelineURL(fromDate, toDate), function(dataDocument) {
+            this._loadingHistoricalData = false;
+            this._loaded(dataDocument);
+        }.bind(this), this._needsAuthentication ? { withCredentials: true } : {});
+    },
 };