<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[210626] trunk/Websites/perf.webkit.org</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/210626">210626</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2017-01-11 23:18:28 -0800 (Wed, 11 Jan 2017)</dd>
</dl>
<h3>Log Message</h3>
<pre>Hide the UI to trigger an A/B testing when there are no triggerables
https://bugs.webkit.org/show_bug.cgi?id=166964
Reviewed by Yusuke Suzuki.
Hide the "Start A/B Testing" button on analysis task pages instead of showing it and failing later
when the user tries to create one it with a TriggerableNotFound error.
Added the list of triggerables to the manifest JSON so that we can determine this condition without
having to fetch /api/triggerable for each analysis task as done in v2 UI.
* public/admin/reprocess-report.php:
* public/api/manifest.php:
* public/api/report.php:
* public/include/admin-header.php:
* public/include/manifest-generator.php: Moved from public/include/manifest.php.
(ManifestGenerator::generate):
(ManifestGenerator::triggerables): Added. Include the list of repositories this triggerable accepts
as well as the list of (test, platform) pairs on which this triggerable is available.
Use [testId, platformId] instead of a dictionary to reduce the file size.
* public/v3/components/customizable-test-group-form.js:
(CustomizableTestGroupForm): Removed this._disabled. This variable was used in TestGroupFrom to
disable the "Start A/B Testing" button when no range is selected but this ended up racy. Compute
the visibility of the button in render() function instead.
(CustomizableTestGroupForm.prototype.setRootSetMap):
(CustomizableTestGroupForm.prototype._submitted):
(CustomizableTestGroupForm.prototype.render): Hide the customize link and the button as needed.
The "Start A/B Testing" button must be hidden when either no range is selected or no title is typed.
"Customize" button must be hidden when no range is selected.
* public/v3/components/test-group-form.js:
(TestGroupForm): Removed _disabled since it's no longer used.
(TestGroupForm.prototype.setDisabled): Ditto.
(TestGroupForm.prototype.render): Ditto.
* public/v3/index.html: Include triggerable.js.
* public/v3/models/manifest.js:
(Manifest._didFetchManifest): Modernized. Create Triggerable objects from the manifest JSON.
* public/v3/models/triggerable.js: Added.
(Triggerable): Add this triggerable object to the static map of (test id, platform id) pair.
(Triggerable.prototype.acceptedRepositories): Added.
(Triggerable.findByTestConfiguration): Added. Finds a triggerable in the aforementioned static map.
* public/v3/pages/analysis-task-page.js:
(AnalysisTaskChartPane.prototype._updateStatus): Added. Re-render the page since time series data
points that were previously not available may have become available. The lack of this update was
causing a race condition in which the "Start A/B Testing" button for the charts is disabled even
after a group name had been specified because setRootSetMap was never called with a valid set.
(AnalysisTaskPage): Added this._triggerable.
(AnalysisTaskPage.prototype._didFetchTask): Find the triggerable now that we've fetched the task.
(AnalysisTaskPage.prototype.render): Hide the group view (the table of A/B testing results) entirely
when there are no groups to show. Also hide the forms to start A/B testing when there are no matching
triggerable, which is the main feature of this patch.
* server-tests/api-manifest.js: Added a test for including a list of triggerables in the manifest JSON.
* server-tests/resources/mock-data.js:
(MockData.resetV3Models): Reset Triggerable's static map.
* server-tests/tools-buildbot-triggerable-tests.js: Assert that Triggerable objects are constructed
with appropriate list of repositories and (test, platform) associations.
* tools/js/database.js:
(tableToPrefixMap): Added triggerable_repositories's prefix.
* tools/js/remote.js:
(RemoteAPI.prototype.getJSON): Log the entire response to stderr when JSON.parse fails to aid debugging.
* tools/js/v3-models.js: Import triggerable.js.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgChangeLog">trunk/Websites/perf.webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicadminreprocessreportphp">trunk/Websites/perf.webkit.org/public/admin/reprocess-report.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicapimanifestphp">trunk/Websites/perf.webkit.org/public/api/manifest.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicapireportphp">trunk/Websites/perf.webkit.org/public/api/report.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludeadminheaderphp">trunk/Websites/perf.webkit.org/public/include/admin-header.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentscustomizabletestgroupformjs">trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentstestgroupformjs">trunk/Websites/perf.webkit.org/public/v3/components/test-group-form.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3indexhtml">trunk/Websites/perf.webkit.org/public/v3/index.html</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsmanifestjs">trunk/Websites/perf.webkit.org/public/v3/models/manifest.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs">trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgservertestsapimanifestjs">trunk/Websites/perf.webkit.org/server-tests/api-manifest.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgservertestsresourcesmockdatajs">trunk/Websites/perf.webkit.org/server-tests/resources/mock-data.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgserverteststoolsbuildbottriggerabletestsjs">trunk/Websites/perf.webkit.org/server-tests/tools-buildbot-triggerable-tests.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgtoolsjsdatabasejs">trunk/Websites/perf.webkit.org/tools/js/database.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgtoolsjsremotejs">trunk/Websites/perf.webkit.org/tools/js/remote.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgtoolsjsv3modelsjs">trunk/Websites/perf.webkit.org/tools/js/v3-models.js</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludemanifestgeneratorphp">trunk/Websites/perf.webkit.org/public/include/manifest-generator.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelstriggerablejs">trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludemanifestphp">trunk/Websites/perf.webkit.org/public/include/manifest.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebsitesperfwebkitorgChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/ChangeLog (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -1,3 +1,66 @@
</span><ins>+2017-01-12 Ryosuke Niwa <rniwa@webkit.org>
+
+ Hide the UI to trigger an A/B testing when there are no triggerables
+ https://bugs.webkit.org/show_bug.cgi?id=166964
+
+ Reviewed by Yusuke Suzuki.
+
+ Hide the "Start A/B Testing" button on analysis task pages instead of showing it and failing later
+ when the user tries to create one it with a TriggerableNotFound error.
+
+ Added the list of triggerables to the manifest JSON so that we can determine this condition without
+ having to fetch /api/triggerable for each analysis task as done in v2 UI.
+
+ * public/admin/reprocess-report.php:
+ * public/api/manifest.php:
+ * public/api/report.php:
+ * public/include/admin-header.php:
+ * public/include/manifest-generator.php: Moved from public/include/manifest.php.
+ (ManifestGenerator::generate):
+ (ManifestGenerator::triggerables): Added. Include the list of repositories this triggerable accepts
+ as well as the list of (test, platform) pairs on which this triggerable is available.
+ Use [testId, platformId] instead of a dictionary to reduce the file size.
+ * public/v3/components/customizable-test-group-form.js:
+ (CustomizableTestGroupForm): Removed this._disabled. This variable was used in TestGroupFrom to
+ disable the "Start A/B Testing" button when no range is selected but this ended up racy. Compute
+ the visibility of the button in render() function instead.
+ (CustomizableTestGroupForm.prototype.setRootSetMap):
+ (CustomizableTestGroupForm.prototype._submitted):
+ (CustomizableTestGroupForm.prototype.render): Hide the customize link and the button as needed.
+ The "Start A/B Testing" button must be hidden when either no range is selected or no title is typed.
+ "Customize" button must be hidden when no range is selected.
+ * public/v3/components/test-group-form.js:
+ (TestGroupForm): Removed _disabled since it's no longer used.
+ (TestGroupForm.prototype.setDisabled): Ditto.
+ (TestGroupForm.prototype.render): Ditto.
+ * public/v3/index.html: Include triggerable.js.
+ * public/v3/models/manifest.js:
+ (Manifest._didFetchManifest): Modernized. Create Triggerable objects from the manifest JSON.
+ * public/v3/models/triggerable.js: Added.
+ (Triggerable): Add this triggerable object to the static map of (test id, platform id) pair.
+ (Triggerable.prototype.acceptedRepositories): Added.
+ (Triggerable.findByTestConfiguration): Added. Finds a triggerable in the aforementioned static map.
+ * public/v3/pages/analysis-task-page.js:
+ (AnalysisTaskChartPane.prototype._updateStatus): Added. Re-render the page since time series data
+ points that were previously not available may have become available. The lack of this update was
+ causing a race condition in which the "Start A/B Testing" button for the charts is disabled even
+ after a group name had been specified because setRootSetMap was never called with a valid set.
+ (AnalysisTaskPage): Added this._triggerable.
+ (AnalysisTaskPage.prototype._didFetchTask): Find the triggerable now that we've fetched the task.
+ (AnalysisTaskPage.prototype.render): Hide the group view (the table of A/B testing results) entirely
+ when there are no groups to show. Also hide the forms to start A/B testing when there are no matching
+ triggerable, which is the main feature of this patch.
+ * server-tests/api-manifest.js: Added a test for including a list of triggerables in the manifest JSON.
+ * server-tests/resources/mock-data.js:
+ (MockData.resetV3Models): Reset Triggerable's static map.
+ * server-tests/tools-buildbot-triggerable-tests.js: Assert that Triggerable objects are constructed
+ with appropriate list of repositories and (test, platform) associations.
+ * tools/js/database.js:
+ (tableToPrefixMap): Added triggerable_repositories's prefix.
+ * tools/js/remote.js:
+ (RemoteAPI.prototype.getJSON): Log the entire response to stderr when JSON.parse fails to aid debugging.
+ * tools/js/v3-models.js: Import triggerable.js.
+
</ins><span class="cx"> 2017-01-11 Ryosuke Niwa <rniwa@webkit.org>
</span><span class="cx">
</span><span class="cx"> fetch-from-remote doesn’t work with some websites
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicadminreprocessreportphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/admin/reprocess-report.php (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/admin/reprocess-report.php        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/admin/reprocess-report.php        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> <?php
</span><span class="cx">
</span><span class="cx"> require_once('../include/json-header.php');
</span><del>-require_once('../include/manifest.php');
</del><ins>+require_once('../include/manifest-generator.php');
</ins><span class="cx"> require_once('../include/report-processor.php');
</span><span class="cx">
</span><span class="cx"> $db = new Database;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicapimanifestphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/api/manifest.php (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/api/manifest.php        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/api/manifest.php        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> <?php
</span><span class="cx">
</span><span class="cx"> require_once('../include/json-header.php');
</span><del>-require_once('../include/manifest.php');
</del><ins>+require_once('../include/manifest-generator.php');
</ins><span class="cx">
</span><span class="cx"> function main() {
</span><span class="cx"> $db = new Database;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicapireportphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/api/report.php (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/api/report.php        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/api/report.php        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> <?php
</span><span class="cx">
</span><span class="cx"> require_once('../include/json-header.php');
</span><del>-require_once('../include/manifest.php');
</del><ins>+require_once('../include/manifest-generator.php');
</ins><span class="cx"> require_once('../include/report-processor.php');
</span><span class="cx">
</span><span class="cx"> function main($post_data) {
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludeadminheaderphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/admin-header.php (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/admin-header.php        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/include/admin-header.php        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> <?php
</span><span class="cx">
</span><span class="cx"> require_once('db.php');
</span><del>-require_once('manifest.php');
</del><ins>+require_once('manifest-generator.php');
</ins><span class="cx">
</span><span class="cx"> ?><!DOCTYPE html>
</span><span class="cx"> <html>
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludemanifestgeneratorphpfromrev210625trunkWebsitesperfwebkitorgpublicincludemanifestphp"></a>
<div class="copfile"><h4>Copied: trunk/Websites/perf.webkit.org/public/include/manifest-generator.php (from rev 210625, trunk/Websites/perf.webkit.org/public/include/manifest.php) (0 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/manifest-generator.php         (rev 0)
+++ trunk/Websites/perf.webkit.org/public/include/manifest-generator.php        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -0,0 +1,218 @@
</span><ins>+<?php
+
+class ManifestGenerator {
+ private $db;
+ private $manifest;
+
+ // FIXME: Compute this value from config.json
+ const MANIFEST_PATH = '../data/manifest.json';
+
+ function __construct($db) {
+ $this->db = $db;
+ }
+
+ function generate() {
+ $start_time = microtime(true);
+
+ $platform_table = $this->db->fetch_table('platforms');
+ $repositories_table = $this->db->fetch_table('repositories');
+
+ $repositories_with_commit = $this->db->query_and_fetch_all(
+ 'SELECT DISTINCT(commit_repository) FROM commits WHERE commit_reported IS TRUE');
+ if (!$repositories_with_commit)
+ $repositories_with_commit = array();
+
+ foreach ($repositories_with_commit as &$row)
+ $row = $row['commit_repository'];
+
+ $tests = (object)$this->tests();
+ $metrics = (object)$this->metrics();
+ $platforms = (object)$this->platforms($platform_table, false);
+ $dashboard = (object)$this->platforms($platform_table, true);
+ $repositories = (object)$this->repositories($repositories_table, $repositories_with_commit);
+
+ $this->manifest = array(
+ 'siteTitle' => config('siteTitle', 'Performance Dashboard'),
+ 'tests' => &$tests,
+ 'metrics' => &$metrics,
+ 'all' => &$platforms,
+ 'dashboard' => &$dashboard,
+ 'repositories' => &$repositories,
+ 'builders' => (object)$this->builders(),
+ 'bugTrackers' => (object)$this->bug_trackers($repositories_table),
+ 'triggerables'=> (object)$this->triggerables(),
+ 'dashboards' => (object)config('dashboards'),
+ 'summaryPages' => config('summaryPages'),
+ );
+
+ $this->manifest['elapsedTime'] = (microtime(true) - $start_time) * 1000;
+
+ return TRUE;
+ }
+
+ function manifest() { return $this->manifest; }
+
+ function store() {
+ return generate_data_file('manifest.json', json_encode($this->manifest));
+ }
+
+ private function tests() {
+ $tests = array();
+ $tests_table = $this->db->fetch_table('tests');
+ if (!$tests_table)
+ return $tests;
+ foreach ($tests_table as $test_row) {
+ $tests[$test_row['test_id']] = array(
+ 'name' => $test_row['test_name'],
+ 'url' => $test_row['test_url'],
+ 'parentId' => $test_row['test_parent'],
+ );
+ }
+ return $tests;
+ }
+
+ private function metrics() {
+ $metrics = array();
+ $metrics_table = $this->db->query_and_fetch_all('SELECT * FROM test_metrics LEFT JOIN aggregators ON metric_aggregator = aggregator_id');
+ if (!$metrics_table)
+ return $metrics;
+ foreach ($metrics_table as $row) {
+ $metrics[$row['metric_id']] = array(
+ 'name' => $row['metric_name'],
+ 'test' => $row['metric_test'],
+ 'aggregator' => $row['aggregator_name']);
+ }
+ return $metrics;
+ }
+
+ private function platforms($platform_table, $is_dashboard) {
+ $metrics = $this->db->query_and_fetch_all('SELECT config_metric AS metric_id, config_platform AS platform_id,
+ extract(epoch from max(config_runs_last_modified) at time zone \'utc\') * 1000 AS last_modified, bool_or(config_is_in_dashboard) AS in_dashboard
+ FROM test_configurations GROUP BY config_metric, config_platform ORDER BY config_platform');
+
+ $platform_metrics = array();
+
+ if ($metrics) {
+ $current_platform_entry = null;
+ foreach ($metrics as $metric_row) {
+ if ($is_dashboard && !Database::is_true($metric_row['in_dashboard']))
+ continue;
+
+ $platform_id = $metric_row['platform_id'];
+ if (!$current_platform_entry || $current_platform_entry['id'] != $platform_id) {
+ $current_platform_entry = &array_ensure_item_has_array($platform_metrics, $platform_id);
+ $current_platform_entry['id'] = $platform_id;
+ array_ensure_item_has_array($current_platform_entry, 'metrics');
+ array_ensure_item_has_array($current_platform_entry, 'last_modified');
+ }
+
+ array_push($current_platform_entry['metrics'], $metric_row['metric_id']);
+ array_push($current_platform_entry['last_modified'], intval($metric_row['last_modified']));
+ }
+ }
+ $configurations = array();
+
+ $platforms = array();
+ if ($platform_table) {
+ foreach ($platform_table as $platform_row) {
+ if (Database::is_true($platform_row['platform_hidden']))
+ continue;
+ $id = $platform_row['platform_id'];
+ if (array_key_exists($id, $platform_metrics)) {
+ $platforms[$id] = array(
+ 'name' => $platform_row['platform_name'],
+ 'metrics' => $platform_metrics[$id]['metrics'],
+ 'lastModified' => $platform_metrics[$id]['last_modified']);
+ }
+ }
+ }
+ return $platforms;
+ }
+
+ private function repositories($repositories_table, $repositories_with_commit) {
+ $repositories = array();
+ if (!$repositories_table)
+ return $repositories;
+ foreach ($repositories_table as $row) {
+ $repositories[$row['repository_id']] = array(
+ 'name' => $row['repository_name'],
+ 'url' => $row['repository_url'],
+ 'blameUrl' => $row['repository_blame_url'],
+ 'hasReportedCommits' => in_array($row['repository_id'], $repositories_with_commit));
+ }
+
+ return $repositories;
+ }
+
+ private function builders() {
+ $builders_table = $this->db->fetch_table('builders');
+ if (!$builders_table)
+ return array();
+ $builders = array();
+ foreach ($builders_table as $row)
+ $builders[$row['builder_id']] = array('name' => $row['builder_name'], 'buildUrl' => $row['builder_build_url']);
+
+ return $builders;
+ }
+
+ private function bug_trackers($repositories_table) {
+ $tracker_id_to_repositories = array();
+ $tracker_repositories_table = $this->db->fetch_table('tracker_repositories');
+ if ($tracker_repositories_table) {
+ foreach ($tracker_repositories_table as $row) {
+ array_push(array_ensure_item_has_array($tracker_id_to_repositories, $row['tracrepo_tracker']),
+ $row['tracrepo_repository']);
+ }
+ }
+
+ $bug_trackers = array();
+ $bug_trackers_table = $this->db->fetch_table('bug_trackers');
+ if ($bug_trackers_table) {
+ foreach ($bug_trackers_table as $row) {
+ $bug_trackers[$row['tracker_id']] = array(
+ 'name' => $row['tracker_name'],
+ 'bugUrl' => $row['tracker_bug_url'],
+ 'newBugUrl' => $row['tracker_new_bug_url'],
+ 'repositories' => array_get($tracker_id_to_repositories, $row['tracker_id']));
+ }
+ }
+
+ return $bug_trackers;
+ }
+
+ private function triggerables() {
+
+ $triggerables = $this->db->fetch_table('build_triggerables');
+ if (!$triggerables)
+ return array();
+
+ $id_to_triggerable = array();
+ foreach ($triggerables as $row) {
+ $id = $row['triggerable_id'];
+ $id_to_triggerable[$id] = array(
+ 'name' => $row['triggerable_name'],
+ 'acceptedRepositories' => array(),
+ 'configurations' => array());
+ }
+
+ $repository_map = $this->db->fetch_table('triggerable_repositories');
+ if ($repository_map) {
+ foreach ($repository_map as $row) {
+ $triggerable = &$id_to_triggerable[$row['trigrepo_triggerable']];
+ array_push($triggerable['acceptedRepositories'], $row['trigrepo_repository']);
+ }
+ }
+
+ $configuration_map = $this->db->fetch_table('triggerable_configurations');
+ if ($configuration_map) {
+ foreach ($configuration_map as $row) {
+ $triggerable = &$id_to_triggerable[$row['trigconfig_triggerable']];
+ array_push($triggerable['configurations'], array($row['trigconfig_test'], $row['trigconfig_platform']));
+ }
+ }
+
+ return $id_to_triggerable;
+ }
+}
+
+?>
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludemanifestphp"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/perf.webkit.org/public/include/manifest.php (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/manifest.php        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/include/manifest.php        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -1,183 +0,0 @@
</span><del>-<?php
-
-class ManifestGenerator {
- private $db;
- private $manifest;
-
- // FIXME: Compute this value from config.json
- const MANIFEST_PATH = '../data/manifest.json';
-
- function __construct($db) {
- $this->db = $db;
- }
-
- function generate() {
- $start_time = microtime(true);
-
- $platform_table = $this->db->fetch_table('platforms');
- $repositories_table = $this->db->fetch_table('repositories');
-
- $repositories_with_commit = $this->db->query_and_fetch_all(
- 'SELECT DISTINCT(commit_repository) FROM commits WHERE commit_reported IS TRUE');
- if (!$repositories_with_commit)
- $repositories_with_commit = array();
-
- foreach ($repositories_with_commit as &$row)
- $row = $row['commit_repository'];
-
- $tests = (object)$this->tests();
- $metrics = (object)$this->metrics();
- $platforms = (object)$this->platforms($platform_table, false);
- $dashboard = (object)$this->platforms($platform_table, true);
- $repositories = (object)$this->repositories($repositories_table, $repositories_with_commit);
-
- $this->manifest = array(
- 'siteTitle' => config('siteTitle', 'Performance Dashboard'),
- 'tests' => &$tests,
- 'metrics' => &$metrics,
- 'all' => &$platforms,
- 'dashboard' => &$dashboard,
- 'repositories' => &$repositories,
- 'builders' => (object)$this->builders(),
- 'bugTrackers' => (object)$this->bug_trackers($repositories_table),
- 'dashboards' => (object)config('dashboards'),
- 'summaryPages' => config('summaryPages'),
- );
-
- $this->manifest['elapsedTime'] = (microtime(true) - $start_time) * 1000;
-
- return TRUE;
- }
-
- function manifest() { return $this->manifest; }
-
- function store() {
- return generate_data_file('manifest.json', json_encode($this->manifest));
- }
-
- private function tests() {
- $tests = array();
- $tests_table = $this->db->fetch_table('tests');
- if (!$tests_table)
- return $tests;
- foreach ($tests_table as $test_row) {
- $tests[$test_row['test_id']] = array(
- 'name' => $test_row['test_name'],
- 'url' => $test_row['test_url'],
- 'parentId' => $test_row['test_parent'],
- );
- }
- return $tests;
- }
-
- private function metrics() {
- $metrics = array();
- $metrics_table = $this->db->query_and_fetch_all('SELECT * FROM test_metrics LEFT JOIN aggregators ON metric_aggregator = aggregator_id');
- if (!$metrics_table)
- return $metrics;
- foreach ($metrics_table as $row) {
- $metrics[$row['metric_id']] = array(
- 'name' => $row['metric_name'],
- 'test' => $row['metric_test'],
- 'aggregator' => $row['aggregator_name']);
- }
- return $metrics;
- }
-
- private function platforms($platform_table, $is_dashboard) {
- $metrics = $this->db->query_and_fetch_all('SELECT config_metric AS metric_id, config_platform AS platform_id,
- extract(epoch from max(config_runs_last_modified)) * 1000 AS last_modified, bool_or(config_is_in_dashboard) AS in_dashboard
- FROM test_configurations GROUP BY config_metric, config_platform ORDER BY config_platform');
-
- $platform_metrics = array();
-
- if ($metrics) {
- $current_platform_entry = null;
- foreach ($metrics as $metric_row) {
- if ($is_dashboard && !Database::is_true($metric_row['in_dashboard']))
- continue;
-
- $platform_id = $metric_row['platform_id'];
- if (!$current_platform_entry || $current_platform_entry['id'] != $platform_id) {
- $current_platform_entry = &array_ensure_item_has_array($platform_metrics, $platform_id);
- $current_platform_entry['id'] = $platform_id;
- array_ensure_item_has_array($current_platform_entry, 'metrics');
- array_ensure_item_has_array($current_platform_entry, 'last_modified');
- }
-
- array_push($current_platform_entry['metrics'], $metric_row['metric_id']);
- array_push($current_platform_entry['last_modified'], intval($metric_row['last_modified']));
- }
- }
- $configurations = array();
-
- $platforms = array();
- if ($platform_table) {
- foreach ($platform_table as $platform_row) {
- if (Database::is_true($platform_row['platform_hidden']))
- continue;
- $id = $platform_row['platform_id'];
- if (array_key_exists($id, $platform_metrics)) {
- $platforms[$id] = array(
- 'name' => $platform_row['platform_name'],
- 'metrics' => $platform_metrics[$id]['metrics'],
- 'lastModified' => $platform_metrics[$id]['last_modified']);
- }
- }
- }
- return $platforms;
- }
-
- private function repositories($repositories_table, $repositories_with_commit) {
- $repositories = array();
- if (!$repositories_table)
- return $repositories;
- foreach ($repositories_table as $row) {
- $repositories[$row['repository_id']] = array(
- 'name' => $row['repository_name'],
- 'url' => $row['repository_url'],
- 'blameUrl' => $row['repository_blame_url'],
- 'hasReportedCommits' => in_array($row['repository_id'], $repositories_with_commit));
- }
-
- return $repositories;
- }
-
- private function builders() {
- $builders_table = $this->db->fetch_table('builders');
- if (!$builders_table)
- return array();
- $builders = array();
- foreach ($builders_table as $row)
- $builders[$row['builder_id']] = array('name' => $row['builder_name'], 'buildUrl' => $row['builder_build_url']);
-
- return $builders;
- }
-
- private function bug_trackers($repositories_table) {
- $tracker_id_to_repositories = array();
- $tracker_repositories_table = $this->db->fetch_table('tracker_repositories');
- if ($tracker_repositories_table) {
- foreach ($tracker_repositories_table as $row) {
- array_push(array_ensure_item_has_array($tracker_id_to_repositories, $row['tracrepo_tracker']),
- $row['tracrepo_repository']);
- }
- }
-
- $bug_trackers = array();
- $bug_trackers_table = $this->db->fetch_table('bug_trackers');
- if ($bug_trackers_table) {
- foreach ($bug_trackers_table as $row) {
- $bug_trackers[$row['tracker_id']] = array(
- 'name' => $row['tracker_name'],
- 'bugUrl' => $row['tracker_bug_url'],
- 'newBugUrl' => $row['tracker_new_bug_url'],
- 'repositories' => array_get($tracker_id_to_repositories, $row['tracker_id']));
- }
- }
-
- return $bug_trackers;
- }
-}
-
-?>
</del></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentscustomizabletestgroupformjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -5,9 +5,10 @@
</span><span class="cx"> {
</span><span class="cx"> super('customizable-test-group-form');
</span><span class="cx"> this._rootSetMap = null;
</span><del>- this._disabled = true;
</del><span class="cx"> this._renderedRepositorylist = null;
</span><span class="cx"> this._customized = false;
</span><ins>+ this._nameControl = this.content().querySelector('.name');
+ this._nameControl.oninput = this.render.bind(this);
</ins><span class="cx"> this.content().querySelector('a').onclick = this._customize.bind(this);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -15,13 +16,12 @@
</span><span class="cx"> {
</span><span class="cx"> this._rootSetMap = map;
</span><span class="cx"> this._customized = false;
</span><del>- this.setDisabled(!map);
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> _submitted()
</span><span class="cx"> {
</span><span class="cx"> if (this._startCallback)
</span><del>- this._startCallback(this.content().querySelector('.name').value, this._repetitionCount, this._computeRootSetMap());
</del><ins>+ this._startCallback(this._nameControl.value, this._repetitionCount, this._computeRootSetMap());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> _customize(event)
</span><span class="lines">@@ -56,13 +56,15 @@
</span><span class="cx"> render()
</span><span class="cx"> {
</span><span class="cx"> super.render();
</span><del>- this.content().querySelector('.customize-link').style.display = this._disabled ? 'none' : null;
</del><ins>+ var map = this._rootSetMap;
</ins><span class="cx">
</span><ins>+ this.content().querySelector('button').disabled = !(map && this._nameControl.value);
+ this.content().querySelector('.customize-link').style.display = !map ? 'none' : null;
+
</ins><span class="cx"> if (!this._customized) {
</span><span class="cx"> this.renderReplace(this.content().querySelector('.custom-table-container'), []);
</span><span class="cx"> return;
</span><span class="cx"> }
</span><del>- var map = this._rootSetMap;
</del><span class="cx"> console.assert(map);
</span><span class="cx">
</span><span class="cx"> var repositorySet = new Set;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentstestgroupformjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/test-group-form.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/test-group-form.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/v3/components/test-group-form.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -5,7 +5,6 @@
</span><span class="cx"> {
</span><span class="cx"> super(name || 'test-group-form');
</span><span class="cx"> this._startCallback = null;
</span><del>- this._disabled = false;
</del><span class="cx"> this._label = undefined;
</span><span class="cx"> this._repetitionCount = 4;
</span><span class="cx">
</span><span class="lines">@@ -24,7 +23,6 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> setStartCallback(callback) { this._startCallback = callback; }
</span><del>- setDisabled(disabled) { this._disabled = !!disabled; }
</del><span class="cx"> setLabel(label) { this._label = label; }
</span><span class="cx"> setRepetitionCount(count) { this._repetitionCount = count; }
</span><span class="cx">
</span><span class="lines">@@ -33,7 +31,6 @@
</span><span class="cx"> var button = this.content().querySelector('button');
</span><span class="cx"> if (this._label)
</span><span class="cx"> button.textContent = this._label;
</span><del>- button.disabled = this._disabled;
</del><span class="cx"> this._repetitionCountControl.value = this._repetitionCount;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3indexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/index.html (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/index.html        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/v3/index.html        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx"> <script src="models/test-group.js"></script>
</span><span class="cx"> <script src="models/build-request.js"></script>
</span><span class="cx"> <script src="models/root-set.js"></script>
</span><ins>+ <script src="models/triggerable.js"></script>
</ins><span class="cx"> <script src="models/manifest.js"></script>
</span><span class="cx">
</span><span class="cx"> <script src="components/base.js"></script>
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsmanifestjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/manifest.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/manifest.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/v3/models/manifest.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -13,35 +13,41 @@
</span><span class="cx"> {
</span><span class="cx"> Instrumentation.startMeasuringTime('Manifest', '_didFetchManifest');
</span><span class="cx">
</span><del>- var tests = [];
- var testParentMap = {};
- for (var testId in rawResponse.tests)
</del><ins>+ const tests = [];
+ const testParentMap = {};
+ for (let testId in rawResponse.tests)
</ins><span class="cx"> tests.push(new Test(testId, rawResponse.tests[testId]));
</span><span class="cx">
</span><span class="cx"> function buildObjectsFromIdMap(idMap, constructor, resolver) {
</span><del>- for (var id in idMap) {
</del><ins>+ for (let id in idMap) {
</ins><span class="cx"> if (resolver)
</span><span class="cx"> resolver(idMap[id]);
</span><span class="cx"> new constructor(id, idMap[id]);
</span><span class="cx"> }
</span><span class="cx"> }
</span><del>- buildObjectsFromIdMap(rawResponse.metrics, Metric, function (raw) {
</del><ins>+
+ buildObjectsFromIdMap(rawResponse.metrics, Metric, (raw) => {
</ins><span class="cx"> raw.test = Test.findById(raw.test);
</span><span class="cx"> });
</span><span class="cx">
</span><del>- buildObjectsFromIdMap(rawResponse.all, Platform, function (raw) {
</del><ins>+ buildObjectsFromIdMap(rawResponse.all, Platform, (raw) => {
</ins><span class="cx"> raw.lastModifiedByMetric = {};
</span><del>- raw.lastModified.forEach(function (lastModified, index) {
</del><ins>+ raw.lastModified.forEach((lastModified, index) => {
</ins><span class="cx"> raw.lastModifiedByMetric[raw.metrics[index]] = lastModified;
</span><span class="cx"> });
</span><del>- raw.metrics = raw.metrics.map(function (id) { return Metric.findById(id); });
</del><ins>+ raw.metrics = raw.metrics.map((id) => { return Metric.findById(id); });
</ins><span class="cx"> });
</span><span class="cx"> buildObjectsFromIdMap(rawResponse.builders, Builder);
</span><span class="cx"> buildObjectsFromIdMap(rawResponse.repositories, Repository);
</span><del>- buildObjectsFromIdMap(rawResponse.bugTrackers, BugTracker, function (raw) {
</del><ins>+ buildObjectsFromIdMap(rawResponse.bugTrackers, BugTracker, (raw) => {
</ins><span class="cx"> if (raw.repositories)
</span><del>- raw.repositories = raw.repositories.map(function (id) { return Repository.findById(id); });
</del><ins>+ raw.repositories = raw.repositories.map((id) => { return Repository.findById(id); });
</ins><span class="cx"> });
</span><ins>+ buildObjectsFromIdMap(rawResponse.triggerables, Triggerable, (raw) => {
+ raw.acceptedRepositories = raw.acceptedRepositories.map((repositoryId) => {
+ return Repository.findById(repositoryId);
+ });
+ });
</ins><span class="cx">
</span><span class="cx"> Instrumentation.endMeasuringTime('Manifest', '_didFetchManifest');
</span><span class="cx">
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelstriggerablejs"></a>
<div class="addfile"><h4>Added: trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js (0 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js         (rev 0)
+++ trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+class Triggerable extends LabeledObject {
+
+ constructor(id, object)
+ {
+ super(id, object);
+ this._name = object.name;
+ this._acceptedRepositories = object.acceptedRepositories;
+ this._configurationList = object.configurations;
+
+ let configurationMap = this.ensureNamedStaticMap('testConfigurations');
+ for (const config of object.configurations) {
+ const [testId, platformId] = config;
+ const key = `${testId}-${platformId}`;
+ console.assert(!(key in configurationMap));
+ configurationMap[key] = this;
+ }
+ }
+
+ acceptedRepositories() { return this._acceptedRepositories; }
+
+ static findByTestConfiguration(test, platform)
+ {
+ let configurationMap = this.ensureNamedStaticMap('testConfigurations');
+ if (!configurationMap)
+ return null;
+ for (; test; test = test.parentTest()) {
+ const key = `${test.id()}-${platform.id()}`;
+ if (key in configurationMap)
+ return configurationMap[key];
+ }
+ return null;
+ }
+
+}
+
+if (typeof module != 'undefined')
+ module.exports.Triggerable = Triggerable;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -16,6 +16,12 @@
</span><span class="cx"> this._page._chartSelectionDidChange();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ _updateStatus()
+ {
+ super._updateStatus();
+ this._page.render();
+ }
+
</ins><span class="cx"> selectedPoints()
</span><span class="cx"> {
</span><span class="cx"> var selection = this._mainChart ? this._mainChart.currentSelection() : null;
</span><span class="lines">@@ -33,6 +39,7 @@
</span><span class="cx"> {
</span><span class="cx"> super('Analysis Task');
</span><span class="cx"> this._task = null;
</span><ins>+ this._triggerable = null;
</ins><span class="cx"> this._relatedTasks = null;
</span><span class="cx"> this._testGroups = null;
</span><span class="cx"> this._renderedTestGroups = null;
</span><span class="lines">@@ -120,20 +127,22 @@
</span><span class="cx"> console.assert(!this._task);
</span><span class="cx">
</span><span class="cx"> this._task = task;
</span><del>- var platform = task.platform();
- var metric = task.metric();
- var lastModified = platform.lastModified(metric);
</del><ins>+ const platform = task.platform();
+ const metric = task.metric();
+ const lastModified = platform.lastModified(metric);
</ins><span class="cx">
</span><ins>+ this._triggerable = Triggerable.findByTestConfiguration(metric.test(), platform);
+
</ins><span class="cx"> this._measurementSet = MeasurementSet.findSet(platform.id(), metric.id(), lastModified);
</span><span class="cx"> this._measurementSet.fetchBetween(task.startTime(), task.endTime(), this._didFetchMeasurement.bind(this));
</span><span class="cx">
</span><del>- var formatter = metric.makeFormatter(4);
</del><ins>+ const formatter = metric.makeFormatter(4);
</ins><span class="cx"> this._analysisResultsViewer.setValueFormatter(formatter);
</span><span class="cx"> this._testGroupResultsTable.setValueFormatter(formatter);
</span><span class="cx">
</span><span class="cx"> this._chartPane.configure(platform.id(), metric.id());
</span><span class="cx">
</span><del>- var domain = ChartsPage.createDomainForAnalysisTask(task);
</del><ins>+ const domain = ChartsPage.createDomainForAnalysisTask(task);
</ins><span class="cx"> this._chartPane.setOverviewDomain(domain[0], domain[1]);
</span><span class="cx"> this._chartPane.setMainDomain(domain[0], domain[1]);
</span><span class="cx">
</span><span class="lines">@@ -265,7 +274,7 @@
</span><span class="cx">
</span><span class="cx"> this.content().querySelector('.analysis-task-status').style.display = this._task ? null : 'none';
</span><span class="cx"> this.content().querySelector('.overview-chart').style.display = this._task ? null : 'none';
</span><del>- this.content().querySelector('.test-group-view').style.display = this._task ? null : 'none';
</del><ins>+ this.content().querySelector('.test-group-view').style.display = this._task && this._testGroups && this._testGroups.length ? null : 'none';
</ins><span class="cx"> this._taskNameLabel.render();
</span><span class="cx">
</span><span class="cx"> if (this._relatedTasks && this._task) {
</span><span class="lines">@@ -288,6 +297,7 @@
</span><span class="cx"> var b = selectedRange['B'];
</span><span class="cx"> this._newTestGroupFormForViewer.setRootSetMap(a && b ? {'A': a.rootSet(), 'B': b.rootSet()} : null);
</span><span class="cx"> this._newTestGroupFormForViewer.render();
</span><ins>+ this._newTestGroupFormForViewer.element().style.display = this._triggerable ? null : 'none';
</ins><span class="cx">
</span><span class="cx"> this._renderTestGroupList();
</span><span class="cx"> this._renderTestGroupDetails();
</span><span class="lines">@@ -299,6 +309,7 @@
</span><span class="cx"> this._newTestGroupFormForChart.setRootSetMap(points && points.length >= 2 ?
</span><span class="cx"> {'A': points[0].rootSet(), 'B': points[points.length - 1].rootSet()} : null);
</span><span class="cx"> this._newTestGroupFormForChart.render();
</span><ins>+ this._newTestGroupFormForChart.element().style.display = this._triggerable ? null : 'none';
</ins><span class="cx">
</span><span class="cx"> this._analysisResultsViewer.setCurrentTestGroup(this._currentTestGroup);
</span><span class="cx"> this._analysisResultsViewer.render();
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgservertestsapimanifestjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/api-manifest.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/api-manifest.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/server-tests/api-manifest.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> it("should generate an empty manifest when database is empty", function (done) {
</span><span class="cx"> TestServer.remoteAPI().getJSON('/api/manifest').then(function (manifest) {
</span><span class="cx"> assert.deepEqual(Object.keys(manifest).sort(), ['all', 'bugTrackers', 'builders', 'dashboard', 'dashboards',
</span><del>- 'elapsedTime', 'metrics', 'repositories', 'siteTitle', 'status', 'summaryPages', 'tests']);
</del><ins>+ 'elapsedTime', 'metrics', 'repositories', 'siteTitle', 'status', 'summaryPages', 'tests', 'triggerables']);
</ins><span class="cx">
</span><span class="cx"> assert.equal(typeof(manifest.elapsedTime), 'number');
</span><span class="cx"> delete manifest.elapsedTime;
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> metrics: {},
</span><span class="cx"> repositories: {},
</span><span class="cx"> tests: {},
</span><ins>+ triggerables: {},
</ins><span class="cx"> summaryPages: [],
</span><span class="cx"> status: 'OK'
</span><span class="cx"> });
</span><span class="lines">@@ -275,4 +276,78 @@
</span><span class="cx"> }).catch(done);
</span><span class="cx"> });
</span><span class="cx">
</span><ins>+ it("should generate manifest with triggerables", function (done) {
+ let db = TestServer.database();
+ db.connect();
+ Promise.all([
+ db.insert('repositories', {id: 11, name: 'WebKit', url: 'https://trac.webkit.org/$1'}),
+ db.insert('repositories', {id: 9, name: 'OS X'}),
+ db.insert('build_triggerables', {id: 200, name: 'build.webkit.org'}),
+ db.insert('build_triggerables', {id: 201, name: 'ios-build.webkit.org'}),
+ db.insert('tests', {id: 1, name: 'SomeTest'}),
+ db.insert('tests', {id: 2, name: 'SomeOtherTest'}),
+ db.insert('tests', {id: 3, name: 'ChildTest', parent: 1}),
+ db.insert('platforms', {id: 23, name: 'iOS 9 iPhone 5s'}),
+ db.insert('platforms', {id: 46, name: 'Trunk Mavericks'}),
+ db.insert('test_metrics', {id: 5, test: 1, name: 'Time'}),
+ db.insert('test_metrics', {id: 8, test: 2, name: 'FrameRate'}),
+ db.insert('test_metrics', {id: 9, test: 3, name: 'Time'}),
+ db.insert('test_configurations', {id: 101, metric: 5, platform: 46, type: 'current'}),
+ db.insert('test_configurations', {id: 102, metric: 8, platform: 46, type: 'current'}),
+ db.insert('test_configurations', {id: 103, metric: 9, platform: 46, type: 'current'}),
+ db.insert('test_configurations', {id: 104, metric: 5, platform: 23, type: 'current'}),
+ db.insert('test_configurations', {id: 105, metric: 8, platform: 23, type: 'current'}),
+ db.insert('test_configurations', {id: 106, metric: 9, platform: 23, type: 'current'}),
+ db.insert('triggerable_repositories', {triggerable: 200, repository: 11}),
+ db.insert('triggerable_repositories', {triggerable: 201, repository: 11}),
+ db.insert('triggerable_configurations', {triggerable: 200, test: 1, platform: 46}),
+ db.insert('triggerable_configurations', {triggerable: 200, test: 2, platform: 46}),
+ db.insert('triggerable_configurations', {triggerable: 201, test: 1, platform: 23}),
+ db.insert('triggerable_configurations', {triggerable: 201, test: 2, platform: 23}),
+ ]).then(function () {
+ return Manifest.fetch();
+ }).then(function () {
+ let webkit = Repository.findById(11);
+ assert.equal(webkit.name(), 'WebKit');
+ assert.equal(webkit.urlForRevision(123), 'https://trac.webkit.org/123');
+
+ let osx = Repository.findById(9);
+ assert.equal(osx.name(), 'OS X');
+
+ let someTest = Test.findById(1);
+ assert.equal(someTest.name(), 'SomeTest');
+
+ let someOtherTest = Test.findById(2);
+ assert.equal(someOtherTest.name(), 'SomeOtherTest');
+
+ let childTest = Test.findById(3);
+ assert.equal(childTest.name(), 'ChildTest');
+
+ let ios9iphone5s = Platform.findById(23);
+ assert.equal(ios9iphone5s.name(), 'iOS 9 iPhone 5s');
+
+ let mavericks = Platform.findById(46);
+ assert.equal(mavericks.name(), 'Trunk Mavericks');
+
+ assert.equal(Triggerable.all().length, 2);
+
+ let osxTriggerable = Triggerable.findByTestConfiguration(someTest, mavericks);
+ assert.equal(osxTriggerable.name(), 'build.webkit.org');
+ assert.deepEqual(osxTriggerable.acceptedRepositories(), [webkit]);
+
+ assert.equal(Triggerable.findByTestConfiguration(someOtherTest, mavericks), osxTriggerable);
+ assert.equal(Triggerable.findByTestConfiguration(childTest, mavericks), osxTriggerable);
+
+ let iosTriggerable = Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s);
+ assert.notEqual(iosTriggerable, osxTriggerable);
+ assert.equal(iosTriggerable.name(), 'ios-build.webkit.org');
+ assert.deepEqual(iosTriggerable.acceptedRepositories(), [webkit]);
+
+ assert.equal(Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s), iosTriggerable);
+ assert.equal(Triggerable.findByTestConfiguration(childTest, ios9iphone5s), iosTriggerable);
+
+ done();
+ }).catch(done);
+ });
+
</ins><span class="cx"> });
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgservertestsresourcesmockdatajs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/resources/mock-data.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/resources/mock-data.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/server-tests/resources/mock-data.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -15,6 +15,7 @@
</span><span class="cx"> RootSet.clearStaticMap();
</span><span class="cx"> Test.clearStaticMap();
</span><span class="cx"> TestGroup.clearStaticMap();
</span><ins>+ Triggerable.clearStaticMap();
</ins><span class="cx"> },
</span><span class="cx"> someTestId() { return 200; },
</span><span class="cx"> somePlatformId() { return 65; },
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgserverteststoolsbuildbottriggerabletestsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/tools-buildbot-triggerable-tests.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/tools-buildbot-triggerable-tests.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/server-tests/tools-buildbot-triggerable-tests.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -910,23 +910,46 @@
</span><span class="cx">
</span><span class="cx"> it('should update available triggerables', function (done) {
</span><span class="cx"> let db = TestServer.database();
</span><del>- MockData.addMockData(db).then(function () {
</del><ins>+ MockData.addMockData(db).then(() => {
</ins><span class="cx"> return Manifest.fetch();
</span><del>- }).then(function () {
</del><ins>+ }).then(() => {
</ins><span class="cx"> return db.selectAll('triggerable_configurations', 'test');
</span><del>- }).then(function (configurations) {
</del><ins>+ }).then((configurations) => {
</ins><span class="cx"> assert.equal(configurations.length, 0);
</span><ins>+ assert.equal(Triggerable.all().length, 1);
+
+ let triggerable = Triggerable.all()[0];
+ assert.equal(triggerable.name(), 'build-webkit');
+ assert.deepEqual(triggerable.acceptedRepositories(), []);
+
+ let test = Test.findById(MockData.someTestId());
+ let platform = Platform.findById(MockData.somePlatformId());
+ assert.equal(Triggerable.findByTestConfiguration(test, platform), null);
+
</ins><span class="cx"> let config = MockData.mockTestSyncConfigWithSingleBuilder();
</span><span class="cx"> let logger = new MockLogger;
</span><span class="cx"> let slaveInfo = {name: 'sync-slave', password: 'password'};
</span><del>- let triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
- return triggerable.updateTriggerable();
- }).then(function () {
</del><ins>+ let buildbotTriggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
+ return buildbotTriggerable.updateTriggerable();
+ }).then(() => {
+ MockData.resetV3Models();
+ assert.equal(Triggerable.all().length, 0);
+ return TestServer.remoteAPI().getJSON('/api/manifest');
+ }).then((manifestContent) => {
+ Manifest._didFetchManifest(manifestContent);
</ins><span class="cx"> return db.selectAll('triggerable_configurations', 'test');
</span><del>- }).then(function (configurations) {
</del><ins>+ }).then((configurations) => {
</ins><span class="cx"> assert.equal(configurations.length, 1);
</span><span class="cx"> assert.equal(configurations[0].test, MockData.someTestId());
</span><span class="cx"> assert.equal(configurations[0].platform, MockData.somePlatformId());
</span><ins>+
+ assert.equal(Triggerable.all().length, 1);
+
+ let test = Test.findById(MockData.someTestId());
+ let platform = Platform.findById(MockData.somePlatformId());
+ let triggerable = Triggerable.findByTestConfiguration(test, platform);
+ assert.equal(triggerable.name(), 'build-webkit');
+
</ins><span class="cx"> done();
</span><span class="cx"> }).catch(done);
</span><span class="cx"> });
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgtoolsjsdatabasejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/tools/js/database.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/tools/js/database.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/tools/js/database.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -143,6 +143,7 @@
</span><span class="cx"> 'tests': 'test',
</span><span class="cx"> 'tracker_repositories': 'tracrepo',
</span><span class="cx"> 'triggerable_configurations': 'trigconfig',
</span><ins>+ 'triggerable_repositories': 'trigrepo',
</ins><span class="cx"> 'platforms': 'platform',
</span><span class="cx"> 'reports': 'report',
</span><span class="cx"> 'repositories': 'repository',
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgtoolsjsremotejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/tools/js/remote.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/tools/js/remote.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/tools/js/remote.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -56,7 +56,12 @@
</span><span class="cx"> getJSON(path)
</span><span class="cx"> {
</span><span class="cx"> return this.sendHttpRequest(path, 'GET', null, null).then(function (result) {
</span><del>- return JSON.parse(result.responseText);
</del><ins>+ try {
+ return JSON.parse(result.responseText);
+ } catch (error) {
+ console.error(result.responseText);
+ throw error;
+ }
</ins><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgtoolsjsv3modelsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/tools/js/v3-models.js (210625 => 210626)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/tools/js/v3-models.js        2017-01-12 06:50:16 UTC (rev 210625)
+++ trunk/Websites/perf.webkit.org/tools/js/v3-models.js        2017-01-12 07:18:28 UTC (rev 210626)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> importFromV3('models/test.js', 'Test');
</span><span class="cx"> importFromV3('models/test-group.js', 'TestGroup');
</span><span class="cx"> importFromV3('models/time-series.js', 'TimeSeries');
</span><ins>+importFromV3('models/triggerable.js', 'Triggerable');
</ins><span class="cx">
</span><span class="cx"> importFromV3('privileged-api.js', 'PrivilegedAPI');
</span><span class="cx"> importFromV3('instrumentation.js', 'Instrumentation');
</span></span></pre>
</div>
</div>
</body>
</html>