Commit 1e0974d1 authored by Arturo Herrero's avatar Arturo Herrero Committed by Imre Farkas

New created projects could inherit services from groups

We can now save integrations that belongs to a group
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39959.

When creating a new project, the precedence to create new integrations
is: closest integration from ancestors to the project, instance-level
integration or template service.
parent 50eaf781
...@@ -8,6 +8,7 @@ class Service < ApplicationRecord ...@@ -8,6 +8,7 @@ class Service < ApplicationRecord
include ProjectServicesLoggable include ProjectServicesLoggable
include DataFields include DataFields
include IgnorableColumns include IgnorableColumns
include FromUnion
ignore_columns %i[default], remove_with: '13.5', remove_after: '2020-10-22' ignore_columns %i[default], remove_with: '13.5', remove_after: '2020-10-22'
...@@ -227,7 +228,8 @@ class Service < ApplicationRecord ...@@ -227,7 +228,8 @@ class Service < ApplicationRecord
service.template = false service.template = false
service.instance = false service.instance = false
service.inherit_from_id = integration.id if integration.instance? service.group = nil
service.inherit_from_id = integration.id if integration.instance? || integration.group
service.project_id = project_id service.project_id = project_id
service.active = false if service.invalid? service.active = false if service.invalid?
service service
......
...@@ -162,7 +162,7 @@ module Projects ...@@ -162,7 +162,7 @@ module Projects
if @project.save if @project.save
unless @project.gitlab_project_import? unless @project.gitlab_project_import?
create_services_from_active_instances_or_templates(@project) create_services_from_active_default_integrations_or_templates(@project)
@project.create_labels @project.create_labels
end end
...@@ -229,14 +229,25 @@ module Projects ...@@ -229,14 +229,25 @@ module Projects
private private
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def create_services_from_active_instances_or_templates(project) def create_services_from_active_default_integrations_or_templates(project)
Service.active.where(instance: true).or(Service.active.where(template: true)).group_by(&:type).each do |type, records| group_ids = project.ancestors.select(:id)
service = records.find(&:instance?) || records.find(&:template?)
Service.build_from_integration(project.id, service).save! Service.from_union([
Service.active.where(instance: true),
Service.active.where(template: true),
Service.active.where(group_id: group_ids)
]).order(by_type_group_ids_and_instance(group_ids)).group_by(&:type).each do |type, records|
Service.build_from_integration(project.id, records.first).save!
end end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def by_type_group_ids_and_instance(group_ids)
array = group_ids.to_sql.present? ? "array(#{group_ids.to_sql})" : 'ARRAY[]'
Arel.sql("type ASC, array_position(#{array}::bigint[], services.group_id), instance DESC")
end
def project_namespace def project_namespace
@project_namespace ||= Namespace.find_by_id(@params[:namespace_id]) || current_user.namespace @project_namespace ||= Namespace.find_by_id(@params[:namespace_id]) || current_user.namespace
end end
......
...@@ -327,7 +327,7 @@ RSpec.describe Service do ...@@ -327,7 +327,7 @@ RSpec.describe Service do
end end
end end
context 'when integration is an instance' do context 'when integration is an instance-level integration' do
let(:integration) { create(:jira_service, :instance) } let(:integration) { create(:jira_service, :instance) }
it 'sets inherit_from_id from integration' do it 'sets inherit_from_id from integration' do
...@@ -337,6 +337,16 @@ RSpec.describe Service do ...@@ -337,6 +337,16 @@ RSpec.describe Service do
end end
end end
context 'when integration is a group-level integration' do
let(:integration) { create(:jira_service, group: group, project: nil) }
it 'sets inherit_from_id from integration' do
service = described_class.build_from_integration(project.id, integration)
expect(service.inherit_from_id).to eq(integration.id)
end
end
describe 'build issue tracker from an integration' do describe 'build issue tracker from an integration' do
let(:url) { 'http://jira.example.com' } let(:url) { 'http://jira.example.com' }
let(:api_url) { 'http://api-jira.example.com' } let(:api_url) { 'http://api-jira.example.com' }
...@@ -360,6 +370,8 @@ RSpec.describe Service do ...@@ -360,6 +370,8 @@ RSpec.describe Service do
expect(service.password).to eq(password) expect(service.password).to eq(password)
expect(service.template).to eq(false) expect(service.template).to eq(false)
expect(service.instance).to eq(false) expect(service.instance).to eq(false)
expect(service.project).to eq(project)
expect(service.group).to eq(nil)
end end
end end
......
...@@ -487,18 +487,7 @@ RSpec.describe Projects::CreateService, '#execute' do ...@@ -487,18 +487,7 @@ RSpec.describe Projects::CreateService, '#execute' do
describe 'create service for the project' do describe 'create service for the project' do
subject(:project) { create_project(user, opts) } subject(:project) { create_project(user, opts) }
context 'when there is an active instance-level and an active template integration' do context 'with an active service template' do
let!(:template_integration) { create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/') }
let!(:instance_integration) { create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/') }
it 'creates a service from the instance-level integration' do
expect(project.services.count).to eq(1)
expect(project.services.first.api_url).to eq(instance_integration.api_url)
expect(project.services.first.inherit_from_id).to eq(instance_integration.id)
end
end
context 'when there is an active service template' do
let!(:template_integration) { create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/') } let!(:template_integration) { create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/') }
it 'creates a service from the template' do it 'creates a service from the template' do
...@@ -506,6 +495,60 @@ RSpec.describe Projects::CreateService, '#execute' do ...@@ -506,6 +495,60 @@ RSpec.describe Projects::CreateService, '#execute' do
expect(project.services.first.api_url).to eq(template_integration.api_url) expect(project.services.first.api_url).to eq(template_integration.api_url)
expect(project.services.first.inherit_from_id).to be_nil expect(project.services.first.inherit_from_id).to be_nil
end end
context 'with an active instance-level integration' do
let!(:instance_integration) { create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/') }
it 'creates a service from the instance-level integration' do
expect(project.services.count).to eq(1)
expect(project.services.first.api_url).to eq(instance_integration.api_url)
expect(project.services.first.inherit_from_id).to eq(instance_integration.id)
end
context 'with an active group-level integration' do
let!(:group_integration) { create(:prometheus_service, group: group, project: nil, api_url: 'https://prometheus.group.com/') }
let!(:group) do
create(:group).tap do |group|
group.add_owner(user)
end
end
let(:opts) do
{
name: 'GitLab',
namespace_id: group.id
}
end
it 'creates a service from the group-level integration' do
expect(project.services.count).to eq(1)
expect(project.services.first.api_url).to eq(group_integration.api_url)
expect(project.services.first.inherit_from_id).to eq(group_integration.id)
end
context 'with an active subgroup' do
let!(:subgroup_integration) { create(:prometheus_service, group: subgroup, project: nil, api_url: 'https://prometheus.subgroup.com/') }
let!(:subgroup) do
create(:group, parent: group).tap do |subgroup|
subgroup.add_owner(user)
end
end
let(:opts) do
{
name: 'GitLab',
namespace_id: subgroup.id
}
end
it 'creates a service from the group-level integration' do
expect(project.services.count).to eq(1)
expect(project.services.first.api_url).to eq(subgroup_integration.api_url)
expect(project.services.first.inherit_from_id).to eq(subgroup_integration.id)
end
end
end
end
end end
context 'when there is an invalid integration' do context 'when there is an invalid integration' do
......
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