Chromium Code Reviews| 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"> |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 "https://build.chromium.org/p/chromium.chrome", | 28 "https://build.chromium.org/p/chromium.chrome", |
| 29 "https://build.chromium.org/p/chromium.chromiumos", | 29 "https://build.chromium.org/p/chromium.chromiumos", |
| 30 "https://build.chromium.org/p/chromium.gpu", | 30 "https://build.chromium.org/p/chromium.gpu", |
| 31 "https://build.chromium.org/p/chromium.linux", | 31 "https://build.chromium.org/p/chromium.linux", |
| 32 "https://build.chromium.org/p/chromium.mac", | 32 "https://build.chromium.org/p/chromium.mac", |
| 33 "https://build.chromium.org/p/chromium.memory", | 33 "https://build.chromium.org/p/chromium.memory", |
| 34 "https://build.chromium.org/p/chromium.win" | 34 "https://build.chromium.org/p/chromium.win" |
| 35 ], | 35 ], |
| 36 }, | 36 }, |
| 37 | 37 |
| 38 _failureListComparator: function(tree, a, b) { | 38 _failureByTreeListComparator: function(tree, a, b) { |
| 39 if (tree === undefined) | 39 if (tree === undefined) |
| 40 tree = 'chromium'; | 40 tree = 'chromium'; |
| 41 | 41 |
| 42 var rev_a = a.failures[0].firstFailingRevisions; | 42 if (!a.revisions || !a.revisions.length) { |
| 43 var rev_b = b.failures[0].firstFailingRevisions; | 43 if (!a.revisions || !b.revisions.length) |
| 44 | |
| 45 // Handle missing revision. | |
| 46 if (!rev_a) { | |
| 47 if (!rev_b) { | |
| 48 return 0; | 44 return 0; |
| 49 } | |
| 50 return -1; | 45 return -1; |
| 51 } else if (!rev_b) { | 46 } else if (!b.revisions || !b.revisions.length) { |
| 52 return 1; | 47 return 1; |
| 53 } | 48 } |
| 54 | 49 |
| 55 // Prioritize the tree's revision. | 50 // At this point |a.revisions| and |b.revisions| are sorted lists of |
|
ojan
2014/08/23 01:23:06
It turns out that we'll be able to keep using git
Mathieu
2014/08/24 23:42:11
No problem. Are you fine with this implementation
ojan
2014/08/25 03:54:13
I'd rather use the old implementation. It's consid
Mathieu
2014/08/25 13:03:22
Much of my rewrite was because the old arguments w
| |
| 56 if (rev_a[tree] != rev_b[tree]) | 51 // revisions of the form '<tree>:<revision>', where <tree> is not |
| 57 return rev_b[tree] - rev_a[tree]; | 52 // necessarily |tree|. Get the latest revision, and favor those related |
| 53 // to |tree|. | |
| 54 var _getLatestRevisionForTree = function(revisions) { | |
|
ojan
2014/08/23 01:23:06
This should have a FIXME to sort by timestamp of t
Mathieu
2014/08/24 23:42:11
Done.
| |
| 55 var i = 0; | |
| 56 var rev = revisions[revisions.length - 1 - i]; | |
| 57 while (rev.lastIndexOf(tree, 0) !== 0) { | |
| 58 i++; | |
| 59 rev = revisions[revisions.length - 1 - i]; | |
| 60 } | |
| 61 return rev; | |
| 62 }; | |
| 63 var rev_a = _getLatestRevisionForTree(a.revisions, tree); | |
| 64 var rev_b = _getLatestRevisionForTree(b.revisions, tree); | |
| 58 | 65 |
| 59 // Compare other revisions in alphabetical order. | 66 // Extract the <tree> and <revision> parts. |
| 60 var keys = Object.keys(rev_a).sort(); | 67 var a_split = rev_a.split(':'); |
| 61 for (var i = 0; i < keys.length; i++) { | 68 var a_tree = a_split[0]; |
| 62 if (rev_a[keys[i]] != rev_b[keys[i]]) | 69 var a_id = a_split[1]; |
| 63 return rev_b[keys[i]] - rev_a[keys[i]]; | 70 |
| 71 var b_split = rev_b.split(':'); | |
| 72 var b_tree = b_split[0]; | |
| 73 var b_id = b_split[1]; | |
| 74 | |
| 75 // If trees mismatch, favor the one matching with |tree|. If none equal | |
| 76 // |tree|, b is favored. | |
| 77 if (a_tree != b_tree) | |
| 78 return b_tree == tree ? 1 : -1; | |
| 79 | |
| 80 if (rev_a == rev_b) { | |
| 81 // In case of tree-revision equality, try a fallback. | |
| 82 var a_last = a.revisions.last(); | |
| 83 var b_last = b.revisions.last(); | |
| 84 if (a_last == b_last) | |
| 85 return 0; | |
| 86 return a_last < b_last ? 1 : -1; | |
| 64 } | 87 } |
| 65 return 0; | 88 |
| 89 return b_id == a_id ? 0 : (b_id > a_id) ? 1 : -1; | |
| 66 }, | 90 }, |
| 67 | 91 |
| 68 update: function() { | 92 update: function() { |
| 69 var annotationPromise = CTFailureGroup.fetchAnnotations(); | 93 var annotationPromise = CTFailureGroup.fetchAnnotations(); |
| 70 net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data ) { | 94 net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data ) { |
| 71 annotationPromise.then(function(annotations) { | 95 annotationPromise.then(function(annotations) { |
| 72 // FIXME: Don't special-case the blink master. | 96 // FIXME: Don't special-case the blink master. |
| 73 this.builderLatestRevisions = new CTBuilderRevisions(data.latest_bui lder_info['chromium.webkit']); | 97 this.builderLatestRevisions = new CTBuilderRevisions(data.latest_bui lder_info['chromium.webkit']); |
| 74 this.failures = {}; | 98 this.failures = {}; |
| 75 this.lastUpdateDate = new Date(data.date * 1000); | 99 this.lastUpdateDate = new Date(data.date * 1000); |
| 76 data.range_groups.forEach(function(group) { | 100 // Update |failures| with the appropriate CTFailureGroup's for each tree. |
| 77 this._processFailuresForGroup(group, data.alerts, annotations); | 101 data.range_groups.forEach(function(range_group) { |
| 102 this._processFailuresForRangeGroup(range_group, data.alerts, annot ations); | |
| 78 }.bind(this)); | 103 }.bind(this)); |
| 104 // Sort failure groups so that newer failures are shown at the top o f the UI. | |
| 79 Object.keys(this.failures, function (tree, failuresByTree) { | 105 Object.keys(this.failures, function (tree, failuresByTree) { |
| 80 this.failures[tree].sort(this._failureListComparator.bind(this, tr ee)); | 106 this.failures[tree].sort(this._failureByTreeListComparator.bind(th is, tree)); |
| 81 }.bind(this)); | 107 }.bind(this)); |
| 82 }.bind(this)); | 108 }.bind(this)); |
| 83 }.bind(this)); | 109 }.bind(this)); |
| 84 }, | 110 }, |
| 85 | 111 |
| 86 _failureComparator: function(a, b) { | 112 _failureComparator: function(a, b) { |
| 87 if (a.step > b.step) | 113 if (a.step > b.step) |
| 88 return 1; | 114 return 1; |
| 89 if (a.step < b.step) | 115 if (a.step < b.step) |
| 90 return -1 | 116 return -1 |
| 91 if (a.testName > b.testName) | 117 if (a.testName > b.testName) |
| 92 return 1; | 118 return 1; |
| 93 if (a.testName < b.testName) | 119 if (a.testName < b.testName) |
| 94 return -1 | 120 return -1 |
| 95 return 0; | 121 return 0; |
| 96 }, | 122 }, |
| 97 | 123 |
| 98 _processFailuresForGroup: function(group, failures, annotations) { | 124 _processFailuresForRangeGroup: function(range_group, alerts, annotations) { |
|
ojan
2014/08/23 01:23:05
s/range_group/rangeGroup/
Mathieu
2014/08/24 23:42:11
Done.
| |
| 99 var failuresByReason = {}; | |
| 100 | |
| 101 var masterToTree = {}; | 125 var masterToTree = {}; |
| 102 Object.keys(this._trees, function(tree, masters) { | 126 Object.keys(this._trees, function(tree, masters) { |
| 103 masters.forEach(function(master) { | 127 masters.forEach(function(master) { |
| 104 masterToTree[master] = tree; | 128 masterToTree[master] = tree; |
| 105 }); | 129 }); |
| 106 }); | 130 }); |
| 107 | 131 |
| 108 group.failure_keys.forEach(function(failure_key) { | 132 // A range_group may be related to multiple alerts (via |failure_keys|). Categorize |
| 109 var failure = failures.find(function(item) { return item.key == failur e_key; }); | 133 // these failures by reason (cause of failure), so that they can be grou ped in the UI |
| 134 // (via a CTFailureGroup). Failures will be grouped in |failuresByReason |. | |
| 135 var failuresByReason = {}; | |
| 136 range_group.failure_keys.forEach(function(failure_key) { | |
| 137 var failure = alerts.find(function(item) { return item.key == failure_ key; }); | |
| 138 // Establish the key to uniquely identify a failure by reason. | |
| 110 var reason, failureType; | 139 var reason, failureType; |
| 111 if (failure.reason) { | 140 if (failure.reason) { |
| 112 // FIXME: Store the actual failure type in a different field instead of smashing it into the reason. | 141 // FIXME: Store the actual failure type in a different field instead of smashing it into the reason. |
| 113 var parts = failure.reason.split(':'); | 142 var parts = failure.reason.split(':'); |
| 114 reason = parts[0]; | 143 reason = parts[0]; |
| 115 failureType = parts[1] || 'FAIL'; | 144 failureType = parts[1] || 'FAIL'; |
| 116 } else { | 145 } else { |
| 117 reason = null; | 146 reason = null; |
| 118 failureType = 'UNKNOWN'; | 147 failureType = 'UNKNOWN'; |
| 119 } | 148 } |
| 120 | 149 |
| 121 var failureKey = JSON.stringify({ | 150 var failureKey = JSON.stringify({ |
| 122 step: failure.step_name, | 151 step: failure.step_name, |
| 123 reason: reason, | 152 reason: reason, |
| 124 }); | 153 }); |
| 125 | 154 |
| 155 // Get the actual tree on which this failure occurred ('blink', 'chrom ium') | |
|
ojan
2014/08/23 01:23:06
IMO, this is pretty clear. No need to give comment
Mathieu
2014/08/24 23:42:11
Sorry, I was annotating as I went along.
| |
| 126 var tree = masterToTree[failure.master_url]; | 156 var tree = masterToTree[failure.master_url]; |
| 157 if (!tree) { | |
| 158 // FIXME: No tree corresponding to master URL! | |
|
ojan
2014/08/23 01:23:05
FIXMEs should state what to fix. Something like...
Mathieu
2014/08/24 23:42:11
Done.
| |
| 159 return; | |
|
ojan
2014/08/23 01:23:05
We don't actually want to early return here. We'll
Mathieu
2014/08/24 23:42:11
Nah, it just didn't seem clean to be using |tree|
ojan
2014/08/25 03:54:13
Yeah. Long-term, the right thing here is to grab t
| |
| 160 } | |
| 127 | 161 |
| 128 // FIXME: Use a model class instead of a dumb object. | 162 // FIXME: Use a model class instead of a dumb object. |
| 129 if (!failuresByReason[failureKey]) | 163 if (!failuresByReason[failureKey]) |
| 130 failuresByReason[failureKey] = {}; | 164 failuresByReason[failureKey] = {}; |
| 131 if (!failuresByReason[failureKey][tree]) | 165 if (!failuresByReason[failureKey][tree]) |
| 132 failuresByReason[failureKey][tree] = {}; | 166 failuresByReason[failureKey][tree] = {}; |
| 133 failuresByReason[failureKey][tree][failure.builder_name] = { | 167 failuresByReason[failureKey][tree][failure.builder_name] = { |
| 134 // FIXME: Rename to failureType. | 168 // FIXME: Rename to failureType. |
| 135 actual: failureType, | 169 actual: failureType, |
| 136 lastFailingBuild: failure.last_failing_build, | 170 lastFailingBuild: failure.last_failing_build, |
| 137 earliestFailingBuild: failure.failing_build, | 171 earliestFailingBuild: failure.failing_build, |
| 138 masterUrl: failure.master_url, | 172 masterUrl: failure.master_url, |
| 139 failingBuildCount: failure.failing_build_count, | 173 failingBuildCount: failure.failing_build_count, |
| 140 }; | 174 }; |
| 141 }.bind(this)); | 175 }.bind(this)); |
| 142 | 176 |
| 177 // Skip further processing if no failures were collected (e.g. the tree | |
|
ojan
2014/08/23 01:23:05
Ditto: This is clearly what the next line of code
Mathieu
2014/08/24 23:42:11
Done.
| |
| 178 // was unknown). | |
| 179 if (!Object.keys(failuresByReason).length) | |
| 180 return; | |
| 181 | |
| 143 var groupedFailures = {}; | 182 var groupedFailures = {}; |
| 144 Object.keys(failuresByReason, function(failureKey, resultsByTree) { | 183 Object.keys(failuresByReason, function(failureKey, resultsByTree) { |
| 145 var failure = JSON.parse(failureKey); | 184 var failure = JSON.parse(failureKey); |
| 146 Object.keys(resultsByTree, function(tree, resultsByBuilder) { | 185 Object.keys(resultsByTree, function(tree, resultsByBuilder) { |
| 147 if (!groupedFailures[tree]) | 186 if (!groupedFailures[tree]) |
| 148 groupedFailures[tree] = []; | 187 groupedFailures[tree] = []; |
| 149 groupedFailures[tree].push(new CTFailure(failure.step, failure.reaso n, resultsByBuilder, group.merged_first_failing, group.merged_last_passing)); | 188 groupedFailures[tree].push( |
| 189 new CTFailure(failure.step, failure.reason, resultsByBuilder)); | |
| 150 }) | 190 }) |
| 151 }); | 191 }); |
| 152 | 192 |
| 153 Object.keys(groupedFailures, function(tree, failures) { | 193 Object.keys(groupedFailures, function(tree, failures) { |
| 154 failures.sort(this._failureComparator); | 194 failures.sort(this._failureComparator); |
| 155 | 195 |
| 156 if (!this.failures[tree]) | 196 if (!this.failures[tree]) |
| 157 this.failures[tree] = []; | 197 this.failures[tree] = []; |
| 158 // FIXME: Need a better identifier for a failure group; | 198 // FIXME: Need a better identifier for a failure group; |
| 159 var key = group.sort_key; | 199 var key = range_group.sort_key; |
| 160 this.failures[tree].push(new CTFailureGroup(key, failures, annotations [key])); | 200 this.failures[tree].push( |
| 201 new CTFailureGroup(key, failures, range_group.likely_revisions, | |
| 202 annotations[key])); | |
| 161 }.bind(this)); | 203 }.bind(this)); |
| 162 }, | 204 }, |
| 163 }); | 205 }); |
| 164 </script> | 206 </script> |
| 165 </polymer-element> | 207 </polymer-element> |
| OLD | NEW |