Update Bot Watcher's Dashboard for Buildbot 0.9
[WebKit-https.git] / Tools / BuildSlaveSupport / build.webkit.org-config / public_html / dashboard / Scripts / Buildbot.js
1 /*
2  * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 Buildbot = function(baseURL, queuesInfo, options)
27 {
28     BaseObject.call(this);
29
30     console.assert(baseURL);
31     console.assert(queuesInfo);
32
33     this.baseURL = baseURL;
34     this.queuesInfo = queuesInfo;
35     this.queues = {};
36
37     this._normalizeQueuesInfo();
38
39     // We regard _needsAuthentication as a hint whether this Buildbot requires authentication so that we can show
40     // an appropriate initial status message (say, an "unauthorized" status if the Buildbot requires authentication)
41     // for its associated queues before we make the actual HTTP request for the status of each queue.
42     this._needsAuthentication = typeof options === "object" && options.needsAuthentication === true;
43     this._authenticationStatus = Buildbot.AuthenticationStatus.Unauthenticated;
44
45     this.VERSION_LESS_THAN_09 = options && options.USE_BUILDBOT_VERSION_LESS_THAN_09;
46
47     if (!this.VERSION_LESS_THAN_09)
48         this._computeBuilderNameToIDMap();
49
50     for (var id in queuesInfo) {
51         if (queuesInfo[id].combinedQueues) {
52             for (var combinedQueueID in queuesInfo[id].combinedQueues)
53                 this.queues[combinedQueueID] = new BuildbotQueue(this, combinedQueueID, queuesInfo[id].combinedQueues[combinedQueueID]);
54         } else
55             this.queues[id] = new BuildbotQueue(this, id, queuesInfo[id]);
56     }
57 };
58
59 BaseObject.addConstructorFunctions(Buildbot);
60
61 Buildbot.AuthenticationStatus = {
62     Unauthenticated: "unauthenticated",
63     Authenticated: "authenticated",
64     InvalidCredentials: "invalid-credentials"
65 };
66
67 Buildbot.UpdateReason = {
68     Reauthenticate: "reauthenticate"
69 };
70
71 // Ordered importance.
72 Buildbot.TestCategory = {
73     WebKit2: "webkit-2",
74     WebKit1: "webkit-1"
75 };
76
77 // Ordered importance.
78 Buildbot.BuildArchitecture = {
79     Universal: "universal",
80     SixtyFourBit: "sixty-four-bit",
81     ThirtyTwoBit: "thirty-two-bit"
82 };
83
84 Buildbot.prototype = {
85     constructor: Buildbot,
86     __proto__: BaseObject.prototype,
87
88     get needsAuthentication()
89     {
90         return this._needsAuthentication;
91     },
92
93     get authenticationStatus()
94     {
95         return this._authenticationStatus;
96     },
97
98     get isAuthenticated()
99     {
100         return this._authenticationStatus === Buildbot.AuthenticationStatus.Authenticated;
101     },
102
103     set isAuthenticated(value)
104     {
105         this._authenticationStatus = value ? Buildbot.AuthenticationStatus.Authenticated : Buildbot.AuthenticationStatus.InvalidCredentials;
106     },
107
108     _normalizeQueueInfo: function(queueInfo)
109     {
110         if (!queueInfo.combinedQueues)
111             queueInfo.branches = queueInfo.branches || this.defaultBranches;
112         queueInfo.debug = queueInfo.debug || false;
113         queueInfo.builder = queueInfo.builder || false;
114         queueInfo.tester = queueInfo.tester || false;
115         queueInfo.performance = queueInfo.performance || false;
116         queueInfo.staticAnalyzer = queueInfo.staticAnalyzer || false;
117         queueInfo.leaks = queueInfo.leaks || false;
118         queueInfo.architecture = queueInfo.architecture || null;
119         queueInfo.testCategory = queueInfo.testCategory || null;
120         queueInfo.heading = queueInfo.heading || null;
121         queueInfo.crashesOnly = queueInfo.crashesOnly || false;
122     },
123
124     _normalizeQueuesInfo: function()
125     {
126         for (queueName in this.queuesInfo) {
127             var queueInfo = this.queuesInfo[queueName];
128             this._normalizeQueueInfo(queueInfo);
129             if (queueInfo.combinedQueues) {
130                 for (combinedQueueName in queueInfo.combinedQueues) {
131                     queueInfo.combinedQueues[combinedQueueName].platform = queueInfo.platform;
132                     this._normalizeQueueInfo(queueInfo.combinedQueues[combinedQueueName]);
133                 }
134             }
135         }
136     },
137
138     updateQueues: function(updateReason)
139     {
140         var shouldReauthenticate = updateReason === Buildbot.UpdateReason.Reauthenticate;
141         if (shouldReauthenticate) {
142             var savedAuthenticationStatus = this._authenticationStatus;
143             this._authenticationStatus = Buildbot.AuthenticationStatus.Unauthenticated;
144         }
145         for (var id in this.queues)
146             this.queues[id].update();
147         if (shouldReauthenticate) {
148             // Assert status wasn't changed synchronously. Otherwise, we will override it (below).
149             console.assert(this._authenticationStatus === Buildbot.AuthenticationStatus.Unauthenticated);
150             this._authenticationStatus = savedAuthenticationStatus;
151         }
152     },
153
154     // FIXME: Remove this logic after <https://github.com/buildbot/buildbot/issues/3465> is fixed.
155     _computeBuilderNameToIDMap: function()
156     {
157         JSON.load(this.baseURL + "api/v2/builders", function(data) {
158             if (!data || !(data.builders instanceof Array))
159                 return;
160
161             this._builderNameToIDMap = {};
162             for (var builder of data.builders)
163                 this._builderNameToIDMap[builder.name] = builder.builderid;
164         }.bind(this));
165     },
166
167     buildPageURLForIteration: function(iteration)
168     {
169         if (this.VERSION_LESS_THAN_09)
170             return this.baseURL + "builders/" + encodeURIComponent(iteration.queue.id) + "/builds/" + iteration.id;
171
172         // FIXME: Remove this._builderNameToIDMap lookup after <https://github.com/buildbot/buildbot/issues/3465> is fixed.
173         return this.baseURL + "#/builders/" + encodeURIComponent(this._builderNameToIDMap[iteration.queue.id]) + "/builds/" + iteration.id;
174     },
175
176     javaScriptCoreTestFailuresURLForIteration: function(iteration, name)
177     {
178         return this.buildPageURLForIteration(iteration) + "/steps/" + name + "/logs/json/text";
179     },
180
181     javaScriptCoreTestStdioUrlForIteration: function(iteration, name)
182     {
183         return this.buildPageURLForIteration(iteration) + "/steps/" + name + "/logs/stdio";
184     },
185
186     layoutTestResultsDirectoryURLForIteration: function(iteration)
187     {
188         var underscoreSeparatedRevisions = "r";
189         sortDictionariesByOrder(Dashboard.Repository).forEach(function(repository) {
190             if (iteration.revision[repository.name]) {
191                 if (underscoreSeparatedRevisions.length > 1)
192                     underscoreSeparatedRevisions += "_";
193                 underscoreSeparatedRevisions += iteration.revision[repository.name];
194             }
195         });
196         return this.baseURL + "results/" + encodeURIComponent(iteration.queue.id) + "/" + encodeURIComponent(underscoreSeparatedRevisions + " (" + iteration.id + ")");
197     },
198
199     layoutTestResultsURLForIteration: function(iteration)
200     {
201         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/results.html";
202     },
203
204     dashboardTestResultsURLForIteration: function(iteration)
205     {
206         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/dashboard-layout-test-results/index-pretty-diff.html";
207     },
208
209     layoutTestFullResultsURLForIteration: function(iteration)
210     {
211         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/full_results.json";
212     },
213
214     layoutTestCrashLogURLForIteration: function(iteration, testPath)
215     {
216         var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-crash-log.txt");
217         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
218     },
219
220     layoutTestStderrURLForIteration: function(iteration, testPath)
221     {
222         var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-stderr.txt");
223         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
224     },
225
226     layoutTestDiffURLForIteration: function(iteration, testPath)
227     {
228         var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-diff.txt");
229         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
230     },
231
232     layoutTestPrettyDiffURLForIteration: function(iteration, testPath)
233     {
234         // pretty-patch may not be available, caller should check JSON results for has_pretty_patch attribute.
235         var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-pretty-diff.html");
236         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
237     },
238
239     layoutTestImagesURLForIteration: function(iteration, testPath)
240     {
241         var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-diffs.html");
242         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
243     },
244
245     layoutTestImageDiffURLForIteration: function(iteration, testPath)
246     {
247         var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-diff.png");
248         return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
249     },
250 };