forked from gitlabhq/gitlabhq
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add latest changes from gitlab-org/gitlab@master
- Loading branch information
GitLab Bot
committed
May 20, 2020
1 parent
1d5ae04
commit f781b0b
Showing
22 changed files
with
553 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# frozen_string_literal: true | ||
|
||
class DataList | ||
def initialize(batch, data_fields_hash, klass) | ||
@batch = batch | ||
@data_fields_hash = data_fields_hash | ||
@klass = klass | ||
end | ||
|
||
def to_array | ||
[klass, columns, values] | ||
end | ||
|
||
private | ||
|
||
attr_reader :batch, :data_fields_hash, :klass | ||
|
||
def columns | ||
data_fields_hash.keys << 'service_id' | ||
end | ||
|
||
def values | ||
batch.map { |row| data_fields_hash.values << row['id'] } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
|
||
class ServiceList | ||
def initialize(batch, service_hash, extra_hash = {}) | ||
@batch = batch | ||
@service_hash = service_hash | ||
@extra_hash = extra_hash | ||
end | ||
|
||
def to_array | ||
[Service, columns, values] | ||
end | ||
|
||
private | ||
|
||
attr_reader :batch, :service_hash, :extra_hash | ||
|
||
def columns | ||
(service_hash.keys << 'project_id') + extra_hash.keys | ||
end | ||
|
||
def values | ||
batch.map do |project_id| | ||
(service_hash.values << project_id) + extra_hash.values | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
# frozen_string_literal: true | ||
|
||
module Admin | ||
class PropagateIntegrationService | ||
BATCH_SIZE = 100 | ||
|
||
delegate :data_fields_present?, to: :integration | ||
|
||
def self.propagate(integration:, overwrite:) | ||
new(integration, overwrite).propagate | ||
end | ||
|
||
def initialize(integration, overwrite) | ||
@integration = integration | ||
@overwrite = overwrite | ||
end | ||
|
||
def propagate | ||
if overwrite | ||
update_integration_for_all_projects | ||
else | ||
update_integration_for_inherited_projects | ||
end | ||
|
||
create_integration_for_projects_without_integration | ||
end | ||
|
||
private | ||
|
||
attr_reader :integration, :overwrite | ||
|
||
# rubocop: disable Cop/InBatches | ||
# rubocop: disable CodeReuse/ActiveRecord | ||
def update_integration_for_inherited_projects | ||
Service.where(type: integration.type, inherit_from_id: integration.id).in_batches(of: BATCH_SIZE) do |batch| | ||
bulk_update_from_integration(batch) | ||
end | ||
end | ||
|
||
def update_integration_for_all_projects | ||
Service.where(type: integration.type).in_batches(of: BATCH_SIZE) do |batch| | ||
bulk_update_from_integration(batch) | ||
end | ||
end | ||
# rubocop: enable Cop/InBatches | ||
# rubocop: enable CodeReuse/ActiveRecord | ||
|
||
# rubocop: disable CodeReuse/ActiveRecord | ||
def bulk_update_from_integration(batch) | ||
# Retrieving the IDs instantiates the ActiveRecord relation (batch) | ||
# into concrete models, otherwise update_all will clear the relation. | ||
# https://stackoverflow.com/q/34811646/462015 | ||
batch_ids = batch.pluck(:id) | ||
|
||
Service.transaction do | ||
batch.update_all(service_hash) | ||
|
||
if data_fields_present? | ||
integration.data_fields.class.where(service_id: batch_ids).update_all(data_fields_hash) | ||
end | ||
end | ||
end | ||
# rubocop: enable CodeReuse/ActiveRecord | ||
|
||
def create_integration_for_projects_without_integration | ||
loop do | ||
batch = Project.uncached { project_ids_without_integration } | ||
|
||
bulk_create_from_integration(batch) unless batch.empty? | ||
|
||
break if batch.size < BATCH_SIZE | ||
end | ||
end | ||
|
||
def bulk_create_from_integration(batch) | ||
service_list = ServiceList.new(batch, service_hash, { 'inherit_from_id' => integration.id }).to_array | ||
|
||
Project.transaction do | ||
results = bulk_insert(*service_list) | ||
|
||
if data_fields_present? | ||
data_list = DataList.new(results, data_fields_hash, integration.data_fields.class).to_array | ||
|
||
bulk_insert(*data_list) | ||
end | ||
|
||
run_callbacks(batch) | ||
end | ||
end | ||
|
||
def bulk_insert(klass, columns, values_array) | ||
items_to_insert = values_array.map { |array| Hash[columns.zip(array)] } | ||
|
||
klass.insert_all(items_to_insert, returning: [:id]) | ||
end | ||
|
||
# rubocop: disable CodeReuse/ActiveRecord | ||
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 | ||
# rubocop: enable CodeReuse/ActiveRecord | ||
|
||
def active_external_issue_tracker? | ||
integration.issue_tracker? && !integration.default | ||
end | ||
|
||
def active_external_wiki? | ||
integration.type == 'ExternalWikiService' | ||
end | ||
|
||
def project_ids_without_integration | ||
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 = #{ActiveRecord::Base.connection.quote(integration.type)} | ||
) | ||
AND projects.pending_delete = false | ||
AND projects.archived = false | ||
LIMIT #{BATCH_SIZE} | ||
SQL | ||
) | ||
end | ||
|
||
def service_hash | ||
@service_hash ||= integration.to_service_hash | ||
.tap { |json| json['inherit_from_id'] = integration.id } | ||
end | ||
|
||
def data_fields_hash | ||
@data_fields_hash ||= integration.to_data_fields_hash | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# frozen_string_literal: true | ||
|
||
class PropagateIntegrationWorker | ||
include ApplicationWorker | ||
|
||
feature_category :integrations | ||
|
||
idempotent! | ||
|
||
def perform(integration_id, overwrite) | ||
Admin::PropagateIntegrationService.propagate( | ||
integration: Service.find(integration_id), | ||
overwrite: overwrite | ||
) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
title: Fix leaky constant issue in task completion status spec | ||
merge_request: 32043 | ||
author: Rajendra Kadam | ||
type: fixed |
Oops, something went wrong.