Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Side by Side Diff: tryconsole/static/builds.js

Issue 517046: Initial check-in of tryconsole. (Closed) Base URL: svn://chrome-svn/chrome/trunk/tools/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tryconsole/queue.yaml ('k') | tryconsole/static/favicon.ico » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:mergeinfo
OLDNEW
(Empty)
1 // Copyright (c) 2009-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview Setups everything needed to show current build status.
7 */
8
9 /**
10 * Namespace for functions related to the status of builds.
11 */
12 var builds = {};
13
14 /**
15 * A function to aggregate together two build stage results.
16 * @param {string} a A build result.
17 * @param {string} b A build result.
18 * @return {string} The combined build result.
19 */
20 builds.statusJoin = function(a, b) {
21 if (a == 'exception' || b == 'exception') return 'exception';
22 if (a == 'failure' || b == 'failure') return 'failure';
23 if (a == 'running' || b == 'running') return 'running';
24 if (a == 'success' || b == 'success') return 'success';
25 return 'running';
26 };
27
28 /**
29 * Mapping from build stage status to color name.
30 * @private
31 */
32 builds.BUILD_COLOR_MAP_ = {
33 'failure': 'red',
34 'warnings': 'orange',
35 'running': 'yellow',
36 'success': 'green',
37 'exception': 'magenta',
38 '': 'gray',
39 };
40
41 /**
42 * Decode the raw result of a build provided by build_info2.
43 * @param {string} rawResults a The raw info from build_info2 about a build.
44 * @return {!Array.<!Object>} A list of build names and links.
45 */
46 builds.decodeResults = function(rawResults) {
47 var rer = /<li><a href="([^"]*)">([^<]*)<\/a><\/li>/g;
48 var results = [];
49 var mr;
50 while (mr = rer.exec(rawResults)) {
51 var result = {
52 'name': mr[2],
53 'link': mr[1]
54 };
55 results.push(result);
56 }
57 return results;
58 };
59
60 /**
61 * Decode the build steps portion of a build result (the stages).
62 * @param {string} logText The text of the steps and logs stage.
63 * @return {list of dicts} A list of dicts encoding each build stage and its
64 * current status.
65 */
66 builds.decodeBuildSteps = function(logText) {
67 var re = /<li><span class="([^"]*)"><a href="([^"]*)">([^<]*)<\/a>[^\]]*\[([^\ ]]*)\] \[([0-9]+) seconds\]<\/span>[ ]*<ol>[ ]*((?:<li><a href[^>]*>[^<]*<\/a><\ /li>[ ]*)*)<\/ol>/g;
68 var steps = [];
69 var m;
70 while (m = re.exec(logText)) {
71 var name = m[4];
72 if (!name.length) name = m[3];
73 name = name.replace(/<.*>/, '');
74 var color;
75 if (m[1] in builds.BUILD_COLOR_MAP_) {
76 color = builds.BUILD_COLOR_MAP_[m[1]];
77 } else {
78 color = 'magenta';
79 }
80 var step = {
81 'name': name,
82 'status': m[1],
83 'time': parseInt(m[5], 10),
84 'color': color,
85 'link': m[2],
86 'results': builds.decodeResults(m[6]),
87 };
88 steps.push(step);
89 }
90 return steps;
91 };
92
93 /**
94 * Summarize the overall status of a build based on the result of each stage.
95 * @param {list of dicts} steps A list of dicts describing the status of each
96 * build stage.
97 * @return {string} A status string (such as 'success').
98 */
99 builds.summarizeStatus = function(steps) {
100 var st = 'unknown';
101 var stepsLen = steps.length;
102 for (var s = 0; s < stepsLen; s++) {
103 st = builds.statusJoin(st, steps[s]['status']);
104 }
105 return st;
106 };
107
108 /**
109 * Update the current list of builds based on the latest data and query.
110 * @param {string} id The id of the <div> containing the list of builds.
111 * @param {string} limitId The id of the prompt containing the current query.
112 * @param {dict} data Dictionary containing information on all builds.
113 */
114 builds.redrawUpdate = function(id, limitId, data) {
115 // Get limit string if any.
116 var limitStr = '';
117 var limitElement = document.getElementById(limitId);
118 if (limitElement) {
119 limitStr = limitElement.value.toLowerCase();
120 }
121
122 // Get dirty bit.
123 dirty = data['dirty'];
124 if (limitStr != data['last_limit']) dirty = true;
125 data['dirty'] = false;
126 data['last_limit'] = limitStr;
127
128 // Quit now if not dirty.
129 if (!dirty) {
130 window.setTimeout(function() {
131 builds.redrawUpdate(id, limitId, data);
132 }, 30);
133 return;
134 }
135
136 // Do the update.
137 var jobs = {};
138 var offset = 0;
139 // Update job set.
140 for (var bid in data) {
141 // Skip short ones (used for other purposes).
142 if (bid.length < 15) continue;
143 // Get out item.
144 var b = data[bid];
145 // Skip empty ones.
146 if (!('last_checked' in b)) continue;
147 // Skip old busted builds for now.
148 if (!('changed_at' in b)) continue;
149 // Skip if doesn't match limit string.
150 if (b['raw_reason'].toLowerCase().search(limitStr) < 0 &&
151 b['account_name'].toLowerCase().search(limitStr) < 0 &&
152 b['builder_name'].toLowerCase().search(limitStr) < 0) continue;
153 // Prepare a key.
154 var key = b['raw_reason'] + '|' + b['changed_at'];
155 if (!(key in jobs)) {
156 jobs[key] = {
157 'title': b['patch_name'],
158 'username': b['username'],
159 'submitted_at': '' + b['changed_at'],
160 'builds': [],
161 'offset': offset,
162 'status': 'unknown',
163 };
164 offset++;
165 }
166 var steps = builds.decodeBuildSteps(b['steps_and_logfiles']);
167 item = {
168 'title': b['builder_name'],
169 'eta': b['etaSeconds'],
170 'steps': steps,
171 'status': builds.summarizeStatus(steps),
172 'link_base': b['master_url'] + '/builders/' + b['builder_name'],
173 'build_number': b['build_number'],
174 };
175 jobs[key]['builds'].push(item);
176 jobs[key]['status'] = builds.statusJoin(jobs[key]['status'],
177 item['status']);
178 }
179
180 // Flatten dict.
181 jobList = [];
182 for (var j in jobs) {
183 jobList.push(jobs[j]);
184 }
185 jobList = jobList.sort(function(a, b) {
186 var aRunning = a['status'] == 'running';
187 var bRunning = b['status'] == 'running';
188 if (aRunning && !bRunning) return -1;
189 if (bRunning && !aRunning) return 1;
190 return a['offset'] - b['offset']});
191
192 // Clip if > 50
193 if (jobList.length > 50) {
194 jobList = jobList.slice(0, 50);
195 }
196
197 // Format into html.
198 var html = '<dl class="job">';
199 var jobListLen = jobList.length;
200 for (var job = 0; job < jobListLen; job++) {
201 var jobi = jobList[job];
202 html += '<dt class="' + jobi['status'] + '"><b>' +
203 jobi['title'] + '</b> - ' + jobi['username'] +
204 ' - <i>' + jobi['submitted_at'] +
205 '</i></dt><dd><dl class="build">';
206 var buildsLen = jobi['builds'].length;
207 for (var build = 0; build < buildsLen; build++) {
208 var buildi = jobi['builds'][build];
209 var etaMin = Math.floor(buildi['eta'] / 60);
210 var etaSec = Math.floor(buildi['eta'] % 60);
211 var link = buildi['link_base'] + '/builds/' + buildi['build_number'];
212 html += '<dt><a href="' + link + '" target="_blank">' +
213 buildi['title'] + '</a>';
214 if (etaMin || etaSec) {
215 html += '- <i>ETA ' + etaMin + ' minutes, ' +
216 etaSec + ' seconds</i>';
217 }
218 html += '</dt>' +
219 '<dd class="' + buildi['status'] + '">' +
220 '<table border="1" cellpadding="4" rules="groups" frame="box">';
221 var stepsLen = buildi['steps'].length;
222 for (var step = 0; step < stepsLen; step++) {
223 html += '<colgroup></colgroup>';
224 }
225 html += '<tr>';
226 for (var step = 0; step < stepsLen; step++) {
227 html += '<td align="center">';
228 var stepi = buildi['steps'][step];
229 if (stepi['results'].length == 1) {
230 var link = stepi['results'][0]['link'];
231 } else {
232 var link = stepi['link'];
233 }
234 link = buildi['link_base'] + '/builds/' + link;
235 if (stepi['color'] != 'gray') {
236 html += '<a href="' + link + '" target="_blank">';
237 }
238 html += '<img src="/static/' + stepi['color'] +
239 '.png" width="32" height="32">';
240 if (stepi['color'] != 'gray') {
241 html += '</a>';
242 }
243 html += '</td>';
244 }
245 html += '</tr>' + '<tr>';
246 for (var step = 0; step < stepsLen; step++) {
247 var stepi = buildi['steps'][step];
248 html += '<td align="center">' +
249 '<a style="font-size:50%">' + stepi['name'] + '</a>' +
250 '</td>';
251 }
252 html += '</tr></table></dd>';
253 }
254 html += '</dl></dd>';
255 }
256 html += '</dl>';
257 var e = document.getElementById(id);
258 e.innerHTML = html;
259
260 // Do it again.
261 window.setTimeout(function() {
262 builds.redrawUpdate(id, limitId, data);
263 }, 30);
264 };
265
266 /**
267 * Update the cached status of a single build (in the background).
268 * @param {string} bid The string id of the build (datastore key).
269 * @param {dict} data Dictionary containing information on all builds.
270 */
271 builds.updateOne = function(bid, data) {
272 // Fetch a info on this one build.
273 http.getText(
274 '/build_info2?id=' + bid,
275 function(text) {
276 if (text != null) {
277 // Decode it.
278 var rows = text.split('\n');
279 var rowsLen = rows.length;
280 for (var r = 0; r < rowsLen; r++) {
281 var row = rows[r];
282 var mid = row.search(' ');
283 if (mid < 0) continue;
284 var key = row.substr(0, mid);
285 var value = row.substr(mid + 1);
286 data[bid][key] = value;
287 }
288 }
289 // Put it back in if end is none.
290 if (!('end' in data[bid]) || data[bid]['end'] == 'None') {
291 data['pending'].push(bid);
292 }
293 // Note the change.
294 data['dirty'] = true;
295 });
296 };
297
298 /**
299 * Update the cached status of all pending builds (in the background).
300 * @param {dict} data Dictionary containing information on all builds.
301 */
302 builds.update = function(data) {
303 // Request all pending builds.
304 var pendingLen = data['pending'].length;
305 for (var bidi = 0; bidi < pendingLen; bidi++) {
306 var bid = data['pending'][bidi];
307 builds.updateOne(bid, data);
308 }
309 data['pending'] = [];
310 };
311
312 /**
313 * Setup the list of builds to manage themselves.
314 * @param {string} id The id of the <div> to contain the list of builds.
315 * @param {string} limitId The id of the prompt containing the current query.
316 * @param {dict} data Dictionary containing information on all builds.
317 */
318 builds.setup = function(id, limitId, data) {
319 // Setup blank pending set.
320 if (!('pending' in data)) {
321 data['pending'] = [];
322 data['last_limit'] = '';
323 data['dirty'] = true;
324 data['fresh_start'] = true;
325 builds.redrawUpdate(id, limitId, data);
326 }
327 // Pick url to use.
328 if (data['fresh_start']) {
329 data['fresh_start'] = false;
330 url = '/list_builds?initial=1';
331 } else {
332 url = '/list_builds';
333 }
334 // Fetch a set of builds.
335 http.getText(url,
336 function(text) {
337 if (text != null) {
338 // Update set of ids.
339 var buildIds = text.split('\n');
340 var buildIdsLen = buildIds.length;
341 for (var bid = 0; bid < buildIdsLen; bid++) {
342 var bidv = buildIds[bid];
343 if (bidv == '') continue;
344 if (!(bidv in data)) {
345 data[bidv] = {};
346 data['pending'].push(bidv);
347 }
348 }
349 }
350 // Update each build.
351 builds.update(data);
352 // Do it again.
353 window.setTimeout(function() {
354 builds.setup(id, limitId, data);
355 }, 20000);
356 });
357 };
358
OLDNEW
« no previous file with comments | « tryconsole/queue.yaml ('k') | tryconsole/static/favicon.ico » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698