Commit 68e796e3 authored by Ash McKenzie's avatar Ash McKenzie

Merge branch 'fix-duplicate-labels-when-moving-projects' into 'master'

Fix duplicate labels when moving projects

See merge request gitlab-org/gitlab!27261
parents 3089df26 527e59d0
...@@ -49,7 +49,7 @@ module Labels ...@@ -49,7 +49,7 @@ module Labels
Label.joins(:issues) Label.joins(:issues)
.where( .where(
issues: { project_id: project.id }, issues: { project_id: project.id },
labels: { type: 'GroupLabel', group_id: old_group.id } labels: { type: 'GroupLabel', group_id: old_group.self_and_ancestors }
) )
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
...@@ -59,14 +59,14 @@ module Labels ...@@ -59,14 +59,14 @@ module Labels
Label.joins(:merge_requests) Label.joins(:merge_requests)
.where( .where(
merge_requests: { target_project_id: project.id }, merge_requests: { target_project_id: project.id },
labels: { type: 'GroupLabel', group_id: old_group.id } labels: { type: 'GroupLabel', group_id: old_group.self_and_ancestors }
) )
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def find_or_create_label!(label) def find_or_create_label!(label)
params = label.attributes.slice('title', 'description', 'color') params = label.attributes.slice('title', 'description', 'color')
new_label = FindOrCreateService.new(current_user, project, params).execute new_label = FindOrCreateService.new(current_user, project, params.merge(include_ancestor_groups: true)).execute
new_label.id new_label.id
end end
......
---
title: Fix duplicate labels when moving projects within the same ancestor group
merge_request: 27261
author:
type: fixed
...@@ -4,65 +4,101 @@ require 'spec_helper' ...@@ -4,65 +4,101 @@ require 'spec_helper'
describe Labels::TransferService do describe Labels::TransferService do
describe '#execute' do describe '#execute' do
let(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
let(:group_1) { create(:group) }
let(:group_2) { create(:group) } let_it_be(:old_group_ancestor) { create(:group) }
let(:group_3) { create(:group) } let_it_be(:old_group) { create(:group, parent: old_group_ancestor) }
let(:project_1) { create(:project, namespace: group_2) }
let(:project_2) { create(:project, namespace: group_3) } let_it_be(:new_group) { create(:group) }
let(:project_3) { create(:project, namespace: group_1) }
let_it_be(:project) { create(:project, :repository, group: new_group) }
let(:group_label_1) { create(:group_label, group: group_1, name: 'Group Label 1') }
let(:group_label_2) { create(:group_label, group: group_1, name: 'Group Label 2') } subject(:service) { described_class.new(user, old_group, project) }
let(:group_label_3) { create(:group_label, group: group_1, name: 'Group Label 3') }
let(:group_label_4) { create(:group_label, group: group_2, name: 'Group Label 4') } it 'recreates missing group labels at project level and assigns them to the issuables' do
let(:group_label_5) { create(:group_label, group: group_3, name: 'Group Label 5') } old_group_label_1 = create(:group_label, group: old_group)
let(:project_label_1) { create(:label, project: project_1, name: 'Project Label 1') } old_group_label_2 = create(:group_label, group: old_group)
subject(:service) { described_class.new(user, group_1, project_1) } labeled_issue = create(:labeled_issue, project: project, labels: [old_group_label_1])
labeled_merge_request = create(:labeled_merge_request, source_project: project, labels: [old_group_label_2])
before do
create(:labeled_issue, project: project_1, labels: [group_label_1]) expect { service.execute }.to change(project.labels, :count).by(2)
create(:labeled_issue, project: project_1, labels: [group_label_4]) expect(labeled_issue.reload.labels).to contain_exactly(project.labels.find_by_title(old_group_label_1.title))
create(:labeled_issue, project: project_1, labels: [project_label_1]) expect(labeled_merge_request.reload.labels).to contain_exactly(project.labels.find_by_title(old_group_label_2.title))
create(:labeled_issue, project: project_2, labels: [group_label_5])
create(:labeled_issue, project: project_3, labels: [group_label_1])
create(:labeled_merge_request, source_project: project_1, labels: [group_label_1, group_label_2])
create(:labeled_merge_request, source_project: project_2, labels: [group_label_5])
end end
it 'recreates the missing group labels at project level' do it 'recreates missing ancestor group labels at project level and assigns them to the issuables' do
expect { service.execute }.to change(project_1.labels, :count).by(2) old_group_ancestor_label_1 = create(:group_label, group: old_group_ancestor)
old_group_ancestor_label_2 = create(:group_label, group: old_group_ancestor)
labeled_issue = create(:labeled_issue, project: project, labels: [old_group_ancestor_label_1])
labeled_merge_request = create(:labeled_merge_request, source_project: project, labels: [old_group_ancestor_label_2])
expect { service.execute }.to change(project.labels, :count).by(2)
expect(labeled_issue.reload.labels).to contain_exactly(project.labels.find_by_title(old_group_ancestor_label_1.title))
expect(labeled_merge_request.reload.labels).to contain_exactly(project.labels.find_by_title(old_group_ancestor_label_2.title))
end end
it 'recreates label priorities related to the missing group labels' do it 'recreates label priorities related to the missing group labels' do
create(:label_priority, project: project_1, label: group_label_1, priority: 1) old_group_label = create(:group_label, group: old_group)
create(:labeled_issue, project: project, labels: [old_group_label])
create(:label_priority, project: project, label: old_group_label, priority: 1)
service.execute service.execute
new_project_label = project_1.labels.find_by(title: group_label_1.title) new_project_label = project.labels.find_by(title: old_group_label.title)
expect(new_project_label.id).not_to eq group_label_1.id expect(new_project_label.id).not_to eq old_group_label.id
expect(new_project_label.priorities).not_to be_empty expect(new_project_label.priorities).not_to be_empty
end end
it 'does not recreate missing group labels that are not applied to issues or merge requests' do it 'does not recreate missing group labels that are not applied to issues or merge requests' do
old_group_label = create(:group_label, group: old_group)
service.execute service.execute
expect(project_1.labels.where(title: group_label_3.title)).to be_empty expect(project.labels.where(title: old_group_label.title)).to be_empty
end end
it 'does not recreate missing group labels that already exist in the project group' do it 'does not recreate missing group labels that already exist in the project group' do
old_group_label = create(:group_label, group: old_group)
labeled_issue = create(:labeled_issue, project: project, labels: [old_group_label])
new_group_label = create(:group_label, group: new_group, title: old_group_label.title)
service.execute service.execute
expect(project_1.labels.where(title: group_label_4.title)).to be_empty expect(project.labels.where(title: old_group_label.title)).to be_empty
expect(labeled_issue.reload.labels).to contain_exactly(new_group_label)
end end
it 'updates only label links in the given project' do it 'updates only label links in the given project' do
old_group_label = create(:group_label, group: old_group)
other_project = create(:project, group: old_group)
labeled_issue = create(:labeled_issue, project: project, labels: [old_group_label])
other_project_labeled_issue = create(:labeled_issue, project: other_project, labels: [old_group_label])
service.execute service.execute
targets = LabelLink.where(label_id: group_label_1.id).map(&:target) expect(labeled_issue.reload.labels).not_to include(old_group_label)
expect(other_project_labeled_issue.reload.labels).to contain_exactly(old_group_label)
end
expect(targets).to eq(project_3.issues) context 'when moving within the same ancestor group' do
let(:other_subgroup) { create(:group, parent: old_group_ancestor) }
let(:project) { create(:project, :repository, group: other_subgroup) }
it 'does not recreate ancestor group labels' do
old_group_ancestor_label_1 = create(:group_label, group: old_group_ancestor)
old_group_ancestor_label_2 = create(:group_label, group: old_group_ancestor)
labeled_issue = create(:labeled_issue, project: project, labels: [old_group_ancestor_label_1])
labeled_merge_request = create(:labeled_merge_request, source_project: project, labels: [old_group_ancestor_label_2])
expect { service.execute }.not_to change(project.labels, :count)
expect(labeled_issue.reload.labels).to contain_exactly(old_group_ancestor_label_1)
expect(labeled_merge_request.reload.labels).to contain_exactly(old_group_ancestor_label_2)
end
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment