blob: aa1b8ce77d3b28db49bbed9644266751ea20fb12 [file] [log] [blame]
<!-- The <commits-panel-sk> custom element declaration.
An element to display information on one or more commits. There is some added complexity
because the tiles storing commits do not keep track of the commit message. Thus,
this element will make an XHR to the repo (or the server, see origin) for the
commit message of a given commit.
Attributes:
progress - Boolean, if true then display the percent complete
for the first hash.
selection - Boolean, if true then selections are displayed, i.e. the user
click on a commit and select it.
selector - The iron-selector element that wraps the commits.
mailbox - The sk.Mailbox name to listen for the data to populate
the element. This is in addition to the 'commits' mailbox
described below.
repo - The URL of the underlying git repo. This assumes a
googlesource repo when deriving URLs from this value.
commitinfo - A list of commits that are passed to setCommitInfo (see below).
This is the direct way to set commits.
origin - a Boolean, if true, indicates the base server should be queried for the commit
messages instead of the repo. This can help prevent CORS errors.
Methods:
setCommitInfo - Sets the commit info, an array of *tiling.Commit. See the
description for the commits Mailbox for more details.
selectHash - Forces the selection of the given hash.
Events:
commit-selected - Event produced when a commit is selected. The event
detail contains:
{
description: "fixed lengh string descripting the commit",
hash: "1213982193 (the commit hash)",
}
Mailboxes:
commits - The sk.Mailbox name to listen for the data to populate
the element. The mailbox data needs to be a serialized slice
of []*tiling.Commit. If not set then the data must be supplied
by the setCommitInfo method.
[
{
commit_time: 1439649751,
author: "reed (reed@chromium.org)",
hash: "bb886749feb444edfd8fbf053a9ea815e3605f8a",
},
{
author: "reed (reed@chromium.org)",
commit_time: 1439648914,
hash: "e02716908fe82c7c4ae9b415793277620a22bcd6",
},
]
Note that the hashes need to be in order, but not necessarily
contiguous. Note that they also need to be supplied in time ascending
order, that is, the commit at index 0 needs to be the oldest commit, and
the last commit in the array needs to be the newest commit.
-->
<link rel="stylesheet" href="/res/common/css/md.css">
<link rel="import" href="/res/imp/bower_components/iron-selector/iron-selector.html">
<link rel="import" href="commit.html">
<dom-module id="commits-panel-sk">
<template>
<style type="text/css" media="screen">
div {
margin-bottom: 0.5em;
}
commit-sk {
display: block;
padding-right: 2em;
}
pre {
font-size: 14px;
margin: 0.2em 0;
padding: 0.3em;
}
.iron-selected {
background: #eee;
}
:host {
display: block;
}
</style>
<template is="dom-if" if="{{progress}}">
<div>
<a target="_blank" href$="{{_statusHref(_firstHash)}}">Buildbot Percent Complete: <span>{{_commitPercent(_percent)}}</span>%</a>
</div>
</template>
<iron-selector id=selector>
<template is="dom-repeat" items="{{_commitinfo}}" as="c">
<commit-sk data-hash$="{{c.hash}}" hash="{{c.hash}}" commit="{{c}}" repo="{{repo}}"></commit-sk>
</template>
</iron-selector>
</template>
<script>
Polymer({
is: 'commits-panel-sk',
properties: {
progress: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
selection: {
type: Boolean,
value: false,
reflectToAttribute: true,
observer: "_selectionChanged",
},
mailbox: {
value: "",
reflectToAttribute: true
},
repo: {
type: String,
value: "https://skia.googlesource.com/skia",
notify: true
},
origin: {
type: Boolean,
value: false
},
commitinfo: {
type: Array,
value: null,
observer: "setCommitInfo"
}
},
listeners: {
"selector.iron-select": "_selectorTap",
},
ready: function () {
this._percent = -1.0;
this._firstHash = '';
this.selector = this.$.selector;
sk.Mailbox.subscribe('commits', this.setCommitInfo.bind(this));
if (this.mailbox != "") {
sk.Mailbox.subscribe(this.mailbox, this.setCommitInfo.bind(this));
}
},
setCommitInfo: function(commitinfo) {
if (commitinfo) {
this._commitinfo = commitinfo;
this._processCommitInfo();
}
},
selectHash: function(hash) {
// Clear the selection.
this.selector.selected = null;
// If the commits have been set then use them to find the hash. This
// avoids timing issues if the commit-sk elements haven't rendered yet.
if (this._commitinfo && (this._commitinfo.length > 0)) {
var idx = this._commitinfo.findIndex(function(c) { return c.hash === hash; });
if (idx >= 0) {
this.selector.select(idx);
}
return;
}
$$('commit-sk', this).forEach(function(ele) {
if (ele.dataset.hash === hash) {
this.selector.select(this.selector.indexOf(ele));
}
}.bind(this));
},
_selectorTap: function(e) {
var detail = {
description: e.detail.item.asString(),
commit: e.detail.item.commit,
};
this.dispatchEvent(new CustomEvent('commit-selected', { detail: detail, bubbles: true }));
},
_selectionChanged: function() {
this.$.selector.selectedClass = this.selection ? "iron-selected" : "no-matching-class";
},
_processCommitInfo: function () {
if (this._commitinfo && this._commitinfo.length) {
var lastHash = this._commitinfo[0].hash;
this._firstHash = this._commitinfo[this._commitinfo.length - 1].hash;
if (!this._commitinfo[0].message) {
var url = this._getCommitRangeURL(this._firstHash, lastHash);
// The git hashes are in time order, but not contiguous, so request
// the log range and them populate messages by matching git hashes.
sk.get(url).then(this._removeSecurityHeader).then(JSON.parse).then(function (json) {
var len = this._commitinfo.length;
for (var i = 0; i < json.log.length; i++) {
var commit = json.log[i].commit;
// Fill out the messages, matching the hashes of the commits in the JSON
// to what we have in _commitinfo.
for (var j = 0; j < len; j++) {
if (this._commitinfo[j].hash === commit) {
this.set('_commitinfo.'+j+'.message', json.log[i].message.slice(0, 60));
break;
}
}
}
// This can go away once we start filling in the message on the server side.
$$('commit-sk', this).forEach(function(ele) {
ele.refresh();
});
this.fire('commits-loaded', {});
}.bind(this)).catch(sk.errorMessage);
} else {
// Fire the message even when the commit messages were cached.
this.fire('commits-loaded', {});
}
if (this.progress) {
var url = 'https://status.skia.org/json/skia/buildProgress?commit=' + this._firstHash;
// The status server returns JSON of the form:
//
// {
// "commit": "e9e3ee33f30c14c31afd5fc3fe4dda7f15783c75",
// "finishedTasks": 111,
// "finishedProportion": 0.7762237762237763,
// "totalTasks": 143
// }
sk.get(url).then(JSON.parse).then(function (json) {
this._percent = json.finishedProportion;
}.bind(this)).catch(sk.errorMessage);
}
}
},
// _getCommitRangeURL returns the URL to retreive a commit range between
// startHash and endHash, inclusive on both ends.
_getCommitRangeURL: function(startHash, endHash) {
if (this.origin) {
return '/json/gitlog?start=' + startHash + '&end=' + endHash;
}
return this.repo + '/+log/' + startHash + '~' + 1 + '..' + endHash + '?format=json';
},
// _removeSecurityHeader strips the first 4 chars from the input. Needed
// since googlesource.com prefixes all JSON responses with )]}' as an
// XSS defense.
_removeSecurityHeader: function (s) {
if (s.startsWith(")]}'")) {
return s.slice(4, s.length);
}
return s;
},
_commitPercent: function (p) {
if (p == -1.0) {
return "[calculating]";
}
return Math.round(p * 100);
},
_statusHref: function (hash) {
return 'https://status.skia.org/?commit=' + hash + '&commitLabel=author&filter=all';
},
});
</script>
</dom-module>