From 8d5019996692bf9e9633e047847f80e8e9f12512 Mon Sep 17 00:00:00 2001 From: "rniwa@webkit.org" Date: Tue, 16 Jun 2015 01:40:56 +0000 Subject: [PATCH] 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. git-svn-id: https://svn.webkit.org/repository/webkit/trunk@185574 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Websites/perf.webkit.org/ChangeLog | 26 ++++++ Websites/perf.webkit.org/public/api/commits.php | 16 ++-- Websites/perf.webkit.org/public/v2/app.js | 95 ++++++++++++++++------ .../perf.webkit.org/public/v2/commits-viewer.js | 2 +- Websites/perf.webkit.org/public/v2/data.js | 2 +- 5 files changed, 111 insertions(+), 30 deletions(-) diff --git a/Websites/perf.webkit.org/ChangeLog b/Websites/perf.webkit.org/ChangeLog index b01d375..981dd9f 100644 --- a/Websites/perf.webkit.org/ChangeLog +++ b/Websites/perf.webkit.org/ChangeLog @@ -1,3 +1,29 @@ +2015-06-15 Ryosuke Niwa + + 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 Add a script to post new OS X builds to perf dashboard diff --git a/Websites/perf.webkit.org/public/api/commits.php b/Websites/perf.webkit.org/public/api/commits.php index 597f716..6dbfb44 100644 --- a/Websites/perf.webkit.org/public/api/commits.php +++ b/Websites/perf.webkit.org/public/api/commits.php @@ -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" - 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) { - $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); - $first = $fitrt_commit['commit_time']; + $first = $first_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); - $statements .= ' AND commit_time >= $' . count($values); + $statements .= ' AND ' . $column . ' >= $' . count($values); array_push($values, $in_order ? $second : $first); - $statements .= ' AND commit_time <= $' . count($values); + $statements .= ' AND ' . $column . ' <= $' . count($values); } if ($keyword) { diff --git a/Websites/perf.webkit.org/public/v2/app.js b/Websites/perf.webkit.org/public/v2/app.js index 04dab60..e25c9e6 100755 --- a/Websites/perf.webkit.org/public/v2/app.js +++ b/Websites/perf.webkit.org/public/v2/app.js @@ -1250,43 +1250,92 @@ App.AnalysisTaskController = Ember.Controller.extend({ 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]; - repositoryToRevisions[repositoryId][pointIndex] = { + repositoryToRevisions[repositoryId].revisions[pointIndex] = { 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; - - 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'), + _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) { diff --git a/Websites/perf.webkit.org/public/v2/commits-viewer.js b/Websites/perf.webkit.org/public/v2/commits-viewer.js index 947c437..4407070 100644 --- a/Websites/perf.webkit.org/public/v2/commits-viewer.js +++ b/Websites/perf.webkit.org/public/v2/commits-viewer.js @@ -14,7 +14,7 @@ App.CommitsViewerComponent = Ember.Component.extend({ 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) { diff --git a/Websites/perf.webkit.org/public/v2/data.js b/Websites/perf.webkit.org/public/v2/data.js index c6417a7..5e2e185 100755 --- a/Websites/perf.webkit.org/public/v2/data.js +++ b/Websites/perf.webkit.org/public/v2/data.js @@ -64,7 +64,7 @@ var CommitLogs = { _cachedCommitsByRepository: {} }; -CommitLogs.fetchForTimeRange = function (repository, from, to, keyword) +CommitLogs.fetchCommits = function (repository, from, to, keyword) { var params = []; if (from && to) { -- 1.8.3.1