| OLD | NEW |
| (Empty) |
| 1 <!-- | |
| 2 Copyright 2014 The Chromium Authors. All rights reserved. | |
| 3 Use of this source code is governed by a BSD-style license that can be | |
| 4 found in the LICENSE file. | |
| 5 --> | |
| 6 | |
| 7 <link rel="import" href="../lib/net.html"> | |
| 8 <link rel="import" href="../lib/update-util.html"> | |
| 9 <link rel="import" href="ct-builder-failure.html"> | |
| 10 <link rel="import" href="ct-step-failure.html"> | |
| 11 <link rel="import" href="ct-failure-group.html"> | |
| 12 <link rel="import" href="ct-builder-failure-group-data.html"> | |
| 13 <link rel="import" href="ct-master-failure.html"> | |
| 14 <link rel="import" href="ct-master-failure-group-data.html"> | |
| 15 <link rel="import" href="ct-step-failure-group-data.html"> | |
| 16 <link rel="import" href="ct-trooper-failure-group-data.html"> | |
| 17 <link rel="import" href="ct-commit-list.html"> | |
| 18 | |
| 19 <script> | |
| 20 function CTFailures(commitLog) { | |
| 21 this.commitLog = commitLog; | |
| 22 // Maps a tree id to an array of CTFailureGroups within that tree. | |
| 23 this.failures = null; | |
| 24 this.lastUpdateDate = null; | |
| 25 } | |
| 26 | |
| 27 (function() { | |
| 28 'use strict'; | |
| 29 | |
| 30 // FIXME: This could potentially move onto CTStepFailureGroupData as it isn't re
levant to | |
| 31 // trooper failures. | |
| 32 // Reverse sorting order, if a > b, return a negative number. | |
| 33 CTFailures.prototype._failureByTreeListComparator = function(tree, a, b) { | |
| 34 if (tree === undefined) | |
| 35 tree = 'chromium'; | |
| 36 | |
| 37 // Always bubble master alerts to the top | |
| 38 if (a.category =='master') { | |
| 39 if (b.category == 'master') | |
| 40 return 0; | |
| 41 return -1; | |
| 42 } else if (b.category == 'master') { | |
| 43 return 1; | |
| 44 } | |
| 45 | |
| 46 if (!a.data.commitList) | |
| 47 return 1; | |
| 48 if (!b.data.commitList) | |
| 49 return -1; | |
| 50 | |
| 51 var rev_a = a.data.commitList.revisions; | |
| 52 var rev_b = b.data.commitList.revisions; | |
| 53 | |
| 54 if (!rev_a || !Object.keys(rev_a).length) { | |
| 55 if (!rev_b || !Object.keys(rev_b).length) | |
| 56 return 0; | |
| 57 return 1; | |
| 58 } else if (!rev_b || !Object.keys(rev_b).length) { | |
| 59 return -1; | |
| 60 } | |
| 61 | |
| 62 // Prioritize the tree's revision, if they are unequal (else, fallback below) | |
| 63 if (rev_a[tree] && rev_b[tree] && | |
| 64 rev_a[tree].last() != rev_b[tree].last()) { | |
| 65 return rev_b[tree].last() - rev_a[tree].last(); | |
| 66 } | |
| 67 | |
| 68 // Compare other revisions in alphabetical order. | |
| 69 var keys = Object.keys(rev_a).sort(); | |
| 70 for (var i = 0; i < keys.length; i++) { | |
| 71 if (keys[i] == tree) // Already taken care of, above. | |
| 72 continue; | |
| 73 | |
| 74 var a_list = rev_a[keys[i]]; | |
| 75 var b_list = rev_b[keys[i]]; | |
| 76 if (!b_list) | |
| 77 return -1; | |
| 78 | |
| 79 if (a_list.last() != b_list.last()) | |
| 80 return b_list.last() - a_list.last(); | |
| 81 } | |
| 82 return 0; | |
| 83 }; | |
| 84 | |
| 85 // Updates the format of the alerts array to be easier to parse. | |
| 86 CTFailures.prototype._mungeAlerts = function(alerts) { | |
| 87 alerts.forEach(function(failure) { | |
| 88 // FIXME: Have the server store the actual failure type in a different | |
| 89 // field instead of smashing it into the reason. | |
| 90 if (failure.failureType) { | |
| 91 // The server has been fixed. | |
| 92 } else { | |
| 93 if (failure.reason) { | |
| 94 var parts = failure.reason.split(':'); | |
| 95 failure.reason = parts[0]; | |
| 96 failure.failureType = parts[1] || 'FAIL'; | |
| 97 } else { | |
| 98 failure.failureType = 'UNKNOWN'; | |
| 99 } | |
| 100 } | |
| 101 }); | |
| 102 }; | |
| 103 | |
| 104 CTFailures.prototype.update = function() { | |
| 105 var annotationPromise = CTFailureGroup.fetchAnnotations(); | |
| 106 return Promise.all([annotationPromise, net.json('https://sheriff-o-matic.appsp
ot.com/alerts'), | |
| 107 net.json('https://trooper-o-matic.appspot.com/alerts')]).then(function(dat
a_array) { | |
| 108 var annotations = data_array[0]; | |
| 109 var sheriff_data = data_array[1]; | |
| 110 var trooper_data = data_array[2]; | |
| 111 | |
| 112 var newFailures = {}; | |
| 113 this.lastUpdateDate = new Date(sheriff_data.date * 1000); | |
| 114 this._mungeAlerts(sheriff_data.alerts); | |
| 115 // FIXME: Change builder_alerts to expose the alerts as a map instead of an
array. | |
| 116 var alertsByKey = {} | |
| 117 sheriff_data.alerts.forEach(function(alert) { | |
| 118 alertsByKey[alert.key] = alert; | |
| 119 }); | |
| 120 // Update |failures| with the appropriate CTFailureGroup's for each | |
| 121 // tree. | |
| 122 sheriff_data.range_groups.forEach(function(rangeGroup) { | |
| 123 this._processFailuresForRangeGroup(newFailures, rangeGroup, alertsByKey, a
nnotations); | |
| 124 }.bind(this)); | |
| 125 | |
| 126 sheriff_data.stale_builder_alerts.forEach(function(alert) { | |
| 127 this._processBuilderFailure(newFailures, alert); | |
| 128 }.bind(this)); | |
| 129 | |
| 130 // Sort failure groups so that newer failures are shown at the top | |
| 131 // of the UI. | |
| 132 Object.keys(newFailures, function (tree, failuresByTree) { | |
| 133 failuresByTree.sort(this._failureByTreeListComparator.bind(this, tree)); | |
| 134 }.bind(this)); | |
| 135 | |
| 136 this.failures = updateUtil.updateLeft(this.failures, newFailures); | |
| 137 this._processTrooperFailures(newFailures, trooper_data); | |
| 138 }.bind(this)); | |
| 139 }; | |
| 140 | |
| 141 CTFailures.prototype._failureComparator = function(a, b) { | |
| 142 if (a.step > b.step) | |
| 143 return 1; | |
| 144 if (a.step < b.step) | |
| 145 return -1 | |
| 146 if (a.testName > b.testName) | |
| 147 return 1; | |
| 148 if (a.testName < b.testName) | |
| 149 return -1 | |
| 150 return 0; | |
| 151 }; | |
| 152 | |
| 153 CTFailures.prototype._processTrooperFailures = function(all_failures, | |
| 154 trooper_data) { | |
| 155 var trooper_failures = []; | |
| 156 Object.keys(trooper_data, function(failureType, failuresByTree) { | |
| 157 Object.keys(failuresByTree, function(tree, failure) { | |
| 158 if (failure.should_alert) { | |
| 159 trooper_failures.push(new CTFailureGroup('trooper', | |
| 160 new CTTrooperFailureGroupData(failure.details, failure.url, failure, | |
| 161 failureType, tree))); | |
| 162 } | |
| 163 }); | |
| 164 }); | |
| 165 | |
| 166 Object.keys(all_failures, function(tree, failuresByTree) { | |
| 167 failuresByTree.forEach(function(failure) { | |
| 168 if (failure.category == 'builder' || failure.category == 'master') { | |
| 169 trooper_failures.push(failure); | |
| 170 } | |
| 171 }); | |
| 172 }); | |
| 173 this.failures['trooper'] = trooper_failures; | |
| 174 }; | |
| 175 | |
| 176 CTFailures.prototype._groupFailuresByTreeAndReason = function(failures, annotati
ons) { | |
| 177 var failuresByTree = {}; | |
| 178 failures.forEach(function(failure) { | |
| 179 // Establish the key to uniquely identify a failure by reason. | |
| 180 var failureKey = CTStepFailure.createKey(failure); | |
| 181 | |
| 182 var reasonKey = JSON.stringify({ | |
| 183 step: failure.step_name, | |
| 184 reason: failure.reason, | |
| 185 }); | |
| 186 | |
| 187 // FIXME: Use a model class instead of a dumb object. | |
| 188 if (!failuresByTree[failure.tree]) | |
| 189 failuresByTree[failure.tree] = {}; | |
| 190 if (!failuresByTree[failure.tree][reasonKey]) | |
| 191 failuresByTree[failure.tree][reasonKey] = {}; | |
| 192 failuresByTree[failure.tree][reasonKey][failure.builder_name] = { | |
| 193 key: failureKey, | |
| 194 // FIXME: Rename to failureType. | |
| 195 actual: failure.failureType, | |
| 196 lastFailingBuild: failure.last_failing_build, | |
| 197 masterUrl: failure.master_url, | |
| 198 failingBuildCount: (1 + failure.last_failing_build - failure.failing_build
), | |
| 199 annotation: annotations[failureKey], | |
| 200 isTreeCloser: failure.would_close_tree, | |
| 201 }; | |
| 202 }); | |
| 203 return failuresByTree | |
| 204 }; | |
| 205 | |
| 206 CTFailures.prototype._processFailuresForRangeGroup = function(newFailures, range
Group, alerts, annotations) { | |
| 207 // A rangeGroup may be related to multiple alerts (via |failure_keys|). Catego
rize | |
| 208 // these failures by reason (cause of failure), so that they can be grouped in
the UI | |
| 209 // (via a CTFailureGroup). | |
| 210 var failures = rangeGroup.failure_keys.map(function(failure_key) { | |
| 211 return alerts[failure_key]; | |
| 212 }); | |
| 213 var failuresByTree = this._groupFailuresByTreeAndReason(failures, annotations)
; | |
| 214 | |
| 215 if (Object.isEmpty(failuresByTree)) | |
| 216 return; | |
| 217 | |
| 218 Object.keys(failuresByTree, function(tree, resultsByReason) { | |
| 219 var treeFailures = []; | |
| 220 Object.keys(resultsByReason, function(reasonKey, resultsByBuilder) { | |
| 221 var failure = JSON.parse(reasonKey); | |
| 222 treeFailures.push( | |
| 223 new CTStepFailure(failure.step, failure.reason, resultsByBuilder)); | |
| 224 }) | |
| 225 treeFailures.sort(this._failureComparator); | |
| 226 | |
| 227 if (!newFailures[tree]) | |
| 228 newFailures[tree] = []; | |
| 229 var commitList = new CTCommitList(this.commitLog, rangeGroup.likely_revision
s); | |
| 230 newFailures[tree].push(new CTFailureGroup(tree, new CTStepFailureGroupData(t
reeFailures, commitList))); | |
| 231 }.bind(this)); | |
| 232 }; | |
| 233 | |
| 234 CTFailures.prototype._processBuilderFailure = function(newFailures, alert) { | |
| 235 var timeSinceLastUpdate = (this.lastUpdateDate.valueOf() / 1000) - alert.last_
update_time; | |
| 236 | |
| 237 var failure; | |
| 238 var data; | |
| 239 var category; | |
| 240 if (alert.hasOwnProperty('builder_name')) { | |
| 241 category = 'builder'; | |
| 242 failure = new CTBuilderFailure(alert.tree, alert.master_url, alert.builder_n
ame, alert.state, | |
| 243 timeSinceLastUpdate, alert.pending_builds, alert.hasOwnProperty('isMaste
r')); | |
| 244 data = new CTBuilderFailureGroupData(failure, alert.builder_name, | |
| 245 alert.master_url + "/builders/" + alert.builder_name); | |
| 246 } else { | |
| 247 category = 'master'; | |
| 248 failure = new CTMasterFailure(alert.tree, alert.master_url, timeSinceLastUpd
ate); | |
| 249 data = new CTMasterFailureGroupData(failure, alert.master_url); | |
| 250 } | |
| 251 if (!newFailures[alert.tree]) | |
| 252 newFailures[alert.tree] = []; | |
| 253 newFailures[alert.tree].push(new CTFailureGroup(alert.tree, data, category)); | |
| 254 }; | |
| 255 | |
| 256 })(); | |
| 257 | |
| 258 </script> | |
| OLD | NEW |