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 ...@@ -26,7 +26,6 @@ module EE
mount ::API::Geo mount ::API::Geo
mount ::API::GeoReplication mount ::API::GeoReplication
mount ::API::GeoNodes mount ::API::GeoNodes
mount ::API::IssueLinks
mount ::API::Ldap mount ::API::Ldap
mount ::API::LdapGroupLinks mount ::API::LdapGroupLinks
mount ::API::License 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 ...@@ -25,7 +25,6 @@ RSpec.describe Projects::IssueLinksController do
end end
before do before do
stub_licensed_features(blocked_issues: true)
project.add_developer(user) project.add_developer(user)
end end
...@@ -55,11 +54,8 @@ RSpec.describe Projects::IssueLinksController do ...@@ -55,11 +54,8 @@ RSpec.describe Projects::IssueLinksController do
post :create, params: post_params, as: :json post :create, params: post_params, as: :json
end end
context 'when related issues are available on the project' do
before do before do
project.add_developer(user) project.add_developer(user)
stub_licensed_features(blocked_issues: true)
stub_feature_flags(link_types: true)
end end
it 'returns success response' do it 'returns success response' do
...@@ -71,17 +67,17 @@ RSpec.describe Projects::IssueLinksController do ...@@ -71,17 +67,17 @@ RSpec.describe Projects::IssueLinksController do
expect(link['id']).to eq(issue2.id) expect(link['id']).to eq(issue2.id)
expect(link['link_type']).to eq('is_blocked_by') expect(link['link_type']).to eq('is_blocked_by')
end end
end
context 'when related issues are not available on the project' do context 'when blocked issues is disabled' do
before do before do
stub_licensed_features(blocked_issues: false) stub_licensed_features(blocked_issues: false)
end end
it 'returns 403' do it 'returns failure response' do
create_link(user, issue1, issue2) create_link(user, issue1, issue2)
expect(response).to have_gitlab_http_status(:forbidden) expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('Blocked issues not available for current license')
end end
end end
end end
......
...@@ -6,200 +6,35 @@ RSpec.describe API::IssueLinks do ...@@ -6,200 +6,35 @@ RSpec.describe API::IssueLinks do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) } let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: 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) } let_it_be(:target_issue) { create(:issue, project: project) }
before do before do
project.add_reporter(user) project.add_reporter(user)
end end
describe 'POST /links' do
context 'when creating a blocked relationship' do
context 'when feature is enabled' do
it 'returns 201 status and contains the expected link response' do it 'returns 201 status and contains the expected link response' do
post api("/projects/#{project.id}/issues/#{issue.iid}/links", user), 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' } 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 have_gitlab_http_status(:created)
expect(response).to match_response_schema('public_api/v4/issue_link') 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
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}") context 'when feature is disabled' do
before do
expect(response).to have_gitlab_http_status(:unauthorized) stub_licensed_features(blocked_issues: false)
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 end
context 'when user has ability to delete the issue link' do it 'returns 403' do
it 'returns 200' do post api("/projects/#{project.id}/issues/#{issue.iid}/links", user),
target_issue = create(:issue, project: project) params: { target_project_id: project.id, target_issue_iid: target_issue.iid, link_type: 'blocks' }
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 have_gitlab_http_status(:forbidden)
expect(response).to match_response_schema('public_api/v4/issue_link')
end end
end end
end end
......
...@@ -167,6 +167,7 @@ module API ...@@ -167,6 +167,7 @@ module API
mount ::API::GroupVariables mount ::API::GroupVariables
mount ::API::ImportBitbucketServer mount ::API::ImportBitbucketServer
mount ::API::ImportGithub mount ::API::ImportGithub
mount ::API::IssueLinks
mount ::API::Issues mount ::API::Issues
mount ::API::JobArtifacts mount ::API::JobArtifacts
mount ::API::Jobs 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 ...@@ -12,20 +12,20 @@ module API
end end
resource :projects, requirements: { id: %r{[^/]+} } do resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get related issues' do desc 'Get related issues' do
success EE::API::Entities::RelatedIssue success Entities::RelatedIssue
end end
get ':id/issues/:issue_iid/links' do get ':id/issues/:issue_iid/links' do
source_issue = find_project_issue(params[:issue_iid]) source_issue = find_project_issue(params[:issue_iid])
related_issues = source_issue.related_issues(current_user) related_issues = source_issue.related_issues(current_user)
present related_issues, present related_issues,
with: EE::API::Entities::RelatedIssue, with: Entities::RelatedIssue,
current_user: current_user, current_user: current_user,
project: user_project project: user_project
end end
desc 'Relate issues' do desc 'Relate issues' do
success EE::API::Entities::IssueLink success Entities::IssueLink
end end
params do params do
requires :target_project_id, type: String, desc: 'The ID of the target project' requires :target_project_id, type: String, desc: 'The ID of the target project'
...@@ -48,7 +48,7 @@ module API ...@@ -48,7 +48,7 @@ module API
if result[:status] == :success if result[:status] == :success
issue_link = IssueLink.find_by!(source: source_issue, target: target_issue) 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 else
render_api_error!(result[:message], result[:http_status]) render_api_error!(result[:message], result[:http_status])
end end
...@@ -56,7 +56,7 @@ module API ...@@ -56,7 +56,7 @@ module API
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
desc 'Remove issues relation' do desc 'Remove issues relation' do
success EE::API::Entities::IssueLink success Entities::IssueLink
end end
params do params do
requires :issue_link_id, type: Integer, desc: 'The ID of an issue link' requires :issue_link_id, type: Integer, desc: 'The ID of an issue link'
...@@ -72,7 +72,7 @@ module API ...@@ -72,7 +72,7 @@ module API
.execute .execute
if result[:status] == :success if result[:status] == :success
present issue_link, with: EE::API::Entities::IssueLink present issue_link, with: Entities::IssueLink
else else
render_api_error!(result[:message], result[:http_status]) render_api_error!(result[:message], result[:http_status])
end 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 @@ ...@@ -3,12 +3,12 @@
"properties" : { "properties" : {
"source_issue": { "source_issue": {
"allOf": [ "allOf": [
{ "$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" } { "$ref": "../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" }
] ]
}, },
"target_issue": { "target_issue": {
"allOf": [ "allOf": [
{ "$ref": "../../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" } { "$ref": "../../../../../../spec/fixtures/api/schemas/public_api/v4/issue.json" }
] ]
}, },
"link_type": { "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 ...@@ -7,10 +7,6 @@ RSpec.describe Projects::IssueLinksController do
let(:project) { create(:project_empty_repo) } let(:project) { create(:project_empty_repo) }
let(:issue) { create :issue, project: project } 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 describe 'GET /*namespace_id/:project_id/issues/:issue_id/links' do
let(:issue_b) { create :issue, project: project } let(:issue_b) { create :issue, project: project }
let!(:issue_link) { create :issue_link, source: issue, target: issue_b } 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