1# frozen_string_literal: true 2 3# Labels::TransferService class 4# 5# User for recreate the missing group labels at project level 6# 7module Labels 8 class TransferService 9 def initialize(current_user, old_group, project) 10 @current_user = current_user 11 @old_group = old_group 12 @project = project 13 end 14 15 def execute 16 return unless old_group.present? 17 18 # rubocop: disable CodeReuse/ActiveRecord 19 link_ids = group_labels_applied_to_issues.pluck("label_links.id") + 20 group_labels_applied_to_merge_requests.pluck("label_links.id") 21 # rubocop: disable CodeReuse/ActiveRecord 22 23 Label.transaction do 24 labels_to_transfer.find_each do |label| 25 new_label_id = find_or_create_label!(label) 26 27 next if new_label_id == label.id 28 29 update_label_links(link_ids, old_label_id: label.id, new_label_id: new_label_id) 30 update_label_priorities(old_label_id: label.id, new_label_id: new_label_id) 31 end 32 end 33 end 34 35 private 36 37 attr_reader :current_user, :old_group, :project 38 39 # rubocop: disable CodeReuse/ActiveRecord 40 def labels_to_transfer 41 Label 42 .from_union([ 43 group_labels_applied_to_issues, 44 group_labels_applied_to_merge_requests 45 ]) 46 .reorder(nil) 47 .distinct 48 end 49 # rubocop: enable CodeReuse/ActiveRecord 50 51 # rubocop: disable CodeReuse/ActiveRecord 52 def group_labels_applied_to_issues 53 @labels_applied_to_issues ||= if use_optimized_group_labels_query? 54 Label.joins(:issues) 55 .joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'" ) 56 .where(issues: { project_id: project.id }).reorder(nil) 57 else 58 Label.joins(:issues).where( 59 issues: { project_id: project.id }, 60 labels: { group_id: old_group.self_and_ancestors } 61 ) 62 end 63 end 64 # rubocop: enable CodeReuse/ActiveRecord 65 66 # rubocop: disable CodeReuse/ActiveRecord 67 def group_labels_applied_to_merge_requests 68 @labels_applied_to_mrs ||= if use_optimized_group_labels_query? 69 Label.joins(:merge_requests) 70 .joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'" ) 71 .where(merge_requests: { target_project_id: project.id }).reorder(nil) 72 else 73 Label.joins(:merge_requests) 74 .where( 75 merge_requests: { target_project_id: project.id }, 76 labels: { group_id: old_group.self_and_ancestors } 77 ) 78 end 79 end 80 # rubocop: enable CodeReuse/ActiveRecord 81 82 def find_or_create_label!(label) 83 params = label.attributes.slice('title', 'description', 'color') 84 new_label = FindOrCreateService.new(current_user, project, params.merge(include_ancestor_groups: true)).execute 85 86 new_label.id 87 end 88 89 # rubocop: disable CodeReuse/ActiveRecord 90 def update_label_links(link_ids, old_label_id:, new_label_id:) 91 LabelLink.where(id: link_ids, label_id: old_label_id) 92 .update_all(label_id: new_label_id) 93 end 94 # rubocop: enable CodeReuse/ActiveRecord 95 96 # rubocop: disable CodeReuse/ActiveRecord 97 def update_label_priorities(old_label_id:, new_label_id:) 98 LabelPriority.where(project_id: project.id, label_id: old_label_id) 99 .update_all(label_id: new_label_id) 100 end 101 # rubocop: enable CodeReuse/ActiveRecord 102 103 def use_optimized_group_labels_query? 104 Feature.enabled?(:use_optimized_group_labels_query, project.root_namespace, default_enabled: :yaml) 105 end 106 end 107end 108