blob: 3b795a3f2435d7d62bae7d14ee78cba05c6cf63e [file] [log] [blame]
'use strict';
let assert = require('assert');
function mapInSerialPromiseChain(list, callback)
{
const results = [];
return list.reduce((chainedPromise, item) => {
return chainedPromise.then(() => callback(item)).then((result) => results.push(result));
}, Promise.resolve()).then(() => results);
}
class OSBuildFetcher {
constructor(osConfig, remoteAPI, slaveAuth, subprocess, logger)
{
this._osConfig = osConfig;
this._logger = logger;
this._slaveAuth = slaveAuth;
this._remoteAPI = remoteAPI;
this._subprocess = subprocess;
this._maxSubmitCount = osConfig['maxSubmitCount'] || 20;
}
static fetchAndReportAllInOrder(fetcherList)
{
return mapInSerialPromiseChain(fetcherList, (fetcher) => fetcher.fetchAndReportNewBuilds());
}
fetchAndReportNewBuilds()
{
return this._fetchAvailableBuilds().then((results) => {
this._logger.log(`Submitting ${results.length} builds for ${this._osConfig['name']}`);
if (results.length == 0)
return this._submitCommits(results);
const splittedResults = [];
for (let startIndex = 0; startIndex < results.length; startIndex += this._maxSubmitCount)
splittedResults.push(results.slice(startIndex, startIndex + this._maxSubmitCount));
return mapInSerialPromiseChain(splittedResults, this._submitCommits.bind(this)).then((responses) => {
assert(responses.every((response) => response['status'] == 'OK'));
assert(responses.length > 0);
return responses[0];
});
});
}
_fetchAvailableBuilds()
{
const config = this._osConfig;
const repositoryName = config['name'];
let customCommands = config['customCommands'];
return mapInSerialPromiseChain(customCommands, (command) => {
assert(command['minRevision']);
assert(command['maxRevision']);
const minRevisionOrder = this._computeOrder(command['minRevision']);
const maxRevisionOrder = this._computeOrder(command['maxRevision']);
const url = `/api/commits/${escape(repositoryName)}/last-reported?from=${minRevisionOrder}&to=${maxRevisionOrder}`;
return this._remoteAPI.getJSONWithStatus(url).then((result) => {
const minOrder = result['commits'].length == 1 ? parseInt(result['commits'][0]['order']) : 0;
return this._commitsForAvailableBuilds(repositoryName, command['command'], command['linesToIgnore'], minOrder);
}).then((commits) => {
const label = 'name' in command ? `"${command['name']}"` : `"${command['minRevision']}" to "${command['maxRevision']}"`;
this._logger.log(`Found ${commits.length} builds for ${label}`);
if ('ownedCommitCommand' in command) {
this._logger.log(`Resolving ownedCommits for ${label}`);
return this._addOwnedCommitsForBuild(commits, command['ownedCommitCommand']);
}
return commits;
});
}).then((results) => [].concat(...results));
}
_computeOrder(revision)
{
const buildNameRegex = /(\d+)([a-zA-Z])(\d+)([a-zA-Z]*)$/;
const match = buildNameRegex.exec(revision);
assert(match);
const major = parseInt(match[1]);
const kind = match[2].toUpperCase().charCodeAt(0) - "A".charCodeAt(0);
const minor = parseInt(match[3]);
const variant = match[4] ? match[4].toUpperCase().charCodeAt(0) - "A".charCodeAt(0) + 1 : 0;
return ((major * 100 + kind) * 10000 + minor) * 100 + variant;
}
_commitsForAvailableBuilds(repository, command, linesToIgnore, minOrder)
{
return this._subprocess.execute(command).then((output) => {
let lines = output.split('\n');
if (linesToIgnore){
const regex = new RegExp(linesToIgnore);
lines = lines.filter((line) => !regex.exec(line));
}
return lines.map((revision) => ({repository, revision, 'order': this._computeOrder(revision)}))
.filter((commit) => commit['order'] > minOrder);
});
}
_addOwnedCommitsForBuild(commits, command)
{
return mapInSerialPromiseChain(commits, (commit) => {
return this._subprocess.execute(command.concat(commit['revision'])).then((ownedCommitOutput) => {
const ownedCommits = JSON.parse(ownedCommitOutput);
this._logger.log(`Got ${Object.keys((ownedCommits)).length} owned commits for "${commit['revision']}"`);
for (let repositoryName in ownedCommits) {
const ownedCommit = ownedCommits[repositoryName];
assert.deepEqual(Object.keys(ownedCommit), ['revision']);
assert(typeof(ownedCommit['revision']) == 'string');
}
commit['ownedCommits'] = ownedCommits;
return commit;
});
});
}
_submitCommits(commits)
{
const commitsToReport = {"slaveName": this._slaveAuth['name'], "slavePassword": this._slaveAuth['password'], 'commits': commits};
return this._remoteAPI.postJSONWithStatus('/api/report-commits/', commitsToReport);
}
}
if (typeof module != 'undefined')
module.exports.OSBuildFetcher = OSBuildFetcher;