<!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>[198265] 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/198265">198265</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-16 00:02:28 -0700 (Wed, 16 Mar 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Analysis task page should allow specifying commits that caused or fixed a regression or a progression
https://bugs.webkit.org/show_bug.cgi?id=155529
Reviewed by Chris Dumez.
Added the capability to associate revisions that caused or fixed a progression or a regression for which
an analysis task was created. Added task_commits that stores this relationship and added the backend
support to retrieve this table in /api/analysis-tasks and an privileged API to update this table at
/privileged-api/associate-commit.
Also extracted a new component, MutableListView, out of AnalysisTaskPage to render and manipulate a list
of mutable items, and used it to render the list of associated bugs and commits. The view takes a list of
kinds (e.g. repositories or bug trackers), and accepts a pair of a kind and arbitrary text as a new item
value.
* init-database.sql: Added task_commits table.
* public/api/analysis-tasks.php:
(main):
(fetch_associated_data_for_tasks): Renamed from fetch_and_push_bugs_to_tasks now that it also fetches
the list of commits associated with each analysis task by calling CommitLogFetcher::fetch_for_tasks.
Also fixe the bug that we were not taking
(format_task): No longer sets 'category' since the computation of category now depends on the list of
commits associated with this analysis task which aren't available until fetch_associated_data_for_tasks.
(determine_category): Added. Categorize any analysis tasks with "fixes" commits as "closed" and "causes"
commits as "identified".
* public/include/commit-log-fetcher.php:
(CommitLogFetcher::__construct): Remove the unused instance variable.
(CommitLogFetcher::fetch_for_tasks): Added. Fetches all commits associated with a list of analysis tasks.
Assumes the caller (fetch_associated_data_for_tasks) had setup "fixes" and "causes" fields on each task.
* public/privileged-api/associate-commit.php: Added. Updates task_commits table to associate or disassociate
a commit with an analysis task. When the specified analysis task and the specified commit are already
associated, we simply update the table instead of adding a duplicating entry or error. For dissociation,
the front-end specifies the commit ID.
(main): Added.
* public/v3/index.html:
* public/v3/components/mutable-list-view.js: Added. Used by the list associated bugs and commits.
(MutableListView): Added.
(MutableListView.prototype.setList): Added.
(MutableListView.prototype.setKindList): Added.
(MutableListView.prototype.setAddCallback): Added. This callback is invoked when the user tries to add
a new item to the list.
(MutableListView.prototype.render): Added.
(MutableListView.prototype._submitted): Added.
(MutableListView.cssTemplate):
(MutableListView.htmlTemplate):
(MutableListItem): Added. RemovalLink could be a hyperlink or a callback and gets involved when the user
tries to delete this item.
(MutableListItem.prototype.content):
* public/v3/models/analysis-task.js:
(AnalysisTask): Added the support of the list of commits that fixed and caused changes.
(AnalysisTask.prototype.updateSingleton): Ditto.
(AnalysisTask.prototype.causes): Added.
(AnalysisTask.prototype.fixes): Added.
(AnalysisTask.prototype.associateCommit): Added. Use the API added at /privileged-api/associate-commit
to associate a new commit with this analysis task. Each commit has either caused or fixed the change.
(AnalysisTask.prototype.dissociateCommit): Added. Use the same API to disassociate each commit.
(AnalysisTask._constructAnalysisTasksFromRawData): Find all commits associated with each analysis task.
Because commit log objects use a fake ID fdue to /api/measurement-set not providing commit IDs, we must
use CommitLog.findByRemoteId to find each commit instead of usual CommitLog.findById.
(AnalysisTask._constructAnalysisTasksFromRawData.resolveCommits): Added.
* public/v3/models/build-request.js:
(BuildRequest.prototype.hasFinished): Renamed from hasCompleted since it was confusing for this._status
being "completed" wasn't a necessary condition for this function to return true.
* public/v3/models/commit-log.js:
(CommitLog): Added the static map for actual commit ID instead of a fake ID created in ensureSingleton.
(CommitLog.prototype.remoteId): Added. Returns the real commit ID.
(CommitLog.findByRemoteId): Added. Finds an CommitLog object using the real ID.
* public/v3/models/test-group.js:
(TestGroup.prototype.hasFinished): Renamed from hasCompleted to match the rename in BuildRequest.
* public/v3/pages/analysis-task-page.js:
(AnalysisTaskPage): Added lists for the commits that fixed and caused the change using MutableListView.
Also adopted MutableListView for the list of associated bugs.
(AnalysisTaskPage.prototype.render): Added the code to populate the newly added lists.
(AnalysisTaskPage.prototype._makeCommitListItem): Added.
(AnalysisTaskPage.prototype._associateBug): Now this is a callback from MutableListView.
(AnalysisTaskPage.prototype._associateCommit): Added.
(AnalysisTaskPage.prototype._dissociateCommit): Added.
(AnalysisTaskPage.htmlTemplate):
(AnalysisTaskPage.cssTemplate):
* public/v3/remote.js:
(getJSON): Spit out the entire responseText when JSON failed to parse to make debugging easier.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgChangeLog">trunk/Websites/perf.webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsitesperfwebkitorginitdatabasesql">trunk/Websites/perf.webkit.org/init-database.sql</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicapianalysistasksphp">trunk/Websites/perf.webkit.org/public/api/analysis-tasks.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludecommitlogfetcherphp">trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3indexhtml">trunk/Websites/perf.webkit.org/public/v3/index.html</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsanalysistaskjs">trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsbuildrequestjs">trunk/Websites/perf.webkit.org/public/v3/models/build-request.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelscommitlogjs">trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelstestgroupjs">trunk/Websites/perf.webkit.org/public/v3/models/test-group.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs">trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3remotejs">trunk/Websites/perf.webkit.org/public/v3/remote.js</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgpublicprivilegedapiassociatecommitphp">trunk/Websites/perf.webkit.org/public/privileged-api/associate-commit.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentsmutablelistviewjs">trunk/Websites/perf.webkit.org/public/v3/components/mutable-list-view.js</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 (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -1,3 +1,97 @@
</span><ins>+2016-03-16 Ryosuke Niwa <rniwa@webkit.org>
+
+ Analysis task page should allow specifying commits that caused or fixed a regression or a progression
+ https://bugs.webkit.org/show_bug.cgi?id=155529
+
+ Reviewed by Chris Dumez.
+
+ Added the capability to associate revisions that caused or fixed a progression or a regression for which
+ an analysis task was created. Added task_commits that stores this relationship and added the backend
+ support to retrieve this table in /api/analysis-tasks and an privileged API to update this table at
+ /privileged-api/associate-commit.
+
+ Also extracted a new component, MutableListView, out of AnalysisTaskPage to render and manipulate a list
+ of mutable items, and used it to render the list of associated bugs and commits. The view takes a list of
+ kinds (e.g. repositories or bug trackers), and accepts a pair of a kind and arbitrary text as a new item
+ value.
+
+ * init-database.sql: Added task_commits table.
+
+ * public/api/analysis-tasks.php:
+ (main):
+ (fetch_associated_data_for_tasks): Renamed from fetch_and_push_bugs_to_tasks now that it also fetches
+ the list of commits associated with each analysis task by calling CommitLogFetcher::fetch_for_tasks.
+ Also fixe the bug that we were not taking
+ (format_task): No longer sets 'category' since the computation of category now depends on the list of
+ commits associated with this analysis task which aren't available until fetch_associated_data_for_tasks.
+ (determine_category): Added. Categorize any analysis tasks with "fixes" commits as "closed" and "causes"
+ commits as "identified".
+
+ * public/include/commit-log-fetcher.php:
+ (CommitLogFetcher::__construct): Remove the unused instance variable.
+ (CommitLogFetcher::fetch_for_tasks): Added. Fetches all commits associated with a list of analysis tasks.
+ Assumes the caller (fetch_associated_data_for_tasks) had setup "fixes" and "causes" fields on each task.
+
+ * public/privileged-api/associate-commit.php: Added. Updates task_commits table to associate or disassociate
+ a commit with an analysis task. When the specified analysis task and the specified commit are already
+ associated, we simply update the table instead of adding a duplicating entry or error. For dissociation,
+ the front-end specifies the commit ID.
+ (main): Added.
+
+ * public/v3/index.html:
+ * public/v3/components/mutable-list-view.js: Added. Used by the list associated bugs and commits.
+ (MutableListView): Added.
+ (MutableListView.prototype.setList): Added.
+ (MutableListView.prototype.setKindList): Added.
+ (MutableListView.prototype.setAddCallback): Added. This callback is invoked when the user tries to add
+ a new item to the list.
+ (MutableListView.prototype.render): Added.
+ (MutableListView.prototype._submitted): Added.
+ (MutableListView.cssTemplate):
+ (MutableListView.htmlTemplate):
+ (MutableListItem): Added. RemovalLink could be a hyperlink or a callback and gets involved when the user
+ tries to delete this item.
+ (MutableListItem.prototype.content):
+
+ * public/v3/models/analysis-task.js:
+ (AnalysisTask): Added the support of the list of commits that fixed and caused changes.
+ (AnalysisTask.prototype.updateSingleton): Ditto.
+ (AnalysisTask.prototype.causes): Added.
+ (AnalysisTask.prototype.fixes): Added.
+ (AnalysisTask.prototype.associateCommit): Added. Use the API added at /privileged-api/associate-commit
+ to associate a new commit with this analysis task. Each commit has either caused or fixed the change.
+ (AnalysisTask.prototype.dissociateCommit): Added. Use the same API to disassociate each commit.
+ (AnalysisTask._constructAnalysisTasksFromRawData): Find all commits associated with each analysis task.
+ Because commit log objects use a fake ID fdue to /api/measurement-set not providing commit IDs, we must
+ use CommitLog.findByRemoteId to find each commit instead of usual CommitLog.findById.
+ (AnalysisTask._constructAnalysisTasksFromRawData.resolveCommits): Added.
+
+ * public/v3/models/build-request.js:
+ (BuildRequest.prototype.hasFinished): Renamed from hasCompleted since it was confusing for this._status
+ being "completed" wasn't a necessary condition for this function to return true.
+
+ * public/v3/models/commit-log.js:
+ (CommitLog): Added the static map for actual commit ID instead of a fake ID created in ensureSingleton.
+ (CommitLog.prototype.remoteId): Added. Returns the real commit ID.
+ (CommitLog.findByRemoteId): Added. Finds an CommitLog object using the real ID.
+
+ * public/v3/models/test-group.js:
+ (TestGroup.prototype.hasFinished): Renamed from hasCompleted to match the rename in BuildRequest.
+
+ * public/v3/pages/analysis-task-page.js:
+ (AnalysisTaskPage): Added lists for the commits that fixed and caused the change using MutableListView.
+ Also adopted MutableListView for the list of associated bugs.
+ (AnalysisTaskPage.prototype.render): Added the code to populate the newly added lists.
+ (AnalysisTaskPage.prototype._makeCommitListItem): Added.
+ (AnalysisTaskPage.prototype._associateBug): Now this is a callback from MutableListView.
+ (AnalysisTaskPage.prototype._associateCommit): Added.
+ (AnalysisTaskPage.prototype._dissociateCommit): Added.
+ (AnalysisTaskPage.htmlTemplate):
+ (AnalysisTaskPage.cssTemplate):
+
+ * public/v3/remote.js:
+ (getJSON): Spit out the entire responseText when JSON failed to parse to make debugging easier.
+
</ins><span class="cx"> 2016-03-15 Ryosuke Niwa <rniwa@webkit.org>
</span><span class="cx">
</span><span class="cx"> Extract the code to format commit logs into its own PHP file
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorginitdatabasesql"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/init-database.sql (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/init-database.sql        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/init-database.sql        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -16,6 +16,7 @@
</span><span class="cx"> DROP TABLE reports CASCADE;
</span><span class="cx"> DROP TABLE tracker_repositories CASCADE;
</span><span class="cx"> DROP TABLE bug_trackers CASCADE;
</span><ins>+DROP TABLE task_commits CASCADE;
</ins><span class="cx"> DROP TABLE analysis_tasks CASCADE;
</span><span class="cx"> DROP TABLE analysis_strategies CASCADE;
</span><span class="cx"> DROP TYPE analysis_task_result_type CASCADE;
</span><span class="lines">@@ -202,6 +203,12 @@
</span><span class="cx"> CONSTRAINT analysis_task_should_not_be_associated_with_single_run
</span><span class="cx"> CHECK ((task_start_run IS NULL AND task_end_run IS NULL) OR (task_start_run IS NOT NULL AND task_end_run IS NOT NULL)));
</span><span class="cx">
</span><ins>+CREATE TABLE task_commits (
+ taskcommit_task integer NOT NULL REFERENCES analysis_tasks ON DELETE CASCADE,
+ taskcommit_commit integer NOT NULL REFERENCES commits ON DELETE CASCADE,
+ taskcommit_is_fix boolean NOT NULL
+ CONSTRAINT task_commit_must_be_unique UNIQUE(taskcommit_task, taskcommit_commit));
+
</ins><span class="cx"> CREATE TABLE bugs (
</span><span class="cx"> bug_id serial PRIMARY KEY,
</span><span class="cx"> bug_task integer REFERENCES analysis_tasks NOT NULL,
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicapianalysistasksphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/api/analysis-tasks.php (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/api/analysis-tasks.php        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/api/analysis-tasks.php        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -1,6 +1,7 @@
</span><span class="cx"> <?php
</span><span class="cx">
</span><span class="cx"> require('../include/json-header.php');
</span><ins>+require('../include/commit-log-fetcher.php');
</ins><span class="cx">
</span><span class="cx"> function main($path) {
</span><span class="cx"> $db = new Database;
</span><span class="lines">@@ -42,12 +43,10 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $tasks = array_map("format_task", $tasks);
</span><del>- $bugs = fetch_and_push_bugs_to_tasks($db, $tasks);
-
- exit_with_success(array('analysisTasks' => $tasks, 'bugs' => $bugs));
</del><ins>+ exit_with_success(fetch_associated_data_for_tasks($db, $tasks));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-function fetch_and_push_bugs_to_tasks($db, &$tasks) {
</del><ins>+function fetch_associated_data_for_tasks($db, &$tasks) {
</ins><span class="cx"> $task_ids = array();
</span><span class="cx"> $task_by_id = array();
</span><span class="cx"> foreach ($tasks as &$task) {
</span><span class="lines">@@ -65,10 +64,15 @@
</span><span class="cx"> array_push($associated_task['bugs'], $bug['id']);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ $commit_log_fetcher = new CommitLogFetcher($db);
+ $commits = $commit_log_fetcher->fetch_for_tasks($task_ids, $task_by_id);
+ if (!is_array($commits))
+ exit_with_error('FailedToFetchCommits');
+
</ins><span class="cx"> $task_build_counts = $db->query_and_fetch_all('SELECT
</span><span class="cx"> testgroup_task AS "task",
</span><span class="cx"> count(testgroup_id) as "total",
</span><del>- sum(case when request_status = \'failed\' or request_status = \'completed\' then 1 else 0 end) as "finished"
</del><ins>+ sum(case when request_status = \'failed\' or request_status = \'completed\' or request_status = \'canceled\' then 1 else 0 end) as "finished"
</ins><span class="cx"> FROM analysis_test_groups, build_requests
</span><span class="cx"> WHERE request_group = testgroup_id AND testgroup_task = ANY($1) GROUP BY testgroup_task',
</span><span class="cx"> array('{' . implode(', ', $task_ids) . '}'));
</span><span class="lines">@@ -79,19 +83,13 @@
</span><span class="cx"> $task = &$task_by_id[$build_count['task']];
</span><span class="cx"> $task['buildRequestCount'] = $build_count['total'];
</span><span class="cx"> $task['finishedBuildRequestCount'] = $build_count['finished'];
</span><ins>+ $task['category'] = determine_category($task);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return $bugs;
</del><ins>+ return array('analysisTasks' => $tasks, 'bugs' => $bugs, 'commits' => $commits);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function format_task($task_row) {
</span><del>- $category = 'unconfirmed';
- $result = $task_row['task_result'];
- if ($result == 'unchanged' || $result == 'inconclusive')
- $category = 'closed';
- else if ($result)
- $category = 'bisecting';
-
</del><span class="cx"> return array(
</span><span class="cx"> 'id' => $task_row['task_id'],
</span><span class="cx"> 'name' => $task_row['task_name'],
</span><span class="lines">@@ -105,13 +103,29 @@
</span><span class="cx"> 'startRunTime' => Database::to_js_time($task_row['task_start_run_time']),
</span><span class="cx"> 'endRun' => $task_row['task_end_run'],
</span><span class="cx"> 'endRunTime' => Database::to_js_time($task_row['task_end_run_time']),
</span><del>- 'category' => $category,
- 'result' => $result,
</del><ins>+ 'category' => null,
+ 'result' => $task_row['task_result'],
</ins><span class="cx"> 'needed' => $task_row['task_needed'] ? Database::is_true($task_row['task_needed']) : null,
</span><span class="cx"> 'bugs' => array(),
</span><ins>+ 'causes' => array(),
+ 'fixes' => array(),
</ins><span class="cx"> );
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+function determine_category($task) {
+ $category = 'unconfirmed';
+
+ $result = $task['result'];
+ if ($result == 'unchanged' || $result == 'inconclusive' || $task['fixes'])
+ $category = 'closed';
+ else if ($task['causes'])
+ $category = 'identified';
+ else if ($result)
+ $category = 'bisecting';
+
+ return $category;
+}
+
</ins><span class="cx"> main(array_key_exists('PATH_INFO', $_SERVER) ? explode('/', trim($_SERVER['PATH_INFO'], '/')) : array());
</span><span class="cx">
</span><span class="cx"> ?>
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludecommitlogfetcherphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -4,9 +4,27 @@
</span><span class="cx">
</span><span class="cx"> function __construct($db) {
</span><span class="cx"> $this->db = $db;
</span><del>- $this->commits = array();
</del><span class="cx"> }
</span><span class="cx">
</span><ins>+ function fetch_for_tasks($task_id_list, $task_by_id)
+ {
+ $commit_rows = $this->db->query_and_fetch_all('SELECT task_commits.*, commits.*, committers.*
+ FROM task_commits, commits LEFT OUTER JOIN committers ON commit_committer = committer_id
+ WHERE taskcommit_commit = commit_id AND taskcommit_task = ANY ($1)', array('{' . implode(', ', $task_id_list) . '}'));
+ if (!is_array($commit_rows))
+ return NULL;
+
+ $commits = array();
+ foreach ($commit_rows as &$commit_row) {
+ $associated_task = &$task_by_id[$commit_row['taskcommit_task']];
+ $commit = $this->format_commit($commit_row, $commit_row);
+ $commit['repository'] = $commit_row['commit_repository'];
+ array_push($commits, $commit);
+ array_push($associated_task[Database::is_true($commit_row['taskcommit_is_fix']) ? 'fixes' : 'causes'], $commit_row['commit_id']);
+ }
+ return $commits;
+ }
+
</ins><span class="cx"> function repository_id_from_name($name)
</span><span class="cx"> {
</span><span class="cx"> $repository_row = $this->db->select_first_row('repositories', 'repository', array('name' => $name));
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicprivilegedapiassociatecommitphp"></a>
<div class="addfile"><h4>Added: trunk/Websites/perf.webkit.org/public/privileged-api/associate-commit.php (0 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/privileged-api/associate-commit.php         (rev 0)
+++ trunk/Websites/perf.webkit.org/public/privileged-api/associate-commit.php        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+<?php
+
+require_once('../include/json-header.php');
+
+function main() {
+ $data = ensure_privileged_api_data_and_token();
+
+ $analysis_task_id = array_get($data, 'task');
+ $repository_id = array_get($data, 'repository');
+ $revision = array_get($data, 'revision');
+ $kind = array_get($data, 'kind');
+ $commit_id_to_diassociate = array_get($data, 'commit');
+
+ $db = connect();
+ $db->begin_transaction();
+
+ require_format('AnalysisTask', $analysis_task_id, '/^\d+$/');
+ if ($commit_id_to_diassociate) {
+ require_format('Commit', $commit_id_to_diassociate, '/^\d*$/');
+
+ $count = $db->query_and_get_affected_rows("DELETE FROM task_commits WHERE taskcommit_task = $1 AND taskcommit_commit = $2",
+ array($analysis_task_id, $commit_id_to_diassociate));
+ if ($count != 1) {
+ $db->rollback_transaction();
+ exit_with_error('UnexpectedNumberOfAffectedRows', array('affectedRows' => $count));
+ }
+ } else {
+ require_format('Repository', $repository_id, '/^\d+$/');
+ require_format('Kind', $kind, '/^(cause|fix)$/');
+
+ $commit_info = array('repository' => $repository_id, 'revision' => $revision);
+ $commit_row = $db->select_first_row('commits', 'commit', $commit_info);
+ if (!$commit_row) {
+ $db->rollback_transaction();
+ exit_with_error('CommitNotFound', $commit_info);
+ }
+ $commit_id = $commit_row['commit_id'];
+
+ $association = array('task' => $analysis_task_id, 'commit' => $commit_id, 'is_fix' => Database::to_database_boolean($kind == 'fix'));
+ $commit_id = $db->update_or_insert_row('task_commits', 'taskcommit',
+ array('task' => $analysis_task_id, 'commit' => $commit_id), $association, 'commit');
+ if (!$commit_id) {
+ $db->rollback_transaction();
+ exit_with_error('FailedToAssociateCommit', $association);
+ }
+ }
+
+ $db->commit_transaction();
+
+ exit_with_success();
+}
+
+main();
+
+?>
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentsmutablelistviewjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/perf.webkit.org/public/v3/components/mutable-list-view.js (0 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/mutable-list-view.js         (rev 0)
+++ trunk/Websites/perf.webkit.org/public/v3/components/mutable-list-view.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -0,0 +1,104 @@
</span><ins>+
+
+class MutableListView extends ComponentBase {
+
+ constructor()
+ {
+ super('mutable-list-view');
+ this._list = [];
+ this._kindList = [];
+ this._addCallback = null;
+ this._kindMap = new Map;
+ this.content().querySelector('form').onsubmit = this._submitted.bind(this);
+ }
+
+ setList(list) { this._list = list; }
+ setKindList(list) { this._kindList = list; }
+ setAddCallback(callback) { this._addCallback = callback; }
+
+ render()
+ {
+ this.renderReplace(this.content().querySelector('.mutable-list'),
+ this._list.map(function (item) {
+ console.assert(item instanceof MutableListItem);
+ return item.content();
+ }));
+
+ var element = ComponentBase.createElement;
+ var kindMap = this._kindMap;
+ kindMap.clear();
+ this.renderReplace(this.content().querySelector('.kind'),
+ this._kindList.map(function (kind) {
+ kindMap.set(kind.id(), kind);
+ return element('option', {value: kind.id()}, kind.label());
+ }));
+ }
+
+ _submitted(event)
+ {
+ event.preventDefault();
+ if (this._addCallback)
+ this._addCallback(this._kindMap.get(this.content().querySelector('.kind').value), this.content().querySelector('.value').value);
+ }
+
+ static cssTemplate()
+ {
+ return `
+ .mutable-list,
+ .mutable-list li {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ .mutable-list:not(:empty) {
+ margin-bottom: 1rem;
+ }
+
+ .mutable-list {
+ margin-bottom: 1rem;
+ }
+
+ .new-list-item-form {
+ white-space: nowrap;
+ }
+ `;
+ }
+
+ static htmlTemplate()
+ {
+ return `
+ <ul class="mutable-list"></ul>
+ <form class="new-list-item-form">
+ <select class="kind"></select>
+ <input class="value">
+ <button type="submit">Add</button>
+ </form>`;
+ }
+
+}
+
+class MutableListItem {
+ constructor(kind, value, valueTitle, valueLink, removalTitle, removalLink)
+ {
+ this._kind = kind;
+ this._value = value;
+ this._valueTitle = valueTitle;
+ this._valueLink = valueLink;
+ this._removalTitle = removalTitle;
+ this._removalLink = removalLink;
+ }
+
+ content()
+ {
+ var link = ComponentBase.createLink;
+ return ComponentBase.createElement('li', [
+ this._kind.label(),
+ ' ',
+ link(this._value, this._valueTitle, this._valueLink),
+ ' ',
+ link(new CloseButton, this._removalTitle, this._removalLink)]);
+ }
+}
+
+ComponentBase.defineElement('mutable-list-view', MutableListView);
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3indexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/index.html (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/index.html        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/index.html        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -79,6 +79,7 @@
</span><span class="cx"> <script src="components/customizable-test-group-form.js"></script>
</span><span class="cx"> <script src="components/chart-styles.js"></script>
</span><span class="cx"> <script src="components/chart-pane-base.js"></script>
</span><ins>+ <script src="components/mutable-list-view.js"></script>
</ins><span class="cx"> <script src="pages/page.js"></script>
</span><span class="cx"> <script src="pages/page-router.js"></script>
</span><span class="cx"> <script src="pages/heading.js"></script>
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsanalysistaskjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -20,6 +20,8 @@
</span><span class="cx"> this._changeType = object.result; // Can't change due to v2 compatibility.
</span><span class="cx"> this._needed = object.needed;
</span><span class="cx"> this._bugs = object.bugs || [];
</span><ins>+ this._causes = object.causes || [];
+ this._fixes = object.fixes || [];
</ins><span class="cx"> this._buildRequestCount = object.buildRequestCount;
</span><span class="cx"> this._finishedBuildRequestCount = object.finishedBuildRequestCount;
</span><span class="cx"> }
</span><span class="lines">@@ -46,6 +48,8 @@
</span><span class="cx"> this._changeType = object.result; // Can't change due to v2 compatibility.
</span><span class="cx"> this._needed = object.needed;
</span><span class="cx"> this._bugs = object.bugs || [];
</span><ins>+ this._causes = object.causes || [];
+ this._fixes = object.fixes || [];
</ins><span class="cx"> this._buildRequestCount = object.buildRequestCount;
</span><span class="cx"> this._finishedBuildRequestCount = object.finishedBuildRequestCount;
</span><span class="cx"> }
</span><span class="lines">@@ -62,6 +66,8 @@
</span><span class="cx"> author() { return this._author || ''; }
</span><span class="cx"> createdAt() { return this._createdAt; }
</span><span class="cx"> bugs() { return this._bugs; }
</span><ins>+ causes() { return this._causes; }
+ fixes() { return this._fixes; }
</ins><span class="cx"> platform() { return this._platform; }
</span><span class="cx"> metric() { return this._metric; }
</span><span class="cx"> category() { return this._category; }
</span><span class="lines">@@ -110,6 +116,35 @@
</span><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ associateCommit(kind, repository, revision)
+ {
+ console.assert(kind == 'cause' || kind == 'fix');
+ console.assert(repository instanceof Repository);
+ var id = this.id();
+ return PrivilegedAPI.sendRequest('associate-commit', {
+ task: id,
+ repository: repository.id(),
+ revision: revision,
+ kind: kind,
+ }).then(function (data) {
+ return AnalysisTask.cachedFetch('../api/analysis-tasks', {id: id}, true)
+ .then(AnalysisTask._constructAnalysisTasksFromRawData.bind(AnalysisTask));
+ });
+ }
+
+ dissociateCommit(commit)
+ {
+ console.assert(commit instanceof CommitLog);
+ var id = this.id();
+ return PrivilegedAPI.sendRequest('associate-commit', {
+ task: id,
+ commit: commit.remoteId(),
+ }).then(function (data) {
+ return AnalysisTask.cachedFetch('../api/analysis-tasks', {id: id}, true)
+ .then(AnalysisTask._constructAnalysisTasksFromRawData.bind(AnalysisTask));
+ });
+ }
+
</ins><span class="cx"> static categories()
</span><span class="cx"> {
</span><span class="cx"> return [
</span><span class="lines">@@ -193,6 +228,17 @@
</span><span class="cx"> taskToBug[rawData.task].push(bug);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ for (var rawData of data.commits) {
+ rawData.repository = Repository.findById(rawData.repository);
+ if (!rawData.repository)
+ continue;
+ CommitLog.ensureSingleton(rawData.repository, rawData);
+ }
+
+ function resolveCommits(commits) {
+ return commits.map(function (id) { return CommitLog.findByRemoteId(id); }).filter(function (commit) { return !!commit; });
+ }
+
</ins><span class="cx"> var results = [];
</span><span class="cx"> for (var rawData of data.analysisTasks) {
</span><span class="cx"> rawData.platform = Platform.findById(rawData.platform);
</span><span class="lines">@@ -201,6 +247,8 @@
</span><span class="cx"> continue;
</span><span class="cx">
</span><span class="cx"> rawData.bugs = taskToBug[rawData.id];
</span><ins>+ rawData.causes = resolveCommits(rawData.causes);
+ rawData.fixes = resolveCommits(rawData.fixes);
</ins><span class="cx"> results.push(AnalysisTask.ensureSingleton(rawData.id, rawData));
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsbuildrequestjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/build-request.js (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/build-request.js        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/models/build-request.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -30,7 +30,7 @@
</span><span class="cx"> order() { return this._order; }
</span><span class="cx"> rootSet() { return this._rootSet; }
</span><span class="cx">
</span><del>- hasCompleted() { return this._status == 'failed' || this._status == 'completed' || this._status == 'canceled'; }
</del><ins>+ hasFinished() { return this._status == 'failed' || this._status == 'completed' || this._status == 'canceled'; }
</ins><span class="cx"> hasStarted() { return this._status != 'pending'; }
</span><span class="cx"> hasPending() { return this._status == 'pending'; }
</span><span class="cx"> statusLabel()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelscommitlogjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -5,8 +5,19 @@
</span><span class="cx"> super(id);
</span><span class="cx"> this._repository = rawData.repository;
</span><span class="cx"> this._rawData = rawData;
</span><ins>+ this._remoteId = rawData.id;
+ if (this._remoteId)
+ this.ensureNamedStaticMap('remoteId')[this._remoteId] = this;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ // FIXME: All this non-sense should go away once measurement-set start returning real commit id.
+ remoteId() { return this._remoteId; }
+ static findByRemoteId(id)
+ {
+ var remoteIdMap = super.namedStaticMap('remoteId');
+ return remoteIdMap ? remoteIdMap[id] : null;
+ }
+
</ins><span class="cx"> static ensureSingleton(repository, rawData)
</span><span class="cx"> {
</span><span class="cx"> var id = repository.id() + '-' + rawData['revision'];
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelstestgroupjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/test-group.js (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/test-group.js        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/models/test-group.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -99,9 +99,9 @@
</span><span class="cx"> this._allRootSets = null;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- hasCompleted()
</del><ins>+ hasFinished()
</ins><span class="cx"> {
</span><del>- return this._buildRequests.every(function (request) { return request.hasCompleted(); });
</del><ins>+ return this._buildRequests.every(function (request) { return request.hasFinished(); });
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> hasStarted()
</span><span class="lines">@@ -126,7 +126,7 @@
</span><span class="cx">
</span><span class="cx"> var result = {changeType: null, status: 'failed', label: 'Failed', fullLabel: 'Failed', isStatisticallySignificant: false};
</span><span class="cx">
</span><del>- var hasCompleted = this.hasCompleted();
</del><ins>+ var hasCompleted = this.hasFinished();
</ins><span class="cx"> if (!hasCompleted) {
</span><span class="cx"> if (this.hasStarted()) {
</span><span class="cx"> result.status = 'running';
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -61,10 +61,16 @@
</span><span class="cx"> this.content().querySelector('.change-type-form').onsubmit = this._updateChangeType.bind(this);
</span><span class="cx"> this._taskStatusControl = this.content().querySelector('.change-type-form select');
</span><span class="cx">
</span><del>- this.content().querySelector('.associate-bug-form').onsubmit = this._associateBug.bind(this);
- this._bugTrackerControl = this.content().querySelector('.bug-tracker-control');
- this._bugNumberControl = this.content().querySelector('.bug-number-control');
</del><ins>+ this._bugList = this.content().querySelector('.associated-bugs mutable-list-view').component();
+ this._bugList.setKindList(BugTracker.all());
+ this._bugList.setAddCallback(this._associateBug.bind(this));
</ins><span class="cx">
</span><ins>+ this._causeList = this.content().querySelector('.cause-list mutable-list-view').component();
+ this._causeList.setAddCallback(this._associateCommit.bind(this, 'cause'));
+
+ this._fixList = this.content().querySelector('.fix-list mutable-list-view').component();
+ this._fixList.setAddCallback(this._associateCommit.bind(this, 'fix'));
+
</ins><span class="cx"> this._newTestGroupFormForChart = this.content().querySelector('.overview-chart customizable-test-group-form').component();
</span><span class="cx"> this._newTestGroupFormForChart.setStartCallback(this._createNewTestGroupFromChart.bind(this));
</span><span class="cx">
</span><span class="lines">@@ -229,25 +235,33 @@
</span><span class="cx"> this.renderReplace(anchor, metric.fullName() + ' on ' + platform.label());
</span><span class="cx"> anchor.href = this.router().url('charts', ChartsPage.createStateForAnalysisTask(this._task));
</span><span class="cx">
</span><del>- var bugs = [];
- for (var bug of this._task.bugs()) {
- bugs.push(element('li', [
- bug.bugTracker().label() + ' ',
- link(bug.label(), bug.title(), bug.url()),
- ' ',
- link(new CloseButton, 'Disassociate this bug', this._disassociateBug.bind(this, bug))]));
- }
- this.renderReplace(this.content().querySelector('.associated-bugs'), bugs);
</del><ins>+ var self = this;
+ this._bugList.setList(this._task.bugs().map(function (bug) {
+ return new MutableListItem(bug.bugTracker(), bug.label(), bug.title(), bug.url(),
+ 'Disassociate this bug', self._disassociateBug.bind(self, bug));
+ }));
</ins><span class="cx">
</span><ins>+ this._causeList.setList(this._task.causes().map(this._makeCommitListItem.bind(this)));
+ this._fixList.setList(this._task.fixes().map(this._makeCommitListItem.bind(this)));
+
</ins><span class="cx"> this._taskStatusControl.value = this._task.changeType() || 'unconfirmed';
</span><span class="cx"> }
</span><span class="cx">
</span><del>- var element = ComponentBase.createElement;
- this.renderReplace(this._bugTrackerControl,
- BugTracker.all().map(function (tracker) {
- return element('option', {value: tracker.id()}, tracker.label());
- }));
</del><ins>+ var repositoryList;
+ if (this._startPoint) {
+ var rootSet = this._startPoint.rootSet();
+ repositoryList = Repository.sortByNamePreferringOnesWithURL(rootSet.repositories());
+ } else
+ repositoryList = Repository.sortByNamePreferringOnesWithURL(Repository.all());
</ins><span class="cx">
</span><ins>+ this._bugList.render();
+
+ this._causeList.setKindList(repositoryList);
+ this._causeList.render();
+
+ this._fixList.setKindList(repositoryList);
+ this._fixList.render();
+
</ins><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><span class="cx"> this.content().querySelector('.test-group-view').style.display = this._task ? null : 'none';
</span><span class="lines">@@ -290,6 +304,12 @@
</span><span class="cx"> Instrumentation.endMeasuringTime('AnalysisTaskPage', 'render');
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ _makeCommitListItem(commit)
+ {
+ return new MutableListItem(commit.repository(), commit.label(), commit.title(), commit.url(),
+ 'Disassociate this commit', this._dissociateCommit.bind(this, commit));
+ }
+
</ins><span class="cx"> _renderTestGroupList()
</span><span class="cx"> {
</span><span class="cx"> var element = ComponentBase.createElement;
</span><span class="lines">@@ -446,15 +466,11 @@
</span><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><del>- _associateBug(event)
</del><ins>+ _associateBug(tracker, bugNumber)
</ins><span class="cx"> {
</span><del>- event.preventDefault();
- console.assert(this._task);
</del><ins>+ console.assert(tracker instanceof BugTracker);
+ bugNumber = parseInt(bugNumber);
</ins><span class="cx">
</span><del>- var tracker = BugTracker.findById(this._bugTrackerControl.value);
- console.assert(tracker);
- var bugNumber = parseInt(this._bugNumberControl.value);
-
</del><span class="cx"> var render = this.render.bind(this);
</span><span class="cx"> return this._task.associateBug(tracker, bugNumber).then(render, function (error) {
</span><span class="cx"> render();
</span><span class="lines">@@ -471,6 +487,24 @@
</span><span class="cx"> });
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ _associateCommit(kind, repository, revision)
+ {
+ var render = this.render.bind(this);
+ return this._task.associateCommit(kind, repository, revision).then(render, function (error) {
+ render();
+ alert('Failed to associate the commit: ' + error);
+ });
+ }
+
+ _dissociateCommit(commit)
+ {
+ var render = this.render.bind(this);
+ return this._task.dissociateCommit(commit).then(render, function (error) {
+ render();
+ alert('Failed to disassociate the commit: ' + error);
+ });
+ }
+
</ins><span class="cx"> _retryCurrentTestGroup(repetitionCount)
</span><span class="cx"> {
</span><span class="cx"> console.assert(this._currentTestGroup);
</span><span class="lines">@@ -595,15 +629,16 @@
</span><span class="cx"> <button type="submit">Save</button>
</span><span class="cx"> </form>
</span><span class="cx"> </section>
</span><del>- <section>
</del><ins>+ <section class="associated-bugs">
</ins><span class="cx"> <h3>Associated Bugs</h3>
</span><del>- <ul class="associated-bugs"></ul>
- <form class="associate-bug-form">
- <select class="bug-tracker-control"></select>
- <input type="number" class="bug-number-control">
- <button type="submit">Add</button>
- </form>
</del><ins>+ <mutable-list-view></mutable-list-view>
</ins><span class="cx"> </section>
</span><ins>+ <section class="cause-fix">
+ <h3>Caused by</h3>
+ <span class="cause-list"><mutable-list-view></mutable-list-view></span>
+ <h3>Fixed by</h3>
+ <span class="fix-list"><mutable-list-view></mutable-list-view></span>
+ </section>
</ins><span class="cx"> <section class="related-tasks">
</span><span class="cx"> <h3>Related Tasks</h3>
</span><span class="cx"> <ul class="related-tasks-list"></ul>
</span><span class="lines">@@ -680,18 +715,20 @@
</span><span class="cx">
</span><span class="cx"> .analysis-task-status > section {
</span><span class="cx"> flex-grow: 1;
</span><ins>+ flex-shrink: 0;
</ins><span class="cx"> border-left: solid 1px #eee;
</span><span class="cx"> padding-left: 1rem;
</span><ins>+ padding-right: 1rem;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ .analysis-task-status > section.related-tasks {
+ flex-shrink: 1;
+ }
+
</ins><span class="cx"> .analysis-task-status > section:first-child {
</span><span class="cx"> border-left: none;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- .associated-bugs:not(:empty) {
- margin-bottom: 1rem;
- }
-
</del><span class="cx"> .analysis-task-status h3 {
</span><span class="cx"> font-size: 1rem;
</span><span class="cx"> font-weight: inherit;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3remotejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/remote.js (198264 => 198265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/remote.js        2016-03-16 06:48:53 UTC (rev 198264)
+++ trunk/Websites/perf.webkit.org/public/v3/remote.js        2016-03-16 07:02:28 UTC (rev 198265)
</span><span class="lines">@@ -19,6 +19,7 @@
</span><span class="cx"> var parsed = JSON.parse(xhr.responseText);
</span><span class="cx"> resolve(parsed);
</span><span class="cx"> } catch (error) {
</span><ins>+ console.error(xhr.responseText);
</ins><span class="cx"> reject(xhr.status + ', ' + error);
</span><span class="cx"> }
</span><span class="cx"> };
</span></span></pre>
</div>
</div>
</body>
</html>