fa55039796924c556017cd5f089a832db9a0a9c0
[WebKit-https.git] / Websites / perf.webkit.org / public / privileged-api / create-test-group.php
1 <?php
2
3 require_once('../include/json-header.php');
4 require_once('../include/commit-log-fetcher.php');
5 require_once('../include/repository-group-finder.php');
6
7 function main()
8 {
9     $db = connect();
10     $data = ensure_privileged_api_data_and_token_or_slave($db);
11     $author = remote_user_name($data);
12
13     $arguments = validate_arguments($data, array(
14         'name' => '/.+/',
15         'task' => 'int?',
16         'repetitionCount' => 'int?',
17     ));
18     $name = $arguments['name'];
19     $task_id = array_get($arguments, 'task');
20     $task_name = array_get($data, 'taskName');
21     $repetition_count = $arguments['repetitionCount'];
22     $platform_id = array_get($data, 'platform');
23     $test_id = array_get($data, 'test');
24     $revision_set_list = array_get($data, 'revisionSets');
25     $commit_sets_info = array_get($data, 'commitSets'); // V2 UI compatibility
26
27     if (!$task_id == !$task_name)
28         exit_with_error('InvalidTask');
29
30     if ($task_id)
31         require_format('Task', $task_id, '/^\d+$/');
32     if ($task_name || $platform_id || $test_id) {
33         require_format('Platform', $platform_id, '/^\d+$/');
34         require_format('Test', $test_id, '/^\d+$/');
35     }
36
37     if (!$revision_set_list && !$commit_sets_info)
38         exit_with_error('InvalidCommitSets');
39
40     if ($repetition_count === null)
41         $repetition_count = 1;
42     else if ($repetition_count < 1)
43         exit_with_error('InvalidRepetitionCount', array('repetitionCount' => $repetition_count));
44
45     $triggerable_id = NULL;
46     if ($task_id) {
47         $task = $db->select_first_row('analysis_tasks', 'task', array('id' => $task_id));
48         if (!$task)
49             exit_with_error('InvalidTask', array('task' => $task_id));
50
51         $duplicate_test_group = $db->select_first_row('analysis_test_groups', 'testgroup', array('task' => $task_id, 'name' => $name));
52         if ($duplicate_test_group)
53             exit_with_error('DuplicateTestGroupName', array('task' => $task_id, 'testGroup' => $duplicate_test_group['testgroup_id']));
54
55         $triggerable = find_triggerable_for_task($db, $task_id);
56         if ($triggerable) {
57             $triggerable_id = $triggerable['id'];
58             if (!$platform_id && !$test_id) {
59                 $platform_id = $triggerable['platform'];
60                 $test_id = $triggerable['test'];
61             } else {
62                 if ($triggerable['platform'] && $platform_id != $triggerable['platform'])
63                     exit_with_error('InconsistentPlatform', array('groupPlatform' => $platform_id, 'taskPlatform' => $triggerable['platform']));
64                 if ($triggerable['test'] && $test_id != $triggerable['test'])
65                     exit_with_error('InconsistentTest', array('groupTest' => $test_id, 'taskTest' => $triggerable['test']));
66             }
67         }
68     }
69     if (!$triggerable_id && $platform_id && $test_id) {
70         $triggerable_configuration = $db->select_first_row('triggerable_configurations', 'trigconfig',
71             array('test' => $test_id, 'platform' => $platform_id));
72         if ($triggerable_configuration)
73             $triggerable_id = $triggerable_configuration['trigconfig_triggerable'];
74     }
75
76     if (!$triggerable_id)
77         exit_with_error('TriggerableNotFoundForTask', array('task' => $task_id, 'platform' => $platform_id, 'test' => $test_id));
78
79     if ($revision_set_list)
80         $commit_sets = commit_sets_from_revision_sets($db, $triggerable_id, $revision_set_list);
81     else // V2 UI compatibility
82         $commit_sets = ensure_commit_sets($db, $triggerable_id, $commit_sets_info);
83
84     $db->begin_transaction();
85
86     if ($task_name)
87         $task_id = $db->insert_row('analysis_tasks', 'task', array('name' => $task_name, 'author' => $author));
88
89     $configuration_list = array();
90     $repository_group_with_builds = array();
91     foreach ($commit_sets as $commit_list) {
92         $commit_set_id = $db->insert_row('commit_sets', 'commitset', array());
93         $need_to_build = FALSE;
94         foreach ($commit_list['set'] as $commit_row) {
95             $commit_row['set'] = $commit_set_id;
96             $requires_build =  $commit_row['requires_build'];
97             assert(is_bool($requires_build));
98             $need_to_build = $need_to_build || $requires_build;
99             $db->insert_row('commit_set_items', 'commitset', $commit_row, 'commit');
100         }
101         $repository_group = $commit_list['repository_group'];
102         if ($need_to_build)
103             $repository_group_with_builds[$repository_group] = TRUE;
104         array_push($configuration_list, array('commit_set' => $commit_set_id, 'repository_group' => $repository_group));
105     }
106
107     $build_count = 0;
108     foreach ($configuration_list as &$config_item) {
109         if (array_get($repository_group_with_builds, $config_item['repository_group'])) {
110             $config_item['need_to_build'] = TRUE;
111             $build_count++;
112         }
113     }
114
115     $group_id = $db->insert_row('analysis_test_groups', 'testgroup',
116         array('task' => $task_id, 'name' => $name, 'author' => $author));
117
118     if ($build_count) {
119         $order = -$build_count;
120         foreach ($configuration_list as $config) {
121             if (!array_get($config, 'need_to_build'))
122                 continue;
123             assert($order < 0);
124             $db->insert_row('build_requests', 'request', array(
125                 'triggerable' => $triggerable_id,
126                 'repository_group' => $config['repository_group'],
127                 'platform' => $platform_id,
128                 'test' => NULL,
129                 'group' => $group_id,
130                 'order' => $order,
131                 'commit_set' => $config['commit_set']));
132             $order++;
133         }
134     }
135
136     $order = 0;
137     for ($i = 0; $i < $repetition_count; $i++) {
138         foreach ($configuration_list as $config) {
139             $db->insert_row('build_requests', 'request', array(
140                 'triggerable' => $triggerable_id,
141                 'repository_group' => $config['repository_group'],
142                 'platform' => $platform_id,
143                 'test' => $test_id,
144                 'group' => $group_id,
145                 'order' => $order,
146                 'commit_set' => $config['commit_set']));
147             $order++;
148         }
149     }
150
151     $db->commit_transaction();
152
153     exit_with_success(array('taskId' => $task_id, 'testGroupId' => $group_id));
154 }
155
156 function commit_sets_from_revision_sets($db, $triggerable_id, $revision_set_list)
157 {
158     if (count($revision_set_list) < 2)
159         exit_with_error('InvalidRevisionSets', array('revisionSets' => $revision_set_list));
160
161     $finder = new RepositoryGroupFinder($db, $triggerable_id);
162     $commit_set_list = array();
163     $repository_owner_list = array();
164     $repositories_require_build = array();
165     $commit_set_items_by_repository = array();
166     foreach ($revision_set_list as $revision_set) {
167         if (!count($revision_set))
168             exit_with_error('InvalidRevisionSets', array('revisionSets' => $revision_set_list));
169
170         $commit_set = array();
171         $repository_list = array();
172         $repository_with_patch = array();
173         foreach ($revision_set as $repository_id => $data) {
174             if ($repository_id == 'customRoots') {
175                 $file_id_list = $data;
176                 foreach ($file_id_list as $file_id) {
177                     if (!is_numeric($file_id) || !$db->select_first_row('uploaded_files', 'file', array('id' => $file_id)))
178                         exit_with_error('InvalidUploadedFile', array('file' => $file_id));
179                     array_push($commit_set, array('root_file' => $file_id, 'patch_file' => NULL, 'requires_build' => FALSE, 'commit_owner' => NULL));
180                 }
181                 continue;
182             }
183             if (!is_numeric($repository_id))
184                 exit_with_error('InvalidRepository', array('repository' => $repository_id));
185
186             if (!is_array($data))
187                 exit_with_error('InvalidRepositoryData', array('repository' => $repository_id, 'data' => $data));
188
189             $revision = array_get($data, 'revision');
190             if (!$revision)
191                 exit_with_error('InvalidRevision', array('repository' => $repository_id, 'data' => $data));
192             $commit_id = CommitLogFetcher::find_commit_id_by_revision($db, $repository_id, $revision);
193             if ($commit_id < 0)
194                 exit_with_error('AmbiguousRevision', array('repository' => $repository_id, 'revision' => $revision));
195             if (!$commit_id)
196                 exit_with_error('RevisionNotFound', array('repository' => $repository_id, 'revision' => $revision));
197
198             $owner_revision = array_get($data, 'ownerRevision');
199             $patch_file_id = array_get($data, 'patch');
200             if ($patch_file_id) {
201                 if (!is_numeric($patch_file_id) || !$db->select_first_row('uploaded_files', 'file', array('id' => $patch_file_id)))
202                     exit_with_error('InvalidPatchFile', array('patch' => $patch_file_id));
203                 array_push($repository_with_patch, $repository_id);
204                 $repositories_require_build[$repository_id] =  TRUE;
205             }
206
207             $repository = NULL;
208             $owner_commit_id = NULL;
209             if ($owner_revision) {
210                 $repository = $db->select_first_row('repositories', 'repository', array('id' => intval($repository_id)));
211                 if (!$repository)
212                     exit_with_error('RepositoryNotFound', array('repository' => $repository_id));
213                 $owner_commit = $db->select_first_row('commits', 'commit', array('repository' => $repository['repository_owner'], 'revision' => $owner_revision));
214                 if (!$owner_commit)
215                     exit_with_error('InvalidOwnerRevision', array('repository' => $repository['repository_owner'], 'revision' => $owner_revision));
216                 if (!$db->select_first_row('commit_ownerships', 'commit', array('owned' => $commit_id, 'owner' => $owner_commit['commit_id'])))
217                     exit_with_error('InvalidCommitOwnership', array('commitOwner' => $owner_commit['commit_id'], 'commitOwned' => $commit_id));
218                 $repositories_require_build[$repository_id] =  TRUE;
219                 $owner_commit_id = $owner_commit['commit_id'];
220             }
221
222             array_push($commit_set, array('commit' => $commit_id, 'patch_file' => $patch_file_id, 'requires_build' => FALSE, 'commit_owner' => $owner_commit_id));
223
224             array_ensure_item_has_array($commit_set_items_by_repository, $repository_id);
225             $commit_set_items_by_repository[$repository_id][] = &$commit_set[count($commit_set) - 1];
226
227             if ($owner_commit_id)
228                 continue;
229             array_push($repository_list, $repository_id);
230         }
231         $repository_group_id = $finder->find_by_repositories($repository_list);
232         if (!$repository_group_id)
233             exit_with_error('NoMatchingRepositoryGroup', array('repositories' => $repository_list));
234
235         foreach ($repository_with_patch as $repository_id) {
236             if (!$finder->accepts_patch($repository_group_id, $repository_id))
237                 exit_with_error('PatchNotAccepted', array('repository' => $repository_id, 'repositoryGroup' => $repository_group_id));
238         }
239
240         array_push($commit_set_list, array('repository_group' => $repository_group_id, 'set' => $commit_set));
241     }
242
243     foreach (array_keys($repositories_require_build) as $repository_id) {
244         foreach($commit_set_items_by_repository[$repository_id] as &$commit_set_item)
245             $commit_set_item['requires_build'] = TRUE;
246     }
247     return $commit_set_list;
248 }
249
250 function ensure_commit_sets($db, $triggerable_id, $commit_sets_info) {
251     $repository_name_to_id = array();
252     foreach ($db->select_rows('repositories', 'repository', array('owner' => NULL)) as $row)
253         $repository_name_to_id[$row['repository_name']] = $row['repository_id'];
254
255     $commit_sets = array();
256     $repository_list = array();
257     foreach ($commit_sets_info as $repository_name => $revisions) {
258         $repository_id = array_get($repository_name_to_id, $repository_name);
259         if (!$repository_id)
260             exit_with_error('RepositoryNotFound', array('name' => $repository_name));
261         array_push($repository_list, $repository_id);
262
263         foreach ($revisions as $i => $revision) {
264             $commit = $db->select_first_row('commits', 'commit', array('repository' => $repository_id, 'revision' => $revision));
265             if (!$commit)
266                 exit_with_error('RevisionNotFound', array('repository' => $repository_name, 'revision' => $revision));
267             array_set_default($commit_sets, $i, array('set' => array()));
268             array_push($commit_sets[$i]['set'], array('commit' => $commit['commit_id'], 'patch_file' => NULL, 'requires_build' => FALSE, 'commit_owner' => NULL));
269         }
270     }
271
272     $finder = new RepositoryGroupFinder($db, $triggerable_id);
273     $repository_group_id = $finder->find_by_repositories($repository_list);
274     if (!$repository_group_id)
275         exit_with_error('NoMatchingRepositoryGroup', array('repositories' => $repository_list));
276
277     if (count($commit_sets) < 2)
278         exit_with_error('InvalidCommitSets', array('commitSets' => $commit_sets_info));
279
280     $commit_count_per_set = count($commit_sets[0]['set']);
281     foreach ($commit_sets as &$commits) {
282         $commits['repository_group'] = $repository_group_id;
283         if ($commit_count_per_set != count($commits['set']))
284             exit_with_error('InvalidCommitSets', array('commitSets' => $commit_sets));
285     }
286
287     return $commit_sets;
288 }
289
290 main();
291
292 ?>