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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tryconsole/queue.yaml ('k') | tryconsole/static/favicon.ico » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tryconsole/static/builds.js
===================================================================
--- tryconsole/static/builds.js (revision 0)
+++ tryconsole/static/builds.js (revision 0)
@@ -0,0 +1,358 @@
+// Copyright (c) 2009-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Setups everything needed to show current build status.
+ */
+
+/**
+ * Namespace for functions related to the status of builds.
+ */
+var builds = {};
+
+/**
+ * A function to aggregate together two build stage results.
+ * @param {string} a A build result.
+ * @param {string} b A build result.
+ * @return {string} The combined build result.
+ */
+builds.statusJoin = function(a, b) {
+ if (a == 'exception' || b == 'exception') return 'exception';
+ if (a == 'failure' || b == 'failure') return 'failure';
+ if (a == 'running' || b == 'running') return 'running';
+ if (a == 'success' || b == 'success') return 'success';
+ return 'running';
+};
+
+/**
+ * Mapping from build stage status to color name.
+ * @private
+ */
+builds.BUILD_COLOR_MAP_ = {
+ 'failure': 'red',
+ 'warnings': 'orange',
+ 'running': 'yellow',
+ 'success': 'green',
+ 'exception': 'magenta',
+ '': 'gray',
+};
+
+/**
+ * Decode the raw result of a build provided by build_info2.
+ * @param {string} rawResults a The raw info from build_info2 about a build.
+ * @return {!Array.<!Object>} A list of build names and links.
+ */
+builds.decodeResults = function(rawResults) {
+ var rer = /<li><a href="([^"]*)">([^<]*)<\/a><\/li>/g;
+ var results = [];
+ var mr;
+ while (mr = rer.exec(rawResults)) {
+ var result = {
+ 'name': mr[2],
+ 'link': mr[1]
+ };
+ results.push(result);
+ }
+ return results;
+};
+
+/**
+ * Decode the build steps portion of a build result (the stages).
+ * @param {string} logText The text of the steps and logs stage.
+ * @return {list of dicts} A list of dicts encoding each build stage and its
+ * current status.
+ */
+builds.decodeBuildSteps = function(logText) {
+ var re = /<li><span class="([^"]*)"><a href="([^"]*)">([^<]*)<\/a>[^\]]*\[([^\]]*)\] \[([0-9]+) seconds\]<\/span>[ ]*<ol>[ ]*((?:<li><a href[^>]*>[^<]*<\/a><\/li>[ ]*)*)<\/ol>/g;
+ var steps = [];
+ var m;
+ while (m = re.exec(logText)) {
+ var name = m[4];
+ if (!name.length) name = m[3];
+ name = name.replace(/<.*>/, '');
+ var color;
+ if (m[1] in builds.BUILD_COLOR_MAP_) {
+ color = builds.BUILD_COLOR_MAP_[m[1]];
+ } else {
+ color = 'magenta';
+ }
+ var step = {
+ 'name': name,
+ 'status': m[1],
+ 'time': parseInt(m[5], 10),
+ 'color': color,
+ 'link': m[2],
+ 'results': builds.decodeResults(m[6]),
+ };
+ steps.push(step);
+ }
+ return steps;
+};
+
+/**
+ * Summarize the overall status of a build based on the result of each stage.
+ * @param {list of dicts} steps A list of dicts describing the status of each
+ * build stage.
+ * @return {string} A status string (such as 'success').
+ */
+builds.summarizeStatus = function(steps) {
+ var st = 'unknown';
+ var stepsLen = steps.length;
+ for (var s = 0; s < stepsLen; s++) {
+ st = builds.statusJoin(st, steps[s]['status']);
+ }
+ return st;
+};
+
+/**
+ * Update the current list of builds based on the latest data and query.
+ * @param {string} id The id of the <div> containing the list of builds.
+ * @param {string} limitId The id of the prompt containing the current query.
+ * @param {dict} data Dictionary containing information on all builds.
+ */
+builds.redrawUpdate = function(id, limitId, data) {
+ // Get limit string if any.
+ var limitStr = '';
+ var limitElement = document.getElementById(limitId);
+ if (limitElement) {
+ limitStr = limitElement.value.toLowerCase();
+ }
+
+ // Get dirty bit.
+ dirty = data['dirty'];
+ if (limitStr != data['last_limit']) dirty = true;
+ data['dirty'] = false;
+ data['last_limit'] = limitStr;
+
+ // Quit now if not dirty.
+ if (!dirty) {
+ window.setTimeout(function() {
+ builds.redrawUpdate(id, limitId, data);
+ }, 30);
+ return;
+ }
+
+ // Do the update.
+ var jobs = {};
+ var offset = 0;
+ // Update job set.
+ for (var bid in data) {
+ // Skip short ones (used for other purposes).
+ if (bid.length < 15) continue;
+ // Get out item.
+ var b = data[bid];
+ // Skip empty ones.
+ if (!('last_checked' in b)) continue;
+ // Skip old busted builds for now.
+ if (!('changed_at' in b)) continue;
+ // Skip if doesn't match limit string.
+ if (b['raw_reason'].toLowerCase().search(limitStr) < 0 &&
+ b['account_name'].toLowerCase().search(limitStr) < 0 &&
+ b['builder_name'].toLowerCase().search(limitStr) < 0) continue;
+ // Prepare a key.
+ var key = b['raw_reason'] + '|' + b['changed_at'];
+ if (!(key in jobs)) {
+ jobs[key] = {
+ 'title': b['patch_name'],
+ 'username': b['username'],
+ 'submitted_at': '' + b['changed_at'],
+ 'builds': [],
+ 'offset': offset,
+ 'status': 'unknown',
+ };
+ offset++;
+ }
+ var steps = builds.decodeBuildSteps(b['steps_and_logfiles']);
+ item = {
+ 'title': b['builder_name'],
+ 'eta': b['etaSeconds'],
+ 'steps': steps,
+ 'status': builds.summarizeStatus(steps),
+ 'link_base': b['master_url'] + '/builders/' + b['builder_name'],
+ 'build_number': b['build_number'],
+ };
+ jobs[key]['builds'].push(item);
+ jobs[key]['status'] = builds.statusJoin(jobs[key]['status'],
+ item['status']);
+ }
+
+ // Flatten dict.
+ jobList = [];
+ for (var j in jobs) {
+ jobList.push(jobs[j]);
+ }
+ jobList = jobList.sort(function(a, b) {
+ var aRunning = a['status'] == 'running';
+ var bRunning = b['status'] == 'running';
+ if (aRunning && !bRunning) return -1;
+ if (bRunning && !aRunning) return 1;
+ return a['offset'] - b['offset']});
+
+ // Clip if > 50
+ if (jobList.length > 50) {
+ jobList = jobList.slice(0, 50);
+ }
+
+ // Format into html.
+ var html = '<dl class="job">';
+ var jobListLen = jobList.length;
+ for (var job = 0; job < jobListLen; job++) {
+ var jobi = jobList[job];
+ html += '<dt class="' + jobi['status'] + '"><b>' +
+ jobi['title'] + '</b> - ' + jobi['username'] +
+ ' - <i>' + jobi['submitted_at'] +
+ '</i></dt><dd><dl class="build">';
+ var buildsLen = jobi['builds'].length;
+ for (var build = 0; build < buildsLen; build++) {
+ var buildi = jobi['builds'][build];
+ var etaMin = Math.floor(buildi['eta'] / 60);
+ var etaSec = Math.floor(buildi['eta'] % 60);
+ var link = buildi['link_base'] + '/builds/' + buildi['build_number'];
+ html += '<dt><a href="' + link + '" target="_blank">' +
+ buildi['title'] + '</a>';
+ if (etaMin || etaSec) {
+ html += '- <i>ETA ' + etaMin + ' minutes, ' +
+ etaSec + ' seconds</i>';
+ }
+ html += '</dt>' +
+ '<dd class="' + buildi['status'] + '">' +
+ '<table border="1" cellpadding="4" rules="groups" frame="box">';
+ var stepsLen = buildi['steps'].length;
+ for (var step = 0; step < stepsLen; step++) {
+ html += '<colgroup></colgroup>';
+ }
+ html += '<tr>';
+ for (var step = 0; step < stepsLen; step++) {
+ html += '<td align="center">';
+ var stepi = buildi['steps'][step];
+ if (stepi['results'].length == 1) {
+ var link = stepi['results'][0]['link'];
+ } else {
+ var link = stepi['link'];
+ }
+ link = buildi['link_base'] + '/builds/' + link;
+ if (stepi['color'] != 'gray') {
+ html += '<a href="' + link + '" target="_blank">';
+ }
+ html += '<img src="/static/' + stepi['color'] +
+ '.png" width="32" height="32">';
+ if (stepi['color'] != 'gray') {
+ html += '</a>';
+ }
+ html += '</td>';
+ }
+ html += '</tr>' + '<tr>';
+ for (var step = 0; step < stepsLen; step++) {
+ var stepi = buildi['steps'][step];
+ html += '<td align="center">' +
+ '<a style="font-size:50%">' + stepi['name'] + '</a>' +
+ '</td>';
+ }
+ html += '</tr></table></dd>';
+ }
+ html += '</dl></dd>';
+ }
+ html += '</dl>';
+ var e = document.getElementById(id);
+ e.innerHTML = html;
+
+ // Do it again.
+ window.setTimeout(function() {
+ builds.redrawUpdate(id, limitId, data);
+ }, 30);
+};
+
+/**
+ * Update the cached status of a single build (in the background).
+ * @param {string} bid The string id of the build (datastore key).
+ * @param {dict} data Dictionary containing information on all builds.
+ */
+builds.updateOne = function(bid, data) {
+ // Fetch a info on this one build.
+ http.getText(
+ '/build_info2?id=' + bid,
+ function(text) {
+ if (text != null) {
+ // Decode it.
+ var rows = text.split('\n');
+ var rowsLen = rows.length;
+ for (var r = 0; r < rowsLen; r++) {
+ var row = rows[r];
+ var mid = row.search(' ');
+ if (mid < 0) continue;
+ var key = row.substr(0, mid);
+ var value = row.substr(mid + 1);
+ data[bid][key] = value;
+ }
+ }
+ // Put it back in if end is none.
+ if (!('end' in data[bid]) || data[bid]['end'] == 'None') {
+ data['pending'].push(bid);
+ }
+ // Note the change.
+ data['dirty'] = true;
+ });
+};
+
+/**
+ * Update the cached status of all pending builds (in the background).
+ * @param {dict} data Dictionary containing information on all builds.
+ */
+builds.update = function(data) {
+ // Request all pending builds.
+ var pendingLen = data['pending'].length;
+ for (var bidi = 0; bidi < pendingLen; bidi++) {
+ var bid = data['pending'][bidi];
+ builds.updateOne(bid, data);
+ }
+ data['pending'] = [];
+};
+
+/**
+ * Setup the list of builds to manage themselves.
+ * @param {string} id The id of the <div> to contain the list of builds.
+ * @param {string} limitId The id of the prompt containing the current query.
+ * @param {dict} data Dictionary containing information on all builds.
+ */
+builds.setup = function(id, limitId, data) {
+ // Setup blank pending set.
+ if (!('pending' in data)) {
+ data['pending'] = [];
+ data['last_limit'] = '';
+ data['dirty'] = true;
+ data['fresh_start'] = true;
+ builds.redrawUpdate(id, limitId, data);
+ }
+ // Pick url to use.
+ if (data['fresh_start']) {
+ data['fresh_start'] = false;
+ url = '/list_builds?initial=1';
+ } else {
+ url = '/list_builds';
+ }
+ // Fetch a set of builds.
+ http.getText(url,
+ function(text) {
+ if (text != null) {
+ // Update set of ids.
+ var buildIds = text.split('\n');
+ var buildIdsLen = buildIds.length;
+ for (var bid = 0; bid < buildIdsLen; bid++) {
+ var bidv = buildIds[bid];
+ if (bidv == '') continue;
+ if (!(bidv in data)) {
+ data[bidv] = {};
+ data['pending'].push(bidv);
+ }
+ }
+ }
+ // Update each build.
+ builds.update(data);
+ // Do it again.
+ window.setTimeout(function() {
+ builds.setup(id, limitId, data);
+ }, 20000);
+ });
+};
+
Property changes on: tryconsole/static/builds.js
___________________________________________________________________
Added: svn:mergeinfo
« 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