Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/projects/propagate_service_template.rb')
-rw-r--r--app/services/projects/propagate_service_template.rb103
1 files changed, 103 insertions, 0 deletions
diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb
new file mode 100644
index 00000000000..32ad68673ac
--- /dev/null
+++ b/app/services/projects/propagate_service_template.rb
@@ -0,0 +1,103 @@
+module Projects
+ class PropagateServiceTemplate
+ BATCH_SIZE = 100
+
+ def self.propagate(*args)
+ new(*args).propagate
+ end
+
+ def initialize(template)
+ @template = template
+ end
+
+ def propagate
+ return unless @template&.active
+
+ Rails.logger.info("Propagating services for template #{@template.id}")
+
+ propagate_projects_with_template
+ end
+
+ private
+
+ def propagate_projects_with_template
+ loop do
+ batch = project_ids_batch
+
+ bulk_create_from_template(batch) unless batch.empty?
+
+ break if batch.size < BATCH_SIZE
+ end
+ end
+
+ def bulk_create_from_template(batch)
+ service_list = batch.map do |project_id|
+ service_hash.merge('project_id' => project_id).values
+ end
+
+ Project.transaction do
+ bulk_insert_services(service_hash.keys + ['project_id'], service_list)
+ run_callbacks(batch)
+ end
+ end
+
+ def project_ids_batch
+ Project.connection.select_values(
+ <<-SQL
+ SELECT id
+ FROM projects
+ WHERE NOT EXISTS (
+ SELECT true
+ FROM services
+ WHERE services.project_id = projects.id
+ AND services.type = '#{@template.type}'
+ )
+ AND projects.pending_delete = false
+ AND projects.archived = false
+ LIMIT #{BATCH_SIZE}
+ SQL
+ )
+ end
+
+ def bulk_insert_services(columns, values_array)
+ ActiveRecord::Base.connection.execute(
+ <<-SQL.strip_heredoc
+ INSERT INTO services (#{columns.join(', ')})
+ VALUES #{values_array.map { |tuple| "(#{tuple.join(', ')})" }.join(', ')}
+ SQL
+ )
+ end
+
+ def service_hash
+ @service_hash ||=
+ 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
+ key = Gitlab::Database.postgresql? ? "\"#{key}\"" : "`#{key}`"
+
+ service_hash[key] = ActiveRecord::Base.sanitize(value)
+ end
+ end
+ end
+
+ def run_callbacks(batch)
+ if active_external_issue_tracker?
+ Project.where(id: batch).update_all(has_external_issue_tracker: true)
+ end
+
+ if active_external_wiki?
+ Project.where(id: batch).update_all(has_external_wiki: true)
+ end
+ end
+
+ def active_external_issue_tracker?
+ @template.category == :issue_tracker && !@template.default
+ end
+
+ def active_external_wiki?
+ @template.type == 'ExternalWikiService'
+ end
+ end
+end