blob: f6d53b41353b8bb38645c5b3c63912308aa140b3 [file] [log] [blame]
/*
* Copyright (C) 2013-2016 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.
*/
Buildbot = function(baseURL, queuesInfo, options)
{
BaseObject.call(this);
console.assert(baseURL);
console.assert(queuesInfo);
this.baseURL = baseURL;
this.queuesInfo = queuesInfo;
this.queues = {};
this._normalizeQueuesInfo();
// We regard _needsAuthentication as a hint whether this Buildbot requires authentication so that we can show
// an appropriate initial status message (say, an "unauthorized" status if the Buildbot requires authentication)
// for its associated queues before we make the actual HTTP request for the status of each queue.
this._needsAuthentication = typeof options === "object" && options.needsAuthentication === true;
this._authenticationStatus = Buildbot.AuthenticationStatus.Unauthenticated;
this.VERSION_LESS_THAN_09 = options && options.USE_BUILDBOT_VERSION_LESS_THAN_09;
if (!this.VERSION_LESS_THAN_09) {
this._builderNameToIDMap = {};
this._computeBuilderNameToIDMap();
}
for (var id in queuesInfo) {
if (queuesInfo[id].combinedQueues) {
for (var combinedQueueID in queuesInfo[id].combinedQueues)
this.queues[combinedQueueID] = new BuildbotQueue(this, combinedQueueID, queuesInfo[id].combinedQueues[combinedQueueID]);
} else
this.queues[id] = new BuildbotQueue(this, id, queuesInfo[id]);
}
};
BaseObject.addConstructorFunctions(Buildbot);
Buildbot.AuthenticationStatus = {
Unauthenticated: "unauthenticated",
Authenticated: "authenticated",
InvalidCredentials: "invalid-credentials"
};
Buildbot.UpdateReason = {
Reauthenticate: "reauthenticate"
};
// Ordered importance.
Buildbot.TestCategory = {
WebKit2: "webkit-2",
WebKit1: "webkit-1"
};
// Ordered importance.
Buildbot.BuildArchitecture = {
Universal: "universal",
SixtyFourBit: "sixty-four-bit",
ThirtyTwoBit: "thirty-two-bit"
};
Buildbot.prototype = {
constructor: Buildbot,
__proto__: BaseObject.prototype,
get needsAuthentication()
{
return this._needsAuthentication;
},
get authenticationStatus()
{
return this._authenticationStatus;
},
get isAuthenticated()
{
return this._authenticationStatus === Buildbot.AuthenticationStatus.Authenticated;
},
set isAuthenticated(value)
{
this._authenticationStatus = value ? Buildbot.AuthenticationStatus.Authenticated : Buildbot.AuthenticationStatus.InvalidCredentials;
},
_normalizeQueueInfo: function(queueInfo)
{
if (!queueInfo.combinedQueues)
queueInfo.branches = queueInfo.branches || this.defaultBranches;
queueInfo.debug = queueInfo.debug || false;
queueInfo.builder = queueInfo.builder || false;
queueInfo.tester = queueInfo.tester || false;
queueInfo.performance = queueInfo.performance || false;
queueInfo.staticAnalyzer = queueInfo.staticAnalyzer || false;
queueInfo.leaks = queueInfo.leaks || false;
queueInfo.architecture = queueInfo.architecture || null;
queueInfo.testCategory = queueInfo.testCategory || null;
queueInfo.heading = queueInfo.heading || null;
queueInfo.crashesOnly = queueInfo.crashesOnly || false;
},
_normalizeQueuesInfo: function()
{
for (queueName in this.queuesInfo) {
var queueInfo = this.queuesInfo[queueName];
this._normalizeQueueInfo(queueInfo);
if (queueInfo.combinedQueues) {
for (combinedQueueName in queueInfo.combinedQueues) {
queueInfo.combinedQueues[combinedQueueName].platform = queueInfo.platform;
this._normalizeQueueInfo(queueInfo.combinedQueues[combinedQueueName]);
}
}
}
},
updateQueues: function(updateReason)
{
var shouldReauthenticate = updateReason === Buildbot.UpdateReason.Reauthenticate;
if (shouldReauthenticate) {
var savedAuthenticationStatus = this._authenticationStatus;
this._authenticationStatus = Buildbot.AuthenticationStatus.Unauthenticated;
}
for (var id in this.queues)
this.queues[id].update();
if (shouldReauthenticate) {
// Assert status wasn't changed synchronously. Otherwise, we will override it (below).
console.assert(this._authenticationStatus === Buildbot.AuthenticationStatus.Unauthenticated);
this._authenticationStatus = savedAuthenticationStatus;
}
},
// FIXME: Remove this logic after <https://github.com/buildbot/buildbot/issues/3465> is fixed.
_computeBuilderNameToIDMap: function()
{
JSON.load(this.baseURL + "api/v2/builders", function(data) {
if (!data || !(data.builders instanceof Array))
return;
for (var builder of data.builders)
this._builderNameToIDMap[builder.name] = builder.builderid;
}.bind(this));
},
buildPageURLForIteration: function(iteration)
{
if (this.VERSION_LESS_THAN_09)
return this.baseURL + "builders/" + encodeURIComponent(iteration.queue.id) + "/builds/" + iteration.id;
// FIXME: Remove this._builderNameToIDMap lookup after <https://github.com/buildbot/buildbot/issues/3465> is fixed.
return this.baseURL + "#/builders/" + encodeURIComponent(this._builderNameToIDMap[iteration.queue.id]) + "/builds/" + iteration.id;
},
javaScriptCoreTestFailuresURLForIteration: function(iteration, name)
{
return this.buildPageURLForIteration(iteration) + "/steps/" + name + "/logs/json/text";
},
javaScriptCoreTestStdioUrlForIteration: function(iteration, name)
{
return this.buildPageURLForIteration(iteration) + "/steps/" + name + "/logs/stdio";
},
layoutTestResultsDirectoryURLForIteration: function(iteration)
{
var underscoreSeparatedRevisions = "r";
sortDictionariesByOrder(Dashboard.Repository).forEach(function(repository) {
if (iteration.revision[repository.name]) {
if (underscoreSeparatedRevisions.length > 1)
underscoreSeparatedRevisions += "_";
underscoreSeparatedRevisions += iteration.revision[repository.name];
}
});
return this.baseURL + "results/" + encodeURIComponent(iteration.queue.id) + "/" + encodeURIComponent(underscoreSeparatedRevisions + " (" + iteration.id + ")");
},
layoutTestResultsURLForIteration: function(iteration)
{
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/results.html";
},
dashboardTestResultsURLForIteration: function(iteration)
{
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/dashboard-layout-test-results/index-pretty-diff.html";
},
layoutTestFullResultsURLForIteration: function(iteration)
{
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/full_results.json";
},
layoutTestCrashLogURLForIteration: function(iteration, testPath)
{
var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-crash-log.txt");
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
},
layoutTestStderrURLForIteration: function(iteration, testPath)
{
var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-stderr.txt");
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
},
layoutTestDiffURLForIteration: function(iteration, testPath)
{
var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-diff.txt");
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
},
layoutTestPrettyDiffURLForIteration: function(iteration, testPath)
{
// pretty-patch may not be available, caller should check JSON results for has_pretty_patch attribute.
var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-pretty-diff.html");
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
},
layoutTestImagesURLForIteration: function(iteration, testPath)
{
var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-diffs.html");
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
},
layoutTestImageDiffURLForIteration: function(iteration, testPath)
{
var path = testPath.replace(/^(.*)\.(?:.*)$/, "$1-diff.png");
return this.layoutTestResultsDirectoryURLForIteration(iteration) + "/" + path;
},
};