Commit ee33e657 authored by Adam Hegyi's avatar Adam Hegyi

Merge branch '214834-propagate-service-tempate' into 'master'

PropagateServiceTemplate for services with data tables

Closes #214834

See merge request gitlab-org/gitlab!29805
parents a349a7be 47ebf568
...@@ -4,8 +4,10 @@ module Projects ...@@ -4,8 +4,10 @@ module Projects
class PropagateServiceTemplate class PropagateServiceTemplate
BATCH_SIZE = 100 BATCH_SIZE = 100
def self.propagate(*args) delegate :data_fields_present?, to: :template
new(*args).propagate
def self.propagate(template)
new(template).propagate
end end
def initialize(template) def initialize(template)
...@@ -13,15 +15,15 @@ module Projects ...@@ -13,15 +15,15 @@ module Projects
end end
def propagate def propagate
return unless @template.active? return unless template.active?
Rails.logger.info("Propagating services for template #{@template.id}") # rubocop:disable Gitlab/RailsLogger
propagate_projects_with_template propagate_projects_with_template
end end
private private
attr_reader :template
def propagate_projects_with_template def propagate_projects_with_template
loop do loop do
batch = Project.uncached { project_ids_batch } batch = Project.uncached { project_ids_batch }
...@@ -38,7 +40,14 @@ module Projects ...@@ -38,7 +40,14 @@ module Projects
end end
Project.transaction do Project.transaction do
bulk_insert_services(service_hash.keys << 'project_id', service_list) results = bulk_insert(Service, service_hash.keys << 'project_id', service_list)
if data_fields_present?
data_list = results.map { |row| data_hash.values << row['id'] }
bulk_insert(template.data_fields.class, data_hash.keys << 'service_id', data_list)
end
run_callbacks(batch) run_callbacks(batch)
end end
end end
...@@ -52,7 +61,7 @@ module Projects ...@@ -52,7 +61,7 @@ module Projects
SELECT true SELECT true
FROM services FROM services
WHERE services.project_id = projects.id WHERE services.project_id = projects.id
AND services.type = '#{@template.type}' AND services.type = #{ActiveRecord::Base.connection.quote(template.type)}
) )
AND projects.pending_delete = false AND projects.pending_delete = false
AND projects.archived = false AND projects.archived = false
...@@ -61,27 +70,18 @@ module Projects ...@@ -61,27 +70,18 @@ module Projects
) )
end end
def bulk_insert_services(columns, values_array) def bulk_insert(klass, columns, values_array)
ActiveRecord::Base.connection.execute( items_to_insert = values_array.map { |array| Hash[columns.zip(array)] }
<<-SQL.strip_heredoc
INSERT INTO services (#{columns.join(', ')}) klass.insert_all(items_to_insert, returning: [:id])
VALUES #{values_array.map { |tuple| "(#{tuple.join(', ')})" }.join(', ')}
SQL
)
end end
def service_hash def service_hash
@service_hash ||= @service_hash ||= template.as_json(methods: :type, except: %w[id template project_id])
begin
template_hash = @template.as_json(methods: :type).except('id', 'template', 'project_id')
template_hash.each_with_object({}) do |(key, value), service_hash|
value = value.is_a?(Hash) ? value.to_json : value
service_hash[ActiveRecord::Base.connection.quote_column_name(key)] =
ActiveRecord::Base.connection.quote(value)
end
end end
def data_hash
@data_hash ||= template.data_fields.as_json(only: template.data_fields.class.column_names).except('id', 'service_id')
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -97,11 +97,11 @@ module Projects ...@@ -97,11 +97,11 @@ module Projects
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def active_external_issue_tracker? def active_external_issue_tracker?
@template.issue_tracker? && !@template.default template.issue_tracker? && !template.default
end end
def active_external_wiki? def active_external_wiki?
@template.type == 'ExternalWikiService' template.type == 'ExternalWikiService'
end end
end end
end end
---
title: Propagation of service templates also covers services with separate data tables.
merge_request: 29805
author:
type: fixed
...@@ -8,16 +8,19 @@ describe Projects::PropagateServiceTemplate do ...@@ -8,16 +8,19 @@ describe Projects::PropagateServiceTemplate do
PushoverService.create( PushoverService.create(
template: true, template: true,
active: true, active: true,
push_events: false,
properties: { properties: {
device: 'MyDevice', device: 'MyDevice',
sound: 'mic', sound: 'mic',
priority: 4, priority: 4,
user_key: 'asdf', user_key: 'asdf',
api_key: '123456789' api_key: '123456789'
}) }
)
end end
let!(:project) { create(:project) } let!(:project) { create(:project) }
let(:excluded_attributes) { %w[id project_id template created_at updated_at title description] }
it 'creates services for projects' do it 'creates services for projects' do
expect(project.pushover_service).to be_nil expect(project.pushover_service).to be_nil
...@@ -35,7 +38,7 @@ describe Projects::PropagateServiceTemplate do ...@@ -35,7 +38,7 @@ describe Projects::PropagateServiceTemplate do
properties: { properties: {
bamboo_url: 'http://gitlab.com', bamboo_url: 'http://gitlab.com',
username: 'mic', username: 'mic',
password: "password", password: 'password',
build_key: 'build' build_key: 'build'
} }
) )
...@@ -54,7 +57,7 @@ describe Projects::PropagateServiceTemplate do ...@@ -54,7 +57,7 @@ describe Projects::PropagateServiceTemplate do
properties: { properties: {
bamboo_url: 'http://gitlab.com', bamboo_url: 'http://gitlab.com',
username: 'mic', username: 'mic',
password: "password", password: 'password',
build_key: 'build' build_key: 'build'
} }
) )
...@@ -70,6 +73,33 @@ describe Projects::PropagateServiceTemplate do ...@@ -70,6 +73,33 @@ describe Projects::PropagateServiceTemplate do
described_class.propagate(service_template) described_class.propagate(service_template)
expect(project.pushover_service.properties).to eq(service_template.properties) expect(project.pushover_service.properties).to eq(service_template.properties)
expect(project.pushover_service.attributes.except(*excluded_attributes))
.to eq(service_template.attributes.except(*excluded_attributes))
end
context 'service with data fields' do
let(:service_template) do
JiraService.create!(
template: true,
active: true,
push_events: false,
url: 'http://jira.instance.com',
username: 'user',
password: 'secret'
)
end
it 'creates the service containing the template attributes' do
described_class.propagate(service_template)
expect(project.jira_service.attributes.except(*excluded_attributes))
.to eq(service_template.attributes.except(*excluded_attributes))
excluded_attributes = %w[id service_id created_at updated_at]
expect(project.jira_service.data_fields.attributes.except(*excluded_attributes))
.to eq(service_template.data_fields.attributes.except(*excluded_attributes))
end
end end
describe 'bulk update', :use_sql_query_cache do describe 'bulk update', :use_sql_query_cache 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