diff --git a/app/adapters/repo.js b/app/adapters/repo.js index b869bcba..e8fcaa9e 100644 --- a/app/adapters/repo.js +++ b/app/adapters/repo.js @@ -1,24 +1,24 @@ import V3Adapter from 'travis/adapters/v3'; +import ApplicationAdapter from 'travis/adapters/application'; +import Config from 'travis/config/environment'; -export default V3Adapter.extend({ +let Adapter = Config.useV3API ? V3Adapter : ApplicationAdapter; + +export default Adapter.extend({ defaultSerializer: '-repo', - buildUrl(modelName, id, snapshot, requestType, query) { - var url = this._super(...arguments); - - return url; - }, - ajaxOptions(url, type, options) { var hash = options || {}; if(!hash.data) { hash.data = {}; } - if(hash.data.include) { - hash.data.include += ',repository.default_branch,branch.last_build,build.commit'; - } else { - hash.data.include = 'repository.default_branch,branch.last_build,build.commit'; + if(Config.useV3API) { + if(hash.data.include) { + hash.data.include += ',repository.default_branch,branch.last_build,build.commit'; + } else { + hash.data.include = 'repository.default_branch,branch.last_build,build.commit'; + } } return this._super(url, type, hash); diff --git a/app/components/repos-list-item.coffee b/app/components/repos-list-item.coffee index 8b6c804e..ef664690 100644 --- a/app/components/repos-list-item.coffee +++ b/app/components/repos-list-item.coffee @@ -16,8 +16,8 @@ ReposListItemComponent = Ember.Component.extend Polling, ).property('selectedRepo') color: (-> - colorForState(@get('repo.defaultBranch.lastBuild.state')) - ).property('repo.defaultBranch.lastBuild.state') + colorForState(@get('repo.lastBuildState')) + ).property('repo.lastBuildState') scrollTop: (-> if (window.scrollY > 0) diff --git a/app/controllers/repo.coffee b/app/controllers/repo.coffee index 8987b66d..b9acf45f 100644 --- a/app/controllers/repo.coffee +++ b/app/controllers/repo.coffee @@ -4,12 +4,14 @@ Controller = Ember.Controller.extend jobController: Ember.inject.controller('job') buildController: Ember.inject.controller('build') + buildsController: Ember.inject.controller('builds') reposController: Ember.inject.controller('repos') currentUserBinding: 'auth.currentUser' classNames: ['repo'] build: Ember.computed.alias('buildController.build') + builds: Ember.computed.alias('buildsController.content') job: Ember.computed.alias('jobController.job') slug: (-> @get('repo.slug') ).property('repo.slug') @@ -77,15 +79,15 @@ Controller = Ember.Controller.extend Ember.run.scheduleOnce('actions', this, @_lastBuildDidChange); _lastBuildDidChange: -> - build = @get('repo.defaultBranch.lastBuild') + build = @get('repo.lastBuild') @set('build', build) stopObservingLastBuild: -> - @removeObserver('repo.defaultBranch.lastBuild', this, 'lastBuildDidChange') + @removeObserver('repo.lastBuild', this, 'lastBuildDidChange') observeLastBuild: -> @lastBuildDidChange() - @addObserver('repo.defaultBranch.lastBuild', this, 'lastBuildDidChange') + @addObserver('repo.lastBuild', this, 'lastBuildDidChange') connectTab: (tab) -> # TODO: such implementation seems weird now, because we render diff --git a/app/controllers/repos.js b/app/controllers/repos.js index 6902dbd7..33d7cd2c 100644 --- a/app/controllers/repos.js +++ b/app/controllers/repos.js @@ -1,27 +1,28 @@ import Ember from 'ember'; import limit from 'travis/utils/computed-limit'; import Repo from 'travis/models/repo'; +import Config from 'travis/config/environment'; var sortCallback = function(repo1, repo2) { // this function could be made simpler, but I think it's clearer this way // what're we really trying to achieve - var lastBuild1 = repo1.get('defaultBranch.lastBuild'); - var lastBuild2 = repo2.get('defaultBranch.lastBuild'); + var lastBuildId1 = repo1.get('lastBuildId'); + var lastBuildId2 = repo2.get('lastBuildId'); - if(!lastBuild1 && !lastBuild2) { + if(!lastBuildId1 && !lastBuildId2) { // if both repos lack builds, put newer repo first return repo1.get('id') > repo2.get('id') ? -1 : 1; - } else if(lastBuild1 && !lastBuild2) { + } else if(lastBuildId1 && !lastBuildId2) { // if only repo1 has a build, it goes first return -1; - } else if(lastBuild2 && !lastBuild1) { + } else if(lastBuildId2 && !lastBuildId1) { // if only repo2 has a build, it goes first return 1; } - var finishedAt1 = lastBuild1.get('finishedAt'); - var finishedAt2 = lastBuild2.get('finishedAt'); + var finishedAt1 = repo1.get('lastBuildFinishedAt'); + var finishedAt2 = repo2.get('lastBuildFinishedAt'); if(finishedAt1) { finishedAt1 = new Date(finishedAt1); @@ -41,7 +42,7 @@ var sortCallback = function(repo1, repo2) { return -1; } else { // none of the builds finished, put newer build first - return lastBuild1.get('id') > lastBuild2.get('id') ? -1 : 1; + return lastBuildId1 > lastBuildId2 ? -1 : 1; } throw "should not happen"; @@ -157,16 +158,22 @@ var Controller = Ember.Controller.extend({ this.set('isLoaded', false); if (user = this.get('currentUser')) { - user.get('_rawPermissions').then( (data) => { - repos = Repo.accessibleBy(this.store, data.pull).then( - (reposRecordArray) => { - this.set('isLoaded', true); - this.set('_repos', reposRecordArray); - this.set('ownedRepos', reposRecordArray); - this.set('fetchingOwnedRepos', false); - return reposRecordArray; - }); - }); + let callback = (reposRecordArray) => { + this.set('isLoaded', true); + this.set('_repos', reposRecordArray); + this.set('ownedRepos', reposRecordArray); + this.set('fetchingOwnedRepos', false); + return reposRecordArray; + }; + + if(Config.useV3API) { + user.get('_rawPermissions').then( (data) => { + Repo.accessibleBy(this.store, data.pull).then(callback); + }); + } else { + let login = user.get('login'); + Repo.accessibleBy(this.store, login).then(callback); + } } } }, diff --git a/app/models/build.coffee b/app/models/build.coffee index a4ceb34e..08d9d04e 100644 --- a/app/models/build.coffee +++ b/app/models/build.coffee @@ -18,7 +18,6 @@ Build = Model.extend DurationCalculations, pullRequestTitle: DS.attr() pullRequestNumber: DS.attr('number') eventType: DS.attr('string') - repositoryId: DS.attr('number') branch: DS.belongsTo('branch', async: false, inverse: 'builds') repo: DS.belongsTo('repo', async: true) diff --git a/app/models/repo.coffee b/app/models/repo.coffee index d5e4394b..783e5209 100644 --- a/app/models/repo.coffee +++ b/app/models/repo.coffee @@ -4,8 +4,54 @@ # the function stops being visible inside computed properties. `import { durationFrom as durationFromHelper } from 'travis/utils/helpers'` `import Build from 'travis/models/build'` +`import Config from 'travis/config/environment'` -Repo = Model.extend +Repo = null + +if Config.useV3API + Repo = Model.extend + defaultBranch: DS.belongsTo('branch', async: false) + + lastBuild: Ember.computed.oneWay('defaultBranch.lastBuild') + + lastBuildFinishedAt: Ember.computed.oneWay('lastBuild.finishedAt') + lastBuildId: Ember.computed.oneWay('lastBuild.id') + lastBuildState: Ember.computed.oneWay('lastBuild.state') + lastBuildNumber: Ember.computed.oneWay('lastBuild.number') + lastBuildStartedAt: Ember.computed.oneWay('lastBuild.startedAt') + lastBuildDuration: Ember.computed.oneWay('lastBuild.duration') + + +else + Repo = Model.extend + lastBuildNumber: DS.attr('number') + lastBuildState: DS.attr() + lastBuildStartedAt: DS.attr() + lastBuildFinishedAt: DS.attr() + _lastBuildDuration: DS.attr('number') + lastBuildLanguage: DS.attr() + lastBuildId: DS.attr('number') + lastBuildHash: (-> + { + id: @get('lastBuildId') + number: @get('lastBuildNumber') + repo: this + } + ).property('lastBuildId', 'lastBuildNumber') + + lastBuild: (-> + if id = @get('lastBuildId') + @store.findRecord('build', id) + @store.recordForId('build', id) + ).property('lastBuildId') + + lastBuildDuration: (-> + duration = @get('_lastBuildDuration') + duration = durationFromHelper(@get('lastBuildStartedAt'), @get('lastBuildFinishedAt')) unless duration + duration + ).property('_lastBuildDuration', 'lastBuildStartedAt', 'lastBuildFinishedAt') + +Repo.reopen ajax: Ember.inject.service() slug: DS.attr() @@ -14,15 +60,8 @@ Repo = Model.extend githubLanguage: DS.attr() active: DS.attr() - #lastBuild: DS.belongsTo('build') - defaultBranch: DS.belongsTo('branch', async: false) - - # just for sorting - lastBuildFinishedAt: Ember.computed.oneWay('defaultBranch.lastBuild.finishedAt') - lastBuildId: Ember.computed.oneWay('defaultBranch.lastBuild.id') - withLastBuild: -> - @filter( (repo) -> repo.get('defaultBranch.lastBuild') ) + @filter( (repo) -> repo.get('lastBuildId') ) sshKey: (-> @store.find('ssh_key', @get('id')) @@ -39,7 +78,7 @@ Repo = Model.extend builds: (-> id = @get('id') builds = @store.filter('build', event_type: ['push', 'api'], repository_id: id, (b) -> - b.get('repositoryId')+'' == id+'' && (b.get('eventType') == 'push' || b.get('eventType') == 'api') + b.get('repo.id')+'' == id+'' && (b.get('eventType') == 'push' || b.get('eventType') == 'api') ) # TODO: move to controller @@ -56,7 +95,7 @@ Repo = Model.extend pullRequests: (-> id = @get('id') builds = @store.filter('build', event_type: 'pull_request', repository_id: id, (b) -> - b.get('repositoryId')+'' == id+'' && b.get('eventType') == 'pull_request' + b.get('repo.id')+'' == id+'' && b.get('eventType') == 'pull_request' ) # TODO: move to controller @@ -90,12 +129,12 @@ Repo = Model.extend ).property('slug') sortOrderForLandingPage: (-> - state = @get('defaultBranch.lastBuild.state') + state = @get('lastBuildState') if state != 'passed' && state != 'failed' 0 else - parseInt(@get('defaultBranch.lastBuild.id')) - ).property('defaultBranch.lastBuild.id', 'defaultBranch.lastBuild.state') + parseInt(@get('lastBuildId')) + ).property('lastBuildId', 'lastBuildState') stats: (-> if @get('slug') @@ -106,8 +145,11 @@ Repo = Model.extend ).property('slug') updateTimes: -> - if lastBuild = @get('defaultBranch.lastBuild') - lastBuild.updateTimes() + if Config.useV3API + if lastBuild = @get('lastBuild') + lastBuild.updateTimes() + else + @notifyPropertyChange 'lastBuildDuration' regenerateKey: (options) -> @get('ajax').ajax '/repos/' + @get('id') + '/key', 'post', options @@ -123,41 +165,49 @@ Repo.reopenClass recent: -> @find() - accessibleBy: (store, reposIds) -> - # this fires only for authenticated users and with API v3 that means getting - # only repos of currently logged in owner, but in the future it would be - # nice to not use that as it may change in the future - repos = store.filter('repo', (repo) -> - reposIds.indexOf(parseInt(repo.get('id'))) != -1 - ) - - promise = new Ember.RSVP.Promise (resolve, reject) -> - store.query('repo', { 'repository.active': 'true', limit: 20 }).then( -> - resolve(repos) - , -> - reject() + accessibleBy: (store, reposIdsOrlogin) -> + if Config.useV3API + reposIds = reposIdsOrlogin + # this fires only for authenticated users and with API v3 that means getting + # only repos of currently logged in owner, but in the future it would be + # nice to not use that as it may change in the future + repos = store.filter('repo', (repo) -> + reposIds.indexOf(parseInt(repo.get('id'))) != -1 ) - promise + promise = new Ember.RSVP.Promise (resolve, reject) -> + store.query('repo', { 'repository.active': 'true', limit: 20 }).then( -> + resolve(repos) + , -> + reject() + ) + + promise + else + login = reposIdsOrlogin + store.find('repo', { member: login, orderBy: 'name' }) search: (store, ajax, query) -> - queryString = $.param(search: query, orderBy: 'name', limit: 5) - promise = ajax.ajax("/repos?#{queryString}", 'get') - result = Ember.ArrayProxy.create(content: []) + if Config.useV3API + queryString = $.param(search: query, orderBy: 'name', limit: 5) + promise = ajax.ajax("/repos?#{queryString}", 'get') + result = Ember.ArrayProxy.create(content: []) - promise.then (data, status, xhr) -> - promises = data.repos.map (repoData) -> - store.findRecord('repo', repoData.id).then (record) -> - result.pushObject(record) - result.set('isLoaded', true) - record + promise.then (data, status, xhr) -> + promises = data.repos.map (repoData) -> + store.findRecord('repo', repoData.id).then (record) -> + result.pushObject(record) + result.set('isLoaded', true) + record - Ember.RSVP.allSettled(promises).then -> - result + Ember.RSVP.allSettled(promises).then -> + result + else + store.find('repo', search: query, orderBy: 'name') withLastBuild: (store) -> repos = store.filter('repo', {}, (build) -> - build.get('defaultBranch.lastBuild') + build.get('lastBuildId') ) repos.then () -> @@ -170,22 +220,31 @@ Repo.reopenClass if repos.get('length') > 0 repos.get('firstObject') else - adapter = store.adapterFor('repo') - modelClass = store.modelFor('repo') - adapter.findRecord(store, modelClass, slug).then (payload) -> - serializer = store.serializerFor('repo') + promise = null + + if Config.useV3API + adapter = store.adapterFor('repo') modelClass = store.modelFor('repo') - result = serializer.normalizeResponse(store, modelClass, payload, null, 'findRecord') - repo = store.push(data: result.data) - for record in result.included - r = store.push(data: record) + promise = adapter.findRecord(store, modelClass, slug).then (payload) -> + serializer = store.serializerFor('repo') + modelClass = store.modelFor('repo') + result = serializer.normalizeResponse(store, modelClass, payload, null, 'findRecord') - repo - , -> + repo = store.push(data: result.data) + for record in result.included + r = store.push(data: record) + + repo + + else + promise = store.find('repo', { slug: slug }).then (repos) -> + repos.get('firstObject') || throw("no repos found") + + promise.catch -> error = new Error('repo not found') error.slug = slug - Ember.get(repos, 'firstObject') || throw(error) + throw(error) # buildURL: (slug) -> # if slug then slug else 'repos' diff --git a/app/routes/repo/index.coffee b/app/routes/repo/index.coffee index e607a1fe..d713441f 100644 --- a/app/routes/repo/index.coffee +++ b/app/routes/repo/index.coffee @@ -1,4 +1,5 @@ `import TravisRoute from 'travis/routes/basic'` +`import Config from 'travis/config/environment'` Route = TravisRoute.extend setupController: (controller, model) -> @@ -6,7 +7,7 @@ Route = TravisRoute.extend @controllerFor('repo').activate('current') renderTemplate: -> - if @modelFor('repo').get('defaultBranch.lastBuild') + if @modelFor('repo').get('lastBuildId') @render 'build' else @render 'builds/not_found' diff --git a/app/serializers/build.js b/app/serializers/build.js index 32d42cdf..4214d47f 100644 --- a/app/serializers/build.js +++ b/app/serializers/build.js @@ -94,14 +94,6 @@ var Serializer = V2FallbackSerializer.extend({ data = result.data; - if (repoId = resourceHash.repository_id) { - data.attributes.repositoryId = repoId; - } else if (resourceHash.repository) { - if (href = resourceHash.repository['@href']) { - id = href.match(/\d+/)[0]; - data.attributes.repositoryId = id; - } - } return result; } }); diff --git a/app/services/store.coffee b/app/services/store.coffee index 499b0818..cec04b64 100644 --- a/app/services/store.coffee +++ b/app/services/store.coffee @@ -1,5 +1,5 @@ `import DS from 'ember-data'` -`import config from 'travis/config/environment'` +`import Config from 'travis/config/environment'` Store = DS.Store.extend auth: Ember.inject.service() @@ -71,21 +71,25 @@ Store = DS.Store.extend if type == 'build' && (json.repository || json.repo) data = json.repository || json.repo - default_branch = data.default_branch - if default_branch - default_branch.default_branch = true + if Config.useV3API + default_branch = data.default_branch + if default_branch + default_branch.default_branch = true - last_build_id = default_branch.last_build_id - # a build is a synchronous relationship on a branch model, so we need to - # have a build record present when we put default_branch from a repository - # model into the store. We don't send last_build's payload in pusher, so - # we need to get it here, if it's not already in the store. In the future - # we may decide to make this relationship async, but I don't want to - # change the code at the moment - if build = @peekRecord('build', last_build_id) - @push(this.normalize('repo', data)) - else - @findRecord('build', last_build_id).then => + last_build_id = default_branch.last_build_id + # a build is a synchronous relationship on a branch model, so we need to + # have a build record present when we put default_branch from a repository + # model into the store. We don't send last_build's payload in pusher, so + # we need to get it here, if it's not already in the store. In the future + # we may decide to make this relationship async, but I don't want to + # change the code at the moment + if !last_build_id || (build = @peekRecord('build', last_build_id)) @push(this.normalize('repo', data)) + else + @findRecord('build', last_build_id).then => + @push(this.normalize('repo', data)) + else + @push(this.normalize('repo', data)) + `export default Store` diff --git a/app/templates/components/repos-list-item.hbs b/app/templates/components/repos-list-item.hbs index 8df5deec..412195ea 100644 --- a/app/templates/components/repos-list-item.hbs +++ b/app/templates/components/repos-list-item.hbs @@ -1,19 +1,19 @@ -
- {{#link-to "build" repo repo.defaultBranch.lastBuild.id}} + {{#if repo.lastBuildId}} +
+ {{#link-to "build" repo repo.lastBuildId}} - {{repo.defaultBranch.lastBuild.number}} + {{repo.lastBuildNumber}} {{/link-to}}
{{/if}} @@ -22,16 +22,16 @@Duration: - - {{format-duration repo.defaultBranch.lastBuild.duration}} + + {{format-duration repo.lastBuildDuration}}
Finished: - - {{format-time repo.defaultBranch.lastBuild.finishedAt}} + + {{format-time repo.lastBuildFinishedAt}}