1 // Copyright 2014 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 /** Information about a particular build. */ 6 function BuildInfo(json) { 7 // Parse out the status message for the build. 8 var statusText; 9 if (json.currentStep) { 10 statusText = 'running ' + json.currentStep.name; 11 } else { 12 statusText = json.text.join(' '); 13 } 14 15 // Determine what state the build is in. 16 var state; 17 if (statusText.indexOf('exception') != -1) { 18 state = 'exception'; 19 } else if (statusText.indexOf('running') != -1) { 20 state = 'running'; 21 } else if (statusText.indexOf('successful') != -1) { 22 state = 'success'; 23 } else if (statusText.indexOf('failed') != -1) { 24 state = 'failed'; 25 } else if (statusText.indexOf('offline') != -1) { 26 state = 'offline'; 27 } else if (statusText.indexOf('warnings') != -1) { 28 state = 'warnings'; 29 } else { 30 state = 'unknown'; 31 } 32 33 var failures = (state == 'failed') ? this.parseFailures(json) : null; 34 35 this.number = json.number; 36 this.state = state; 37 this.failures = failures; 38 this.statusText = statusText; 39 this.truncatedStatusText = truncateStatusText(statusText); 40 } 41 42 /** Save data about failed tests to perform blamelist intersections. */ 43 BuildInfo.prototype.parseFailures = function(json) { 44 var revisionRange = this.getRevisionRange(json); 45 if (revisionRange == null) return null; 46 47 var failures = []; 48 var botName = json.builderName; 49 for (var i = 0; i < json.steps.length; ++i) { 50 var step = json.steps[i]; 51 var binaryName = step.name; 52 if (step.results[0] != 0) { // Failed. 53 for (var j = 0; j < step.logs.length; ++j) { 54 var log = step.logs[j]; 55 if (log[0] == 'stdio') 56 continue; 57 var testName = log[0]; 58 failures.push([botName, binaryName, testName, revisionRange]); 59 } 60 } 61 } 62 63 return failures; 64 }; 65 66 /** 67 * Get the revisions involved in a build. Sadly, this only works on Chromium's 68 * main builders because downstream trees provide git revision SHA1s through 69 * JSON instead of SVN numbers. 70 */ 71 BuildInfo.prototype.getRevisionRange = function(json) { 72 if (json.sourceStamp.changes.length == 0) { 73 return null; 74 } 75 76 var lowest = parseInt(json.sourceStamp.changes[0].revision, 10); 77 var highest = parseInt(json.sourceStamp.changes[0].revision, 10); 78 for (var i = 1; i < json.sourceStamp.changes.length; ++i) { 79 var rev = parseInt(json.sourceStamp.changes[i].revision, 10); 80 if (rev < lowest) 81 lowest = rev; 82 if (rev > highest) 83 highest = rev; 84 } 85 return [lowest, highest]; 86 }; 87 88 /** Creates HTML to display info about this build. */ 89 BuildInfo.prototype.createHtml = function(buildNumberCell, 90 botUrl, 91 showFullInfo) { 92 var fullStatusText = 'Build ' + this.number + ':\n' + this.statusText; 93 createBuildHtml(buildNumberCell, 94 botUrl + '/builds/' + this.number, 95 showFullInfo ? this.number : null, 96 fullStatusText, 97 showFullInfo ? this.truncatedStatusText : null, 98 this.state); 99 }; 100 101 /** Creates a table cell for a particular build number. */ 102 function createBuildHtml(cellElement, 103 url, 104 buildNumber, 105 fullStatusText, 106 truncatedStatusText, 107 buildState) { 108 // Create a link to the build results. 109 var linkElement = document.createElement('a'); 110 linkElement.href = url; 111 112 // Display either the build number (for the last completed build), or show the 113 // status of the step. 114 var buildIdentifierElement = document.createElement('span'); 115 if (buildNumber) { 116 buildIdentifierElement.className = 'build-identifier'; 117 buildIdentifierElement.innerHTML = buildNumber; 118 } else { 119 buildIdentifierElement.className = 'build-letter'; 120 buildIdentifierElement.innerHTML = buildState.toUpperCase()[0]; 121 } 122 linkElement.appendChild(buildIdentifierElement); 123 124 // Show the status of the build in truncated form so it doesn't take up the 125 // whole screen. 126 if (truncatedStatusText) { 127 var statusElement = document.createElement('span'); 128 statusElement.className = 'build-status'; 129 statusElement.innerHTML = truncatedStatusText; 130 linkElement.appendChild(statusElement); 131 } 132 133 // Tack the cell onto the end of the row. 134 cellElement.className = buildState; 135 cellElement.title = fullStatusText; 136 cellElement.appendChild(linkElement); 137 } 138