Commit 263f4ce0 authored by Alex Kalderimis's avatar Alex Kalderimis

Rebalance issues if needed on create and update

This adds a new method in the issues base_service that rebalances the
issue set when the issue is placed in the extreme 0.0001 fringes of the
relative positioning range.
parent ce699b25
......@@ -19,6 +19,16 @@ module Issues
private
NO_REBALANCING_NEEDED = ((RelativePositioning::MIN_POSITION * 0.9999)..(RelativePositioning::MAX_POSITION * 0.9999)).freeze
def rebalance_if_needed(issue)
return unless issue
return if issue.relative_position.nil?
return if NO_REBALANCING_NEEDED.cover?(issue.relative_position)
IssueRebalancingWorker.perform_async(issue.id)
end
def create_assignee_note(issue, old_assignees)
SystemNoteService.change_issuable_assignees(
issue, issue.project, current_user, old_assignees)
......
......@@ -30,6 +30,7 @@ module Issues
user_agent_detail_service.create
resolve_discussions_with_issue(issuable)
delete_milestone_total_issue_counter_cache(issuable.milestone)
rebalance_if_needed(issuable)
super
end
......
......@@ -83,6 +83,7 @@ module Issues
raise ActiveRecord::RecordNotFound unless issue_before || issue_after
issue.move_between(issue_before, issue_after)
rebalance_if_needed(issue)
end
# rubocop: disable CodeReuse/ActiveRecord
......
......@@ -75,6 +75,19 @@ RSpec.describe Issues::CreateService do
expect(Todo.where(attributes).count).to eq 1
end
it 'rebalances if needed' do
create(:issue, project: project, relative_position: RelativePositioning::MAX_POSITION)
expect(IssueRebalancingWorker).to receive(:perform_async).with(Integer)
expect(issue.relative_position).to eq(project.issues.maximum(:relative_position))
end
it 'does not rebalance unless needed' do
expect(IssueRebalancingWorker).not_to receive(:perform_async).with(Integer)
expect(issue.relative_position).to eq(project.issues.maximum(:relative_position))
end
context 'when label belongs to project group' do
let(:group) { create(:group) }
let(:group_labels) { create_pair(:group_label, group: group) }
......
......@@ -106,7 +106,7 @@ RSpec.describe Issues::UpdateService, :mailer do
[issue, issue1, issue2].each do |issue|
issue.move_to_end
issue.save
issue.save!
end
opts[:move_between_ids] = [issue1.id, issue2.id]
......@@ -116,6 +116,34 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
end
it 'rebalances if needed on the left' do
range = described_class::NO_REBALANCING_NEEDED
issue1 = create(:issue, project: project, relative_position: range.first - 100)
issue2 = create(:issue, project: project, relative_position: range.first)
issue.update!(relative_position: RelativePositioning::START_POSITION)
opts[:move_between_ids] = [issue1.id, issue2.id]
expect(IssueRebalancingWorker).to receive(:perform_async).with(issue.id)
update_issue(opts)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
end
it 'rebalances if needed on the right' do
range = described_class::NO_REBALANCING_NEEDED
issue1 = create(:issue, project: project, relative_position: range.last)
issue2 = create(:issue, project: project, relative_position: range.last + 100)
issue.update!(relative_position: RelativePositioning::START_POSITION)
opts[:move_between_ids] = [issue1.id, issue2.id]
expect(IssueRebalancingWorker).to receive(:perform_async).with(issue.id)
update_issue(opts)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
end
context 'when moving issue between issues from different projects' do
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
......
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