Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: Tools/GardeningServer/ui/ct-failure-analyzer.html

Issue 498523002: [Sheriff-o-matic] Use likely_revisions instead of first_failing/last_passing (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: sort git hashes Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698