93 lines
2.6 KiB
Ruby
93 lines
2.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module ImportExport
|
|
# Given a class, it finds or creates a new object
|
|
# (initializes in the case of Label) at group or project level.
|
|
# If it does not exist in the group, it creates it at project level.
|
|
#
|
|
# Example:
|
|
# `GroupProjectObjectBuilder.build(Label, label_attributes)`
|
|
# finds or initializes a label with the given attributes.
|
|
#
|
|
# It also adds some logic around Group Labels/Milestones for edge cases.
|
|
class GroupProjectObjectBuilder
|
|
def self.build(*args)
|
|
Project.transaction do
|
|
new(*args).find
|
|
end
|
|
end
|
|
|
|
def initialize(klass, attributes)
|
|
@klass = klass < Label ? Label : klass
|
|
@attributes = attributes
|
|
@group = @attributes['group']
|
|
@project = @attributes['project']
|
|
end
|
|
|
|
def find
|
|
find_object || @klass.create(project_attributes)
|
|
end
|
|
|
|
private
|
|
|
|
def find_object
|
|
@klass.where(where_clause).first
|
|
end
|
|
|
|
def where_clause
|
|
@attributes.slice('title').map do |key, value|
|
|
scope_clause = table[:project_id].eq(@project.id)
|
|
scope_clause = scope_clause.or(table[:group_id].eq(@group.id)) if @group
|
|
|
|
table[key].eq(value).and(scope_clause)
|
|
end.reduce(:or)
|
|
end
|
|
|
|
def table
|
|
@table ||= @klass.arel_table
|
|
end
|
|
|
|
def project_attributes
|
|
@attributes.except('group').tap do |atts|
|
|
if label?
|
|
atts['type'] = 'ProjectLabel' # Always create project labels
|
|
elsif milestone?
|
|
if atts['group_id'] # Transform new group milestones into project ones
|
|
atts['iid'] = nil
|
|
atts.delete('group_id')
|
|
else
|
|
claim_iid
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def label?
|
|
@klass == Label
|
|
end
|
|
|
|
def milestone?
|
|
@klass == Milestone
|
|
end
|
|
|
|
# If an existing group milestone used the IID
|
|
# claim the IID back and set the group milestone to use one available
|
|
# This is necessary to fix situations like the following:
|
|
# - Importing into a user namespace project with exported group milestones
|
|
# where the IID of the Group milestone could conflict with a project one.
|
|
def claim_iid
|
|
# The milestone has to be a group milestone, as it's the only case where
|
|
# we set the IID as the maximum. The rest of them are fixed.
|
|
milestone = @project.milestones.find_by(iid: @attributes['iid'])
|
|
|
|
return unless milestone
|
|
|
|
milestone.iid = nil
|
|
milestone.ensure_project_iid!
|
|
milestone.save!
|
|
end
|
|
end
|
|
end
|
|
end
|