| <!-- |
| 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> |