Add the support for scheduling a A/B testing with a patch.
[WebKit-https.git] / Websites / perf.webkit.org / public / include / manifest-generator.php
1 <?php
2
3 class ManifestGenerator {
4     private $db;
5     private $manifest;
6
7     // FIXME: Compute this value from config.json
8     const MANIFEST_PATH = '../data/manifest.json';
9
10     function __construct($db) {
11         $this->db = $db;
12     }
13
14     function generate() {
15         $start_time = microtime(true);
16
17         $platform_table = $this->db->fetch_table('platforms');
18         $repositories_table = $this->db->fetch_table('repositories');
19
20         $repositories_with_commit = $this->db->query_and_fetch_all(
21             'SELECT DISTINCT(commit_repository) FROM commits WHERE commit_reported IS TRUE');
22         if (!$repositories_with_commit)
23             $repositories_with_commit = array();
24
25         foreach ($repositories_with_commit as &$row)
26             $row = $row['commit_repository'];
27
28         $tests = (object)$this->tests();
29         $metrics = (object)$this->metrics();
30         $platforms = (object)$this->platforms($platform_table, false);
31         $dashboard = (object)$this->platforms($platform_table, true);
32         $repositories = (object)$this->repositories($repositories_table, $repositories_with_commit);
33
34         $this->manifest = array(
35             'siteTitle' => config('siteTitle', 'Performance Dashboard'),
36             'tests' => &$tests,
37             'metrics' => &$metrics,
38             'all' => &$platforms,
39             'dashboard' => &$dashboard,
40             'repositories' => &$repositories,
41             'builders' => (object)$this->builders(),
42             'bugTrackers' => (object)$this->bug_trackers($repositories_table),
43             'triggerables'=> (object)$this->triggerables(),
44             'dashboards' => (object)config('dashboards'),
45             'summaryPages' => config('summaryPages'),
46             'fileUploadSizeLimit' => config('uploadFileLimitInMB', 0) * 1024 * 1024,
47         );
48
49         $this->manifest['elapsedTime'] = (microtime(true) - $start_time) * 1000;
50
51         return TRUE;
52     }
53
54     function manifest() { return $this->manifest; }
55
56     function store() {
57         return generate_data_file('manifest.json', json_encode($this->manifest));
58     }
59
60     private function tests() {
61         $tests = array();
62         $tests_table = $this->db->fetch_table('tests');
63         if (!$tests_table)
64             return $tests;
65         foreach ($tests_table as $test_row) {
66             $tests[$test_row['test_id']] = array(
67                 'name' => $test_row['test_name'],
68                 'url' => $test_row['test_url'],
69                 'parentId' => $test_row['test_parent'],
70             );
71         }
72         return $tests;
73     }
74
75     private function metrics() {
76         $metrics = array();
77         $metrics_table = $this->db->query_and_fetch_all('SELECT * FROM test_metrics LEFT JOIN aggregators ON metric_aggregator = aggregator_id');
78         if (!$metrics_table)
79             return $metrics;
80         foreach ($metrics_table as $row) {
81             $metrics[$row['metric_id']] = array(
82                 'name' => $row['metric_name'],
83                 'test' => $row['metric_test'],
84                 'aggregator' => $row['aggregator_name']);
85         }
86         return $metrics;
87     }
88
89     private function platforms($platform_table, $is_dashboard) {
90         $metrics = $this->db->query_and_fetch_all('SELECT config_metric AS metric_id, config_platform AS platform_id,
91             extract(epoch from max(config_runs_last_modified) at time zone \'utc\') * 1000 AS last_modified, bool_or(config_is_in_dashboard) AS in_dashboard
92             FROM test_configurations GROUP BY config_metric, config_platform ORDER BY config_platform');
93
94         $platform_metrics = array();
95
96         if ($metrics) {
97             $current_platform_entry = null;
98             foreach ($metrics as $metric_row) {
99                 if ($is_dashboard && !Database::is_true($metric_row['in_dashboard']))
100                     continue;
101
102                 $platform_id = $metric_row['platform_id'];
103                 if (!$current_platform_entry || $current_platform_entry['id'] != $platform_id) {
104                     $current_platform_entry = &array_ensure_item_has_array($platform_metrics, $platform_id);
105                     $current_platform_entry['id'] = $platform_id;
106                     array_ensure_item_has_array($current_platform_entry, 'metrics');
107                     array_ensure_item_has_array($current_platform_entry, 'last_modified');
108                 }
109
110                 array_push($current_platform_entry['metrics'], $metric_row['metric_id']);
111                 array_push($current_platform_entry['last_modified'], intval($metric_row['last_modified']));
112             }
113         }
114         $configurations = array();
115
116         $platforms = array();
117         if ($platform_table) {
118             foreach ($platform_table as $platform_row) {
119                 if (Database::is_true($platform_row['platform_hidden']))
120                     continue;
121                 $id = $platform_row['platform_id'];
122                 if (array_key_exists($id, $platform_metrics)) {
123                     $platforms[$id] = array(
124                         'name' => $platform_row['platform_name'],
125                         'metrics' => $platform_metrics[$id]['metrics'],
126                         'lastModified' => $platform_metrics[$id]['last_modified']);
127                 }
128             }
129         }
130         return $platforms;
131     }
132
133     private function repositories($repositories_table, $repositories_with_commit) {
134         $repositories = array();
135         if (!$repositories_table)
136             return $repositories;
137         foreach ($repositories_table as $row) {
138             $repositories[$row['repository_id']] = array(
139                 'name' => $row['repository_name'],
140                 'url' => $row['repository_url'],
141                 'blameUrl' => $row['repository_blame_url'],
142                 'owner'=> $row['repository_owner'],
143                 'hasReportedCommits' => in_array($row['repository_id'], $repositories_with_commit));
144         }
145
146         return $repositories;
147     }
148
149     private function builders() {
150         $builders_table = $this->db->fetch_table('builders');
151         if (!$builders_table)
152             return array();
153         $builders = array();
154         foreach ($builders_table as $row)
155             $builders[$row['builder_id']] = array('name' => $row['builder_name'], 'buildUrl' => $row['builder_build_url']);
156
157         return $builders;
158     }
159
160     private function bug_trackers($repositories_table) {
161         $tracker_id_to_repositories = array();
162         $tracker_repositories_table = $this->db->fetch_table('tracker_repositories');
163         if ($tracker_repositories_table) {
164             foreach ($tracker_repositories_table as $row) {
165                 array_push(array_ensure_item_has_array($tracker_id_to_repositories, $row['tracrepo_tracker']),
166                     $row['tracrepo_repository']);
167             }
168         }
169
170         $bug_trackers = array();
171         $bug_trackers_table = $this->db->fetch_table('bug_trackers');
172         if ($bug_trackers_table) {
173             foreach ($bug_trackers_table as $row) {
174                 $bug_trackers[$row['tracker_id']] = array(
175                     'name' => $row['tracker_name'],
176                     'bugUrl' => $row['tracker_bug_url'],
177                     'newBugUrl' => $row['tracker_new_bug_url'],
178                     'repositories' => array_get($tracker_id_to_repositories, $row['tracker_id']));
179             }
180         }
181
182         return $bug_trackers;
183     }
184
185     private function triggerables()
186     {
187         return ManifestGenerator::fetch_triggerables($this->db, array());
188     }
189
190     static function fetch_triggerables($db, $query)
191     {
192         $triggerables = $db->select_rows('build_triggerables', 'triggerable', $query);
193         if (!$triggerables)
194             return array();
195
196         $id_to_triggerable = array();
197         $triggerable_id_to_repository_set = array();
198         foreach ($triggerables as &$row) {
199             $id = $row['triggerable_id'];
200             $id_to_triggerable[$id] = array(
201                 'name' => $row['triggerable_name'],
202                 'isDisabled' => Database::is_true($row['triggerable_disabled']),
203                 'acceptedRepositories' => array(),
204                 'repositoryGroups' => array(),
205                 'configurations' => array());
206             $triggerable_id_to_repository_set[$id] = array();
207         }
208
209         $repository_groups = $db->fetch_table('triggerable_repository_groups', 'repositorygroup_name');
210         $group_repositories = $db->fetch_table('triggerable_repositories');
211         if ($repository_groups && $group_repositories) {
212             $repository_set_by_group = array();
213             foreach ($group_repositories as &$repository_row) {
214                 $group_id = $repository_row['trigrepo_group'];
215                 array_ensure_item_has_array($repository_set_by_group, $group_id);
216                 array_push($repository_set_by_group[$group_id], array(
217                     'repository' => $repository_row['trigrepo_repository'],
218                     'acceptsPatch' => Database::is_true($repository_row['trigrepo_accepts_patch'])));
219             }
220             foreach ($repository_groups as &$group_row) {
221                 $triggerable_id = $group_row['repositorygroup_triggerable'];
222                 if (!array_key_exists($triggerable_id, $id_to_triggerable))
223                     continue;
224                 $triggerable = &$id_to_triggerable[$triggerable_id];
225                 $group_id = $group_row['repositorygroup_id'];
226                 $repository_list = array_get($repository_set_by_group, $group_id, array());
227                 array_push($triggerable['repositoryGroups'], array(
228                     'id' => $group_row['repositorygroup_id'],
229                     'name' => $group_row['repositorygroup_name'],
230                     'description' => $group_row['repositorygroup_description'],
231                     'acceptsCustomRoots' => Database::is_true($group_row['repositorygroup_accepts_roots']),
232                     'repositories' => $repository_list));
233                 // V2 UI compatibility.
234                 foreach ($repository_list as $repository_data) {
235                     $repository_id = $repository_data['repository'];
236                     $set = &$triggerable_id_to_repository_set[$triggerable_id];
237                     if (array_key_exists($repository_id, $set))
238                         continue;
239                     $set[$repository_id] = true;
240                     array_push($triggerable['acceptedRepositories'], $repository_id);
241                 }
242
243             }
244         }
245
246         $configuration_map = $db->fetch_table('triggerable_configurations');
247         if ($configuration_map) {
248             foreach ($configuration_map as &$row) {
249                 $triggerable_id = $row['trigconfig_triggerable'];
250                 if (!array_key_exists($triggerable_id, $id_to_triggerable))
251                     continue;
252                 $triggerable = &$id_to_triggerable[$triggerable_id];
253                 array_push($triggerable['configurations'], array($row['trigconfig_test'], $row['trigconfig_platform']));
254             }
255         }
256
257         return $id_to_triggerable;
258     }
259 }
260
261 ?>