Commit a077194f authored by Jan Provaznik's avatar Jan Provaznik

Allow to create epic from ancestor board

When an epic is created from an epic board, user can
can select a group where the epic will be created. This group
can be either the same group as board's group or any subgroup.

For this reason when we are searching for the board, it can exist in
any ancestor group.

Changelog: added
EE: true
parent 31462b14
......@@ -10,7 +10,7 @@ module Boards
end
def execute
relation = group.epic_boards
relation = init_relation
relation = by_id(relation)
relation.order_by_name_asc
......@@ -18,6 +18,12 @@ module Boards
private
def init_relation
return group.epic_boards unless params[:include_ancestor_groups]
::Boards::EpicBoard.for_groups(group.self_and_ancestors)
end
def by_id(relation)
return relation unless params[:id].present?
......
......@@ -12,6 +12,7 @@ module Boards
validates :name, length: { maximum: 255 }, presence: true
scope :order_by_name_asc, -> { order(arel_table[:name].lower.asc).order(id: :asc) }
scope :for_groups, ->(ids) { where(group_id: ids) }
def lists
epic_lists
......
......@@ -34,7 +34,10 @@ module Boards
end
def board
@board ||= parent.epic_boards.find(params.delete(:board_id))
@board ||= Boards::EpicBoardsFinder
.new(group, include_ancestor_groups: true, id: params.delete(:board_id))
.execute
.first
end
def list
......@@ -50,10 +53,8 @@ module Boards
end
def check_arguments
begin
board
rescue ActiveRecord::RecordNotFound
return 'Board not found' if @board.blank?
unless board && Ability.allowed?(current_user, :read_epic_board, board)
return 'Board not found'
end
begin
......
......@@ -4,11 +4,13 @@ require 'spec_helper'
RSpec.describe Boards::EpicBoardsFinder do
describe '#execute' do
let_it_be(:group) { create(:group) }
let_it_be(:parent_group) { create(:group) }
let_it_be(:group) { create(:group, parent: parent_group) }
let_it_be(:epic_board1) { create(:epic_board, name: 'Acd', group: group) }
let_it_be(:epic_board2) { create(:epic_board, name: 'abd', group: group) }
let_it_be(:epic_board3) { create(:epic_board, name: 'Bbd', group: group) }
let_it_be(:epic_board4) { create(:epic_board) }
let_it_be(:epic_board5) { create(:epic_board, name: 'foo', group: parent_group) }
let(:params) { {} }
......@@ -18,6 +20,14 @@ RSpec.describe Boards::EpicBoardsFinder do
expect(result).to eq([epic_board2, epic_board1, epic_board3])
end
context 'when include_ancestor_groups parameter is set' do
let(:params) { { include_ancestor_groups: true } }
it 'finds all epic boards in the group or ancestor groups' do
expect(result).to eq([epic_board2, epic_board1, epic_board3, epic_board5])
end
end
context 'when ID parameter is set' do
let(:params) { { id: epic_board2.id } }
......
......@@ -15,13 +15,21 @@ RSpec.describe Boards::EpicBoard do
it { is_expected.to validate_length_of(:name).is_at_most(255) }
end
describe '.order_by_name_asc' do
describe 'scopes' do
let_it_be(:board1) { create(:epic_board, name: 'B') }
let_it_be(:board2) { create(:epic_board, name: 'a') }
let_it_be(:board3) { create(:epic_board, name: 'A') }
it 'returns in case-insensitive alphabetical order and then by ascending ID' do
expect(described_class.order_by_name_asc).to eq [board2, board3, board1]
describe '.order_by_name_asc' do
it 'returns in case-insensitive alphabetical order and then by ascending ID' do
expect(described_class.order_by_name_asc).to eq [board2, board3, board1]
end
end
describe '.for_groups' do
it 'returns boards only in selected groups' do
expect(described_class.for_groups([board1.group_id, board2.group_id])).to match_array([board1, board2])
end
end
end
end
......@@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe Boards::Epics::CreateService do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:parent_group) { create(:group) }
let_it_be(:group) { create(:group, parent: parent_group) }
let_it_be(:board) { create(:epic_board, group: group) }
describe '#execute' do
......@@ -19,34 +20,41 @@ RSpec.describe Boards::Epics::CreateService do
let(:params) { valid_params }
subject do
subject(:response) do
described_class.new(group, user, params).execute
end
shared_examples 'epic creation error' do |error_pattern|
it 'does not create epic' do
response = subject
expect(response).to be_error
expect(response.message).to match(error_pattern)
end
end
shared_examples 'success epic creation' do
it 'creates an epic' do
expect(response).to be_success
expect(response.payload).to be_a(Epic)
end
specify { expect { subject }.to change { Epic.count }.by(1) }
end
context 'when epics feature is available' do
before do
stub_licensed_features(epics: true)
group.add_developer(user)
end
context 'when arguments are valid' do
it 'creates an epic' do
response = subject
it_behaves_like 'success epic creation'
expect(response).to be_success
expect(response.payload).to be_a(Epic)
end
context 'when board is in an ancestor group' do
let_it_be(:parent_board) { create(:epic_board, group: parent_group) }
let_it_be(:parent_list) { create(:epic_list, epic_board: parent_board) }
let(:params) { valid_params.merge(board_id: parent_board.id, list_id: parent_list.id) }
specify { expect { subject }.to change { Epic.count }.by(1) }
it_behaves_like 'success epic creation'
end
context 'when arguments are not valid' do
......
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