Home | History | Annotate | Download | only in sheriffing
      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