| // Copyright 2014 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. |
| |
| /** Information about a particular build. */ |
| function BuildInfo(json) { |
| // Parse out the status message for the build. |
| var statusText; |
| if (json.currentStep) { |
| statusText = 'running ' + json.currentStep.name; |
| } else { |
| statusText = json.text.join(' '); |
| } |
| |
| // Determine what state the build is in. |
| var state; |
| if (statusText.indexOf('exception') != -1) { |
| state = 'exception'; |
| } else if (statusText.indexOf('running') != -1) { |
| state = 'running'; |
| } else if (statusText.indexOf('successful') != -1) { |
| state = 'success'; |
| } else if (statusText.indexOf('failed') != -1) { |
| state = 'failed'; |
| } else if (statusText.indexOf('offline') != -1) { |
| state = 'offline'; |
| } else if (statusText.indexOf('warnings') != -1) { |
| state = 'warnings'; |
| } else { |
| state = 'unknown'; |
| } |
| |
| var failures = (state == 'failed') ? this.parseFailures(json) : null; |
| |
| this.number = json.number; |
| this.state = state; |
| this.failures = failures; |
| this.statusText = statusText; |
| this.truncatedStatusText = truncateStatusText(statusText); |
| } |
| |
| /** Save data about failed tests to perform blamelist intersections. */ |
| BuildInfo.prototype.parseFailures = function(json) { |
| var revisionRange = this.getRevisionRange(json); |
| if (revisionRange == null) return null; |
| |
| var failures = []; |
| var botName = json.builderName; |
| for (var i = 0; i < json.steps.length; ++i) { |
| var step = json.steps[i]; |
| var binaryName = step.name; |
| if (step.results[0] != 0) { // Failed. |
| for (var j = 0; j < step.logs.length; ++j) { |
| var log = step.logs[j]; |
| if (log[0] == 'stdio') |
| continue; |
| var testName = log[0]; |
| failures.push([botName, binaryName, testName, revisionRange]); |
| } |
| } |
| } |
| |
| return failures; |
| }; |
| |
| /** |
| * Get the revisions involved in a build. Sadly, this only works on Chromium's |
| * main builders because downstream trees provide git revision SHA1s through |
| * JSON instead of SVN numbers. |
| */ |
| BuildInfo.prototype.getRevisionRange = function(json) { |
| if (json.sourceStamp.changes.length == 0) { |
| return null; |
| } |
| |
| var lowest = parseInt(json.sourceStamp.changes[0].revision, 10); |
| var highest = parseInt(json.sourceStamp.changes[0].revision, 10); |
| for (var i = 1; i < json.sourceStamp.changes.length; ++i) { |
| var rev = parseInt(json.sourceStamp.changes[i].revision, 10); |
| if (rev < lowest) |
| lowest = rev; |
| if (rev > highest) |
| highest = rev; |
| } |
| return [lowest, highest]; |
| }; |
| |
| /** Creates HTML to display info about this build. */ |
| BuildInfo.prototype.createHtml = function(buildNumberCell, |
| botUrl, |
| showFullInfo) { |
| var fullStatusText = 'Build ' + this.number + ':\n' + this.statusText; |
| createBuildHtml(buildNumberCell, |
| botUrl + '/builds/' + this.number, |
| showFullInfo ? this.number : null, |
| fullStatusText, |
| showFullInfo ? this.truncatedStatusText : null, |
| this.state); |
| }; |
| |
| /** Creates a table cell for a particular build number. */ |
| function createBuildHtml(cellElement, |
| url, |
| buildNumber, |
| fullStatusText, |
| truncatedStatusText, |
| buildState) { |
| // Create a link to the build results. |
| var linkElement = document.createElement('a'); |
| linkElement.href = url; |
| |
| // Display either the build number (for the last completed build), or show the |
| // status of the step. |
| var buildIdentifierElement = document.createElement('span'); |
| if (buildNumber) { |
| buildIdentifierElement.className = 'build-identifier'; |
| buildIdentifierElement.innerHTML = buildNumber; |
| } else { |
| buildIdentifierElement.className = 'build-letter'; |
| buildIdentifierElement.innerHTML = buildState.toUpperCase()[0]; |
| } |
| linkElement.appendChild(buildIdentifierElement); |
| |
| // Show the status of the build in truncated form so it doesn't take up the |
| // whole screen. |
| if (truncatedStatusText) { |
| var statusElement = document.createElement('span'); |
| statusElement.className = 'build-status'; |
| statusElement.innerHTML = truncatedStatusText; |
| linkElement.appendChild(statusElement); |
| } |
| |
| // Tack the cell onto the end of the row. |
| cellElement.className = buildState; |
| cellElement.title = fullStatusText; |
| cellElement.appendChild(linkElement); |
| } |