<!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>[213788] 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/213788">213788</a></dd>
<dt>Author</dt> <dd>dewei_zhu@apple.com</dd>
<dt>Date</dt> <dd>2017-03-13 02:10:29 -0700 (Mon, 13 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add the ability to report a commit with sub-commits.
https://bugs.webkit.org/show_bug.cgi?id=168962

Reviewed by Ryosuke Niwa.

Introduce 'commit_ownerships' which records ownership between commits.
On existing production server, run ```
    CREATE TABLE commit_ownerships (
        commit_owner integer NOT NULL REFERENCES commits ON DELETE CASCADE,
        commit_ownee integer NOT NULL REFERENCES commits ON DELETE CASCADE,
        PRIMARY KEY (commit_owner, commit_ownee)
    );
    ALTER TABLE repositories RENAME repository_parent TO repository_owner;
    ALTER TABLE repositories DROP repository_name_must_be_unique;
    CREATE UNIQUE INDEX repository_name_owner_unique_index ON repositories (repository_owner, repository_name) WHERE repository_owner IS NOT NULL;
    CREATE UNIQUE INDEX repository_name_unique_index ON repositories (repository_name) WHERE repository_owner IS NULL;
``` to update database.
Add unit-tests to cover this change.

* init-database.sql:
* public/api/report-commits.php:
* public/include/commit-log-fetcher.php:
* public/include/db.php:
* public/include/manifest-generator.php:
* public/include/report-processor.php:
* public/v3/models/repository.js:
(Repository):
(Repository.prototype.owner):
* server-tests/admin-reprocess-report-tests.js:
(addBuilderForReport.simpleReportWithRevisions.0.then):
(then):
* server-tests/api-manifest.js:
(then):
* server-tests/api-report-commits-tests.js:
(addSlaveForReport.sameRepositoryNameInSubCommitAndMajorCommit.then):
(then):
(addSlaveForReport.systemVersionCommitWithSubcommits.then):
(addSlaveForReport.multipleSystemVersionCommitsWithSubcommits.then):
(addSlaveForReport.systemVersionCommitWithEmptySubcommits.then):
(addSlaveForReport.systemVersionCommitAndSubcommitWithTimestamp.then):
* tools/js/database.js:</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="#trunkWebsitesperfwebkitorgpublicapireportcommitsphp">trunk/Websites/perf.webkit.org/public/api/report-commits.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludecommitlogfetcherphp">trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludedbphp">trunk/Websites/perf.webkit.org/public/include/db.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludemanifestgeneratorphp">trunk/Websites/perf.webkit.org/public/include/manifest-generator.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludereportprocessorphp">trunk/Websites/perf.webkit.org/public/include/report-processor.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsrepositoryjs">trunk/Websites/perf.webkit.org/public/v3/models/repository.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgservertestsadminreprocessreporttestsjs">trunk/Websites/perf.webkit.org/server-tests/admin-reprocess-report-tests.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgservertestsapimanifestjs">trunk/Websites/perf.webkit.org/server-tests/api-manifest.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgservertestsapireportcommitstestsjs">trunk/Websites/perf.webkit.org/server-tests/api-report-commits-tests.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgtoolsjsdatabasejs">trunk/Websites/perf.webkit.org/tools/js/database.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 (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -1,3 +1,47 @@
</span><ins>+2017-03-13  Dewei Zhu  &lt;dewei_zhu@apple.com&gt;
+
+        Add the ability to report a commit with sub-commits.
+        https://bugs.webkit.org/show_bug.cgi?id=168962
+
+        Reviewed by Ryosuke Niwa.
+
+        Introduce 'commit_ownerships' which records ownership between commits.
+        On existing production server, run ```
+            CREATE TABLE commit_ownerships (
+                commit_owner integer NOT NULL REFERENCES commits ON DELETE CASCADE,
+                commit_ownee integer NOT NULL REFERENCES commits ON DELETE CASCADE,
+                PRIMARY KEY (commit_owner, commit_ownee)
+            );
+            ALTER TABLE repositories RENAME repository_parent TO repository_owner;
+            ALTER TABLE repositories DROP repository_name_must_be_unique;
+            CREATE UNIQUE INDEX repository_name_owner_unique_index ON repositories (repository_owner, repository_name) WHERE repository_owner IS NOT NULL;
+            CREATE UNIQUE INDEX repository_name_unique_index ON repositories (repository_name) WHERE repository_owner IS NULL;
+        ``` to update database.
+        Add unit-tests to cover this change.
+
+        * init-database.sql:
+        * public/api/report-commits.php:
+        * public/include/commit-log-fetcher.php:
+        * public/include/db.php:
+        * public/include/manifest-generator.php:
+        * public/include/report-processor.php:
+        * public/v3/models/repository.js:
+        (Repository):
+        (Repository.prototype.owner):
+        * server-tests/admin-reprocess-report-tests.js:
+        (addBuilderForReport.simpleReportWithRevisions.0.then):
+        (then):
+        * server-tests/api-manifest.js:
+        (then):
+        * server-tests/api-report-commits-tests.js:
+        (addSlaveForReport.sameRepositoryNameInSubCommitAndMajorCommit.then):
+        (then):
+        (addSlaveForReport.systemVersionCommitWithSubcommits.then):
+        (addSlaveForReport.multipleSystemVersionCommitsWithSubcommits.then):
+        (addSlaveForReport.systemVersionCommitWithEmptySubcommits.then):
+        (addSlaveForReport.systemVersionCommitAndSubcommitWithTimestamp.then):
+        * tools/js/database.js:
+
</ins><span class="cx"> 2017-03-07  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Update ReadMe.md to use directory format for backing up &amp; restoring the database
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorginitdatabasesql"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/init-database.sql (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/init-database.sql        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/init-database.sql        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -7,6 +7,7 @@
</span><span class="cx"> DROP TABLE IF EXISTS committers CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS commits CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS build_commits CASCADE;
</span><ins>+DROP TABLE IF EXISTS commit_ownerships CASCADE;
</ins><span class="cx"> DROP TABLE IF EXISTS build_slaves CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS builders CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS repositories CASCADE;
</span><span class="lines">@@ -38,12 +39,16 @@
</span><span class="cx"> 
</span><span class="cx"> CREATE TABLE repositories (
</span><span class="cx">     repository_id serial PRIMARY KEY,
</span><del>-    repository_parent integer REFERENCES repositories ON DELETE CASCADE,
</del><ins>+    repository_owner integer REFERENCES repositories ON DELETE CASCADE,
</ins><span class="cx">     repository_name varchar(64) NOT NULL,
</span><span class="cx">     repository_url varchar(1024),
</span><del>-    repository_blame_url varchar(1024),
-    CONSTRAINT repository_name_must_be_unique UNIQUE(repository_parent, repository_name));
</del><ins>+    repository_blame_url varchar(1024));
</ins><span class="cx"> 
</span><ins>+CREATE UNIQUE INDEX repository_name_owner_unique_index ON repositories (repository_owner, repository_name)
+    WHERE repository_owner IS NOT NULL;
+CREATE UNIQUE INDEX repository_name_unique_index ON repositories (repository_name)
+    WHERE repository_owner IS NULL;
+
</ins><span class="cx"> CREATE TABLE bug_trackers (
</span><span class="cx">     tracker_id serial PRIMARY KEY,
</span><span class="cx">     tracker_name varchar(64) NOT NULL,
</span><span class="lines">@@ -98,6 +103,12 @@
</span><span class="cx"> CREATE INDEX commit_time_index ON commits(commit_time);
</span><span class="cx"> CREATE INDEX commit_order_index ON commits(commit_order);
</span><span class="cx"> 
</span><ins>+CREATE TABLE commit_ownerships (
+    commit_owner integer NOT NULL REFERENCES commits ON DELETE CASCADE,
+    commit_owned integer NOT NULL REFERENCES commits ON DELETE CASCADE,
+    PRIMARY KEY (commit_owner, commit_owned)
+);
+
</ins><span class="cx"> CREATE TABLE build_commits (
</span><span class="cx">     commit_build integer NOT NULL REFERENCES builds ON DELETE CASCADE,
</span><span class="cx">     build_commit integer NOT NULL REFERENCES commits ON DELETE CASCADE,
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicapireportcommitsphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/api/report-commits.php (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/api/report-commits.php        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/public/api/report-commits.php        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -2,7 +2,8 @@
</span><span class="cx"> 
</span><span class="cx"> require('../include/json-header.php');
</span><span class="cx"> 
</span><del>-function main($post_data) {
</del><ins>+function main($post_data)
+{
</ins><span class="cx">     $db = new Database;
</span><span class="cx">     if (!$db-&gt;connect())
</span><span class="cx">         exit_with_error('DatabaseConnectionFailure');
</span><span class="lines">@@ -25,50 +26,27 @@
</span><span class="cx"> 
</span><span class="cx">     $db-&gt;begin_transaction();
</span><span class="cx">     foreach ($commits as $commit_info) {
</span><del>-        $repository_id = $db-&gt;select_or_insert_row('repositories', 'repository', array('name' =&gt; $commit_info['repository']));
</del><ins>+        $repository_id = $db-&gt;select_or_insert_repository_row($commit_info['repository'], NULL);
</ins><span class="cx">         if (!$repository_id) {
</span><span class="cx">             $db-&gt;rollback_transaction();
</span><span class="cx">             exit_with_error('FailedToInsertRepository', array('commit' =&gt; $commit_info));
</span><span class="cx">         }
</span><ins>+        $owner_commit_id = insert_commit($db, $commit_info, $repository_id, NULL);
+        if (!array_key_exists('subCommits', $commit_info))
+            continue;
</ins><span class="cx"> 
</span><del>-        $author = array_get($commit_info, 'author');
-        $committer_id = NULL;
-        if ($author) {
-            $account = array_get($author, 'account');
-            $committer_query = array('repository' =&gt; $repository_id, 'account' =&gt; $account);
-            $committer_data = $committer_query;
-            $name = array_get($author, 'name');
-            if ($name)
-                $committer_data['name'] = $name;
-            $committer_id = $db-&gt;update_or_insert_row('committers', 'committer', $committer_query, $committer_data);
-            if (!$committer_id) {
</del><ins>+        foreach($commit_info['subCommits'] as $sub_commit_repository_name =&gt; $sub_commit_info) {
+            if (array_key_exists('time', $sub_commit_info)) {
</ins><span class="cx">                 $db-&gt;rollback_transaction();
</span><del>-                exit_with_error('FailedToInsertCommitter', array('committer' =&gt; $committer_data));
</del><ins>+                exit_with_error('SubCommitShouldNotContainTimestamp', array('commit' =&gt; $sub_commit_info));
</ins><span class="cx">             }
</span><del>-        }
-
-        $previous_commit_revision = array_get($commit_info, 'previousCommit');
-        $previous_commit_id = NULL;
-        if ($previous_commit_revision) {
-            $previous_commit = $db-&gt;select_first_row('commits', 'commit', array('repository' =&gt; $repository_id, 'revision' =&gt; $previous_commit_revision));
-            if (!$previous_commit) {
</del><ins>+            $sub_commit_repository_id = $db-&gt;select_or_insert_repository_row($sub_commit_repository_name, $repository_id);
+            if (!$sub_commit_repository_id) {
</ins><span class="cx">                 $db-&gt;rollback_transaction();
</span><del>-                exit_with_error('FailedToFindPreviousCommit', array('commit' =&gt; $commit_info));
</del><ins>+                exit_with_error('FailedToInsertRepository', array('commit' =&gt; $sub_commit_info));
</ins><span class="cx">             }
</span><del>-            $previous_commit_id = $previous_commit['commit_id'];
</del><ins>+            insert_commit($db, $sub_commit_info, $sub_commit_repository_id, $owner_commit_id);
</ins><span class="cx">         }
</span><del>-
-        $data = array(
-            'repository' =&gt; $repository_id,
-            'revision' =&gt; $commit_info['revision'],
-            'previous_commit' =&gt; $previous_commit_id,
-            'order' =&gt; array_get($commit_info, 'order'),
-            'time' =&gt; array_get($commit_info, 'time'),
-            'committer' =&gt; $committer_id,
-            'message' =&gt; array_get($commit_info, 'message'),
-            'reported' =&gt; true,
-        );
-        $db-&gt;update_or_insert_row('commits', 'commit', array('repository' =&gt; $repository_id, 'revision' =&gt; $data['revision']), $data);
</del><span class="cx">     }
</span><span class="cx">     $db-&gt;commit_transaction();
</span><span class="cx"> 
</span><span class="lines">@@ -75,6 +53,52 @@
</span><span class="cx">     exit_with_success();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function insert_commit($db, $commit_info, $repository_id, $owner_commit_id)
+{
+    $author = array_get($commit_info, 'author');
+    $committer_id = NULL;
+    if ($author) {
+        $account = array_get($author, 'account');
+        $committer_query = array('repository' =&gt; $repository_id, 'account' =&gt; $account);
+        $committer_data = $committer_query;
+        $name = array_get($author, 'name');
+        if ($name)
+            $committer_data['name'] = $name;
+        $committer_id = $db-&gt;update_or_insert_row('committers', 'committer', $committer_query, $committer_data);
+        if (!$committer_id) {
+            $db-&gt;rollback_transaction();
+            exit_with_error('FailedToInsertCommitter', array('committer' =&gt; $committer_data));
+        }
+    }
+
+    $previous_commit_revision = array_get($commit_info, 'previousCommit');
+    $previous_commit_id = NULL;
+    if ($previous_commit_revision) {
+        $previous_commit = $db-&gt;select_first_row('commits', 'commit', array('repository' =&gt; $repository_id, 'revision' =&gt; $previous_commit_revision));
+        if (!$previous_commit) {
+            $db-&gt;rollback_transaction();
+            exit_with_error('FailedToFindPreviousCommit', array('commit' =&gt; $commit_info));
+        }
+        $previous_commit_id = $previous_commit['commit_id'];
+    }
+
+    $data = array(
+        'repository' =&gt; $repository_id,
+        'revision' =&gt; $commit_info['revision'],
+        'previous_commit' =&gt; $previous_commit_id,
+        'order' =&gt; array_get($commit_info, 'order'),
+        'time' =&gt; array_get($commit_info, 'time'),
+        'committer' =&gt; $committer_id,
+        'message' =&gt; array_get($commit_info, 'message'),
+        'reported' =&gt; true,
+    );
+    $inserted_commit_id = $db-&gt;update_or_insert_row('commits', 'commit', array('repository' =&gt; $repository_id, 'revision' =&gt; $data['revision']), $data);
+
+    if ($owner_commit_id)
+        $db-&gt;select_or_insert_row('commit_ownerships', 'commit', array('owner' =&gt; $owner_commit_id, 'owned' =&gt; $inserted_commit_id), NULL, '*');
+    return $inserted_commit_id;
+}
+
</ins><span class="cx"> main($HTTP_RAW_POST_DATA);
</span><span class="cx"> 
</span><span class="cx"> ?&gt;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludecommitlogfetcherphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -27,10 +27,10 @@
</span><span class="cx"> 
</span><span class="cx">     function repository_id_from_name($name)
</span><span class="cx">     {
</span><del>-        $repository_row = $this-&gt;db-&gt;select_first_row('repositories', 'repository', array('name' =&gt; $name));
</del><ins>+        $repository_row = $this-&gt;db-&gt;query_and_fetch_all('SELECT repository_id FROM repositories WHERE repository_name = $1 AND repository_owner is NULL', array($name));
</ins><span class="cx">         if (!$repository_row)
</span><span class="cx">             return NULL;
</span><del>-        return $repository_row['repository_id'];
</del><ins>+        return $repository_row[0]['repository_id'];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function fetch_between($repository_id, $first, $second, $keyword = NULL) {
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludedbphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/db.php (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/db.php        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/public/include/db.php        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -188,6 +188,26 @@
</span><span class="cx">         return $rows ? ($returning == '*' ? $rows[0] : $rows[0][$returning_column_name]) : NULL;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // FIXME: Should improve _select_update_or_insert_row to handle the NULL column case.
+    function select_or_insert_repository_row($repository_name, $repository_owner_id)
+    {
+        $result = NULL;
+        if ($repository_owner_id == NULL) {
+            $result = $this-&gt;query_and_fetch_all('INSERT INTO repositories (repository_name) SELECT $1
+                WHERE NOT EXISTS (SELECT repository_id FROM repositories WHERE repository_name = $2 AND repository_owner IS NULL) RETURNING repository_id',
+                array($repository_name, $repository_name));
+            if (!$result)
+                $result = $this-&gt;query_and_fetch_all('SELECT repository_id FROM repositories WHERE repository_name = $1 AND repository_owner IS NULL', array($repository_name));
+        } else {
+            $result = $this-&gt;query_and_fetch_all('INSERT INTO repositories (repository_name, repository_owner) SELECT $1, $2
+                WHERE NOT EXISTS (SELECT repository_id FROM repositories WHERE (repository_name, repository_owner) = ($3, $4)) RETURNING repository_id',
+                array($repository_name, $repository_owner_id, $repository_name, $repository_owner_id));
+            if (!$result)
+                $result = $this-&gt;query_and_fetch_all('SELECT repository_id FROM repositories WHERE (repository_name, repository_owner) = ($1, $2)', array($repository_name, $repository_owner_id));
+        }
+        return $result ? $result[0]['repository_id'] : NULL;
+    }
+
</ins><span class="cx">     function select_first_row($table, $prefix, $params, $order_by = NULL) {
</span><span class="cx">         return $this-&gt;select_first_or_last_row($table, $prefix, $params, $order_by, FALSE);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludemanifestgeneratorphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/manifest-generator.php (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/manifest-generator.php        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/public/include/manifest-generator.php        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -138,6 +138,7 @@
</span><span class="cx">                 'name' =&gt; $row['repository_name'],
</span><span class="cx">                 'url' =&gt; $row['repository_url'],
</span><span class="cx">                 'blameUrl' =&gt; $row['repository_blame_url'],
</span><ins>+                'owner'=&gt; $row['repository_owner'],
</ins><span class="cx">                 'hasReportedCommits' =&gt; in_array($row['repository_id'], $repositories_with_commit));
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicincludereportprocessorphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/include/report-processor.php (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/report-processor.php        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/public/include/report-processor.php        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -150,7 +150,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">         foreach ($revisions as $repository_name =&gt; $revision_data) {
</span><del>-            $repository_id = $this-&gt;db-&gt;select_or_insert_row('repositories', 'repository', array('name' =&gt; $repository_name));
</del><ins>+            $repository_id = $this-&gt;db-&gt;select_or_insert_repository_row($repository_name, NULL);
</ins><span class="cx">             if (!$repository_id)
</span><span class="cx">                 $this-&gt;exit_with_error('FailedToInsertRepository', array('name' =&gt; $repository_name));
</span><span class="cx"> 
</span><span class="lines">@@ -309,7 +309,7 @@
</span><span class="cx">                 foreach ($aggregators_and_values as $aggregator_and_values) {
</span><span class="cx">                     if ($aggregator_and_values['aggregator'] == $aggregator) {
</span><span class="cx">                         $values = $aggregator_and_values['values'];
</span><del>-                        break;                        
</del><ins>+                        break;
</ins><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx">                 if (!$values) {
</span><span class="lines">@@ -404,7 +404,7 @@
</span><span class="cx">                         }
</span><span class="cx">                         $iteration_value = $iteration_value[1];
</span><span class="cx">                     }
</span><del>-                    array_push($flattened_value, $iteration_value);                    
</del><ins>+                    array_push($flattened_value, $iteration_value);
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">             $this-&gt;values_to_commit[$i]['mean'] = $this-&gt;aggregate_values('Arithmetic', $flattened_value);
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsrepositoryjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/repository.js (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/repository.js        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/public/v3/models/repository.js        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -7,6 +7,7 @@
</span><span class="cx">         this._url = object.url;
</span><span class="cx">         this._blameUrl = object.blameUrl;
</span><span class="cx">         this._hasReportedCommits = object.hasReportedCommits;
</span><ins>+        this._owner = object.owner;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     hasUrlForRevision() { return !!this._url; }
</span><span class="lines">@@ -21,6 +22,11 @@
</span><span class="cx">         return (this._blameUrl || '').replace(/\$1/g, from).replace(/\$2/g, to);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    owner()
+    {
+        return this._owner;
+    }
+
</ins><span class="cx">     static sortByNamePreferringOnesWithURL(repositories)
</span><span class="cx">     {
</span><span class="cx">         return repositories.sort(function (a, b) {
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgservertestsadminreprocessreporttestsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/admin-reprocess-report-tests.js (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/admin-reprocess-report-tests.js        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/server-tests/admin-reprocess-report-tests.js        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -24,6 +24,44 @@
</span><span class="cx">             },
</span><span class="cx">         }];
</span><span class="cx"> 
</span><ins>+    const simpleReportWithRevisions = [{
+        &quot;buildNumber&quot;: &quot;1986&quot;,
+        &quot;buildTime&quot;: &quot;2013-02-28T10:12:03&quot;,
+        &quot;builderName&quot;: &quot;someBuilder&quot;,
+        &quot;builderPassword&quot;: &quot;somePassword&quot;,
+        &quot;platform&quot;: &quot;Mountain Lion&quot;,
+        &quot;tests&quot;: {
+                &quot;test&quot;: {
+                    &quot;metrics&quot;: {&quot;FrameRate&quot;: { &quot;current&quot;: [[1, 2, 3], [4, 5, 6]] }}
+                },
+            },
+        &quot;revisions&quot;: {
+                &quot;WebKit&quot;: {
+                    &quot;timestamp&quot;: &quot;2017-03-01T09:38:44.826833Z&quot;,
+                    &quot;revision&quot;: &quot;213214&quot;
+                }
+            }
+        }];
+
+    it(&quot;should still create new repository when repository ownerships are different&quot;, function (done) {
+        let db = TestServer.database();
+        addBuilderForReport(simpleReportWithRevisions[0]).then(function () {
+            return db.insert('repositories', {'name': 'WebKit', 'owner': 1});
+        }).then(function () {
+            return TestServer.remoteAPI().postJSON('/api/report/', simpleReportWithRevisions);
+        }).then(function (response) {
+            assert.equal(response['status'], 'OK');
+            return db.selectRows('repositories', {'name': 'WebKit'});
+        }).then(function (repositories) {
+            assert.equal(repositories.length, 2);
+            const webkitRepsitoryId = repositories[0].owner == 1 ? repositories[1].id : repositories[0].id;
+            return db.selectRows('commits', {'revision': '213214', 'repository': webkitRepsitoryId});
+        }).then(function (result) {
+            assert(result.length, 1);
+            done();
+        }).catch(done);
+    });
+
</ins><span class="cx">     it(&quot;should add build&quot;, function (done) {
</span><span class="cx">         let db = TestServer.database();
</span><span class="cx">         let reportId;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgservertestsapimanifestjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/api-manifest.js (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/api-manifest.js        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/server-tests/api-manifest.js        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -282,6 +282,7 @@
</span><span class="cx">         Promise.all([
</span><span class="cx">             db.insert('repositories', {id: 11, name: 'WebKit', url: 'https://trac.webkit.org/$1'}),
</span><span class="cx">             db.insert('repositories', {id: 9, name: 'OS X'}),
</span><ins>+            db.insert('repositories', {id: 101, name: 'WebKit', owner: 9, url: 'https://trac.webkit.org/$1'}),
</ins><span class="cx">             db.insert('build_triggerables', {id: 200, name: 'build.webkit.org'}),
</span><span class="cx">             db.insert('build_triggerables', {id: 201, name: 'ios-build.webkit.org'}),
</span><span class="cx">             db.insert('tests', {id: 1, name: 'SomeTest'}),
</span><span class="lines">@@ -311,6 +312,11 @@
</span><span class="cx">             assert.equal(webkit.name(), 'WebKit');
</span><span class="cx">             assert.equal(webkit.urlForRevision(123), 'https://trac.webkit.org/123');
</span><span class="cx"> 
</span><ins>+            let osWebkit1 = Repository.findById(101);
+            assert.equal(osWebkit1.name(), 'WebKit');
+            assert.equal(osWebkit1.owner(), 9);
+            assert.equal(osWebkit1.urlForRevision(123), 'https://trac.webkit.org/123');
+
</ins><span class="cx">             let osx = Repository.findById(9);
</span><span class="cx">             assert.equal(osx.name(), 'OS X');
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgservertestsapireportcommitstestsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/api-report-commits-tests.js (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/api-report-commits-tests.js        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/server-tests/api-report-commits-tests.js        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -287,4 +287,334 @@
</span><span class="cx">         }).catch(done);
</span><span class="cx">     });
</span><span class="cx"> 
</span><ins>+    const sameRepositoryNameInSubCommitAndMajorCommit = {
+        &quot;slaveName&quot;: &quot;someSlave&quot;,
+        &quot;slavePassword&quot;: &quot;somePassword&quot;,
+        &quot;commits&quot;: [
+            {
+                &quot;repository&quot;: &quot;OSX&quot;,
+                &quot;revision&quot;: &quot;Sierra16D32&quot;,
+                &quot;order&quot;: 1,
+                &quot;subCommits&quot;: {
+                    &quot;WebKit&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Commit Queue&quot;, &quot;account&quot;: &quot;commit-queue@webkit.org&quot;},
+                        &quot;message&quot;: &quot;WebKit Commit&quot;,
+                    },
+                    &quot;JavaScriptCore&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Mikhail Pozdnyakov&quot;, &quot;account&quot;: &quot;mikhail.pozdnyakov@intel.com&quot;},
+                        &quot;message&quot;: &quot;JavaScriptCore commit&quot;,
+                    }
+                }
+            },
+            {
+                &quot;repository&quot;: &quot;WebKit&quot;,
+                &quot;revision&quot;: &quot;141978&quot;,
+                &quot;author&quot;: {&quot;name&quot;: &quot;Commit Queue&quot;, &quot;account&quot;: &quot;commit-queue@webkit.org&quot;},
+                &quot;message&quot;: &quot;WebKit Commit&quot;,
+            }
+        ]
+    }
+
+    it(&quot;should distinguish between repositories with the asme name but with a different owner.&quot;, function (done) {
+        const db = TestServer.database();
+        addSlaveForReport(sameRepositoryNameInSubCommitAndMajorCommit).then(function () {
+            return TestServer.remoteAPI().postJSON('/api/report-commits/', sameRepositoryNameInSubCommitAndMajorCommit);
+        }).then(function (response) {
+            assert.equal(response['status'], 'OK');
+            return db.selectRows('repositories', {'name': 'WebKit'});
+        }).then(function (result) {
+            assert.equal(result.length, 2);
+            let osWebKit = result[0];
+            let webkitRepository = result[1];
+            assert.notEqual(osWebKit.id, webkitRepository.id);
+            assert.equal(osWebKit.name, webkitRepository.name);
+            assert.equal(webkitRepository.owner, null);
+            done();
+        })
+    });
+
+    const systemVersionCommitWithSubcommits = {
+        &quot;slaveName&quot;: &quot;someSlave&quot;,
+        &quot;slavePassword&quot;: &quot;somePassword&quot;,
+        &quot;commits&quot;: [
+            {
+                &quot;repository&quot;: &quot;OSX&quot;,
+                &quot;revision&quot;: &quot;Sierra16D32&quot;,
+                &quot;order&quot;: 1,
+                &quot;subCommits&quot;: {
+                    &quot;WebKit&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Commit Queue&quot;, &quot;account&quot;: &quot;commit-queue@webkit.org&quot;},
+                        &quot;message&quot;: &quot;WebKit Commit&quot;,
+                    },
+                    &quot;JavaScriptCore&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Mikhail Pozdnyakov&quot;, &quot;account&quot;: &quot;mikhail.pozdnyakov@intel.com&quot;},
+                        &quot;message&quot;: &quot;JavaScriptCore commit&quot;,
+                    }
+                }
+            }
+        ]
+    }
+
+    it(&quot;should accept inserting one commit with some sub commits&quot;, function (done) {
+        const db = TestServer.database();
+        addSlaveForReport(systemVersionCommitWithSubcommits).then(function () {
+            return TestServer.remoteAPI().postJSON('/api/report-commits/', systemVersionCommitWithSubcommits);
+        }).then(function (response) {
+            assert.equal(response['status'], 'OK');
+            return Promise.all([db.selectRows('commits', {'revision': 'Sierra16D32'}),
+                db.selectRows('commits', {'message': 'WebKit Commit'}),
+                db.selectRows('commits', {'message': 'JavaScriptCore commit'}),
+                db.selectRows('repositories', {'name': 'OSX'}),
+                db.selectRows('repositories', {'name': &quot;WebKit&quot;}),
+                db.selectRows('repositories', {'name': 'JavaScriptCore'})])
+        }).then(function (result) {
+            assert.equal(result.length, 6);
+
+            assert.equal(result[0].length, 1);
+            const osxCommit = result[0][0];
+            assert.notEqual(osxCommit, null);
+
+            assert.equal(result[1].length, 1);
+            const webkitCommit = result[1][0];
+            assert.notEqual(webkitCommit, null);
+
+            assert.equal(result[2].length, 1);
+            const jscCommit = result[2][0];
+            assert.notEqual(jscCommit, null);
+
+            assert.equal(result[3].length, 1);
+            const osxRepository = result[3][0];
+            assert.notEqual(osxRepository, null);
+
+            assert.equal(result[4].length, 1);
+            const webkitRepository = result[4][0];
+            assert.notEqual(webkitRepository, null);
+
+            assert.equal(result[5].length, 1);
+            const jscRepository = result[5][0];
+            assert.notEqual(jscRepository, null);
+
+            assert.equal(osxCommit.repository, osxRepository.id);
+            assert.equal(webkitCommit.repository, webkitRepository.id);
+            assert.equal(jscCommit.repository, jscRepository.id);
+            assert.equal(osxRepository.owner, null);
+            assert.equal(webkitRepository.owner, osxRepository.id);
+            assert.equal(jscRepository.owner, osxRepository.id);
+
+            return Promise.all([db.selectRows('commit_ownerships', {'owner': osxCommit.id, 'owned': webkitCommit.id}, {'sortBy': 'owner'}),
+                db.selectRows('commit_ownerships', {'owner': osxCommit.id, 'owned': jscCommit.id}, {'sortBy': 'owner'}),
+                db.selectRows('commits', {'repository': webkitRepository.id})]);
+        }).then(function (result) {
+            assert.equal(result.length, 3);
+
+            assert.equal(result[0].length, 1);
+            const ownerCommitForWebKitCommit = result[0][0];
+            assert.notEqual(ownerCommitForWebKitCommit, null);
+
+            assert.equal(result[1].length, 1);
+            const ownerCommitForJSCCommit =  result[1][0];
+            assert.notEqual(ownerCommitForJSCCommit, null);
+
+            assert.equal(result[2].length, 1);
+            done();
+        }).catch(done);
+    })
+
+    const multipleSystemVersionCommitsWithSubcommits = {
+        &quot;slaveName&quot;: &quot;someSlave&quot;,
+        &quot;slavePassword&quot;: &quot;somePassword&quot;,
+        &quot;commits&quot;: [
+            {
+                &quot;repository&quot;: &quot;OSX&quot;,
+                &quot;revision&quot;: &quot;Sierra16D32&quot;,
+                &quot;order&quot;: 2,
+                &quot;subCommits&quot;: {
+                    &quot;WebKit&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Commit Queue&quot;, &quot;account&quot;: &quot;commit-queue@webkit.org&quot;},
+                        &quot;message&quot;: &quot;WebKit Commit&quot;,
+                    },
+                    &quot;JavaScriptCore&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Mikhail Pozdnyakov&quot;, &quot;account&quot;: &quot;mikhail.pozdnyakov@intel.com&quot;},
+                        &quot;message&quot;: &quot;JavaScriptCore commit&quot;,
+                    }
+                }
+            },
+            {
+                &quot;repository&quot;: &quot;OSX&quot;,
+                &quot;revision&quot;: &quot;Sierra16C67&quot;,
+                &quot;order&quot;: 1,
+                &quot;subCommits&quot;: {
+                    &quot;WebKit&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Commit Queue&quot;, &quot;account&quot;: &quot;commit-queue@webkit.org&quot;},
+                        &quot;message&quot;: &quot;WebKit Commit&quot;,
+                    },
+                    &quot;JavaScriptCore&quot;: {
+                        &quot;revision&quot;: &quot;141999&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Mikhail Pozdnyakov&quot;, &quot;account&quot;: &quot;mikhail.pozdnyakov@intel.com&quot;},
+                        &quot;message&quot;: &quot;new JavaScriptCore commit&quot;,
+                    }
+                }
+            }
+        ]
+    };
+
+    it(&quot;should accept inserting multiple commits with multiple sub-commits&quot;, function (done) {
+        const db = TestServer.database();
+        addSlaveForReport(multipleSystemVersionCommitsWithSubcommits).then(function () {
+            return TestServer.remoteAPI().postJSON('/api/report-commits/', multipleSystemVersionCommitsWithSubcommits);
+        }).then(function (response) {
+            assert.equal(response['status'], 'OK');
+            return Promise.all([db.selectRows('commits', {'revision': 'Sierra16D32'}),
+                db.selectRows('commits', {'revision': 'Sierra16C67'}),
+                db.selectRows('commits', {'message': 'WebKit Commit'}),
+                db.selectRows('commits', {'message': 'JavaScriptCore commit'}),
+                db.selectRows('commits', {'message': 'new JavaScriptCore commit'}),
+                db.selectRows('repositories', {'name': 'OSX'}),
+                db.selectRows('repositories', {'name': &quot;WebKit&quot;}),
+                db.selectRows('repositories', {'name': 'JavaScriptCore'})])
+        }).then(function (result) {
+            assert.equal(result.length, 8);
+
+            assert.equal(result[0].length, 1);
+            const osxCommit0 = result[0][0];
+            assert.notEqual(osxCommit0, null);
+
+            assert.equal(result[1].length, 1);
+            const osxCommit1 = result[1][0];
+            assert.notEqual(osxCommit1, null);
+
+            assert.equal(result[2].length, 1);
+            const webkitCommit = result[2][0];
+            assert.notEqual(webkitCommit, null);
+
+            assert.equal(result[3].length, 1);
+            const jscCommit0 = result[3][0];
+            assert.notEqual(jscCommit0, null);
+
+            assert.equal(result[4].length, 1);
+            const jscCommit1 = result[4][0];
+            assert.notEqual(jscCommit1, null);
+
+            assert.equal(result[5].length, 1)
+            const osxRepository = result[5][0];
+            assert.notEqual(osxRepository, null);
+            assert.equal(osxRepository.owner, null);
+
+            assert.equal(result[6].length, 1)
+            const webkitRepository = result[6][0];
+            assert.equal(webkitRepository.owner, osxRepository.id);
+
+            assert.equal(result[7].length, 1);
+            const jscRepository = result[7][0];
+            assert.equal(jscRepository.owner, osxRepository.id);
+
+            assert.equal(osxCommit0.repository, osxRepository.id);
+            assert.equal(osxCommit1.repository, osxRepository.id);
+            assert.equal(webkitCommit.repository, webkitRepository.id);
+            assert.equal(jscCommit0.repository, jscRepository.id);
+            assert.equal(jscCommit1.repository, jscRepository.id);
+            assert.equal(osxRepository.owner, null);
+            assert.equal(webkitRepository.owner, osxRepository.id);
+            assert.equal(jscRepository.owner, osxRepository.id);
+
+            return Promise.all([db.selectRows('commit_ownerships', {'owner': osxCommit0.id, 'owned': webkitCommit.id}, {'sortBy': 'owner'}),
+                db.selectRows('commit_ownerships', {'owner': osxCommit1.id, 'owned': webkitCommit.id}, {'sortBy': 'owner'}),
+                db.selectRows('commit_ownerships', {'owner': osxCommit0.id, 'owned': jscCommit0.id}, {'sortBy': 'owner'}),
+                db.selectRows('commit_ownerships', {'owner': osxCommit1.id, 'owned': jscCommit1.id}, {'sortBy': 'owner'}),
+                db.selectRows('commits', {'repository': webkitRepository.id})]);
+        }).then(function (result) {
+            assert.equal(result.length, 5);
+
+            assert.equal(result[0].length, 1);
+            const ownerCommitForWebKitCommit0 = result[0][0];
+            assert.notEqual(ownerCommitForWebKitCommit0, null);
+
+            assert.equal(result[1].length, 1);
+            const ownerCommitForWebKitCommit1 = result[1][0];
+            assert.notEqual(ownerCommitForWebKitCommit1, null);
+
+            assert.equal(result[2].length, 1);
+            const ownerCommitForJSCCommit0 = result[2][0];
+            assert.notEqual(ownerCommitForJSCCommit0, null);
+
+            assert.equal(result[3].length, 1);
+            const ownerCommitForJSCCommit1 = result[3][0];
+            assert.notEqual(ownerCommitForJSCCommit1, null);
+
+            assert.equal(result[4].length, 1);
+
+            done();
+        }).catch(done);
+    });
+
+    const systemVersionCommitWithEmptySubcommits = {
+        &quot;slaveName&quot;: &quot;someSlave&quot;,
+        &quot;slavePassword&quot;: &quot;somePassword&quot;,
+        &quot;commits&quot;: [
+            {
+                &quot;repository&quot;: &quot;OSX&quot;,
+                &quot;revision&quot;: &quot;Sierra16D32&quot;,
+                &quot;order&quot;: 1,
+                &quot;subCommits&quot;: {
+                }
+            }
+        ]
+    }
+
+    it(&quot;should accept inserting one commit with no sub commits&quot;, function (done) {
+        const db = TestServer.database();
+        addSlaveForReport(systemVersionCommitWithEmptySubcommits).then(function () {
+            return TestServer.remoteAPI().postJSON('/api/report-commits/', systemVersionCommitWithEmptySubcommits);
+        }).then(function (response) {
+            assert.equal(response['status'], 'OK');
+            return Promise.all([db.selectAll('commits'), db.selectAll('repositories'), db.selectAll('commit_ownerships', 'owner')]);
+        }).then(function (result) {
+            let commits = result[0];
+            let repositories = result[1];
+            let commit_ownerships = result[2];
+            assert.equal(commits.length, 1);
+            assert.equal(repositories.length, 1);
+            assert.equal(commits[0].repository, repositories[0].id);
+            assert.equal(repositories[0].name, 'OSX');
+            assert.equal(commit_ownerships.length, 0);
+            done();
+        }).catch(done);
+    });
+
+    const systemVersionCommitAndSubcommitWithTimestamp = {
+        &quot;slaveName&quot;: &quot;someSlave&quot;,
+        &quot;slavePassword&quot;: &quot;somePassword&quot;,
+        &quot;commits&quot;: [
+            {
+                &quot;repository&quot;: &quot;OSX&quot;,
+                &quot;revision&quot;: &quot;Sierra16D32&quot;,
+                &quot;order&quot;: 1,
+                &quot;subCommits&quot;: {
+                    &quot;WebKit&quot;: {
+                        &quot;revision&quot;: &quot;141978&quot;,
+                        &quot;time&quot;: &quot;2013-02-06T08:55:20.9Z&quot;,
+                        &quot;author&quot;: {&quot;name&quot;: &quot;Commit Queue&quot;, &quot;account&quot;: &quot;commit-queue@webkit.org&quot;},
+                        &quot;message&quot;: &quot;WebKit Commit&quot;,
+                    }
+                }
+            }
+        ]
+    }
+
+    it(&quot;should reject inserting one commit with sub commits that contains timestamp&quot;, function (done) {
+        const db = TestServer.database();
+        addSlaveForReport(systemVersionCommitAndSubcommitWithTimestamp).then(function () {
+            return TestServer.remoteAPI().postJSON('/api/report-commits/', systemVersionCommitAndSubcommitWithTimestamp);
+        }).then(function (response) {
+            assert.equal(response['status'], 'SubCommitShouldNotContainTimestamp');
+            done();
+        }).catch(done);
+    });
</ins><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 (213787 => 213788)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/tools/js/database.js        2017-03-13 08:01:16 UTC (rev 213787)
+++ trunk/Websites/perf.webkit.org/tools/js/database.js        2017-03-13 09:10:29 UTC (rev 213788)
</span><span class="lines">@@ -136,6 +136,7 @@
</span><span class="cx">     'builds': 'build',
</span><span class="cx">     'builders': 'builder',
</span><span class="cx">     'commits': 'commit',
</span><ins>+    'commit_ownerships': 'commit',
</ins><span class="cx">     'committers': 'committer',
</span><span class="cx">     'test_configurations': 'config',
</span><span class="cx">     'test_metrics': 'metric',
</span></span></pre>
</div>
</div>

</body>
</html>