Commit b9bf2f5e authored by Alan (Maciej) Paruszewski's avatar Alan (Maciej) Paruszewski Committed by Gabriel Mazetto

Return only supported issue types for selected Jira Project

This change improves the way we fetch available issue types for Jira.
From now we will fetch only these types that are available in the
workflow for given project instead of loading all possible issue types
from the system.
parent 09f676e1
...@@ -22,20 +22,10 @@ module EE ...@@ -22,20 +22,10 @@ module EE
jira_vulnerabilities_integration_available? && vulnerabilities_enabled jira_vulnerabilities_integration_available? && vulnerabilities_enabled
end end
def project_key_required?
issues_enabled || vulnerabilities_enabled
end
def configured_to_create_issues_from_vulnerabilities? def configured_to_create_issues_from_vulnerabilities?
strong_memoize(:configured_to_create_issues_from_vulnerabilities) do
active? && project_key.present? && vulnerabilities_issuetype.present? && jira_vulnerabilities_integration_enabled? active? && project_key.present? && vulnerabilities_issuetype.present? && jira_vulnerabilities_integration_enabled?
end end
def issue_types
client
.Issuetype
.all
.reject { |issue_type| issue_type.subtask }
.map { |issue_type| { id: issue_type.id, name: issue_type.name, description: issue_type.description } }
end end
def test(_) def test(_)
...@@ -71,10 +61,70 @@ module EE ...@@ -71,10 +61,70 @@ module EE
end end
end end
private
def project_key_required?
strong_memoize(:project_key_required) do
issues_enabled || vulnerabilities_enabled
end
end
# Returns internal JIRA Project ID
#
# @return [String, nil] the internal JIRA ID of the Project
def jira_project_id def jira_project_id
strong_memoize(:jira_project_id) do jira_project&.id
client_url.present? ? jira_request { client.Project.find(project_key).id } : nil end
# Returns JIRA Project for selected Project Key
#
# @return [JIRA::Resource::Project, nil] the object that represents JIRA Projects
def jira_project
strong_memoize(:jira_project) do
client_url.present? ? jira_request { client.Project.find(project_key) } : nil
end end
end end
# Returns list of Issue Type Scheme IDs in selected JIRA Project
#
# @return [Array] the array of IDs
def project_issuetype_scheme_ids
query_url = Addressable::URI.join("#{client.options[:rest_base_path]}/", 'issuetypescheme/', 'project')
query_url.query_values = { 'projectId' => jira_project_id }
client
.get(query_url.to_s)
.fetch('values', [])
.map { |schemes| schemes.dig('issueTypeScheme', 'id') }
end
# Returns list of Issue Type IDs available in active Issue Type Scheme in selected JIRA Project
#
# @return [Array] the array of IDs
def project_issuetype_ids
strong_memoize(:project_issuetype_ids) do
query_url = Addressable::URI.join("#{client.options[:rest_base_path]}/", 'issuetypescheme/', 'mapping')
query_url.query_values = { 'issueTypeSchemeId' => project_issuetype_scheme_ids }
client
.get(query_url.to_s)
.fetch('values', [])
.map { |schemes| schemes['issueTypeId'] }
end
end
# Returns list of available Issue tTpes in selected JIRA Project
#
# @return [Array] the array of objects with JIRA Issuetype ID, Name and Description
def issue_types
return [] if jira_project.blank?
client
.Issuetype
.all
.select { |issue_type| issue_type.id.in?(project_issuetype_ids) }
.reject { |issue_type| issue_type.subtask }
.map { |issue_type| { id: issue_type.id, name: issue_type.name, description: issue_type.description } }
end
end end
end end
---
title: Return only supported issue types for selected Jira Project
merge_request: 53705
author:
type: fixed
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe JiraService do RSpec.describe JiraService do
let(:jira_service) { build(:jira_service, **options) } let(:jira_service) { build(:jira_service, **options) }
let(:headers) { { 'Content-Type' => 'application/json' } }
let(:options) do let(:options) do
{ {
...@@ -83,24 +84,9 @@ RSpec.describe JiraService do ...@@ -83,24 +84,9 @@ RSpec.describe JiraService do
end end
end end
describe '#issue_types' do
subject(:issue_types) { jira_service.issue_types }
let(:client) { double(Issuetype: issue_type_jira_resource) }
let(:issue_type_jira_resource) { double(all: jira_issue_types) }
let(:jira_issue_types) { [double(subtask: true), double(subtask: false, id: '10001', name: 'Bug', description: 'Jira Bug')] }
before do
allow(jira_service.project).to receive(:jira_vulnerabilities_integration_enabled?).and_return(true)
allow(jira_service).to receive(:client).and_return(client)
end
it 'loads all issue types without subtask issue types' do
expect(issue_types).to eq([{ id: '10001', name: 'Bug', description: 'Jira Bug' }])
end
end
describe '#test' do describe '#test' do
let(:jira_service) { described_class.new(options) }
subject(:jira_test) { jira_service.test(nil) } subject(:jira_test) { jira_service.test(nil) }
context 'when server is not responding' do context 'when server is not responding' do
...@@ -125,9 +111,77 @@ RSpec.describe JiraService do ...@@ -125,9 +111,77 @@ RSpec.describe JiraService do
end end
context 'when vulnerabilities integration is enabled' do context 'when vulnerabilities integration is enabled' do
let(:project_info_result) { { 'id' => '10000' } }
let(:issue_type_scheme_response) do
{
values: [
{
issueTypeScheme: {
id: '10126',
name: 'GV: Software Development Issue Type Scheme',
defaultIssueTypeId: '10001'
},
projectIds: [
'10000'
]
}
]
}
end
let(:issue_type_mapping_response) do
{
values: [
{
issueTypeSchemeId: '10126',
issueTypeId: '10003'
},
{
issueTypeSchemeId: '10126',
issueTypeId: '10001'
}
]
}
end
let(:issue_types_response) do
[
{
id: '10004',
description: 'A new feature of the product, which has yet to be developed.',
name: 'New Feature',
untranslatedName: 'New Feature',
subtask: false,
avatarId: 10311
},
{
id: '10001',
description: 'Jira Bug',
name: 'Bug',
untranslatedName: 'Bug',
subtask: false,
avatarId: 10303
},
{
id: '10003',
description: 'A small piece of work thats part of a larger task.',
name: 'Sub-task',
untranslatedName: 'Sub-task',
subtask: true,
avatarId: 10316
}
]
end
before do before do
allow(jira_service.project).to receive(:jira_vulnerabilities_integration_enabled?).and_return(true) allow(jira_service.project).to receive(:jira_vulnerabilities_integration_enabled?).and_return(true)
allow(jira_service).to receive(:issue_types).and_return([{ id: '10001', name: 'Bug', description: 'Jira Bug' }])
WebMock.stub_request(:get, /api\/2\/project\/GL/).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)).to_return(body: project_info_result.to_json )
WebMock.stub_request(:get, /api\/2\/project\/GL\z/).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)).to_return(body: { 'id' => '10000' }.to_json, headers: headers)
WebMock.stub_request(:get, /api\/2\/issuetype\z/).to_return(body: issue_types_response.to_json, headers: headers)
WebMock.stub_request(:get, /api\/2\/issuetypescheme\/project\?projectId\=10000\z/).to_return(body: issue_type_scheme_response.to_json, headers: headers)
WebMock.stub_request(:get, /api\/2\/issuetypescheme\/mapping\?issueTypeSchemeId\=10126\z/).to_return(body: issue_type_mapping_response.to_json, headers: headers)
end end
it { is_expected.to eq(success: true, result: { jira: true }, data: { issuetypes: [{ id: '10001', name: 'Bug', description: 'Jira Bug' }] }) } it { is_expected.to eq(success: true, result: { jira: true }, data: { issuetypes: [{ id: '10001', name: 'Bug', description: 'Jira Bug' }] }) }
...@@ -261,17 +315,4 @@ RSpec.describe JiraService do ...@@ -261,17 +315,4 @@ RSpec.describe JiraService do
it { is_expected.to eq(expected_new_issue_url) } it { is_expected.to eq(expected_new_issue_url) }
end end
describe '#jira_project_id' do
let(:jira_service) { described_class.new(options) }
let(:project_info_result) { { 'id' => '10000' } }
subject(:jira_project_id) { jira_service.jira_project_id }
before do
WebMock.stub_request(:get, /api\/2\/project\/GL/).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password)).to_return(body: project_info_result.to_json )
end
it { is_expected.to eq('10000') }
end
end 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