Perf dashboard should be able to trigger A/B testing jobs for iOS
[WebKit-https.git] / Websites / perf.webkit.org / public / v2 / analysis.js
1 App.AnalysisTask = App.NameLabelModel.extend({
2     author: DS.attr('string'),
3     createdAt: DS.attr('date'),
4     platform: DS.belongsTo('platform'),
5     metric: DS.belongsTo('metric'),
6     startRun: DS.attr('number'),
7     endRun: DS.attr('number'),
8     bugs: DS.hasMany('bugs'),
9     testGroups: function (key, value, oldValue) {
10         return this.store.find('testGroup', {task: this.get('id')});
11     }.property(),
12     triggerable: function () {
13         return this.store.find('triggerable', {task: this.get('id')}).then(function (triggerables) {
14             return triggerables.objectAt(0);
15         }, function (error) {
16             console.log('Failed to fetch triggerables', error);
17             return null;
18         });
19     }.property(),
20     label: function () {
21         var label = this.get('name');
22         var bugs = this.get('bugs').map(function (bug) { return bug.get('label'); }).join(' / ');
23         return bugs ? label + ' (' + bugs + ')' : label;
24     }.property('name', 'bugs'),
25 });
26
27 App.Bug = App.Model.extend({
28     task: DS.belongsTo('AnalysisTask'),
29     bugTracker: DS.belongsTo('BugTracker'),
30     createdAt: DS.attr('date'),
31     number: DS.attr('number'),
32     label: function () {
33         return this.get('bugTracker').get('label') + ': ' + this.get('number');
34     }.property('name', 'bugTracker'),
35 });
36
37 // FIXME: Use DS.RESTAdapter instead.
38 App.AnalysisTask.create = function (name, startMeasurement, endMeasurement)
39 {
40     return PrivilegedAPI.sendRequest('create-analysis-task', {
41         name: name,
42         startRun: startMeasurement.id(),
43         endRun: endMeasurement.id(),
44     });
45 }
46
47 App.AnalysisTaskAdapter = DS.RESTAdapter.extend({
48     buildURL: function (type, id)
49     {
50         return '../api/analysis-tasks/' + (id ? id : '');
51     },
52 });
53
54 App.BugAdapter = DS.RESTAdapter.extend({
55     createRecord: function (store, type, record)
56     {
57         var param = {
58             task: record.get('task').get('id'),
59             bugTracker: record.get('bugTracker').get('id'),
60             number: record.get('number'),
61         };
62         return PrivilegedAPI.sendRequest('associate-bug', param).then(function (data) {
63             param['id'] = data['bugId'];
64             return {'bug': param};
65         });
66     }
67 });
68
69 App.Root = App.Model.extend({
70     repository: DS.belongsTo('repository'),
71     revision: DS.attr('string'),
72 });
73
74 App.RootSet = App.Model.extend({
75     roots: DS.hasMany('roots'),
76     revisionForRepository: function (repository)
77     {
78         var root = this.get('roots').findBy('repository', repository);
79         if (!root)
80             return null;
81         return root.get('revision');
82     }
83 });
84
85 App.TestGroup = App.NameLabelModel.extend({
86     task: DS.belongsTo('analysisTask'),
87     author: DS.attr('string'),
88     createdAt: DS.attr('date'),
89     buildRequests: DS.hasMany('buildRequests'),
90     rootSets: DS.hasMany('rootSets'),
91     _fetchTestResults: function ()
92     {
93         var task = this.get('task');
94         if (!task)
95             return null;
96         var self = this;
97         return App.Manifest.fetchRunsWithPlatformAndMetric(this.store,
98             task.get('platform').get('id'), task.get('metric').get('id'), this.get('id')).then(
99             function (result) { self.set('testResults', result.data); },
100             function (error) {
101                 // FIXME: Somehow this never gets called.
102                 alert('Failed to fetch the results:' + error);
103                 return null;
104             });
105     }.observes('task', 'task.platform', 'task.metric').on('init'),
106 });
107
108 App.TestGroup.create = function (analysisTask, name, rootSets, repetitionCount)
109 {
110     var param = {
111         task: analysisTask.get('id'),
112         name: name,
113         rootSets: rootSets,
114         repetitionCount: repetitionCount,
115     };
116     return PrivilegedAPI.sendRequest('create-test-group', param).then(function (data) {
117         analysisTask.set('testGroups'); // Refetch test groups.
118         return analysisTask.store.find('testGroup', data['testGroupId']);
119     });
120 }
121
122 App.TestGroupAdapter = DS.RESTAdapter.extend({
123     buildURL: function (type, id)
124     {
125         return '../api/test-groups/' + (id ? id : '');
126     },
127 });
128
129 App.Triggerable = App.NameLabelModel.extend({
130     acceptedRepositories: DS.hasMany('repositories'),
131 });
132
133 App.TriggerableAdapter = DS.RESTAdapter.extend({
134     buildURL: function (type, id)
135     {
136         return '../api/triggerables/' + (id ? id : '');
137     },
138 });
139
140 App.AnalysisTaskSerializer = App.TestGroupSerializer = App.TriggerableSerializer = DS.RESTSerializer.extend({
141     normalizePayload: function (payload)
142     {
143         delete payload['status'];
144         return payload;
145     }
146 });
147
148 App.BuildRequest = App.Model.extend({
149     testGroup: DS.belongsTo('testGroup'),
150     order: DS.attr('number'),
151     orderLabel: function ()
152     {
153         return this.get('order') + 1;
154     }.property('order'),
155     rootSet: DS.belongsTo('rootSet'),
156     status: DS.attr('string'),
157     statusLabel: function ()
158     {
159         switch (this.get('status')) {
160         case 'pending':
161             return 'Waiting to be scheduled';
162         case 'scheduled':
163             return 'Scheduled';
164         case 'running':
165             return 'Running';
166         case 'failed':
167             return 'Failed';
168         case 'completed':
169             return 'Completed';
170         }
171     }.property('status'),
172     url: DS.attr('string'),
173     build: DS.attr('number'),
174 });
175
176 App.BuildRequest.aggregateStatuses = function (requests)
177 {
178     var completeCount = 0;
179     var failureCount = 0;
180     requests.forEach(function (request) {
181         switch (request.get('status')) {
182         case 'failed':
183             failureCount++;
184             break;
185         case 'completed':
186             completeCount++;
187             break;
188         }
189     });
190     if (completeCount == requests.length)
191         return 'Done';
192     if (failureCount == requests.length)
193         return 'All failed';
194     var status = completeCount + ' out of ' + requests.length + ' completed';
195     if (failureCount)
196         status += ', ' + failureCount + ' failed';
197     return status;
198 }