<!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>[214975] 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/214975">214975</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2017-04-05 16:12:46 -0700 (Wed, 05 Apr 2017)</dd>
</dl>
<h3>Log Message</h3>
<pre>Introduce the notion of repository groups to triggerables
https://bugs.webkit.org/show_bug.cgi?id=170228
Reviewed by Chris Dumez.
On some triggerable, it's desirable to specify multiple sets of repositories that are accepted.
For example, if a repository X transitioned from Subversion to Git, and if a triggerable accepted X and
some other repository Y, then it's desirable to two sets: (X-Subversion, Y) and (X-Git, Y) since neither
(X-Subversion, X-Git) nor (X-Subversion, X-Git, Y) makes sense as a set.
This patch introduces triggerable_repository_groups table to represent a set of repositories accepted by
a triggerable. It has many to one relationship to build_triggerables and triggerable_repositories in turn
now has many to one relationship to triggerable_repository_groups instead of build_triggerables.
Also make it possible to disable a triggerable e.g. a set of tests and platforms are no longer supported.
We don't want to delete the triggerable completely from the database since it would result in the associated
A/B testing results being purged, which is not desirale.
To migrate an existing database, run the following transaction:
```sql
BEGIN;
ALTER TABLE build_triggerables ADD COLUMN triggerable_disabled boolean NOT NULL DEFAULT FALSE;
CREATE TABLE triggerable_repository_groups (
repositorygroup_id serial PRIMARY KEY,
repositorygroup_triggerable integer REFERENCES build_triggerables NOT NULL,
repositorygroup_name varchar(256) NOT NULL,
repositorygroup_description varchar(256),
repositorygroup_accepts_roots boolean NOT NULL DEFAULT FALSE,
CONSTRAINT repository_group_name_must_be_unique_for_triggerable
UNIQUE(repositorygroup_triggerable, repositorygroup_name));
INSERT INTO triggerable_repository_groups (repositorygroup_triggerable, repositorygroup_name)
SELECT triggerable_id, 'default' FROM build_triggerables;
ALTER TABLE triggerable_repositories ADD COLUMN trigrepo_group integer REFERENCES triggerable_repository_groups;
UPDATE triggerable_repositories SET trigrepo_group = repositorygroup_id FROM triggerable_repository_groups
WHERE trigrepo_triggerable = repositorygroup_triggerable;
ALTER TABLE triggerable_repositories ALTER COLUMN trigrepo_group SET NOT NULL;
ALTER TABLE triggerable_repositories DROP COLUMN trigrepo_triggerable;
ALTER TABLE triggerable_repositories DROP COLUMN trigrepo_sub_roots;
END;
```
* init-database.sql:
* public/admin/triggerables.php: Use a custom column to make forms to add and configure repository groups.
(insert_triggerable_repositories): Added.
(generate_repository_list): Added.
(generate_repository_form): Added.
(generate_repository_checkboxes): Now generates checkboxes for a repository group instead of a triggerable.
* public/include/manifest-generator.php:
(fetch_triggerables): Fixed the bug that we were not filtering results with query in /api/triggerable.
Rewrote it to include an array of repository groups, which in turn contains an array of repositories along
with its name and a description, and a boolean indicating whether it accepts a custom root file or not.
The boolean will be used when we're adding the support for perf try bots. We will keep acceptedRepositories
since it's still used by detect-changes.js.
* public/v3/models/manifest.js:
(Manifest._didFetchManifest): Resolve repositoriy, test, and platform IDs to their respective objects.
* public/v3/models/triggerable.js:
(Triggerable):
(Triggerable.prototype.isDisabled): Added.
(Triggerable.prototype.repositoryGroups): Added.
(Triggerable.prototype.acceptsTest): Added.
(TriggerableRepositoryGroup): Added.
(TriggerableRepositoryGroup.prototype.description): Added.
(TriggerableRepositoryGroup.prototype.acceptsCustomRoots): Added.
(TriggerableRepositoryGroup.prototype.repositories): Added.
* public/v3/pages/analysis-task-page.js:
(AnalysisTaskPage.prototype._didFetchTask): Don't use a disabled triggerable.
* server-tests/api-manifest-tests.js: Updated a test case to test repository groups.
* tools/js/database.js:
(tableToPrefixMap): Added triggerable_repository_groups.
* tools/js/v3-models.js: Imported TriggerableRepositoryGroup from triggerable.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="#trunkWebsitesperfwebkitorgpublicadmintriggerablesphp">trunk/Websites/perf.webkit.org/public/admin/triggerables.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicincludemanifestgeneratorphp">trunk/Websites/perf.webkit.org/public/include/manifest-generator.php</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelsmanifestjs">trunk/Websites/perf.webkit.org/public/v3/models/manifest.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelstriggerablejs">trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs">trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgservertestsapimanifesttestsjs">trunk/Websites/perf.webkit.org/server-tests/api-manifest-tests.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgtoolsjsdatabasejs">trunk/Websites/perf.webkit.org/tools/js/database.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgtoolsjsv3modelsjs">trunk/Websites/perf.webkit.org/tools/js/v3-models.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 (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -1,3 +1,87 @@
</span><ins>+2017-04-05 Ryosuke Niwa <rniwa@webkit.org>
+
+ Introduce the notion of repository groups to triggerables
+ https://bugs.webkit.org/show_bug.cgi?id=170228
+
+ Reviewed by Chris Dumez.
+
+ On some triggerable, it's desirable to specify multiple sets of repositories that are accepted.
+
+ For example, if a repository X transitioned from Subversion to Git, and if a triggerable accepted X and
+ some other repository Y, then it's desirable to two sets: (X-Subversion, Y) and (X-Git, Y) since neither
+ (X-Subversion, X-Git) nor (X-Subversion, X-Git, Y) makes sense as a set.
+
+ This patch introduces triggerable_repository_groups table to represent a set of repositories accepted by
+ a triggerable. It has many to one relationship to build_triggerables and triggerable_repositories in turn
+ now has many to one relationship to triggerable_repository_groups instead of build_triggerables.
+
+ Also make it possible to disable a triggerable e.g. a set of tests and platforms are no longer supported.
+ We don't want to delete the triggerable completely from the database since it would result in the associated
+ A/B testing results being purged, which is not desirale.
+
+ To migrate an existing database, run the following transaction:
+ ```sql
+ BEGIN;
+ ALTER TABLE build_triggerables ADD COLUMN triggerable_disabled boolean NOT NULL DEFAULT FALSE;
+
+ CREATE TABLE triggerable_repository_groups (
+ repositorygroup_id serial PRIMARY KEY,
+ repositorygroup_triggerable integer REFERENCES build_triggerables NOT NULL,
+ repositorygroup_name varchar(256) NOT NULL,
+ repositorygroup_description varchar(256),
+ repositorygroup_accepts_roots boolean NOT NULL DEFAULT FALSE,
+ CONSTRAINT repository_group_name_must_be_unique_for_triggerable
+ UNIQUE(repositorygroup_triggerable, repositorygroup_name));
+ INSERT INTO triggerable_repository_groups (repositorygroup_triggerable, repositorygroup_name)
+ SELECT triggerable_id, 'default' FROM build_triggerables;
+
+ ALTER TABLE triggerable_repositories ADD COLUMN trigrepo_group integer REFERENCES triggerable_repository_groups;
+ UPDATE triggerable_repositories SET trigrepo_group = repositorygroup_id FROM triggerable_repository_groups
+ WHERE trigrepo_triggerable = repositorygroup_triggerable;
+ ALTER TABLE triggerable_repositories ALTER COLUMN trigrepo_group SET NOT NULL;
+
+ ALTER TABLE triggerable_repositories DROP COLUMN trigrepo_triggerable;
+ ALTER TABLE triggerable_repositories DROP COLUMN trigrepo_sub_roots;
+ END;
+ ```
+
+ * init-database.sql:
+ * public/admin/triggerables.php: Use a custom column to make forms to add and configure repository groups.
+ (insert_triggerable_repositories): Added.
+ (generate_repository_list): Added.
+ (generate_repository_form): Added.
+ (generate_repository_checkboxes): Now generates checkboxes for a repository group instead of a triggerable.
+
+ * public/include/manifest-generator.php:
+ (fetch_triggerables): Fixed the bug that we were not filtering results with query in /api/triggerable.
+ Rewrote it to include an array of repository groups, which in turn contains an array of repositories along
+ with its name and a description, and a boolean indicating whether it accepts a custom root file or not.
+ The boolean will be used when we're adding the support for perf try bots. We will keep acceptedRepositories
+ since it's still used by detect-changes.js.
+
+ * public/v3/models/manifest.js:
+ (Manifest._didFetchManifest): Resolve repositoriy, test, and platform IDs to their respective objects.
+
+ * public/v3/models/triggerable.js:
+ (Triggerable):
+ (Triggerable.prototype.isDisabled): Added.
+ (Triggerable.prototype.repositoryGroups): Added.
+ (Triggerable.prototype.acceptsTest): Added.
+ (TriggerableRepositoryGroup): Added.
+ (TriggerableRepositoryGroup.prototype.description): Added.
+ (TriggerableRepositoryGroup.prototype.acceptsCustomRoots): Added.
+ (TriggerableRepositoryGroup.prototype.repositories): Added.
+
+ * public/v3/pages/analysis-task-page.js:
+ (AnalysisTaskPage.prototype._didFetchTask): Don't use a disabled triggerable.
+
+ * server-tests/api-manifest-tests.js: Updated a test case to test repository groups.
+
+ * tools/js/database.js:
+ (tableToPrefixMap): Added triggerable_repository_groups.
+
+ * tools/js/v3-models.js: Imported TriggerableRepositoryGroup from triggerable.js.
+
</ins><span class="cx"> 2017-03-31 Ryosuke Niwa <rniwa@webkit.org>
</span><span class="cx">
</span><span class="cx"> Build fix. For OS versions, we can end up with non-alphanumeric revision.
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorginitdatabasesql"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/init-database.sql (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/init-database.sql        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/init-database.sql        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> DROP TYPE IF EXISTS analysis_task_result_type CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS build_triggerables CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS triggerable_configurations CASCADE;
</span><ins>+DROP TABLE IF EXISTS triggerable_repository_groups CASCADE;
</ins><span class="cx"> DROP TABLE IF EXISTS triggerable_repositories CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS uploaded_files CASCADE;
</span><span class="cx"> DROP TABLE IF EXISTS bugs CASCADE;
</span><span class="lines">@@ -229,12 +230,20 @@
</span><span class="cx">
</span><span class="cx"> CREATE TABLE build_triggerables (
</span><span class="cx"> triggerable_id serial PRIMARY KEY,
</span><del>- triggerable_name varchar(64) NOT NULL UNIQUE);
</del><ins>+ triggerable_name varchar(64) NOT NULL UNIQUE,
+ triggerable_disabled boolean NOT NULL DEFAULT FALSE);
</ins><span class="cx">
</span><ins>+CREATE TABLE triggerable_repository_groups (
+ repositorygroup_id serial PRIMARY KEY,
+ repositorygroup_triggerable integer REFERENCES build_triggerables NOT NULL,
+ repositorygroup_name varchar(256) NOT NULL,
+ repositorygroup_description varchar(256),
+ repositorygroup_accepts_roots boolean NOT NULL DEFAULT FALSE,
+ CONSTRAINT repository_group_name_must_be_unique_for_triggerable UNIQUE(repositorygroup_triggerable, repositorygroup_name));
+
</ins><span class="cx"> CREATE TABLE triggerable_repositories (
</span><del>- trigrepo_triggerable integer REFERENCES build_triggerables NOT NULL,
</del><span class="cx"> trigrepo_repository integer REFERENCES repositories NOT NULL,
</span><del>- trigrepo_sub_roots boolean NOT NULL DEFAULT FALSE);
</del><ins>+ trigrepo_group integer REFERENCES triggerable_repository_groups NOT NULL);
</ins><span class="cx">
</span><span class="cx"> CREATE TABLE triggerable_configurations (
</span><span class="cx"> trigconfig_test integer REFERENCES tests NOT NULL,
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicadmintriggerablesphp"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/admin/triggerables.php (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/admin/triggerables.php        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/public/admin/triggerables.php        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -13,25 +13,53 @@
</span><span class="cx"> } else if ($action == 'update') {
</span><span class="cx"> if (update_field('build_triggerables', 'triggerable', 'name'))
</span><span class="cx"> regenerate_manifest();
</span><ins>+ else if (update_field('build_triggerables', 'triggerable', 'disabled', Database::to_database_boolean(array_get($_POST, 'disabled'))))
+ regenerate_manifest();
</ins><span class="cx"> else
</span><span class="cx"> notice('Invalid parameters.');
</span><ins>+ } else if ($action == 'update-group-name') {
+ if (update_field('triggerable_repository_groups', 'repositorygroup', 'name'))
+ regenerate_manifest();
+ } else if ($action == 'update-group-description') {
+ if (update_field('triggerable_repository_groups', 'repositorygroup', 'description'))
+ regenerate_manifest();
+ } else if ($action == 'update-group-accept-roots') {
+ if (update_field('triggerable_repository_groups', 'repositorygroup', 'accepts_roots',
+ Database::to_database_boolean(array_get($_POST, 'accepts'))))
+ regenerate_manifest();
+ } else if ($action == 'update-repository') {
+ $association = array_get($_POST, 'association');
+ $triggerable_id = array_get($_POST, 'triggerable');
+ $repository_id = array_get($_POST, 'repository');
+
+ $should_delete = FALSE;
+ $accepted = $association == 'accepted';
+ $required = $association == 'required';
+ if ($accepted || $required) {
+ $db->begin_transaction();
+ $select = array('repository' => $repository_id, 'triggerable' => $triggerable_id);
+ $update = array('repository' => $repository_id, 'triggerable' => $triggerable_id, 'required' => Database::to_database_boolean($required));
+ if (!$db->update_row('triggerable_repositories', 'trigrepo', $select, $update, 'repository')) {
+ notice("Failed to update the association of repository $repository_id with triggerable $triggerable_id.");
+ $db->rollback_transaction();
+ } else
+ $db->commit_transaction();
+ } else if ($association == 'not-accepted') {
+ $db->begin_transaction();
+ $result = $db->query_and_get_affected_rows("DELETE FROM triggerable_repositories WHERE trigrepo_triggerable = $1 AND trigrepo_repository = $2",
+ array($triggerable_id, $repository_id));
+ if ($result > 1) {
+ notice("Failed to update the association of repository $repository_id with triggerable $triggerable_id.");
+ $db->rollback_transaction();
+ } else
+ $db->commit_transaction();
+ }
</ins><span class="cx"> } else if ($action == 'update-repositories') {
</span><del>- $triggerable_id = intval($_POST['id']);
</del><ins>+ $group_id = intval($_POST['group']);
</ins><span class="cx">
</span><span class="cx"> $db->begin_transaction();
</span><del>- $db->query_and_get_affected_rows("DELETE FROM triggerable_repositories WHERE trigrepo_triggerable = $1", array($triggerable_id));
-
- $repositories = array_get($_POST, 'repositories');
- $suceeded = TRUE;
- if ($repositories) {
- foreach ($repositories as $repository_id) {
- if (!$db->insert_row('triggerable_repositories', 'trigrepo', array('triggerable' => $triggerable_id, 'repository' => $repository_id), NULL)) {
- $suceeded = FALSE;
- notice("Failed to associate repository $repository_id with triggerable $triggerable_id.");
- break;
- }
- }
- }
</del><ins>+ $db->query_and_get_affected_rows("DELETE FROM triggerable_repositories WHERE trigrepo_group = $1", array($group_id));
+ $suceeded = insert_triggerable_repositories($db, $group_id, array_get($_POST, 'repositories'));
</ins><span class="cx"> if ($suceeded) {
</span><span class="cx"> $db->commit_transaction();
</span><span class="cx"> notice('Updated the association.');
</span><span class="lines">@@ -38,48 +66,138 @@
</span><span class="cx"> regenerate_manifest();
</span><span class="cx"> } else
</span><span class="cx"> $db->rollback_transaction();
</span><ins>+ } else if ($action == 'add-repository-group') {
+ $triggerable_id = intval($_POST['triggerable']);
+ $name = $_POST['name'];
+
+ $db->begin_transaction();
+ $group_id = $db->insert_row('triggerable_repository_groups', 'repositorygroup', array('name' => $name, 'triggerable' => $triggerable_id));
+ if (!$group_id)
+ notice('Failed to insert the specified repository group.');
+ else if (!insert_triggerable_repositories($db, $group_id, array_get($_POST, 'repositories')))
+ $db->rollback_transaction();
+ else {
+ $db->commit_transaction();
+ notice('Updated the association.');
+ regenerate_manifest();
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $repository_rows = $db->fetch_table('repositories', 'repository_name');
</span><del>- $repository_names = array();
</del><span class="cx">
</span><del>-
</del><span class="cx"> $page = new AdministrativePage($db, 'build_triggerables', 'triggerable', array(
</span><span class="cx"> 'name' => array('editing_mode' => 'string'),
</span><del>- 'repositories' => array('custom' => function ($triggerable_row) use (&$repository_rows) {
- return array(generate_repository_checkboxes($triggerable_row['triggerable_id'], $repository_rows));
- }),
</del><ins>+ 'disabled' => array('editing_mode' => 'boolean', 'post_insertion' => TRUE),
+ 'repositories' => array(
+ 'label' => 'Repository Groups',
+ 'subcolumns'=> array('ID', 'Name', 'Description', 'Accepts Roots', 'Repositories'),
+ 'custom' => function ($triggerable_row) use (&$db, &$repository_rows) {
+ return generate_repository_list($db, $triggerable_row['triggerable_id'], $repository_rows);
+ }),
</ins><span class="cx"> ));
</span><span class="cx">
</span><del>- function generate_repository_checkboxes($triggerable_id, $repository_rows) {
- global $db;
</del><ins>+ $page->render_table('name');
+ $page->render_form_to_add();
+}
</ins><span class="cx">
</span><del>- $repository_rows = $db->query_and_fetch_all('SELECT * FROM repositories LEFT OUTER JOIN triggerable_repositories
- ON trigrepo_repository = repository_id AND trigrepo_triggerable = $1 ORDER BY repository_name', array($triggerable_id));
</del><ins>+function insert_triggerable_repositories($db, $group_id, $repositories)
+{
+ if (!$repositories)
+ return TRUE;
+ foreach ($repositories as $repository_id) {
+ if (!$db->insert_row('triggerable_repositories', 'trigrepo', array('group' => $group_id, 'repository' => $repository_id), NULL)) {
+ notice("Failed to associate repository $repository_id with repository group $group_id.");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
</ins><span class="cx">
</span><del>- $form = <<< END
-<form method="POST">
-<input type="hidden" name="id" value="$triggerable_id">
-<input type="hidden" name="action" value="update-repositories">
</del><ins>+
+function generate_repository_list($db, $triggerable_id, $repository_rows) {
+ $group_forms = array();
+
+ $repository_groups = $db->select_rows('triggerable_repository_groups', 'repositorygroup', array('triggerable' => $triggerable_id), 'name');
+ foreach ($repository_groups as $group_row) {
+ $group_id = $group_row['repositorygroup_id'];
+ $group_name = $group_row['repositorygroup_name'];
+ $group_description = $group_row['repositorygroup_description'];
+ $checked_if_accepts_roots = Database::is_true($group_row['repositorygroup_accepts_roots']) ? 'checked' : '';
+
+ $group_name_form = <<< END
+ <form method="POST">
+ <input type="hidden" name="action" value="update-group-name">
+ <input type="hidden" name="id" value="$group_id">
+ <input type="text" name="name" value="$group_name">
+ </form>
</ins><span class="cx"> END;
</span><span class="cx">
</span><del>- foreach ($repository_rows as $row) {
- $checked = $row['trigrepo_triggerable'] ? ' checked' : '';
- $form .= <<< END
-<label><input type="checkbox" name="repositories[]" value="{$row['repository_id']}"$checked>{$row['repository_name']}</label>
</del><ins>+ $group_description_form = <<< END
+ <form method="POST">
+ <input type="hidden" name="action" value="update-group-description">
+ <input type="hidden" name="id" value="$group_id">
+ <input name="description" value="$group_description">
+ </form>
</ins><span class="cx"> END;
</span><del>- }
</del><span class="cx">
</span><del>- return $form . <<< END
-<button>Save</button>
-</form>
</del><ins>+ $group_accepts_roots = <<< END
+ <form method="POST">
+ <input type="hidden" name="action" value="update-group-accept-roots">
+ <input type="hidden" name="id" value="$group_id">
+ <input type="checkbox" name="accepts" $checked_if_accepts_roots>
+ <button type="submit">Save</button>
+ </form>
</ins><span class="cx"> END;
</span><ins>+
+ array_push($group_forms, array($group_id, $group_name_form, $group_description_form, $group_accepts_roots, generate_repository_form($db, $repository_rows, $group_id)));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- $page->render_table('name');
- $page->render_form_to_add();
</del><ins>+ $new_group_checkboxes = generate_repository_checkboxes($db, $repository_rows);
+ $new_group_form = <<< END
+ <form method="POST">
+ <input type="hidden" name="action" value="add-repository-group">
+ <input type="hidden" name="triggerable" value="$triggerable_id">
+ <input type="text" name="name" value="" required><br>
+ $new_group_checkboxes
+ <br><button type="submit">Add</button></form>
+END;
+
+ array_push($group_forms, $new_group_form);
+
+ return $group_forms;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+function generate_repository_form($db, $repository_rows, $group_id)
+{
+ $checkboxes = generate_repository_checkboxes($db, $repository_rows, $group_id);
+ return <<< END
+ <form method="POST">
+ <input type="hidden" name="action" value="update-repositories">
+ <input type="hidden" name="group" value="$group_id">
+ $checkboxes
+ <br><button type="submit">Save</button></form>
+END;
+}
+
+function generate_repository_checkboxes($db, $repository_rows, $group_id = NULL)
+{
+ $repositories_in_group = array();
+ if ($group_id) {
+ $group_repository_rows = $db->select_rows('triggerable_repositories', 'trigrepo', array('group' => $group_id));
+ foreach ($group_repository_rows as $row)
+ $repositories_in_group[$row['trigrepo_repository']] = TRUE;
+ }
+
+ $form = '';
+ foreach ($repository_rows as $row) {
+ $id = $row['repository_id'];
+ $name = $row['repository_name'];
+ $checked = array_key_exists($id, $repositories_in_group) ? 'checked' : '';
+ $form .= "<label><input type=\"checkbox\" name=\"repositories[]\" value=\"$id\" $checked>$name</label>";
+ }
+ return $form;
+}
+
</ins><span class="cx"> require('../include/admin-footer.php');
</span><span class="cx">
</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 (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/include/manifest-generator.php        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/public/include/manifest-generator.php        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -189,32 +189,64 @@
</span><span class="cx">
</span><span class="cx"> static function fetch_triggerables($db, $query)
</span><span class="cx"> {
</span><del>- $triggerables = $db->fetch_table('build_triggerables');
</del><ins>+ $triggerables = $db->select_rows('build_triggerables', 'triggerable', $query);
</ins><span class="cx"> if (!$triggerables)
</span><span class="cx"> return array();
</span><span class="cx">
</span><span class="cx"> $id_to_triggerable = array();
</span><del>- foreach ($triggerables as $row) {
</del><ins>+ $triggerable_id_to_repository_set = array();
+ foreach ($triggerables as &$row) {
</ins><span class="cx"> $id = $row['triggerable_id'];
</span><span class="cx"> $id_to_triggerable[$id] = array(
</span><del>- 'id' => $id,
</del><span class="cx"> 'name' => $row['triggerable_name'],
</span><ins>+ 'isDisabled' => Database::is_true($row['triggerable_disabled']),
</ins><span class="cx"> 'acceptedRepositories' => array(),
</span><ins>+ 'repositoryGroups' => array(),
</ins><span class="cx"> 'configurations' => array());
</span><ins>+ $triggerable_id_to_repository_set[$id] = array();
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- $repository_map = $db->fetch_table('triggerable_repositories');
- if ($repository_map) {
- foreach ($repository_map as $row) {
- $triggerable = &$id_to_triggerable[$row['trigrepo_triggerable']];
- array_push($triggerable['acceptedRepositories'], $row['trigrepo_repository']);
</del><ins>+ $repository_groups = $db->fetch_table('triggerable_repository_groups', 'repositorygroup_name');
+ $group_repositories = $db->fetch_table('triggerable_repositories');
+ if ($repository_groups && $group_repositories) {
+ $repository_set_by_group = array();
+ foreach ($group_repositories as &$repository_row) {
+ $group_id = $repository_row['trigrepo_group'];
+ array_ensure_item_has_array($repository_set_by_group, $group_id);
+ array_push($repository_set_by_group[$group_id], $repository_row['trigrepo_repository']);
</ins><span class="cx"> }
</span><ins>+ foreach ($repository_groups as &$group_row) {
+ $triggerable_id = $group_row['repositorygroup_triggerable'];
+ if (!array_key_exists($triggerable_id, $id_to_triggerable))
+ continue;
+ $triggerable = &$id_to_triggerable[$triggerable_id];
+ $group_id = $group_row['repositorygroup_id'];
+ $repository_list = array_get($repository_set_by_group, $group_id, array());
+ array_push($triggerable['repositoryGroups'], array(
+ 'id' => $group_row['repositorygroup_id'],
+ 'name' => $group_row['repositorygroup_name'],
+ 'description' => $group_row['repositorygroup_description'],
+ 'acceptsCustomRoots' => Database::is_true($group_row['repositorygroup_accepts_roots']),
+ 'repositories' => $repository_list));
+ // V2 UI compatibility.
+ foreach ($repository_list as $repository_id) {
+ $set = &$triggerable_id_to_repository_set[$triggerable_id];
+ if (array_key_exists($repository_id, $set))
+ continue;
+ $set[$repository_id] = true;
+ array_push($triggerable['acceptedRepositories'], $repository_id);
+ }
+
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> $configuration_map = $db->fetch_table('triggerable_configurations');
</span><span class="cx"> if ($configuration_map) {
</span><del>- foreach ($configuration_map as $row) {
- $triggerable = &$id_to_triggerable[$row['trigconfig_triggerable']];
</del><ins>+ foreach ($configuration_map as &$row) {
+ $triggerable_id = $row['trigconfig_triggerable'];
+ if (!array_key_exists($triggerable_id, $id_to_triggerable))
+ continue;
+ $triggerable = &$id_to_triggerable[$triggerable_id];
</ins><span class="cx"> array_push($triggerable['configurations'], array($row['trigconfig_test'], $row['trigconfig_platform']));
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelsmanifestjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/manifest.js (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/manifest.js        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/public/v3/models/manifest.js        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -47,6 +47,14 @@
</span><span class="cx"> raw.acceptedRepositories = raw.acceptedRepositories.map((repositoryId) => {
</span><span class="cx"> return Repository.findById(repositoryId);
</span><span class="cx"> });
</span><ins>+ raw.repositoryGroups = raw.repositoryGroups.map((group) => {
+ group.repositories = group.repositories.map((repositoryId) => Repository.findById(repositoryId));
+ return TriggerableRepositoryGroup.ensureSingleton(group.id, group);
+ });
+ raw.configurations = raw.configurations.map((configuration) => {
+ const [testId, platformId] = configuration;
+ return {test: Test.findById(testId), platform: Platform.findById(platformId)};
+ });
</ins><span class="cx"> });
</span><span class="cx">
</span><span class="cx"> Instrumentation.endMeasuringTime('Manifest', '_didFetchManifest');
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelstriggerablejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -4,20 +4,27 @@
</span><span class="cx"> {
</span><span class="cx"> super(id, object);
</span><span class="cx"> this._name = object.name;
</span><ins>+ this._isDisabled = !!object.isDisabled;
</ins><span class="cx"> this._acceptedRepositories = object.acceptedRepositories;
</span><ins>+ this._repositoryGroups = object.repositoryGroups;
</ins><span class="cx"> this._configurationList = object.configurations;
</span><ins>+ this._acceptedTests = new Set;
</ins><span class="cx">
</span><del>- let configurationMap = this.ensureNamedStaticMap('testConfigurations');
</del><ins>+ const configurationMap = this.ensureNamedStaticMap('testConfigurations');
</ins><span class="cx"> for (const config of object.configurations) {
</span><del>- const [testId, platformId] = config;
- const key = `${testId}-${platformId}`;
</del><ins>+ const key = `${config.test.id()}-${config.platform.id()}`;
+ this._acceptedTests.add(config.test);
</ins><span class="cx"> console.assert(!(key in configurationMap));
</span><span class="cx"> configurationMap[key] = this;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ isDisabled() { return this._isDisabled; }
</ins><span class="cx"> acceptedRepositories() { return this._acceptedRepositories; }
</span><ins>+ repositoryGroups() { return this._repositoryGroups; }
</ins><span class="cx">
</span><ins>+ acceptsTest(test) { return this._acceptedTests.has(test); }
+
</ins><span class="cx"> static findByTestConfiguration(test, platform)
</span><span class="cx"> {
</span><span class="cx"> let configurationMap = this.ensureNamedStaticMap('testConfigurations');
</span><span class="lines">@@ -30,8 +37,25 @@
</span><span class="cx"> }
</span><span class="cx"> return null;
</span><span class="cx"> }
</span><ins>+}
</ins><span class="cx">
</span><ins>+class TriggerableRepositoryGroup extends LabeledObject {
+
+ constructor(id, object)
+ {
+ super(id, object);
+ this._description = object.description;
+ this._acceptsCustomRoots = !!object.acceptsCustomRoots;
+ this._repositories = object.repositories;
+ }
+
+ description() { return this._description || this.name(); }
+ acceptsCustomRoots() { return this._acceptsCustomRoots; }
+ repositories() { return this._repositories; }
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-if (typeof module != 'undefined')
</del><ins>+if (typeof module != 'undefined') {
</ins><span class="cx"> module.exports.Triggerable = Triggerable;
</span><ins>+ module.exports.TriggerableRepositoryGroup = TriggerableRepositoryGroup;
+}
+
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -413,7 +413,8 @@
</span><span class="cx"> const platform = task.platform();
</span><span class="cx"> const metric = task.metric();
</span><span class="cx"> const lastModified = platform.lastModified(metric);
</span><del>- this._triggerable = Triggerable.findByTestConfiguration(metric.test(), platform);
</del><ins>+ const triggerable = Triggerable.findByTestConfiguration(metric.test(), platform);
+ this._triggerable = triggerable && !triggerable.isDisabled() ? triggerable : null;
</ins><span class="cx"> this._metric = metric;
</span><span class="cx">
</span><span class="cx"> this._measurementSet = MeasurementSet.findSet(platform.id(), metric.id(), lastModified);
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgservertestsapimanifesttestsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/server-tests/api-manifest-tests.js (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/server-tests/api-manifest-tests.js        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/server-tests/api-manifest-tests.js        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -268,11 +268,13 @@
</span><span class="cx"> db.insert('repositories', {id: 101, name: 'WebKit', owner: 9, url: 'https://trac.webkit.org/$1'}),
</span><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><ins>+ db.insert('build_triggerables', {id: 202, name: 'mac-build.webkit.org', disabled: true}),
</ins><span class="cx"> db.insert('tests', {id: 1, name: 'SomeTest'}),
</span><span class="cx"> db.insert('tests', {id: 2, name: 'SomeOtherTest'}),
</span><span class="cx"> db.insert('tests', {id: 3, name: 'ChildTest', parent: 1}),
</span><span class="cx"> db.insert('platforms', {id: 23, name: 'iOS 9 iPhone 5s'}),
</span><span class="cx"> db.insert('platforms', {id: 46, name: 'Trunk Mavericks'}),
</span><ins>+ db.insert('platforms', {id: 104, name: 'Trunk Sierra MacBookPro11,2'}),
</ins><span class="cx"> db.insert('test_metrics', {id: 5, test: 1, name: 'Time'}),
</span><span class="cx"> db.insert('test_metrics', {id: 8, test: 2, name: 'FrameRate'}),
</span><span class="cx"> db.insert('test_metrics', {id: 9, test: 3, name: 'Time'}),
</span><span class="lines">@@ -282,45 +284,60 @@
</span><span class="cx"> db.insert('test_configurations', {id: 104, metric: 5, platform: 23, type: 'current'}),
</span><span class="cx"> db.insert('test_configurations', {id: 105, metric: 8, platform: 23, type: 'current'}),
</span><span class="cx"> db.insert('test_configurations', {id: 106, metric: 9, platform: 23, type: 'current'}),
</span><del>- db.insert('triggerable_repositories', {triggerable: 200, repository: 11}),
- db.insert('triggerable_repositories', {triggerable: 201, repository: 11}),
</del><ins>+ db.insert('test_configurations', {id: 107, metric: 5, platform: 104, type: 'current'}),
+ db.insert('test_configurations', {id: 108, metric: 8, platform: 104, type: 'current'}),
+ db.insert('test_configurations', {id: 109, metric: 9, platform: 104, type: 'current'}),
+ db.insert('triggerable_repository_groups', {id: 300, triggerable: 200, name: 'default'}),
+ db.insert('triggerable_repository_groups', {id: 301, triggerable: 201, name: 'default'}),
+ db.insert('triggerable_repository_groups', {id: 302, triggerable: 202, name: 'system-and-webkit'}),
+ db.insert('triggerable_repository_groups', {id: 312, triggerable: 202, name: 'system-and-roots', accepts_roots: true}),
+ db.insert('triggerable_repositories', {group: 300, repository: 11}),
+ db.insert('triggerable_repositories', {group: 301, repository: 11}),
+ db.insert('triggerable_repositories', {group: 302, repository: 11}),
+ db.insert('triggerable_repositories', {group: 302, repository: 9}),
+ db.insert('triggerable_repositories', {group: 312, repository: 9}),
</ins><span class="cx"> db.insert('triggerable_configurations', {triggerable: 200, test: 1, platform: 46}),
</span><span class="cx"> db.insert('triggerable_configurations', {triggerable: 200, test: 2, platform: 46}),
</span><span class="cx"> db.insert('triggerable_configurations', {triggerable: 201, test: 1, platform: 23}),
</span><span class="cx"> db.insert('triggerable_configurations', {triggerable: 201, test: 2, platform: 23}),
</span><ins>+ db.insert('triggerable_configurations', {triggerable: 202, test: 1, platform: 104}),
+ db.insert('triggerable_configurations', {triggerable: 202, test: 2, platform: 104}),
</ins><span class="cx"> ]).then(() => {
</span><span class="cx"> return Manifest.fetch();
</span><span class="cx"> }).then(() => {
</span><del>- let webkit = Repository.findById(11);
</del><ins>+ const webkit = Repository.findById(11);
</ins><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><del>- let osWebkit1 = Repository.findById(101);
</del><ins>+ const osWebkit1 = Repository.findById(101);
</ins><span class="cx"> assert.equal(osWebkit1.name(), 'WebKit');
</span><span class="cx"> assert.equal(osWebkit1.owner(), 9);
</span><span class="cx"> assert.equal(osWebkit1.urlForRevision(123), 'https://trac.webkit.org/123');
</span><span class="cx">
</span><del>- let osx = Repository.findById(9);
</del><ins>+ const osx = Repository.findById(9);
</ins><span class="cx"> assert.equal(osx.name(), 'OS X');
</span><span class="cx">
</span><del>- let someTest = Test.findById(1);
</del><ins>+ const someTest = Test.findById(1);
</ins><span class="cx"> assert.equal(someTest.name(), 'SomeTest');
</span><span class="cx">
</span><del>- let someOtherTest = Test.findById(2);
</del><ins>+ const someOtherTest = Test.findById(2);
</ins><span class="cx"> assert.equal(someOtherTest.name(), 'SomeOtherTest');
</span><span class="cx">
</span><del>- let childTest = Test.findById(3);
</del><ins>+ const childTest = Test.findById(3);
</ins><span class="cx"> assert.equal(childTest.name(), 'ChildTest');
</span><span class="cx">
</span><del>- let ios9iphone5s = Platform.findById(23);
</del><ins>+ const ios9iphone5s = Platform.findById(23);
</ins><span class="cx"> assert.equal(ios9iphone5s.name(), 'iOS 9 iPhone 5s');
</span><span class="cx">
</span><del>- let mavericks = Platform.findById(46);
</del><ins>+ const mavericks = Platform.findById(46);
</ins><span class="cx"> assert.equal(mavericks.name(), 'Trunk Mavericks');
</span><span class="cx">
</span><del>- assert.equal(Triggerable.all().length, 2);
</del><ins>+ const sierra = Platform.findById(104);
+ assert.equal(sierra.name(), 'Trunk Sierra MacBookPro11,2');
</ins><span class="cx">
</span><del>- let osxTriggerable = Triggerable.findByTestConfiguration(someTest, mavericks);
</del><ins>+ assert.equal(Triggerable.all().length, 3);
+
+ const osxTriggerable = Triggerable.findByTestConfiguration(someTest, mavericks);
</ins><span class="cx"> assert.equal(osxTriggerable.name(), 'build.webkit.org');
</span><span class="cx"> assert.deepEqual(osxTriggerable.acceptedRepositories(), [webkit]);
</span><span class="cx">
</span><span class="lines">@@ -327,7 +344,7 @@
</span><span class="cx"> assert.equal(Triggerable.findByTestConfiguration(someOtherTest, mavericks), osxTriggerable);
</span><span class="cx"> assert.equal(Triggerable.findByTestConfiguration(childTest, mavericks), osxTriggerable);
</span><span class="cx">
</span><del>- let iosTriggerable = Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s);
</del><ins>+ const iosTriggerable = Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s);
</ins><span class="cx"> assert.notEqual(iosTriggerable, osxTriggerable);
</span><span class="cx"> assert.equal(iosTriggerable.name(), 'ios-build.webkit.org');
</span><span class="cx"> assert.deepEqual(iosTriggerable.acceptedRepositories(), [webkit]);
</span><span class="lines">@@ -334,6 +351,24 @@
</span><span class="cx">
</span><span class="cx"> assert.equal(Triggerable.findByTestConfiguration(someOtherTest, ios9iphone5s), iosTriggerable);
</span><span class="cx"> assert.equal(Triggerable.findByTestConfiguration(childTest, ios9iphone5s), iosTriggerable);
</span><ins>+
+ const macTriggerable = Triggerable.findByTestConfiguration(someTest, sierra);
+ assert.equal(macTriggerable.name(), 'mac-build.webkit.org');
+ assert.deepEqual(Repository.sortByName(macTriggerable.acceptedRepositories()), [osx, webkit]);
+ assert(macTriggerable.acceptsTest(someTest));
+
+ const groups = macTriggerable.repositoryGroups();
+ assert.deepEqual(groups.length, 2);
+ TriggerableRepositoryGroup.sortByName(groups);
+
+ assert.equal(groups[0].name(), 'system-and-roots');
+ assert.equal(groups[0].acceptsCustomRoots(), true);
+ assert.deepEqual(Repository.sortByName(groups[0].repositories()), [osx]);
+
+ assert.equal(groups[1].name(), 'system-and-webkit');
+ assert.equal(groups[1].acceptsCustomRoots(), false);
+ assert.deepEqual(Repository.sortByName(groups[1].repositories()), [osx, webkit]);
+
</ins><span class="cx"> });
</span><span class="cx"> });
</span><span class="cx">
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgtoolsjsdatabasejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/tools/js/database.js (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/tools/js/database.js        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/tools/js/database.js        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -145,6 +145,7 @@
</span><span class="cx"> 'tests': 'test',
</span><span class="cx"> 'tracker_repositories': 'tracrepo',
</span><span class="cx"> 'triggerable_configurations': 'trigconfig',
</span><ins>+ 'triggerable_repository_groups': 'repositorygroup',
</ins><span class="cx"> 'triggerable_repositories': 'trigrepo',
</span><span class="cx"> 'platforms': 'platform',
</span><span class="cx"> 'reports': 'report',
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgtoolsjsv3modelsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/tools/js/v3-models.js (214974 => 214975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/tools/js/v3-models.js        2017-04-05 22:55:25 UTC (rev 214974)
+++ trunk/Websites/perf.webkit.org/tools/js/v3-models.js        2017-04-05 23:12:46 UTC (rev 214975)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> importFromV3('models/test-group.js', 'TestGroup');
</span><span class="cx"> importFromV3('models/time-series.js', 'TimeSeries');
</span><span class="cx"> importFromV3('models/triggerable.js', 'Triggerable');
</span><ins>+importFromV3('models/triggerable.js', 'TriggerableRepositoryGroup');
</ins><span class="cx"> importFromV3('models/uploaded-file.js', 'UploadedFile');
</span><span class="cx">
</span><span class="cx"> importFromV3('privileged-api.js', 'PrivilegedAPI');
</span></span></pre>
</div>
</div>
</body>
</html>