Commit 53d04fa3 authored by Douwe Maan's avatar Douwe Maan

Merge branch '2646-osw-support-mrs-on-jira-dev-panel' into 'master'

Add Merge Requests support for Jira Development Panel

Closes #2646

See merge request gitlab-org/gitlab-ee!5534
parents 87c3890b a5ea8b16
---
title: Present MRs on Jira development panel integration
merge_request: 5534
author:
type: added
......@@ -109,6 +109,65 @@ module API
options[:project].repository.commit(repo_branch.dereferenced_target)
end
end
class User < Grape::Entity
expose :id
expose :username, as: :login
expose :url do |user|
Gitlab::Routing.url_helpers.user_url(user)
end
end
class NoteableComment < Grape::Entity
expose :id
expose :author, as: :user, using: User
expose :note, as: :body
expose :created_at
end
class PullRequest < Grape::Entity
expose :title
expose :assignee, using: User
expose :author, as: :user, using: User
expose :created_at
expose :description, as: :body
# Since Jira service requests `/repos/-/jira/pulls` (without project
# scope), we need to make it work with ID instead IID.
expose :id, as: :number
# GitHub doesn't have a "merged" or "closed" state. It's just "open" or
# "closed".
expose :state do |merge_request|
case merge_request.state
when 'opened', 'locked'
'open'
when 'merged'
'closed'
else
merge_request.state
end
end
expose :merged?, as: :merged
expose :merged_at do |merge_request|
merge_request.metrics&.merged_at
end
expose :closed_at do |merge_request|
merge_request.metrics&.latest_closed_at
end
expose :updated_at
expose :html_url do |merge_request|
Gitlab::UrlBuilder.build(merge_request)
end
expose :head do
expose :source_branch, as: :label
expose :source_branch, as: :ref
expose :source_project, as: :repo, using: Repository
end
expose :base do
expose :target_branch, as: :label
expose :target_branch, as: :ref
expose :target_project, as: :repo, using: Repository
end
end
end
end
end
......@@ -6,6 +6,8 @@
module API
module V3
class Github < Grape::API
JIRA_DEV_PANEL_FEATURE = :jira_dev_panel_integration.freeze
include PaginationParams
before do
......@@ -25,9 +27,36 @@ module API
def find_project_with_access(full_path)
project = find_project!(full_path)
not_found! unless project.feature_available?(:jira_dev_panel_integration)
not_found! unless licensed_project?(project)
project
end
def find_merge_requests
merge_requests = authorized_merge_requests.reorder(updated_at: :desc).preload(:target_project)
merge_requests = paginate(merge_requests)
merge_requests.select { |mr| licensed_project?(mr.target_project) }
end
def find_merge_request_with_access(id, access_level = :read_merge_request)
merge_request = authorized_merge_requests.find_by(id: id)
not_found! unless can?(current_user, access_level, merge_request)
merge_request
end
def authorized_merge_requests
MergeRequestsFinder.new(current_user, authorized_only: true).execute
end
def find_notes(noteable)
# They're not presented on Jira Dev Panel ATM. A comments count with a
# redirect link is presented.
notes = paginate(noteable.notes.user.reorder(nil))
notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
end
def licensed_project?(project)
project.feature_available?(JIRA_DEV_PANEL_FEATURE)
end
end
resource :orgs do
......@@ -47,14 +76,43 @@ module API
use :pagination
end
get ':namespace/repos' do
projects = current_user.authorized_projects.select { |project| project.feature_available?(:jira_dev_panel_integration) }
projects = current_user.authorized_projects.select { |project| licensed_project?(project) }
projects = ::Kaminari.paginate_array(projects)
present paginate(projects), with: ::API::Github::Entities::Repository
end
end
# Jira dev panel integration weirdly requests for "/-/jira/pulls" instead
# "/api/v3/repos/<namespace>/<project>/pulls". This forces us into
# returning _all_ Merge Requests from authorized projects (user is a member),
# instead just the authorized MRs from a project.
# Jira handles the filtering, presenting just MRs mentioning the Jira
# issue ID on the MR title / description.
resource :repos do
get '/-/jira/pulls' do
present find_merge_requests, with: ::API::Github::Entities::PullRequest
end
# In Github, each Merge Request is automatically also an issue.
# Therefore we return its comments here.
# It'll present _just_ the comments counting with a link to GitLab on
# Jira dev panel, not the actual note content.
#
get '/-/jira/issues/:id/comments' do
merge_request = find_merge_request_with_access(params[:id])
present find_notes(merge_request), with: ::API::Github::Entities::NoteableComment
end
# This refers to "review" comments but Jira dev panel doesn't seem to
# present it accordingly.
get '/-/jira/pulls/:id/comments' do
present []
end
# Commits are not presented within "Pull Requests" modal on Jira dev
# panel.
get '/-/jira/pulls/:id/commits' do
present []
end
......
{
"type": "array",
"items": {
"type": "object",
"properties" : {
"title": { "type": "string" },
"created_at": { "type": "string" },
"body": { "type": ["string", "null"] },
"id": { "type": "integer" },
"number": { "type": "integer" },
"state": { "type": "string" },
"html_url": { "type": "string" },
"merged": { "type": "boolean" },
"merged_at": { "type": ["date", "null"] },
"closed_at": { "type": ["date", "null"] },
"updated_at": { "type": "date" },
"assignee": {
"type": "object",
"required": ["id", "login", "url"],
"properties" : {
"id": { "type": "integer" },
"login": { "type": "string" },
"url": { "type": "string" }
},
"additionalProperties": false
},
"author": {
"type": "object",
"required": ["id", "login", "url"],
"properties" : {
"id": { "type": "integer" },
"login": { "type": "string" },
"url": { "type": "string" }
},
"additionalProperties": false
},
"head": {
"type": "object",
"required": ["label", "ref", "repo"],
"properties" : {
"label": { "type": "string" },
"ref": { "type": "string" },
"repo": {
"oneOf": [
{ "type": "null" },
{ "$ref": "repository.json" }
]
}
},
"additionalProperties": false
},
"base": {
"type": "object",
"required": ["label", "ref", "repo"],
"properties" : {
"label": { "type": "string" },
"ref": { "type": "string" },
"repo": {
"oneOf": [
{ "type": "null" },
{ "$ref": "repository.json" }
]
}
},
"additionalProperties": false
},
"additionalProperties": false
}
}
}
{
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"owner": {
"type": "object",
"required": ["login"],
"properties" : {
"login": { "type": "string" }
},
"additionalProperties": false
},
"additionalProperties": false
}
}
......@@ -30,9 +30,79 @@ describe API::V3::Github do
end
describe 'GET /-/jira/pulls' do
it 'returns an empty array' do
let(:assignee) { create(:user) }
let!(:merge_request) do
create(:merge_request, source_project: project, target_project: project, author: user, assignee: assignee)
end
it 'returns an array of merge requests with github format' do
stub_licensed_features(jira_dev_panel_integration: true)
get v3_api('/repos/-/jira/pulls', user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an(Array)
expect(json_response.size).to eq(1)
expect(response).to match_response_schema('entities/github/pull_requests', dir: 'ee')
end
end
describe 'GET /-/jira/issues/:id/comments' do
context 'when user has access to the merge request' do
let(:merge_request) do
create(:merge_request, source_project: project, target_project: project)
end
let!(:note) do
create(:note, project: project, noteable: merge_request)
end
it 'returns an array of notes' do
stub_licensed_features(jira_dev_panel_integration: true)
get v3_api("/repos/-/jira/issues/#{merge_request.id}/comments", user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an(Array)
expect(json_response.size).to eq(1)
end
end
context 'when user has no access to the merge request' do
let(:private_project) { create(:project, :private) }
let(:merge_request) do
create(:merge_request, source_project: private_project, target_project: private_project)
end
let!(:note) do
create(:note, project: private_project, noteable: merge_request)
end
before do
private_project.add_guest(user)
end
it 'returns 404' do
stub_licensed_features(jira_dev_panel_integration: true)
get v3_api("/repos/-/jira/issues/#{merge_request.id}/comments", user)
expect(response).to have_gitlab_http_status(404)
end
end
end
describe 'GET /-/jira/pulls/:id/commits' do
it 'returns an empty array' do
get v3_api("/repos/-/jira/pulls/xpto/commits", user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to eq([])
end
end
describe 'GET /-/jira/pulls/:id/comments' do
it 'returns an empty array' do
get v3_api("/repos/-/jira/pulls/xpto/comments", user)
expect(response).to have_gitlab_http_status(200)
expect(json_response).to eq([])
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment