Commit 25fa8e4c authored by Ash McKenzie's avatar Ash McKenzie

Merge branch '212329-related-issues-to-core_controllers-and-model' into 'master'

[Related Issues to core] Move all Related Issues controllers to core

See merge request gitlab-org/gitlab!39764
parents 041a498c 3642c199
......@@ -26,7 +26,6 @@ module EE
mount ::API::Geo
mount ::API::GeoReplication
mount ::API::GeoNodes
mount ::API::IssueLinks
mount ::API::Ldap
mount ::API::LdapGroupLinks
mount ::API::License
......
# frozen_string_literal: true
module EE
module API
module Entities
class IssueLink < Grape::Entity
expose :source, as: :source_issue, using: ::API::Entities::IssueBasic
expose :target, as: :target_issue, using: ::API::Entities::IssueBasic
expose :link_type
end
end
end
end
# frozen_string_literal: true
module EE
module API
module Entities
class RelatedIssue < ::API::Entities::Issue
expose :issue_link_id
expose :issue_link_type, as: :link_type
end
end
end
end
......@@ -25,7 +25,6 @@ RSpec.describe Projects::IssueLinksController do
end
before do
stub_licensed_features(blocked_issues: true)
project.add_developer(user)
end
......@@ -55,33 +54,30 @@ RSpec.describe Projects::IssueLinksController do
post :create, params: post_params, as: :json
end
context 'when related issues are available on the project' do
before do
project.add_developer(user)
stub_licensed_features(blocked_issues: true)
stub_feature_flags(link_types: true)
end
before do
project.add_developer(user)
end
it 'returns success response' do
create_link(user, issue1, issue2)
it 'returns success response' do
create_link(user, issue1, issue2)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to have_gitlab_http_status(:ok)
link = json_response['issuables'].first
expect(link['id']).to eq(issue2.id)
expect(link['link_type']).to eq('is_blocked_by')
end
link = json_response['issuables'].first
expect(link['id']).to eq(issue2.id)
expect(link['link_type']).to eq('is_blocked_by')
end
context 'when related issues are not available on the project' do
context 'when blocked issues is disabled' do
before do
stub_licensed_features(blocked_issues: false)
end
it 'returns 403' do
it 'returns failure response' do
create_link(user, issue1, issue2)
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('Blocked issues not available for current license')
end
end
end
......
......@@ -6,200 +6,35 @@ RSpec.describe API::IssueLinks do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:target_issue) { create(:issue, project: project) }
before do
project.add_guest(user)
end
describe 'GET /links' do
context 'when unauthenticated' do
it 'returns 401' do
get api("/projects/#{project.id}/issues/#{issue.iid}/links")
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
it 'returns related issues' do
target_issue = create(:issue, project: project)
create(:issue_link, source: issue, target: target_issue)
get api("/projects/#{project.id}/issues/#{issue.iid}/links", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(response).to match_response_schema('public_api/v4/issue_links')
end
end
project.add_reporter(user)
end
describe 'POST /links' do
context 'when unauthenticated' do
it 'returns 401' do
target_issue = create(:issue)
post api("/projects/#{project.id}/issues/#{issue.iid}/links"),
params: { target_project_id: target_issue.project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
context 'given target project not found' do
it 'returns 404' do
target_issue = create(:issue)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: -1, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Project Not Found')
end
end
context 'given target issue not found' do
it 'returns 404' do
target_project = create(:project, :public)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: target_project.id, target_issue_iid: non_existing_record_iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'when user does not have write access to given issue' do
it 'returns 404' do
unauthorized_project = create(:project)
target_issue = create(:issue, project: unauthorized_project)
unauthorized_project.add_guest(user)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: unauthorized_project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('No Issue found for given params')
end
end
context 'when trying to relate to a confidential issue' do
it 'returns 404' do
project = create(:project, :public)
target_issue = create(:issue, :confidential, project: project)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'when trying to relate to a private project issue' do
it 'returns 404' do
project = create(:project, :private)
target_issue = create(:issue, project: project)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Project Not Found')
end
end
context 'when user has ability to create an issue link' do
let_it_be(:target_issue) { create(:issue, project: project) }
before do
project.add_reporter(user)
end
context 'when creating a blocked relationship' do
context 'when feature is enabled' do
it 'returns 201 status and contains the expected link response' do
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid, link_type: 'blocks' }
expect_link_response(link_type: 'blocks')
end
it 'returns 201 when sending full path of target project' do
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.full_path, target_issue_iid: target_issue.iid }
expect_link_response
end
def expect_link_response(link_type: 'relates_to')
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/issue_link')
expect(json_response['link_type']).to eq(link_type)
expect(json_response['link_type']).to eq('blocks')
end
end
end
end
describe 'DELETE /links/:issue_link_id' do
context 'when unauthenticated' do
it 'returns 401' do
issue_link = create(:issue_link)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}")
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
context 'when user does not have write access to given issue link' do
it 'returns 404' do
unauthorized_project = create(:project)
target_issue = create(:issue, project: unauthorized_project)
issue_link = create(:issue_link, source: issue, target: target_issue)
unauthorized_project.add_guest(user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('No Issue Link found')
end
end
context 'issue link not found' do
it 'returns 404' do
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'when trying to delete a link with a private project issue' do
it 'returns 404' do
project = create(:project, :private)
target_issue = create(:issue, project: project)
issue_link = create(:issue_link, source: issue, target: target_issue)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Project Not Found')
context 'when feature is disabled' do
before do
stub_licensed_features(blocked_issues: false)
end
end
context 'when user has ability to delete the issue link' do
it 'returns 200' do
target_issue = create(:issue, project: project)
issue_link = create(:issue_link, source: issue, target: target_issue)
project.add_reporter(user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}", user)
it 'returns 403' do
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid, link_type: 'blocks' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/issue_link')
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
......
......@@ -167,6 +167,7 @@ module API
mount ::API::GroupVariables
mount ::API::ImportBitbucketServer
mount ::API::ImportGithub
mount ::API::IssueLinks
mount ::API::Issues
mount ::API::JobArtifacts
mount ::API::Jobs
......
# frozen_string_literal: true
module API
module Entities
class IssueLink < Grape::Entity
expose :source, as: :source_issue, using: ::API::Entities::IssueBasic
expose :target, as: :target_issue, using: ::API::Entities::IssueBasic
expose :link_type
end
end
end
# frozen_string_literal: true
module API
module Entities
class RelatedIssue < ::API::Entities::Issue
expose :issue_link_id
expose :issue_link_type, as: :link_type
end
end
end
......@@ -12,20 +12,20 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get related issues' do
success EE::API::Entities::RelatedIssue
success Entities::RelatedIssue
end
get ':id/issues/:issue_iid/links' do
source_issue = find_project_issue(params[:issue_iid])
related_issues = source_issue.related_issues(current_user)
present related_issues,
with: EE::API::Entities::RelatedIssue,
with: Entities::RelatedIssue,
current_user: current_user,
project: user_project
end
desc 'Relate issues' do
success EE::API::Entities::IssueLink
success Entities::IssueLink
end
params do
requires :target_project_id, type: String, desc: 'The ID of the target project'
......@@ -48,7 +48,7 @@ module API
if result[:status] == :success
issue_link = IssueLink.find_by!(source: source_issue, target: target_issue)
present issue_link, with: EE::API::Entities::IssueLink
present issue_link, with: Entities::IssueLink
else
render_api_error!(result[:message], result[:http_status])
end
......@@ -56,7 +56,7 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Remove issues relation' do
success EE::API::Entities::IssueLink
success Entities::IssueLink
end
params do
requires :issue_link_id, type: Integer, desc: 'The ID of an issue link'
......@@ -72,7 +72,7 @@ module API
.execute
if result[:status] == :success
present issue_link, with: EE::API::Entities::IssueLink
present issue_link, with: Entities::IssueLink
else
render_api_error!(result[:message], result[:http_status])
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Projects::IssueLinksController do
let_it_be(:namespace) { create(:group, :public) }
let_it_be(:project) { create(:project, :public, namespace: namespace) }
let_it_be(:user) { create(:user) }
let_it_be(:issue1) { create(:issue, project: project) }
let_it_be(:issue2) { create(:issue, project: project) }
describe 'GET #index' do
let_it_be(:issue_link) { create(:issue_link, source: issue1, target: issue2, link_type: 'relates_to') }
def get_link(user, issue)
sign_in(user)
params = {
namespace_id: issue.project.namespace.to_param,
project_id: issue.project,
issue_id: issue.iid
}
get :index, params: params, as: :json
end
before do
project.add_developer(user)
end
it 'returns success response' do
get_link(user, issue1)
expect(response).to have_gitlab_http_status(:ok)
link = json_response.first
expect(link['id']).to eq(issue2.id)
expect(link['link_type']).to eq('relates_to')
end
end
describe 'POST #create' do
def create_link(user, issue, target)
sign_in(user)
post_params = {
namespace_id: issue.project.namespace.to_param,
project_id: issue.project,
issue_id: issue.iid,
issuable_references: [target.to_reference],
link_type: 'relates_to'
}
post :create, params: post_params, as: :json
end
before do
project.add_developer(user)
end
it 'returns success response' do
create_link(user, issue1, issue2)
expect(response).to have_gitlab_http_status(:ok)
link = json_response['issuables'].first
expect(link['id']).to eq(issue2.id)
expect(link['link_type']).to eq('relates_to')
end
end
end
......@@ -3,12 +3,12 @@
"properties" : {
"source_issue": {
"allOf": [
{ "$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" }
{ "$ref": "../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" }
]
},
"target_issue": {
"allOf": [
{ "$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" }
{ "$ref": "../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" }
]
},
"link_type": {
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::IssueLinks do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
before do
project.add_guest(user)
end
describe 'GET /links' do
context 'when unauthenticated' do
it 'returns 401' do
get api("/projects/#{project.id}/issues/#{issue.iid}/links")
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
it 'returns related issues' do
target_issue = create(:issue, project: project)
create(:issue_link, source: issue, target: target_issue)
get api("/projects/#{project.id}/issues/#{issue.iid}/links", user)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(response).to match_response_schema('public_api/v4/issue_links')
end
end
end
describe 'POST /links' do
context 'when unauthenticated' do
it 'returns 401' do
target_issue = create(:issue)
post api("/projects/#{project.id}/issues/#{issue.iid}/links"),
params: { target_project_id: target_issue.project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
context 'given target project not found' do
it 'returns 404' do
target_issue = create(:issue)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: -1, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Project Not Found')
end
end
context 'given target issue not found' do
it 'returns 404' do
target_project = create(:project, :public)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: target_project.id, target_issue_iid: non_existing_record_iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'when user does not have write access to given issue' do
it 'returns 404' do
unauthorized_project = create(:project)
target_issue = create(:issue, project: unauthorized_project)
unauthorized_project.add_guest(user)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: unauthorized_project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('No Issue found for given params')
end
end
context 'when trying to relate to a confidential issue' do
it 'returns 404' do
project = create(:project, :public)
target_issue = create(:issue, :confidential, project: project)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'when trying to relate to a private project issue' do
it 'returns 404' do
project = create(:project, :private)
target_issue = create(:issue, project: project)
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid }
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Project Not Found')
end
end
context 'when user has ability to create an issue link' do
let_it_be(:target_issue) { create(:issue, project: project) }
before do
project.add_reporter(user)
end
it 'returns 201 status and contains the expected link response' do
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.id, target_issue_iid: target_issue.iid, link_type: 'relates_to' }
expect_link_response(link_type: 'relates_to')
end
it 'returns 201 when sending full path of target project' do
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
params: { target_project_id: project.full_path, target_issue_iid: target_issue.iid }
expect_link_response
end
def expect_link_response(link_type: 'relates_to')
expect(response).to have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/issue_link')
expect(json_response['link_type']).to eq(link_type)
end
end
end
end
describe 'DELETE /links/:issue_link_id' do
context 'when unauthenticated' do
it 'returns 401' do
issue_link = create(:issue_link)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}")
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
context 'when user does not have write access to given issue link' do
it 'returns 404' do
unauthorized_project = create(:project)
target_issue = create(:issue, project: unauthorized_project)
issue_link = create(:issue_link, source: issue, target: target_issue)
unauthorized_project.add_guest(user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('No Issue Link found')
end
end
context 'issue link not found' do
it 'returns 404' do
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{non_existing_record_id}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
end
context 'when trying to delete a link with a private project issue' do
it 'returns 404' do
project = create(:project, :private)
target_issue = create(:issue, project: project)
issue_link = create(:issue_link, source: issue, target: target_issue)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}", user)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Project Not Found')
end
end
context 'when user has ability to delete the issue link' do
it 'returns 200' do
target_issue = create(:issue, project: project)
issue_link = create(:issue_link, source: issue, target: target_issue)
project.add_reporter(user)
delete api("/projects/#{project.id}/issues/#{issue.iid}/links/#{issue_link.id}", user)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/issue_link')
end
end
end
end
end
......@@ -7,10 +7,6 @@ RSpec.describe Projects::IssueLinksController do
let(:project) { create(:project_empty_repo) }
let(:issue) { create :issue, project: project }
before do
stub_licensed_features(blocked_issues: true)
end
describe 'GET /*namespace_id/:project_id/issues/:issue_id/links' do
let(:issue_b) { create :issue, project: project }
let!(:issue_link) { create :issue_link, source: issue, target: issue_b }
......
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