Commit d0ccbb2e authored by Jan Provaznik's avatar Jan Provaznik Committed by charlie ablett

Reuse scope board mutation logic for epic boards

Label arguments and related logic (arguments validation) is needed
for epic boards too, so these arguments are moved to
ScopedBoardMutation and issue-specific arguments are renamed left in
ScopedIssueBoardArguments.
parent 8df02215
...@@ -22,7 +22,7 @@ module Mutations ...@@ -22,7 +22,7 @@ module Mutations
response = ::Boards::CreateService.new(board_parent, current_user, args).execute response = ::Boards::CreateService.new(board_parent, current_user, args).execute
{ {
board: response.payload, board: response.success? ? response.payload : nil,
errors: response.errors errors: response.errors
} }
end end
......
---
title: Fixed error handling GraphQL API when issue board creation fails
merge_request: 55982
author:
type: fixed
...@@ -5,10 +5,10 @@ module EE ...@@ -5,10 +5,10 @@ module EE
module Boards module Boards
module Create module Create
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepend ::Mutations::Boards::ScopedBoardMutation
prepended do prepended do
include Mutations::Boards::ScopedBoardArguments prepend ::Mutations::Boards::ScopedIssueBoardArguments
prepend ::Mutations::Boards::ScopedBoardMutation
end end
end end
end end
......
# frozen_string_literal: true
module EE
module Mutations
module Boards
module ScopedBoardArguments
extend ActiveSupport::Concern
included do
argument :assignee_id,
::Types::GlobalIDType[::User],
required: false,
description: 'The ID of user to be assigned to the board.'
# Cannot pre-load ::Types::MilestoneType because we are also assigning values like:
# ::Timebox::None(0), ::Timebox::Upcoming(-2) or ::Timebox::Started(-3), that cannot be resolved to a DB record.
argument :milestone_id,
::Types::GlobalIDType[::Milestone],
required: false,
description: 'The ID of milestone to be assigned to the board.'
# Cannot pre-load ::Types::IterationType because we are also assigning values like:
# ::Iteration::Predefined::None(0) or ::Iteration::Predefined::Current(-4), that cannot be resolved to a DB record.
argument :iteration_id,
::Types::GlobalIDType[::Iteration],
required: false,
description: 'The ID of iteration to be assigned to the board.'
argument :weight,
GraphQL::INT_TYPE,
required: false,
description: 'The weight value to be assigned to the board.'
argument :labels, [GraphQL::STRING_TYPE],
required: false,
description: copy_field_description(::Types::IssueType, :labels)
argument :label_ids, [::Types::GlobalIDType[::Label]],
required: false,
description: 'The IDs of labels to be added to the board.'
end
end
end
end
end
...@@ -5,10 +5,10 @@ module EE ...@@ -5,10 +5,10 @@ module EE
module Boards module Boards
module Update module Update
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepend ::Mutations::Boards::ScopedBoardMutation
prepended do prepended do
include Mutations::Boards::ScopedBoardArguments prepend ::Mutations::Boards::ScopedIssueBoardArguments
prepend ::Mutations::Boards::ScopedBoardMutation
end end
end end
end end
......
...@@ -6,6 +6,7 @@ module Mutations ...@@ -6,6 +6,7 @@ module Mutations
class Create < ::Mutations::BaseMutation class Create < ::Mutations::BaseMutation
include Mutations::ResolvesGroup include Mutations::ResolvesGroup
include Mutations::Boards::CommonMutationArguments include Mutations::Boards::CommonMutationArguments
prepend Mutations::Boards::ScopedBoardMutation
graphql_name 'EpicBoardCreate' graphql_name 'EpicBoardCreate'
...@@ -27,7 +28,7 @@ module Mutations ...@@ -27,7 +28,7 @@ module Mutations
service_response = ::Boards::EpicBoards::CreateService.new(group, current_user, args).execute service_response = ::Boards::EpicBoards::CreateService.new(group, current_user, args).execute
{ {
epic_board: service_response.payload, epic_board: service_response.success? ? service_response.payload : nil,
errors: service_response.errors errors: service_response.errors
} }
end end
......
...@@ -16,14 +16,6 @@ module Mutations ...@@ -16,14 +16,6 @@ module Mutations
required: true, required: true,
description: 'The epic board global ID.' description: 'The epic board global ID.'
argument :labels, [GraphQL::STRING_TYPE],
required: false,
description: 'Labels to be added to the board.'
argument :label_ids, [::Types::GlobalIDType[::Label]],
required: false,
description: 'The IDs of labels to be added to the board.'
field :epic_board, field :epic_board,
Types::Boards::EpicBoardType, Types::Boards::EpicBoardType,
null: true, null: true,
......
...@@ -5,6 +5,16 @@ module Mutations ...@@ -5,6 +5,16 @@ module Mutations
module ScopedBoardMutation module ScopedBoardMutation
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do
argument :labels, [GraphQL::STRING_TYPE],
required: false,
description: copy_field_description(::Types::IssueType, :labels)
argument :label_ids, [::Types::GlobalIDType[::Label]],
required: false,
description: 'IDs of labels to be added to the board.'
end
def resolve(**args) def resolve(**args)
parsed_params = parse_arguments(args) parsed_params = parse_arguments(args)
......
# frozen_string_literal: true
module Mutations
module Boards
module ScopedIssueBoardArguments
extend ActiveSupport::Concern
prepended do
argument :assignee_id,
::Types::GlobalIDType[::User],
required: false,
description: 'ID of user to be assigned to the board.'
# Cannot pre-load ::Types::MilestoneType because we are also assigning values like:
# ::Timebox::None(0), ::Timebox::Upcoming(-2) or ::Timebox::Started(-3), that cannot be resolved to a DB record.
argument :milestone_id,
::Types::GlobalIDType[::Milestone],
required: false,
description: 'ID of milestone to be assigned to the board.'
# Cannot pre-load ::Types::IterationType because we are also assigning values like:
# ::Iteration::Predefined::None(0) or ::Iteration::Predefined::Current(-4), that cannot be resolved to a DB record.
argument :iteration_id,
::Types::GlobalIDType[::Iteration],
required: false,
description: 'ID of iteration to be assigned to the board.'
argument :weight,
GraphQL::INT_TYPE,
required: false,
description: 'Weight value to be assigned to the board.'
end
end
end
end
...@@ -23,7 +23,7 @@ RSpec.describe ::Mutations::Boards::EpicBoards::Create do ...@@ -23,7 +23,7 @@ RSpec.describe ::Mutations::Boards::EpicBoards::Create do
context 'field tests' do context 'field tests' do
subject { described_class } subject { described_class }
it { is_expected.to have_graphql_arguments(:groupPath, :name, :hideBacklogList, :hideClosedList) } it { is_expected.to have_graphql_arguments(:groupPath, :name, :hideBacklogList, :hideClosedList, :labels, :labelIds) }
it { is_expected.to have_graphql_fields(:epic_board).at_least } it { is_expected.to have_graphql_fields(:epic_board).at_least }
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Boards::EpicBoards::Create do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group) }
let(:name) { 'board name' }
let(:mutation) { graphql_mutation(:epic_board_create, params) }
let(:label) { create(:group_label, group: group) }
let(:params) { { groupPath: group.full_path, name: 'foo', hide_backlog_list: true, labels: [label.name] } }
subject { post_graphql_mutation(mutation, current_user: current_user) }
def mutation_response
graphql_mutation_response(:epic_board_create)
end
before do
stub_licensed_features(epics: true, scoped_issue_board: true)
end
context 'when the user does not have permission' do
it_behaves_like 'a mutation that returns a top-level access error'
end
context 'when the user has permission' do
before do
group.add_developer(current_user)
end
it 'returns the created board' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response).to have_key('epicBoard')
expect(mutation_response['epicBoard']['name']).to eq(params[:name])
expect(mutation_response['epicBoard']['hideBacklogList']).to eq(params[:hide_backlog_list])
expect(mutation_response['epicBoard']['labels']['count']).to eq(1)
end
context 'when create fails' do
let(:params) { { groupPath: group.full_path, name: 'x' * 256 } }
it 'returns an error' do
post_graphql_mutation(mutation, current_user: current_user)
expect(mutation_response).to have_key('epicBoard')
expect(mutation_response['epicBoard']).to be_nil
expect(mutation_response['errors'].first).to eq('There was an error when creating a board.')
end
end
end
end
...@@ -66,9 +66,7 @@ RSpec.shared_examples 'boards create mutation' do ...@@ -66,9 +66,7 @@ RSpec.shared_examples 'boards create mutation' do
context 'when the Boards::CreateService returns an error response' do context 'when the Boards::CreateService returns an error response' do
before do before do
allow_next_instance_of(Boards::CreateService) do |service| params[:name] = ''
allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'There was an error.'))
end
end end
it 'does not create a board' do it 'does not create a board' do
...@@ -80,7 +78,7 @@ RSpec.shared_examples 'boards create mutation' do ...@@ -80,7 +78,7 @@ RSpec.shared_examples 'boards create mutation' do
expect(mutation_response).to have_key('board') expect(mutation_response).to have_key('board')
expect(mutation_response['board']).to be_nil expect(mutation_response['board']).to be_nil
expect(mutation_response['errors'].first).to eq('There was an error.') expect(mutation_response['errors'].first).to eq('There was an error when creating a board.')
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