blob: e0da090982a46fb1b939fb89d2db95820cab0330 [file] [log] [blame]
<!--
The bisect-form element includes the form for all of the different stages of
the bisect process after the user clicks on the bisect button.
-->
<link rel="import" href="/components/paper-button/paper-button.html">
<link rel="import" href="/components/paper-dialog/paper-action-dialog.html">
<link rel="import" href="/components/paper-spinner/paper-spinner.html">
<link rel="import" href="/dashboard/elements/base-form.html">
<link rel="import" href="/dashboard/static/simple_xhr.html">
<polymer-element name="bisect-form" extends="base-form"
attributes="xsrfToken testPath
earlierRevision laterRevision bugId">
<template>
<paper-action-dialog id="container" autoCloseDisabled="true">
<!-- Styling for paper-action-dialog's children. -->
<style>
#loading {
background-color: white;
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
justify-content: center;
-webkit-justify-content: center;
}
select, input[type=text], input[type=number] {
border-radius: 1px;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
font-size: 13px;
height: 25px; /* 29 px total height incl padding + border */
width: 300px;
padding: 1px 2px;
}
paper-button[affirmative] {
background: #4285f4;
color: #fff;
}
.error {
color: #dd4b39;
}
</style>
<form>
<table>
<tr>
<td>Bisect bot:</td>
<td>
<select id="bot" value="{{bot}}">
<template repeat="{{name in botList}}">
<option value="{{name}}">{{name}}</option>
</template>
</select>
</td>
</tr>
<tr>
<td>Metric:</td>
<td>
<select id="metric" value="{{metric}}">
<template repeat="{{name in metricList}}">
<option value="{{name}}">{{name}}</option>
</template>
</select>
</td>
</tr>
<tr>
<td>Bug ID:</td>
<td><input type="number" value="{{bugId}}"></td>
</tr>
<tr>
<td>Earlier revision:</td>
<td><input type="text" value="{{earlierRevision}}"></td>
</tr>
<tr>
<td>Later revision:</td>
<td><input type="text" value="{{laterRevision}}"></td>
</tr>
<tr>
<td>Repeat count:</td>
<td><input type="number" min="1" max="100" value="{{REPEAT_COUNT}}"></td>
</tr>
<tr>
<td>Max time (min):</td>
<td><input type="number" min="1" max="60" value="{{MAX_TIME_MINUTES}}"></td>
</tr>
<template if="{{canUseArchive}}">
<tr>
<td>Use archive:</td>
<td><input type="checkbox"
on-change="{{onUseArchiveChange}}"
checked="{{useArchive}}">
</td>
</tr>
</template>
<tr>
<td>Bisect mode:</td>
<td>
<select type="text" value="{{BISECT_MODE}}">
<option value="mean">mean</option>
<option value="std_dev">std_dev</option>
<option value="return_code">return_code</option>
</select>
<p class="error" hidden?="{{BISECT_MODE != 'return_code'}}">
If you would like to bisect on a test failure, please carefully
check the revision range on the buildbot status page and update
the <b>Earlier Revision</b> and <b>Later Revision</b> fields above
accordingly. Note that the revisions for a test failure will
<b>not</b> show up on the graph.
</p>
</td>
</tr>
<tr>
<td>Bypass no-repro check:</td>
<td><input type="checkbox" checked="{{bypassNoRepro}}"></td>
</tr>
</table>
</form>
<p><a href="http://www.chromium.org/developers/speed-infra/perf-try-bots-bisect-bots/config">
About the config parameters</a></p>
<p class="error">{{error}}</p>
<paper-button affirmative raised autofocus disabled?="{{error}}"
on-click="{{onSendToTrybot}}">Start bisect</paper-button>
<paper-button dismissive raised>Close</paper-button>
<template if="{{loading}}">
<div id="loading">
<paper-spinner active></paper-spinner>
</div>
</template>
</paper-action-dialog>
</template>
<script>
'use strict';
(function() {
/**
* Checks whether a revision appears to be OK to use for bisect.
* TODO(qyearsley): Extract common code in trace-form and bisect-form.
*/
function validateRev(rev) {
if (/^[a-fA-F0-9]{40}$/.test(rev)) {
return true;
}
if (!/^\d+/.test(rev)) {
return false;
}
rev = Number(rev);
return rev > 200000 && rev < 500000;
}
Polymer('bisect-form', {
// Default values of variables that are bound to inputs in the form.
// See: http://goo.gl/I94Kyj
REPEAT_COUNT: 20,
MAX_TIME_MINUTES: 20,
BISECT_MODE: 'mean',
/**
* Initializes and shows the bisect form.
*/
show: function() {
this.canUseArchive = false,
this.bypassNoRepro = false,
this.useArchive = true,
this.loading = true;
this.open();
simple_xhr.send('/start_try_job',
{
'test_path': this.testPath,
'step': 'prefill-info',
'xsrf_token': this.xsrfToken
},
function successCallback(info) {
this.bot = info['bisect_bot'];
this.botList = info['all_bots'];
this.metric = info['default_metric'];
this.metricList = info['all_metrics'];
this.canUseArchive = info['use_archive'];
this.email = info['email'];
this.suite = info['suite'];
this.master = info['master'];
this.internalOnly = info['internal_only'];
this.loading = false;
}.bind(this),
function errorCallback(msg) {
this.showErrorMessage('An error occurred', msg);
this.close();
}.bind(this));
},
/**
* Makes a request to /start_try_job to perform a bisect.
*/
onSendToTrybot: function(event) {
event.preventDefault();
this.loading = true;
var params = {
'step': 'perform-bisect',
'bisect_bot': this.bot,
'suite': this.suite,
'metric': this.metric,
'good_revision': this.earlierRevision,
'bad_revision': this.laterRevision,
'repeat_count': this.REPEAT_COUNT,
'max_time_minutes': this.MAX_TIME_MINUTES,
'use_archive': this.useArchive ? 'true' : '',
'bypass_no_repro_check': this.bypassNoRepro ? 'true' : '',
'master': this.master,
'internal_only': this.internalOnly,
'bisect_mode': this.BISECT_MODE,
'xsrf_token': this.xsrfToken
};
if (this.bugId) {
params['bug_id'] = this.bugId;
}
simple_xhr.send(
'/start_try_job', params,
function successCallback(info) {
var message = '<b>Job submitted!</b> ' +
'<a href="{{issue_url}}" target="_blank">' +
'View job {{issue_id}}.</a>';
this.showMessage(message, info);
// Refresh bisect result log element.
var bisectLog = document.getElementById('bisect-result-log');
if (bisectLog) {
bisectLog['refresh']();
}
this.close();
}.bind(this),
function errorCallback(msg) {
this.showErrorMessage('An error occurred', msg);
this.close();
}.bind(this));
},
earlierRevisionChanged: function() {
this.error = '';
if (!validateRev(this.earlierRevision)) {
this.error = 'Revisions should be git commit positions or hashes.';
return;
}
this.onRevisionsChange();
},
laterRevisionChanged: function() {
this.error = '';
if (!validateRev(this.laterRevision)) {
this.error = 'Revisions should be git commit positions or hashes.';
return;
}
this.onRevisionsChange();
},
onRevisionsChange: function() {
if (!/^\d+$/.test(this.earlierRevision) ||
!/^\d+$/.test(this.laterRevision)) {
return;
}
if (Number(this.earlierRevision) > Number(this.laterRevision)) {
this.error = (
'"Earlier revision" should be less than "later revision".');
}
},
open: function() {
this.$.container.open();
},
close: function() {
this.$.container.close();
}
});
})();
</script>
</polymer-element>