| OLD | NEW |
| 1 <!-- | 1 <!-- |
| 2 Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 3 Use of this source code is governed by a BSD-style license that can be |
| 4 found in the LICENSE file. | 4 found in the LICENSE file. |
| 5 --> | 5 --> |
| 6 <link href="../model/ct-builder-revisions.html" rel="import"> | 6 <link href="../model/ct-builder-revisions.html" rel="import"> |
| 7 | 7 |
| 8 <link rel="import" href="../lib/net.html"> | 8 <link rel="import" href="../lib/net.html"> |
| 9 <link rel="import" href="../model/ct-failure.html"> | 9 <link rel="import" href="../model/ct-failure.html"> |
| 10 <link rel="import" href="../model/ct-failure-group.html"> | 10 <link rel="import" href="../model/ct-failure-group.html"> |
| 11 | 11 |
| 12 <polymer-element name="ct-failure-analyzer" attributes="failures builderLatestRe
visions lastUpdateDate"> | 12 <polymer-element name="ct-failure-analyzer" attributes="commitLog failures build
erLatestRevisions lastUpdateDate"> |
| 13 <script> | 13 <script> |
| 14 // FIXME: Don't use a polymer component for this. Instead use a Failures mod
el | 14 // FIXME: Don't use a polymer component for this. Instead use a Failures mod
el |
| 15 // object that knows how to do the XHR and process the data appropriately. | 15 // object that knows how to do the XHR and process the data appropriately. |
| 16 Polymer({ | 16 Polymer({ |
| 17 commitLog: null, |
| 17 builderLatestRevisions: null, | 18 builderLatestRevisions: null, |
| 18 failures: null, | 19 failures: null, |
| 19 lastUpdateDate: null, | 20 lastUpdateDate: null, |
| 20 | 21 |
| 21 // FIXME: Get this from https://chromium.googlesource.com/chromium/tools/b
uild/+/master/scripts/slave/gatekeeper_trees.json?format=text. | 22 // FIXME: Get this from https://chromium.googlesource.com/chromium/tools/b
uild/+/master/scripts/slave/gatekeeper_trees.json?format=text. |
| 22 _trees: { | 23 _trees: { |
| 23 blink: [ | 24 blink: [ |
| 24 "https://build.chromium.org/p/chromium.webkit", | 25 "https://build.chromium.org/p/chromium.webkit", |
| 25 ], | 26 ], |
| 26 chromium: [ | 27 chromium: [ |
| 27 "https://build.chromium.org/p/chromium", | 28 "https://build.chromium.org/p/chromium", |
| 28 "https://build.chromium.org/p/chromium.chrome", | 29 "https://build.chromium.org/p/chromium.chrome", |
| 29 "https://build.chromium.org/p/chromium.chromiumos", | 30 "https://build.chromium.org/p/chromium.chromiumos", |
| 30 "https://build.chromium.org/p/chromium.gpu", | 31 "https://build.chromium.org/p/chromium.gpu", |
| 31 "https://build.chromium.org/p/chromium.linux", | 32 "https://build.chromium.org/p/chromium.linux", |
| 32 "https://build.chromium.org/p/chromium.mac", | 33 "https://build.chromium.org/p/chromium.mac", |
| 33 "https://build.chromium.org/p/chromium.memory", | 34 "https://build.chromium.org/p/chromium.memory", |
| 34 "https://build.chromium.org/p/chromium.win" | 35 "https://build.chromium.org/p/chromium.win" |
| 35 ], | 36 ], |
| 36 }, | 37 }, |
| 37 | 38 |
| 38 _failureListComparator: function(tree, a, b) { | 39 // Reverse sorting order, if a > b, return a negative number. |
| 40 _failureByTreeListComparator: function(tree, a, b) { |
| 39 if (tree === undefined) | 41 if (tree === undefined) |
| 40 tree = 'chromium'; | 42 tree = 'chromium'; |
| 41 | 43 |
| 42 var rev_a = a.failures[0].firstFailingRevisions; | 44 var rev_a = a.commitList.revisions; |
| 43 var rev_b = b.failures[0].firstFailingRevisions; | 45 var rev_b = b.commitList.revisions; |
| 44 | 46 |
| 45 // Handle missing revision. | 47 if (!rev_a || !Object.keys(rev_a).length) { |
| 46 if (!rev_a) { | 48 if (!rev_b || !Object.keys(rev_b).length) |
| 47 if (!rev_b) { | |
| 48 return 0; | 49 return 0; |
| 49 } | 50 return 1; |
| 51 } else if (!rev_b || !Object.keys(rev_b).length) { |
| 50 return -1; | 52 return -1; |
| 51 } else if (!rev_b) { | |
| 52 return 1; | |
| 53 } | 53 } |
| 54 | 54 |
| 55 // Prioritize the tree's revision. | 55 // Prioritize the tree's revision, if they are unequal (else, fallback |
| 56 if (rev_a[tree] != rev_b[tree]) | 56 // below). |
| 57 return rev_b[tree] - rev_a[tree]; | 57 if (rev_a[tree] && rev_b[tree] && |
| 58 rev_a[tree].last() != rev_b[tree].last()) { |
| 59 return rev_b[tree].last() - rev_a[tree].last(); |
| 60 } |
| 58 | 61 |
| 59 // Compare other revisions in alphabetical order. | 62 // Compare other revisions in alphabetical order. |
| 60 var keys = Object.keys(rev_a).sort(); | 63 var keys = Object.keys(rev_a).sort(); |
| 61 for (var i = 0; i < keys.length; i++) { | 64 for (var i = 0; i < keys.length; i++) { |
| 62 if (rev_a[keys[i]] != rev_b[keys[i]]) | 65 if (keys[i] == tree) // Already taken care of, above. |
| 63 return rev_b[keys[i]] - rev_a[keys[i]]; | 66 continue; |
| 67 |
| 68 var a_list = rev_a[keys[i]]; |
| 69 var b_list = rev_b[keys[i]]; |
| 70 if (!b_list) |
| 71 return -1; |
| 72 |
| 73 if (a_list.last() != b_list.last()) |
| 74 return b_list.last() - a_list.last(); |
| 64 } | 75 } |
| 65 return 0; | 76 return 0; |
| 66 }, | 77 }, |
| 67 | 78 |
| 68 update: function() { | 79 update: function() { |
| 69 var annotationPromise = CTFailureGroup.fetchAnnotations(); | 80 var annotationPromise = CTFailureGroup.fetchAnnotations(); |
| 70 net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data
) { | 81 net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data
) { |
| 71 annotationPromise.then(function(annotations) { | 82 annotationPromise.then(function(annotations) { |
| 72 // FIXME: Don't special-case the blink master. | 83 // FIXME: Don't special-case the blink master. |
| 73 this.builderLatestRevisions = new CTBuilderRevisions(data.latest_bui
lder_info['chromium.webkit']); | 84 this.builderLatestRevisions = new CTBuilderRevisions(data.latest_bui
lder_info['chromium.webkit']); |
| 74 this.failures = {}; | 85 this.failures = {}; |
| 75 this.lastUpdateDate = new Date(data.date * 1000); | 86 this.lastUpdateDate = new Date(data.date * 1000); |
| 76 data.range_groups.forEach(function(group) { | 87 // Update |failures| with the appropriate CTFailureGroup's for each
tree. |
| 77 this._processFailuresForGroup(group, data.alerts, annotations); | 88 data.range_groups.forEach(function(rangeGroup) { |
| 89 this._processFailuresForRangeGroup(rangeGroup, data.alerts, annota
tions); |
| 78 }.bind(this)); | 90 }.bind(this)); |
| 91 // Sort failure groups so that newer failures are shown at the top o
f the UI. |
| 79 Object.keys(this.failures, function (tree, failuresByTree) { | 92 Object.keys(this.failures, function (tree, failuresByTree) { |
| 80 this.failures[tree].sort(this._failureListComparator.bind(this, tr
ee)); | 93 this.failures[tree].sort(this._failureByTreeListComparator.bind(th
is, tree)); |
| 81 }.bind(this)); | 94 }.bind(this)); |
| 82 }.bind(this)); | 95 }.bind(this)); |
| 83 }.bind(this)); | 96 }.bind(this)); |
| 84 }, | 97 }, |
| 85 | 98 |
| 86 _failureComparator: function(a, b) { | 99 _failureComparator: function(a, b) { |
| 87 if (a.step > b.step) | 100 if (a.step > b.step) |
| 88 return 1; | 101 return 1; |
| 89 if (a.step < b.step) | 102 if (a.step < b.step) |
| 90 return -1 | 103 return -1 |
| 91 if (a.testName > b.testName) | 104 if (a.testName > b.testName) |
| 92 return 1; | 105 return 1; |
| 93 if (a.testName < b.testName) | 106 if (a.testName < b.testName) |
| 94 return -1 | 107 return -1 |
| 95 return 0; | 108 return 0; |
| 96 }, | 109 }, |
| 97 | 110 |
| 98 _processFailuresForGroup: function(group, failures, annotations) { | 111 _processFailuresForRangeGroup: function(rangeGroup, alerts, annotations) { |
| 99 var failuresByReason = {}; | |
| 100 | |
| 101 var masterToTree = {}; | 112 var masterToTree = {}; |
| 102 Object.keys(this._trees, function(tree, masters) { | 113 Object.keys(this._trees, function(tree, masters) { |
| 103 masters.forEach(function(master) { | 114 masters.forEach(function(master) { |
| 104 masterToTree[master] = tree; | 115 masterToTree[master] = tree; |
| 105 }); | 116 }); |
| 106 }); | 117 }); |
| 107 | 118 |
| 108 group.failure_keys.forEach(function(failure_key) { | 119 // A rangeGroup may be related to multiple alerts (via |failure_keys|).
Categorize |
| 109 var failure = failures.find(function(item) { return item.key == failur
e_key; }); | 120 // these failures by reason (cause of failure), so that they can be grou
ped in the UI |
| 121 // (via a CTFailureGroup). Failures will be grouped in |failuresByReason
|. |
| 122 var failuresByReason = {}; |
| 123 rangeGroup.failure_keys.forEach(function(failure_key) { |
| 124 var failure = alerts.find(function(item) { return item.key == failure_
key; }); |
| 125 // Establish the key to uniquely identify a failure by reason. |
| 110 var reason, failureType; | 126 var reason, failureType; |
| 111 if (failure.reason) { | 127 if (failure.reason) { |
| 112 // FIXME: Store the actual failure type in a different field instead
of smashing it into the reason. | 128 // FIXME: Store the actual failure type in a different field instead
of smashing it into the reason. |
| 113 var parts = failure.reason.split(':'); | 129 var parts = failure.reason.split(':'); |
| 114 reason = parts[0]; | 130 reason = parts[0]; |
| 115 failureType = parts[1] || 'FAIL'; | 131 failureType = parts[1] || 'FAIL'; |
| 116 } else { | 132 } else { |
| 117 reason = null; | 133 reason = null; |
| 118 failureType = 'UNKNOWN'; | 134 failureType = 'UNKNOWN'; |
| 119 } | 135 } |
| 120 | 136 |
| 121 var failureKey = CTFailure.createKey(failure); | 137 var failureKey = CTFailure.createKey(failure); |
| 122 | 138 |
| 123 var reasonKey = JSON.stringify({ | 139 var reasonKey = JSON.stringify({ |
| 124 step: failure.step_name, | 140 step: failure.step_name, |
| 125 reason: reason, | 141 reason: reason, |
| 126 }); | 142 }); |
| 127 | 143 |
| 144 // FIXME: Figure out what tree masters that aren't in masterToTree |
| 145 // we should have. |
| 128 var tree = masterToTree[failure.master_url]; | 146 var tree = masterToTree[failure.master_url]; |
| 129 | 147 |
| 130 // FIXME: Use a model class instead of a dumb object. | 148 // FIXME: Use a model class instead of a dumb object. |
| 131 if (!failuresByReason[reasonKey]) | 149 if (!failuresByReason[reasonKey]) |
| 132 failuresByReason[reasonKey] = {}; | 150 failuresByReason[reasonKey] = {}; |
| 133 if (!failuresByReason[reasonKey][tree]) | 151 if (!failuresByReason[reasonKey][tree]) |
| 134 failuresByReason[reasonKey][tree] = {}; | 152 failuresByReason[reasonKey][tree] = {}; |
| 135 failuresByReason[reasonKey][tree][failure.builder_name] = { | 153 failuresByReason[reasonKey][tree][failure.builder_name] = { |
| 136 key: failureKey, | 154 key: failureKey, |
| 137 // FIXME: Rename to failureType. | 155 // FIXME: Rename to failureType. |
| 138 actual: failureType, | 156 actual: failureType, |
| 139 lastFailingBuild: failure.last_failing_build, | 157 lastFailingBuild: failure.last_failing_build, |
| 140 earliestFailingBuild: failure.failing_build, | 158 earliestFailingBuild: failure.failing_build, |
| 141 masterUrl: failure.master_url, | 159 masterUrl: failure.master_url, |
| 142 failingBuildCount: failure.failing_build_count, | 160 failingBuildCount: failure.failing_build_count, |
| 143 annotation: annotations[failureKey], | 161 annotation: annotations[failureKey], |
| 144 }; | 162 }; |
| 145 }.bind(this)); | 163 }.bind(this)); |
| 146 | 164 |
| 165 if (!Object.keys(failuresByReason).length) |
| 166 return; |
| 167 |
| 147 var groupedFailures = {}; | 168 var groupedFailures = {}; |
| 148 Object.keys(failuresByReason, function(reasonKey, resultsByTree) { | 169 Object.keys(failuresByReason, function(reasonKey, resultsByTree) { |
| 149 var failure = JSON.parse(reasonKey); | 170 var failure = JSON.parse(reasonKey); |
| 150 Object.keys(resultsByTree, function(tree, resultsByBuilder) { | 171 Object.keys(resultsByTree, function(tree, resultsByBuilder) { |
| 151 if (!groupedFailures[tree]) | 172 if (!groupedFailures[tree]) |
| 152 groupedFailures[tree] = []; | 173 groupedFailures[tree] = []; |
| 153 groupedFailures[tree].push(new CTFailure(failure.step, failure.reaso
n, resultsByBuilder, group.merged_first_failing, group.merged_last_passing)); | 174 groupedFailures[tree].push( |
| 175 new CTFailure(failure.step, failure.reason, resultsByBuilder)); |
| 154 }) | 176 }) |
| 155 }); | 177 }); |
| 156 | 178 |
| 157 Object.keys(groupedFailures, function(tree, failures) { | 179 Object.keys(groupedFailures, function(tree, failures) { |
| 158 failures.sort(this._failureComparator); | 180 failures.sort(this._failureComparator); |
| 159 | 181 |
| 160 if (!this.failures[tree]) | 182 if (!this.failures[tree]) |
| 161 this.failures[tree] = []; | 183 this.failures[tree] = []; |
| 162 this.failures[tree].push(new CTFailureGroup(failures)); | 184 var commitList = new CTCommitList(this.commitLog, rangeGroup.likely_re
visions); |
| 185 this.failures[tree].push(new CTFailureGroup(failures, commitList)); |
| 163 }.bind(this)); | 186 }.bind(this)); |
| 164 }, | 187 }, |
| 165 }); | 188 }); |
| 166 </script> | 189 </script> |
| 167 </polymer-element> | 190 </polymer-element> |
| OLD | NEW |