From 6ad3ed7ef53a5f134e8fe9fe482678019d9c5dc7 Mon Sep 17 00:00:00 2001 From: Yana Agun Siswanto Date: Thu, 7 Jun 2018 10:16:18 +0700 Subject: [PATCH] Support GitLab Issues Move GitHub Tasks to github namespace `/tasks/github` Add a new gitlab route `/tasks/gitlab` Add a new gitlab serializer Closes https://github.com/coala/git-task-list/issues/38 --- app/components/settings-modal.js | 2 + app/controllers/tasks/github.js | 4 ++ app/data/organizations.js | 6 ++- app/models/gitlab-task.js | 3 ++ app/router.js | 1 + app/routes/tasks/gitlab.js | 23 ++++++++ app/serializers/gitlab-task.js | 30 +++++++++++ app/services/gitlab.js | 53 +++++++++++++++++++ app/services/organizations.js | 18 ++++++- app/templates/components/settings-modal.hbs | 8 +++ app/templates/tasks.hbs | 5 -- app/templates/tasks/github.hbs | 9 ++++ app/templates/tasks/gitlab.hbs | 16 ++++++ .../tasks/list-gitlab-tasks-test.js | 24 +++++++++ 14 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 app/controllers/tasks/github.js create mode 100644 app/models/gitlab-task.js create mode 100644 app/routes/tasks/gitlab.js create mode 100644 app/serializers/gitlab-task.js create mode 100644 app/services/gitlab.js create mode 100644 app/templates/tasks/gitlab.hbs create mode 100644 tests/acceptance/tasks/list-gitlab-tasks-test.js diff --git a/app/components/settings-modal.js b/app/components/settings-modal.js index 387173c..d7711bd 100644 --- a/app/components/settings-modal.js +++ b/app/components/settings-modal.js @@ -8,6 +8,7 @@ export default Component.extend({ // Properties token_github_com: oneWay('userSettings.tokens.github_com'), + token_gitlab_com: oneWay('userSettings.tokens.gitlab_com'), init(...args) { this._super(...args); @@ -19,6 +20,7 @@ export default Component.extend({ }, saveSettings() { this.userSettings.setToken('github_com', this.get('token_github_com')); + this.userSettings.setToken('gitlab_com', this.get('token_gitlab_com')); this.set('isActive', false); }, }, 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..eeaab5f 100644 --- a/app/data/organizations.js +++ b/app/data/organizations.js @@ -11,7 +11,11 @@ export default { }, { type: 'gitlab', - identifier: 'coala', + identifier: 'coala/mobans', + }, + { + type: 'gitlab', + identifier: 'coala/coala-utils', }, ], }, 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..3fa1f62 --- /dev/null +++ b/app/services/gitlab.js @@ -0,0 +1,53 @@ +import { inject } from '@ember/service'; +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({ + userSettings: inject(), + + host: 'https://gitlab.com/', + _issueUrl: '', + + init(...arg) { + this._super(...arg); + this.set('headers', { 'Private-Token': this.get('userSettings').tokens.get('gitlab_com') }); + }, + + 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/components/settings-modal.hbs b/app/templates/components/settings-modal.hbs index 39f55d8..7af925c 100644 --- a/app/templates/components/settings-modal.hbs +++ b/app/templates/components/settings-modal.hbs @@ -14,6 +14,14 @@

In order to fetch results from GitHub, you must specify GitHub token. With ANY scope you like. No exact scope is required.

Get GitHub user token from https://github.com/settings/tokens

+
+ +
+ {{input class="input" value=token_gitlab_com}} +
+

In order to fetch results from GitLab, you must specify GitLab token. With ANY scope you like. No exact scope is required.

+

Get GitHub user token from https://github.com/settings/tokens

+