103 lines
2.7 KiB
Ruby
103 lines
2.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module Ci
|
|
module Tags
|
|
class BulkInsert
|
|
include Gitlab::Utils::StrongMemoize
|
|
|
|
TAGGINGS_BATCH_SIZE = 1000
|
|
TAGS_BATCH_SIZE = 500
|
|
|
|
def initialize(statuses)
|
|
@statuses = statuses
|
|
end
|
|
|
|
def insert!
|
|
return false if tag_list_by_status.empty?
|
|
|
|
persist_build_tags!
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :statuses
|
|
|
|
def tag_list_by_status
|
|
strong_memoize(:tag_list_by_status) do
|
|
statuses.each.with_object({}) do |status, acc|
|
|
tag_list = status.tag_list
|
|
next unless tag_list
|
|
|
|
acc[status] = tag_list
|
|
end
|
|
end
|
|
end
|
|
|
|
def persist_build_tags!
|
|
all_tags = tag_list_by_status.values.flatten.uniq.reject(&:blank?)
|
|
tag_records_by_name = create_tags(all_tags).index_by(&:name)
|
|
taggings = build_taggings_attributes(tag_records_by_name)
|
|
|
|
return false if taggings.empty?
|
|
|
|
taggings.each_slice(TAGGINGS_BATCH_SIZE) do |taggings_slice|
|
|
ActsAsTaggableOn::Tagging.insert_all!(taggings)
|
|
end
|
|
|
|
true
|
|
end
|
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
|
def create_tags(tags)
|
|
existing_tag_records = ActsAsTaggableOn::Tag.where(name: tags).to_a
|
|
missing_tags = detect_missing_tags(tags, existing_tag_records)
|
|
return existing_tag_records if missing_tags.empty?
|
|
|
|
missing_tags
|
|
.map { |tag| { name: tag } }
|
|
.each_slice(TAGS_BATCH_SIZE) do |tags_attributes|
|
|
ActsAsTaggableOn::Tag.insert_all!(tags_attributes)
|
|
end
|
|
|
|
ActsAsTaggableOn::Tag.where(name: tags).to_a
|
|
end
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
|
|
|
def build_taggings_attributes(tag_records_by_name)
|
|
taggings = statuses.flat_map do |status|
|
|
tag_list = tag_list_by_status[status]
|
|
next unless tag_list
|
|
|
|
tags = tag_records_by_name.values_at(*tag_list)
|
|
taggings_for(tags, status)
|
|
end
|
|
|
|
taggings.compact!
|
|
taggings
|
|
end
|
|
|
|
def taggings_for(tags, status)
|
|
tags.map do |tag|
|
|
{
|
|
tag_id: tag.id,
|
|
taggable_type: CommitStatus.name,
|
|
taggable_id: status.id,
|
|
created_at: Time.current,
|
|
context: 'tags'
|
|
}
|
|
end
|
|
end
|
|
|
|
def detect_missing_tags(tags, tag_records)
|
|
if tags.size != tag_records.size
|
|
tags - tag_records.map(&:name)
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|