Use 'owned commit' instead of 'sub commit' whenever refers to a commit owned by anoth...
[WebKit.git] / Websites / perf.webkit.org / tools / js / os-build-fetcher.js
1 'use strict';
2
3 let assert = require('assert');
4
5 function mapInSerialPromiseChain(list, callback)
6 {
7     const results = [];
8     return list.reduce((chainedPromise, item) => {
9         return chainedPromise.then(() => callback(item)).then((result) => results.push(result));
10     }, Promise.resolve()).then(() => results);
11 }
12
13 class OSBuildFetcher {
14
15     constructor(osConfig, remoteAPI, slaveAuth, subprocess, logger)
16     {
17         this._osConfig = osConfig;
18         this._reportedRevisions = new Set();
19         this._logger = logger;
20         this._slaveAuth = slaveAuth;
21         this._remoteAPI = remoteAPI;
22         this._subprocess = subprocess;
23     }
24
25     static fetchAndReportAllInOrder(fetcherList)
26     {
27         return mapInSerialPromiseChain(fetcherList, (fetcher) => fetcher.fetchAndReportNewBuilds());
28     }
29
30     fetchAndReportNewBuilds()
31     {
32         return this._fetchAvailableBuilds().then((results) => {
33             this._logger.log(`Submitting ${results.length} builds for ${this._osConfig['name']}`);
34             return this._submitCommits(results);
35         });
36     }
37
38     _fetchAvailableBuilds()
39     {
40         const config = this._osConfig;
41         const repositoryName = config['name'];
42         let customCommands = config['customCommands'];
43
44         return mapInSerialPromiseChain(customCommands, (command) => {
45             assert(command['minRevision']);
46             assert(command['maxRevision']);
47             const minRevisionOrder = this._computeOrder(command['minRevision']);
48             const maxRevisionOrder = this._computeOrder(command['maxRevision']);
49
50             const url = `/api/commits/${escape(repositoryName)}/last-reported?from=${minRevisionOrder}&to=${maxRevisionOrder}`;
51
52             return this._remoteAPI.getJSONWithStatus(url).then((result) => {
53                 const minOrder = result['commits'].length == 1 ? parseInt(result['commits'][0]['order']) : 0;
54                 return this._commitsForAvailableBuilds(repositoryName, command['command'], command['linesToIgnore'], minOrder);
55             }).then((commits) => {
56                 const label = 'name' in command ? `"${command['name']}"` : `"command['minRevision']" to "command['maxRevision']"`;
57                 this._logger.log(`Found ${commits.length} builds for ${label}`);
58
59                 if ('ownedCommitCommand' in command) {
60                     this._logger.log(`Resolving ownedCommits for "${label}"`);
61                     return this._addOwnedCommitsForBuild(commits, command['ownedCommitCommand']);
62                 }
63
64                 return commits;
65             });
66         }).then((results) => [].concat(...results));
67     }
68
69     _computeOrder(revision)
70     {
71         const buildNameRegex = /(\d+)([a-zA-Z])(\d+)([a-zA-Z]*)$/;
72         const match = buildNameRegex.exec(revision);
73         assert(match);
74         const major = parseInt(match[1]);
75         const kind = match[2].toUpperCase().charCodeAt(0) - "A".charCodeAt(0);
76         const minor = parseInt(match[3]);
77         const variant = match[4] ? match[4].toUpperCase().charCodeAt(0) - "A".charCodeAt(0) + 1 : 0;
78         return ((major * 100 + kind) * 10000 + minor) * 100 + variant;
79     }
80
81     _commitsForAvailableBuilds(repository, command, linesToIgnore, minOrder)
82     {
83         return this._subprocess.execute(command).then((output) => {
84             let lines = output.split('\n');
85             if (linesToIgnore){
86                 const regex = new RegExp(linesToIgnore);
87                 lines = lines.filter((line) => !regex.exec(line));
88             }
89             return lines.map((revision) => ({repository, revision, 'order': this._computeOrder(revision)}))
90                 .filter((commit) => commit['order'] > minOrder);
91         });
92     }
93
94     _addOwnedCommitsForBuild(commits, command)
95     {
96         return mapInSerialPromiseChain(commits, (commit) => {
97             return this._subprocess.execute(command.concat(commit['revision'])).then((ownedCommitOutput) => {
98                 const ownedCommits = JSON.parse(ownedCommitOutput);
99                 for (let repositoryName in ownedCommits) {
100                     const ownedCommit = ownedCommits[repositoryName];
101                     assert.deepEqual(Object.keys(ownedCommit), ['revision']);
102                     assert(typeof(ownedCommit['revision']) == 'string');
103                 }
104                 commit['ownedCommits'] = ownedCommits;
105                 return commit;
106             });
107         });
108     }
109
110     _submitCommits(commits)
111     {
112         const commitsToReport = {"slaveName": this._slaveAuth['name'], "slavePassword": this._slaveAuth['password'], 'commits': commits};
113         return this._remoteAPI.postJSONWithStatus('/api/report-commits/', commitsToReport);
114     }
115 }
116
117 if (typeof module != 'undefined')
118     module.exports.OSBuildFetcher = OSBuildFetcher;