Analysis task should show all possible revisions for A/B testing
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Jun 2015 01:40:56 +0000 (01:40 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 16 Jun 2015 01:40:56 +0000 (01:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=145996

Reviewed by Chris Dumez.

* public/api/commits.php:
(fetch_commits_between): When the time stamp is not available for commits, use revision numbers
to find revisions between two ranges. This is necessary for OS X and iOS versions since they don't
have a "commit time".

* public/v2/app.js:
(App.AnalysisTaskController.updateRootConfigurations): Fetch commits between two end points.
(App.AnalysisTaskController._createConfiguration): Extracted from updateRootConfigurations. List
the fetched list of commits if available.
(App.AnalysisTaskController._serializeNumbersSkippingConsecutiveEntries): Added. Serializes an list
of numbers intelligently. For example, [1, 2, 4, 5] turns into "1-2, 4-5". Without this, some lists
of points shown in the A/B testing configurations become too long.

* public/v2/commits-viewer.js:
(App.CommitsViewerComponent.commitsChanged):

* public/v2/data.js:
(CommitLogs.fetchCommits): Renamed from fetchForTimeRange.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@185574 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Websites/perf.webkit.org/ChangeLog
Websites/perf.webkit.org/public/api/commits.php
Websites/perf.webkit.org/public/v2/app.js
Websites/perf.webkit.org/public/v2/commits-viewer.js
Websites/perf.webkit.org/public/v2/data.js

index b01d375..981dd9f 100644 (file)
@@ -1,3 +1,29 @@
+2015-06-15  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Analysis task should show all possible revisions for A/B testing
+        https://bugs.webkit.org/show_bug.cgi?id=145996
+
+        Reviewed by Chris Dumez.
+
+        * public/api/commits.php:
+        (fetch_commits_between): When the time stamp is not available for commits, use revision numbers
+        to find revisions between two ranges. This is necessary for OS X and iOS versions since they don't
+        have a "commit time".
+
+        * public/v2/app.js:
+        (App.AnalysisTaskController.updateRootConfigurations): Fetch commits between two end points.
+        (App.AnalysisTaskController._createConfiguration): Extracted from updateRootConfigurations. List
+        the fetched list of commits if available.
+        (App.AnalysisTaskController._serializeNumbersSkippingConsecutiveEntries): Added. Serializes an list
+        of numbers intelligently. For example, [1, 2, 4, 5] turns into "1-2, 4-5". Without this, some lists
+        of points shown in the A/B testing configurations become too long. 
+
+        * public/v2/commits-viewer.js:
+        (App.CommitsViewerComponent.commitsChanged):
+
+        * public/v2/data.js:
+        (CommitLogs.fetchCommits): Renamed from fetchForTimeRange.
+
 2015-06-13  Ryosuke Niwa  <rniwa@webkit.org>
 
         Add a script to post new OS X builds to perf dashboard
 2015-06-13  Ryosuke Niwa  <rniwa@webkit.org>
 
         Add a script to post new OS X builds to perf dashboard
index 597f716..6dbfb44 100644 (file)
@@ -70,20 +70,26 @@ function fetch_commits_between($db, $repository_id, $first, $second, $keyword =
         committer_name as "authorName",
         committer_account as "authorEmail",
         commit_message as "message"
         committer_name as "authorName",
         committer_account as "authorEmail",
         commit_message as "message"
-        FROM commits JOIN committers ON commit_committer = committer_id
+        FROM commits LEFT OUTER JOIN committers ON commit_committer = committer_id
         WHERE commit_repository = $1 AND commit_reported = true';
     $values = array($repository_id);
 
     if ($first && $second) {
         WHERE commit_repository = $1 AND commit_reported = true';
     $values = array($repository_id);
 
     if ($first && $second) {
-        $fitrt_commit = commit_from_revision($db, $repository_id, $first);
+        $first_commit = commit_from_revision($db, $repository_id, $first);
         $second_commit = commit_from_revision($db, $repository_id, $second);
         $second_commit = commit_from_revision($db, $repository_id, $second);
-        $first = $fitrt_commit['commit_time'];
+        $first = $first_commit['commit_time'];
         $second = $second_commit['commit_time'];
         $second = $second_commit['commit_time'];
+        $column = 'commit_time';
+        if (!$first && !$second) {
+            $first = $first_commit['commit_revision'];
+            $second = $second_commit['commit_revision'];
+            $column = 'commit_revision';
+        }
         $in_order = $first < $second;
         array_push($values, $in_order ? $first : $second);
         $in_order = $first < $second;
         array_push($values, $in_order ? $first : $second);
-        $statements .= ' AND commit_time >= $' . count($values);
+        $statements .= ' AND ' . $column . ' >= $' . count($values);
         array_push($values, $in_order ? $second : $first);
         array_push($values, $in_order ? $second : $first);
-        $statements .= ' AND commit_time <= $' . count($values);
+        $statements .= ' AND ' . $column . ' <= $' . count($values);
     }
 
     if ($keyword) {
     }
 
     if ($keyword) {
index 04dab60..e25c9e6 100755 (executable)
@@ -1250,43 +1250,92 @@ App.AnalysisTaskController = Ember.Controller.extend({
             var revisions = point.measurement.formattedRevisions();
             for (var repositoryId in revisions) {
                 if (!repositoryToRevisions[repositoryId])
             var revisions = point.measurement.formattedRevisions();
             for (var repositoryId in revisions) {
                 if (!repositoryToRevisions[repositoryId])
-                    repositoryToRevisions[repositoryId] = new Array(analysisPoints.length);
+                    repositoryToRevisions[repositoryId] = {commits: null, revisions: []};
                 var revision = revisions[repositoryId];
                 var revision = revisions[repositoryId];
-                repositoryToRevisions[repositoryId][pointIndex] = {
+                repositoryToRevisions[repositoryId].revisions[pointIndex] = {
                     label: point.label + ': ' + revision.label,
                     value: revision.currentRevision,
                 };
             }
         });
 
                     label: point.label + ': ' + revision.label,
                     value: revision.currentRevision,
                 };
             }
         });
 
+        var commitsPromises = [];
+        var repositoryToIndex = {};
+        for (var repositoryId in repositoryToRevisions) {
+            var revisions = repositoryToRevisions[repositoryId].revisions;
+            repositoryToIndex[repositoryId] = commitsPromises.length;
+            console.log(repositoryId)
+            commitsPromises.push(CommitLogs.fetchCommits(repositoryId, revisions[0].value, revisions[revisions.length - 1].value));
+        }
+
         var self = this;
         this.get('model').get('triggerable').then(function (triggerable) {
             if (!triggerable)
                 return;
         var self = this;
         this.get('model').get('triggerable').then(function (triggerable) {
             if (!triggerable)
                 return;
-
-            self.set('configurations', ['A', 'B']);
-            self.set('rootConfigurations', triggerable.get('acceptedRepositories').map(function (repository) {
-                var repositoryId = repository.get('id');
-                var options = [{label: 'None'}].concat((repositoryToRevisions[repositoryId] || []).map(function (option, index) {
-                    if (!option || !option['value'])
-                        return {value: '', label: analysisPoints[index].label + ': None'}; 
-                    return option;
+            Ember.RSVP.Promise.all(commitsPromises).then(function (commitsList) {
+                self.set('configurations', ['A', 'B']);
+                self.set('rootConfigurations', triggerable.get('acceptedRepositories').map(function (repository) {
+                    return self._createConfiguration(repository, commitsList[repositoryToIndex[repository.get('id')]], analysisPoints);
                 }));
                 }));
-                return Ember.Object.create({
-                    repository: repository,
-                    name: repository.get('name'),
-                    sets: [
-                        Ember.Object.create({name: 'A[' + repositoryId + ']',
-                            options: options,
-                            selection: options[1]}),
-                        Ember.Object.create({name: 'B[' + repositoryId + ']',
-                            options: options,
-                            selection: options[options.length - 1]}),
-                    ],
-                });
-            }));
+            });
         });
     }.observes('analysisPoints'),
         });
     }.observes('analysisPoints'),
+    _createConfiguration: function(repository, commits, analysisPoints) {
+        var repositoryId = repository.get('id');
+
+        var options = [{label: 'None'}];
+        var revisionToPoints = {};
+        analysisPoints.forEach(function (point, pointIndex) {
+            var revision = point.measurement.revisionForRepository(repositoryId);
+            if (!revision)
+                return;
+            if (!revisionToPoints[revision])
+                revisionToPoints[revision] = [];
+            revisionToPoints[revision].push(pointIndex);
+        });
+
+        if (!commits || !commits.length) {
+            commits = [];
+            for (var revision in revisionToPoints)
+                commits.push({revision: revision});
+        }
+
+        for (var commit of commits) {
+            var revision = commit.revision;
+            var label = Measurement.formatRevisionRange(revision).label;
+            var points = revisionToPoints[revision];
+            if (points) {
+                var serializedPoints = this._serializeNumbersSkippingConsecutiveEntries(revisionToPoints[revision]);
+                label += ' ' + ['(', points.length > 1 ? 'points' : 'point', serializedPoints, ')'].join(' ');
+            }
+            options.push({value: revision, label: label});
+        }
+
+        return Ember.Object.create({
+            repository: repository,
+            name: repository.get('name'),
+            sets: [
+                Ember.Object.create({name: 'A[' + repositoryId + ']',
+                    options: options,
+                    selection: options[1]}),
+                Ember.Object.create({name: 'B[' + repositoryId + ']',
+                    options: options,
+                    selection: options[options.length - 1]}),
+            ]});
+    },
+    _serializeNumbersSkippingConsecutiveEntries: function (numbers) {
+        var result = numbers[0];
+        for (var i = 1; i < numbers.length; i++) {
+            if (numbers[i - 1] + 1 == numbers[i]) {
+                while (numbers[i] + 1 == numbers[i + 1])
+                    i++;
+                result += '-' + numbers[i];
+                continue;
+            }
+            result += ', ' + numbers[i]
+        }
+        return result;
+    },
     actions: {
         addBug: function (bugTracker, bugNumber)
         {
     actions: {
         addBug: function (bugTracker, bugNumber)
         {
index 947c437..4407070 100644 (file)
@@ -14,7 +14,7 @@ App.CommitsViewerComponent = Ember.Component.extend({
             return;
 
         var self = this;
             return;
 
         var self = this;
-        CommitLogs.fetchForTimeRange(repository.get('id'), from, to).then(function (commits) {
+        CommitLogs.fetchCommits(repository.get('id'), from, to).then(function (commits) {
             if (self.isDestroyed)
                 return;
             self.set('commits', commits.map(function (commit) {
             if (self.isDestroyed)
                 return;
             self.set('commits', commits.map(function (commit) {
index c6417a7..5e2e185 100755 (executable)
@@ -64,7 +64,7 @@ var CommitLogs = {
     _cachedCommitsByRepository: {}
 };
 
     _cachedCommitsByRepository: {}
 };
 
-CommitLogs.fetchForTimeRange = function (repository, from, to, keyword)
+CommitLogs.fetchCommits = function (repository, from, to, keyword)
 {
     var params = [];
     if (from && to) {
 {
     var params = [];
     if (from && to) {