diff --git a/app/controllers/tasks/github.js b/app/controllers/tasks/github.js new file mode 100644 index 0000000..d630f31 --- /dev/null +++ b/app/controllers/tasks/github.js @@ -0,0 +1,4 @@ +import Controller from '@ember/controller'; + +export default Controller.extend({ +}); diff --git a/app/data/organizations.js b/app/data/organizations.js index 70633d9..5a59999 100644 --- a/app/data/organizations.js +++ b/app/data/organizations.js @@ -11,7 +11,7 @@ export default { }, { type: 'gitlab', - identifier: 'coala', + identifier: 'coala/mobans', }, ], }, diff --git a/app/models/gitlab-task.js b/app/models/gitlab-task.js new file mode 100644 index 0000000..bef98f1 --- /dev/null +++ b/app/models/gitlab-task.js @@ -0,0 +1,3 @@ +import TaskModel from './task'; + +export default TaskModel.extend({}); diff --git a/app/router.js b/app/router.js index 88ca55f..e0066b4 100644 --- a/app/router.js +++ b/app/router.js @@ -9,6 +9,7 @@ const Router = EmberRouter.extend({ Router.map(function mainRoute() { return this.route('tasks', function tasksRoute() { this.route('github'); + this.route('gitlab'); }); }); diff --git a/app/routes/tasks/gitlab.js b/app/routes/tasks/gitlab.js new file mode 100644 index 0000000..2b38260 --- /dev/null +++ b/app/routes/tasks/gitlab.js @@ -0,0 +1,23 @@ +import Route from '@ember/routing/route'; +import { inject } from '@ember/service'; + +export default Route.extend({ + gitlab: inject(), + store: inject(), + organizations: inject(), + + model(params, transition) { + const { org } = transition.queryParams; + const store = this.get('store'); + const projects = this.get('organizations').fetchGitlabProjects(org); + if (projects.length > 0) { + return this.get('gitlab').tasks({ projects }).then((data) => { + data.forEach((task) => { + store.pushPayload('gitlab-task', task); + }); + return store.peekAll('gitlab-task'); + }); + } + return []; + }, +}); diff --git a/app/serializers/gitlab-task.js b/app/serializers/gitlab-task.js new file mode 100644 index 0000000..b913727 --- /dev/null +++ b/app/serializers/gitlab-task.js @@ -0,0 +1,30 @@ +import DS from 'ember-data'; + +export default DS.JSONSerializer.extend({ + pushPayload(store, payload) { + const task = {}; + task.id = payload.id; + task.bodyText = payload.description; + task.commentCount = payload.user_notes_count; + // Set the default color to 65C8FF, otherwise, we need to refetch the default + // color from `project/:id/labels` endpoint. + task.labels = payload.labels.map(label => ({ color: '65C8FF', name: label })); + task.updatedAt = payload.updated_at; + task.title = payload.title; + task.url = payload.web_url; + + task.author = {}; + task.author.url = payload.author.web_url; + task.author.login = payload.author.username; + task.author.avatarUrl = payload.author.avatar_url; + + task.repository = {}; + task.repository.nameWithOwner = payload.repository.path_with_namespace; + task.repository.url = payload.repository.web_url; + + task.isPullRequest = payload._type === 'PullRequest'; + + store.push(this.normalize(store.modelFor('gitlab-task'), task)); + return task; + }, +}); diff --git a/app/services/gitlab.js b/app/services/gitlab.js new file mode 100644 index 0000000..ccbd63e --- /dev/null +++ b/app/services/gitlab.js @@ -0,0 +1,50 @@ +// https://gitlab.com/api/v4/projects/coala%2Fmobans/issues?order_by=created_at&state=opened +import AjaxService from 'ember-ajax/services/ajax'; +import RSVP from 'rsvp'; + +const ENDPOINT = 'https://gitlab.com/api/v4'; +const PROJECT_ENDPOINT = `${ENDPOINT}/projects/{projectId}`; +const ISSUE_ENDPOINT = `${PROJECT_ENDPOINT}/issues?order_by=created_at&state=opened&per_page=100`; + +function buildIssuesUrl(projectId) { + return ISSUE_ENDPOINT.replace('{projectId}', encodeURIComponent(projectId)); +} + +function buildProjectUrl(projectId) { + return PROJECT_ENDPOINT.replace('{projectId}', encodeURIComponent(projectId)); +} + +export default AjaxService.extend({ + host: 'https://gitlab.com/', + _issueUrl: '', + init(...arg) { + this._super(...arg); + this.set('headers', { 'Private-Token': 'sVfZzagWtemrV-suxYK-' }); + }, + + tasks({ projects }) { + const tasks = projects.map((projectId) => { + const embedRepoInfo = taskList => this.fetchRepositoryInfo(projectId) + .then(repoInfo => taskList.map((task) => { + const decoratedTask = Object.assign({}, task); + decoratedTask.repository = repoInfo; + decoratedTask.type = 'gitlab-task'; + return decoratedTask; + })); + return this.fetchIssues(projectId).then(embedRepoInfo); + }); + + return RSVP.all(tasks).then(taskList => + taskList + .reduce((combinedTasks, initialTasklist) => combinedTasks.concat(initialTasklist), [])); + }, + + fetchRepositoryInfo(projectId) { + return this.request(buildProjectUrl(projectId)); + }, + + fetchIssues(projectId) { + return this.request(buildIssuesUrl(projectId)); + }, + +}); diff --git a/app/services/organizations.js b/app/services/organizations.js index c04e628..550b16f 100644 --- a/app/services/organizations.js +++ b/app/services/organizations.js @@ -1,11 +1,11 @@ -import Object, { computed } from '@ember/object'; +import EmberObject, { computed } from '@ember/object'; import Service from '@ember/service'; import organizations from '../data/organizations'; export default Service.extend({ init(...args) { this._super(...args); - this.organizations = Object.create(organizations); + this.organizations = EmberObject.create(organizations); }, list: computed('organizations', function getOrganizationList() { @@ -15,4 +15,18 @@ export default Service.extend({ fetch(slug) { return this.organizations.get(slug); }, + + fetchGitlabProjects(slug) { + const { trackers } = this.fetch(slug); + if (!trackers) { + return []; + } + return trackers.reduce((previous, tracker) => { + if (tracker.type === 'gitlab') { + return [...previous, tracker.identifier]; + } + return previous; + }, []); + }, + }); diff --git a/app/templates/tasks.hbs b/app/templates/tasks.hbs index b4bd825..f59fe28 100644 --- a/app/templates/tasks.hbs +++ b/app/templates/tasks.hbs @@ -24,11 +24,6 @@
This Org doesn't have any gitlab repository.
+{{/unless}} diff --git a/tests/acceptance/tasks/list-gitlab-tasks-test.js b/tests/acceptance/tasks/list-gitlab-tasks-test.js new file mode 100644 index 0000000..43a0f52 --- /dev/null +++ b/tests/acceptance/tasks/list-gitlab-tasks-test.js @@ -0,0 +1,24 @@ +import Service from '@ember/service'; +import { visit, find } from '@ember/test-helpers'; +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; + +// Simulating empty gitlab Projects +const emptyGitlabOrgService = Service.extend({ + fetchGitlabProjects: () => [], + fetch: () => ({}), +}); + +module('Acceptance/tasks/list-gitlab-tasks-test', function listGitlabTaskTests(hooks) { + setupApplicationTest(hooks); + + hooks.beforeEach(function beforeEach() { + this.owner.register('service:organizations', emptyGitlabOrgService); + }); + + test('should show no gitlab repository', async function listGitlabTasks(assert) { + await visit('/tasks/gitlab?org=discourse'); + const $noGitlabRepo = find('.is-three-quarters > p'); + assert.equal($noGitlabRepo.innerText, "This Org doesn't have any gitlab repository."); + }); +});