blob: 22431aabf91c4ebb8c239d4e38c3bb0c499eb2ca [file] [log] [blame]
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link href="../model/ct-builder-revisions.html" rel="import">
<link rel="import" href="../lib/net.html">
<link rel="import" href="../model/ct-failure.html">
<link rel="import" href="../model/ct-failure-group.html">
<polymer-element name="ct-failure-analyzer" attributes="failures builderLatestRevisions lastUpdateDate">
<script>
// FIXME: Don't use a polymer component for this. Instead use a Failures model
// object that knows how to do the XHR and process the data appropriately.
Polymer({
builderLatestRevisions: null,
failures: null,
lastUpdateDate: null,
// FIXME: Get this from https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/gatekeeper_trees.json?format=text.
_trees: {
blink: [
"https://build.chromium.org/p/chromium.webkit",
],
chromium: [
"https://build.chromium.org/p/chromium",
"https://build.chromium.org/p/chromium.chrome",
"https://build.chromium.org/p/chromium.chromiumos",
"https://build.chromium.org/p/chromium.gpu",
"https://build.chromium.org/p/chromium.linux",
"https://build.chromium.org/p/chromium.mac",
"https://build.chromium.org/p/chromium.memory",
"https://build.chromium.org/p/chromium.win"
],
},
_failureListComparator: function(tree, a, b) {
if (tree === undefined)
tree = 'chromium';
var rev_a = a[0].firstFailingRevisions;
var rev_b = b[0].firstFailingRevisions;
// Handle missing revision.
if (!rev_a) {
if (!rev_b) {
return 0;
}
return -1;
} else if (!rev_b) {
return 1;
}
// Prioritize the tree's revision.
if (rev_a[tree] != rev_b[tree])
return rev_b[tree] - rev_a[tree];
// Compare other revisions in alphabetical order.
var keys = Object.keys(rev_a).sort();
for (var i = 0; i < keys.length; i++) {
if (rev_a[keys[i]] != rev_b[keys[i]])
return rev_b[keys[i]] - rev_a[keys[i]];
}
return 0;
},
update: function() {
var annotationPromise = CTFailureGroup.fetchAnnotations();
net.json('http://sheriff-o-matic.appspot.com/alerts').then(function(data) {
annotationPromise.then(function(annotations) {
// FIXME: Don't special-case the blink master.
this.builderLatestRevisions = new CTBuilderRevisions(data.latest_revisions['chromium.webkit']);
this.failures = {};
this.lastUpdateDate = new Date(data.date * 1000);
data.range_groups.forEach(function(group) {
this._processFailuresForGroup(group, data.alerts, annotations);
}.bind(this));
Object.keys(this.failures, function (tree, failuresByTree) {
this.failures[tree].sort(this._failureListComparator.bind(this, tree));
}.bind(this));
}.bind(this));
}.bind(this));
},
_failureComparator: function(a, b) {
if (a.step > b.step)
return 1;
if (a.step < b.step)
return -1
if (a.testName > b.testName)
return 1;
if (a.testName < b.testName)
return -1
return 0;
},
_processFailuresForGroup: function(group, failures, annotations) {
var failuresByReason = {};
var masterToTree = {};
Object.keys(this._trees, function(tree, masters) {
masters.forEach(function(master) {
masterToTree[master] = tree;
});
});
group.failure_keys.forEach(function(failure_key) {
var failure = failures.find(function(item) { return item.key == failure_key; });
var reason, failureType;
if (failure.reason) {
// FIXME: Store the actual failure type in a different field instead of smashing it into the reason.
var parts = failure.reason.split(':');
reason = parts[0];
failureType = parts[1] || 'FAIL';
} else {
reason = null;
failureType = 'UNKNOWN';
}
var failureKey = JSON.stringify({
step: failure.step_name,
reason: reason,
});
var tree = masterToTree[failure.master_url];
// FIXME: Use a model class instead of a dumb object.
if (!failuresByReason[failureKey])
failuresByReason[failureKey] = {};
if (!failuresByReason[failureKey][tree])
failuresByReason[failureKey][tree] = {};
failuresByReason[failureKey][tree][failure.builder_name] = {
// FIXME: Rename to failureType.
actual: failureType,
lastFailingBuild: failure.last_failing_build,
earliestFailingBuild: failure.failing_build,
masterUrl: failure.master_url,
};
}.bind(this));
var groupedFailures = {};
Object.keys(failuresByReason, function(failureKey, resultsByTree) {
var failure = JSON.parse(failureKey);
Object.keys(resultsByTree, function(tree, resultsByBuilder) {
if (!groupedFailures[tree])
groupedFailures[tree] = [];
groupedFailures[tree].push(new CTFailure(failure.step, failure.reason, resultsByBuilder, group.merged_first_failing, group.merged_last_passing));
})
});
Object.keys(groupedFailures, function(tree, failures) {
failures.sort(this._failureComparator);
if (!this.failures[tree])
this.failures[tree] = [];
// FIXME: Need a better identifier for a failure group;
var key = group.sort_key;
this.failures[tree].push(new CTFailureGroup(key, failures, annotations[key]));
}.bind(this));
},
});
</script>
</polymer-element>