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 |
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 // FIXME: Sort by timestamp of the last (or first?) commit. | |
55 var _getLatestRevisionForTree = function(revisions) { | |
56 var i = 0; | |
57 var rev = revisions[revisions.length - 1 - i]; | |
ojan
2014/08/25 18:09:40
Nit: I'd find this easier to read if you started w
Mathieu
2014/08/26 15:47:40
Acknowledged.
| |
58 while (!rev.startsWith(tree)) { | |
ojan
2014/08/25 18:09:40
Nit: Lets check startsWith(tree + ':') to avoid is
Mathieu
2014/08/26 15:47:40
Acknowledged.
| |
59 i++; | |
60 rev = revisions[revisions.length - 1 - i]; | |
61 } | |
62 return rev; | |
63 }; | |
64 var rev_a = _getLatestRevisionForTree(a.revisions, tree); | |
65 var rev_b = _getLatestRevisionForTree(b.revisions, tree); | |
58 | 66 |
59 // Compare other revisions in alphabetical order. | 67 // Extract the <tree> and <revision> parts. |
60 var keys = Object.keys(rev_a).sort(); | 68 var a_split = rev_a.split(':'); |
61 for (var i = 0; i < keys.length; i++) { | 69 var a_tree = a_split[0]; |
62 if (rev_a[keys[i]] != rev_b[keys[i]]) | 70 var a_id = a_split[1]; |
63 return rev_b[keys[i]] - rev_a[keys[i]]; | 71 |
72 var b_split = rev_b.split(':'); | |
73 var b_tree = b_split[0]; | |
74 var b_id = b_split[1]; | |
75 | |
76 // If trees mismatch, favor the one matching with |tree|. If none equal | |
77 // |tree|, b is favored. | |
78 if (a_tree != b_tree) | |
79 return b_tree == tree ? 1 : -1; | |
80 | |
81 if (rev_a == rev_b) { | |
ojan
2014/08/25 18:09:40
Can we move this check right after line 65? I thin
Mathieu
2014/08/26 15:47:40
Acknowledged.
| |
82 // In case of tree-revision equality, try a fallback. | |
ojan
2014/08/25 18:09:40
This comment is a little confusing. Would be more
Mathieu
2014/08/26 15:47:40
Acknowledged.
| |
83 var a_last = a.revisions.last(); | |
84 var b_last = b.revisions.last(); | |
85 if (a_last == b_last) | |
86 return 0; | |
87 return a_last < b_last ? 1 : -1; | |
64 } | 88 } |
65 return 0; | 89 |
90 return b_id == a_id ? 0 : (b_id > a_id) ? 1 : -1; | |
ojan
2014/08/25 18:09:41
Can this just be the following?
return b_id - a_id
Mathieu
2014/08/26 15:47:40
Acknowledged.
Mathieu
2014/08/26 15:47:40
Acknowledged.
| |
66 }, | 91 }, |
67 | 92 |
68 update: function() { | 93 update: function() { |
69 var annotationPromise = CTFailureGroup.fetchAnnotations(); | 94 var annotationPromise = CTFailureGroup.fetchAnnotations(); |
70 net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data ) { | 95 net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data ) { |
71 annotationPromise.then(function(annotations) { | 96 annotationPromise.then(function(annotations) { |
72 // FIXME: Don't special-case the blink master. | 97 // FIXME: Don't special-case the blink master. |
73 this.builderLatestRevisions = new CTBuilderRevisions(data.latest_bui lder_info['chromium.webkit']); | 98 this.builderLatestRevisions = new CTBuilderRevisions(data.latest_bui lder_info['chromium.webkit']); |
74 this.failures = {}; | 99 this.failures = {}; |
75 this.lastUpdateDate = new Date(data.date * 1000); | 100 this.lastUpdateDate = new Date(data.date * 1000); |
76 data.range_groups.forEach(function(group) { | 101 // Update |failures| with the appropriate CTFailureGroup's for each tree. |
77 this._processFailuresForGroup(group, data.alerts, annotations); | 102 data.range_groups.forEach(function(rangeGroup) { |
103 this._processFailuresForRangeGroup(rangeGroup, data.alerts, annota tions); | |
78 }.bind(this)); | 104 }.bind(this)); |
105 // Sort failure groups so that newer failures are shown at the top o f the UI. | |
79 Object.keys(this.failures, function (tree, failuresByTree) { | 106 Object.keys(this.failures, function (tree, failuresByTree) { |
80 this.failures[tree].sort(this._failureListComparator.bind(this, tr ee)); | 107 this.failures[tree].sort(this._failureByTreeListComparator.bind(th is, tree)); |
81 }.bind(this)); | 108 }.bind(this)); |
82 }.bind(this)); | 109 }.bind(this)); |
83 }.bind(this)); | 110 }.bind(this)); |
84 }, | 111 }, |
85 | 112 |
86 _failureComparator: function(a, b) { | 113 _failureComparator: function(a, b) { |
87 if (a.step > b.step) | 114 if (a.step > b.step) |
88 return 1; | 115 return 1; |
89 if (a.step < b.step) | 116 if (a.step < b.step) |
90 return -1 | 117 return -1 |
91 if (a.testName > b.testName) | 118 if (a.testName > b.testName) |
92 return 1; | 119 return 1; |
93 if (a.testName < b.testName) | 120 if (a.testName < b.testName) |
94 return -1 | 121 return -1 |
95 return 0; | 122 return 0; |
96 }, | 123 }, |
97 | 124 |
98 _processFailuresForGroup: function(group, failures, annotations) { | 125 _processFailuresForRangeGroup: function(rangeGroup, alerts, annotations) { |
99 var failuresByReason = {}; | |
100 | |
101 var masterToTree = {}; | 126 var masterToTree = {}; |
102 Object.keys(this._trees, function(tree, masters) { | 127 Object.keys(this._trees, function(tree, masters) { |
103 masters.forEach(function(master) { | 128 masters.forEach(function(master) { |
104 masterToTree[master] = tree; | 129 masterToTree[master] = tree; |
105 }); | 130 }); |
106 }); | 131 }); |
107 | 132 |
108 group.failure_keys.forEach(function(failure_key) { | 133 // 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; }); | 134 // these failures by reason (cause of failure), so that they can be grou ped in the UI |
135 // (via a CTFailureGroup). Failures will be grouped in |failuresByReason |. | |
136 var failuresByReason = {}; | |
137 rangeGroup.failure_keys.forEach(function(failure_key) { | |
138 var failure = alerts.find(function(item) { return item.key == failure_ key; }); | |
139 // Establish the key to uniquely identify a failure by reason. | |
110 var reason, failureType; | 140 var reason, failureType; |
111 if (failure.reason) { | 141 if (failure.reason) { |
112 // FIXME: Store the actual failure type in a different field instead of smashing it into the reason. | 142 // FIXME: Store the actual failure type in a different field instead of smashing it into the reason. |
113 var parts = failure.reason.split(':'); | 143 var parts = failure.reason.split(':'); |
114 reason = parts[0]; | 144 reason = parts[0]; |
115 failureType = parts[1] || 'FAIL'; | 145 failureType = parts[1] || 'FAIL'; |
116 } else { | 146 } else { |
117 reason = null; | 147 reason = null; |
118 failureType = 'UNKNOWN'; | 148 failureType = 'UNKNOWN'; |
119 } | 149 } |
120 | 150 |
121 var failureKey = JSON.stringify({ | 151 var failureKey = JSON.stringify({ |
122 step: failure.step_name, | 152 step: failure.step_name, |
123 reason: reason, | 153 reason: reason, |
124 }); | 154 }); |
125 | 155 |
156 // FIXME: Figure out what tree masters that aren't in masterToTree | |
157 // we should have. | |
126 var tree = masterToTree[failure.master_url]; | 158 var tree = masterToTree[failure.master_url]; |
127 | 159 |
128 // FIXME: Use a model class instead of a dumb object. | 160 // FIXME: Use a model class instead of a dumb object. |
129 if (!failuresByReason[failureKey]) | 161 if (!failuresByReason[failureKey]) |
130 failuresByReason[failureKey] = {}; | 162 failuresByReason[failureKey] = {}; |
131 if (!failuresByReason[failureKey][tree]) | 163 if (!failuresByReason[failureKey][tree]) |
132 failuresByReason[failureKey][tree] = {}; | 164 failuresByReason[failureKey][tree] = {}; |
133 failuresByReason[failureKey][tree][failure.builder_name] = { | 165 failuresByReason[failureKey][tree][failure.builder_name] = { |
134 // FIXME: Rename to failureType. | 166 // FIXME: Rename to failureType. |
135 actual: failureType, | 167 actual: failureType, |
136 lastFailingBuild: failure.last_failing_build, | 168 lastFailingBuild: failure.last_failing_build, |
137 earliestFailingBuild: failure.failing_build, | 169 earliestFailingBuild: failure.failing_build, |
138 masterUrl: failure.master_url, | 170 masterUrl: failure.master_url, |
139 failingBuildCount: failure.failing_build_count, | 171 failingBuildCount: failure.failing_build_count, |
140 }; | 172 }; |
141 }.bind(this)); | 173 }.bind(this)); |
142 | 174 |
175 if (!Object.keys(failuresByReason).length) | |
176 return; | |
177 | |
143 var groupedFailures = {}; | 178 var groupedFailures = {}; |
144 Object.keys(failuresByReason, function(failureKey, resultsByTree) { | 179 Object.keys(failuresByReason, function(failureKey, resultsByTree) { |
145 var failure = JSON.parse(failureKey); | 180 var failure = JSON.parse(failureKey); |
146 Object.keys(resultsByTree, function(tree, resultsByBuilder) { | 181 Object.keys(resultsByTree, function(tree, resultsByBuilder) { |
147 if (!groupedFailures[tree]) | 182 if (!groupedFailures[tree]) |
148 groupedFailures[tree] = []; | 183 groupedFailures[tree] = []; |
149 groupedFailures[tree].push(new CTFailure(failure.step, failure.reaso n, resultsByBuilder, group.merged_first_failing, group.merged_last_passing)); | 184 groupedFailures[tree].push( |
185 new CTFailure(failure.step, failure.reason, resultsByBuilder)); | |
150 }) | 186 }) |
151 }); | 187 }); |
152 | 188 |
153 Object.keys(groupedFailures, function(tree, failures) { | 189 Object.keys(groupedFailures, function(tree, failures) { |
154 failures.sort(this._failureComparator); | 190 failures.sort(this._failureComparator); |
155 | 191 |
156 if (!this.failures[tree]) | 192 if (!this.failures[tree]) |
157 this.failures[tree] = []; | 193 this.failures[tree] = []; |
158 // FIXME: Need a better identifier for a failure group; | 194 // FIXME: Need a better identifier for a failure group; |
159 var key = group.sort_key; | 195 var key = rangeGroup.sort_key; |
160 this.failures[tree].push(new CTFailureGroup(key, failures, annotations [key])); | 196 this.failures[tree].push( |
197 new CTFailureGroup(key, failures, rangeGroup.likely_revisions, | |
198 annotations[key])); | |
161 }.bind(this)); | 199 }.bind(this)); |
162 }, | 200 }, |
163 }); | 201 }); |
164 </script> | 202 </script> |
165 </polymer-element> | 203 </polymer-element> |
OLD | NEW |