diff --git a/Gemfile b/Gemfile index 4c6b0596b7dfad6ad720e3c7afe605d2626cb04d..a318a61a9d9fdeadef819df36795afb2ff88ed72 100644 --- a/Gemfile +++ b/Gemfile @@ -141,11 +141,11 @@ gem 'grape-path-helpers', '~> 2.0.0', feature_category: :api gem 'rack-cors', '~> 2.0.1', require: 'rack/cors' # rubocop:todo Gemfile/MissingFeatureCategory # GraphQL API -gem 'graphql', '~> 2.0.27', feature_category: :api +gem 'graphql', '~> 2.2.5', feature_category: :api gem 'graphql-docs', '~> 4.0.0', group: [:development, :test], feature_category: :api gem 'graphiql-rails', '~> 1.8.0', feature_category: :api gem 'apollo_upload_server', '~> 2.1.5', feature_category: :api -gem 'graphlient', '~> 0.5.0', feature_category: :importers # Used by BulkImport feature (group::import) +gem 'graphlient', '~> 0.6.0', feature_category: :importers # Used by BulkImport feature (group::import) # Generate Fake data gem 'ffaker', '~> 2.10' # rubocop:todo Gemfile/MissingFeatureCategory diff --git a/Gemfile.checksum b/Gemfile.checksum index f6f36ecd72ca83ae319fcdf8b94f2c4b25b69b71..3b69af5d85c73f0810185185b13370916f71096b 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -275,10 +275,10 @@ {"name":"grape-swagger-entity","version":"0.5.1","platform":"ruby","checksum":"f51e372d00ac96cf90d948f87b3f4eb287ab053976ca57ad503d442ad8605523"}, {"name":"grape_logging","version":"1.8.4","platform":"ruby","checksum":"efcc3e322dbd5d620a68f078733b7db043cf12680144cd03c982f14115c792d1"}, {"name":"graphiql-rails","version":"1.8.0","platform":"ruby","checksum":"02e2c5098be2c6c29219a0e9b2910a2cd3c494301587a3199a7c4484d8038ed1"}, -{"name":"graphlient","version":"0.5.0","platform":"ruby","checksum":"0f2c9416142e50b6bd4edcd86fe6810f792951732c487f9061aee6d420e0f292"}, +{"name":"graphlient","version":"0.6.0","platform":"ruby","checksum":"b8d8664b4c8ec215012cbe3cca918a045b0a206d709712d68b6db51fd215c5c0"}, {"name":"graphlyte","version":"1.0.0","platform":"ruby","checksum":"b5af4ab67dde6e961f00ea1c18f159f73b52ed11395bb4ece297fe628fa1804d"}, -{"name":"graphql","version":"2.0.27","platform":"ruby","checksum":"1f59be5a770248595971a261c96edef3adcf323e93387e53d1ca1ffd16448b36"}, -{"name":"graphql-client","version":"0.18.0","platform":"ruby","checksum":"98aadc810f23dce5404621903945aa584279574f87855b4301d69c90ddc6250b"}, +{"name":"graphql","version":"2.2.5","platform":"ruby","checksum":"15eeb4b4b29b8502de22e6f2794ea5b7bf75b3a8c0aa5d776f5e614ef543bc7e"}, +{"name":"graphql-client","version":"0.19.0","platform":"ruby","checksum":"fe699d81976f916bd8f989216155326449cb8475a5d69fa1dd054012a86969c7"}, {"name":"graphql-docs","version":"4.0.0","platform":"ruby","checksum":"f68296959263db26e1b7ba7058856d67b641cf508187222268be58f09dfa02d7"}, {"name":"grpc","version":"1.60.0","platform":"aarch64-linux","checksum":"f8b29900bf9a8f18ac362da4057983ad7fe3774bec3f308ac3f3006669c670f9"}, {"name":"grpc","version":"1.60.0","platform":"arm64-darwin","checksum":"57e4477f85fd98822b9421a5c702c642ff8a8cc1624ec4325604867017c67ec3"}, diff --git a/Gemfile.lock b/Gemfile.lock index 6c3c81f3d7d26d989b1907143da081d8dbb02e23..4f4e332720a7d0420ad8477362de5ca2c8a693dc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -870,13 +870,14 @@ GEM graphiql-rails (1.8.0) railties sprockets-rails - graphlient (0.5.0) + graphlient (0.6.0) faraday (>= 1.0) faraday_middleware graphql-client graphlyte (1.0.0) - graphql (2.0.27) - graphql-client (0.18.0) + graphql (2.2.5) + racc (~> 1.4) + graphql-client (0.19.0) activesupport (>= 3.0) graphql graphql-docs (4.0.0) @@ -1959,9 +1960,9 @@ DEPENDENCIES grape-swagger-entity (~> 0.5.1) grape_logging (~> 1.8) graphiql-rails (~> 1.8.0) - graphlient (~> 0.5.0) + graphlient (~> 0.6.0) graphlyte (~> 1.0.0) - graphql (~> 2.0.27) + graphql (~> 2.2.5) graphql-docs (~> 4.0.0) grpc (~> 1.60.0) gssapi (~> 1.3.1) diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb index 0b56d6f4a90554be6b3634b1661276518ca6949f..2c4cbb45f97207f8fe47a44d333747e24d4fff20 100644 --- a/app/graphql/gitlab_schema.rb +++ b/app/graphql/gitlab_schema.rb @@ -79,7 +79,11 @@ def object_from_id(global_id, ctx = {}) def resolve_type(type, object, ctx = :__undefined__) return if type.respond_to?(:assignable?) && !type.assignable?(object) - super + if type.kind.object? + type + else + super + end end # Find an object by looking it up from its 'GlobalID'. diff --git a/ee/spec/graphql/mutations/boards/epic_boards/create_spec.rb b/ee/spec/graphql/mutations/boards/epic_boards/create_spec.rb index 39f69b5459dbdc11799f406d9a41ba0a05845ebc..396085f8db70be57dde072e8a903aca3eb6e54e5 100644 --- a/ee/spec/graphql/mutations/boards/epic_boards/create_spec.rb +++ b/ee/spec/graphql/mutations/boards/epic_boards/create_spec.rb @@ -25,7 +25,7 @@ specify do is_expected.to have_graphql_arguments( - :groupPath, :name, :hideBacklogList, :hideClosedList, :labels, :labelIds, :displayColors) + :clientMutationId, :groupPath, :name, :hideBacklogList, :hideClosedList, :labels, :labelIds, :displayColors) end it { is_expected.to have_graphql_fields(:epic_board).at_least } diff --git a/ee/spec/graphql/mutations/boards/epic_boards/destroy_spec.rb b/ee/spec/graphql/mutations/boards/epic_boards/destroy_spec.rb index 6f2f04acd36b179349de016b9f11b0e9f36f95a1..2dc04b58165f9a7bc685a12b8cfcd89bd33f4a12 100644 --- a/ee/spec/graphql/mutations/boards/epic_boards/destroy_spec.rb +++ b/ee/spec/graphql/mutations/boards/epic_boards/destroy_spec.rb @@ -17,7 +17,7 @@ context 'field tests' do subject { described_class } - it { is_expected.to have_graphql_arguments(:id) } + it { is_expected.to have_graphql_arguments(:clientMutationId, :id) } it { is_expected.to have_graphql_fields(:epic_board).at_least } end diff --git a/ee/spec/graphql/mutations/boards/epic_boards/epic_move_list_spec.rb b/ee/spec/graphql/mutations/boards/epic_boards/epic_move_list_spec.rb index 17a64ef145979a4281fb886970582c60082c82a9..5bae9e4960e0f1cba2fbc6052ba4aedc00c8af5c 100644 --- a/ee/spec/graphql/mutations/boards/epic_boards/epic_move_list_spec.rb +++ b/ee/spec/graphql/mutations/boards/epic_boards/epic_move_list_spec.rb @@ -38,7 +38,7 @@ it 'has the correct arguments' do expect(subject).to have_graphql_arguments( - :boardId, :epicId, :fromListId, :toListId, :moveBeforeId, :moveAfterId, :positionInList + :clientMutationId, :boardId, :epicId, :fromListId, :toListId, :moveBeforeId, :moveAfterId, :positionInList ) end end diff --git a/ee/spec/graphql/mutations/boards/epic_boards/update_spec.rb b/ee/spec/graphql/mutations/boards/epic_boards/update_spec.rb index df04daf7a541747b4adfbf85614d47e207164d8b..b6905a21ee3d2ff72fdec574a369a151199fd2ee 100644 --- a/ee/spec/graphql/mutations/boards/epic_boards/update_spec.rb +++ b/ee/spec/graphql/mutations/boards/epic_boards/update_spec.rb @@ -25,7 +25,7 @@ specify do is_expected.to have_graphql_arguments( - :id, :name, :hideBacklogList, :hideClosedList, :labels, :labelIds, :displayColors) + :clientMutationId, :id, :name, :hideBacklogList, :hideClosedList, :labels, :labelIds, :displayColors) end it { is_expected.to have_graphql_fields(:epic_board).at_least } diff --git a/ee/spec/graphql/mutations/boards/epics/create_spec.rb b/ee/spec/graphql/mutations/boards/epics/create_spec.rb index 560c24e860e06d88182f07fa69a231d8896f3f43..23eb1180dbc70373428f25c056d3ccfa1faa6e67 100644 --- a/ee/spec/graphql/mutations/boards/epics/create_spec.rb +++ b/ee/spec/graphql/mutations/boards/epics/create_spec.rb @@ -28,7 +28,7 @@ context 'field tests' do subject { described_class } - it { is_expected.to have_graphql_arguments(:boardId, :listId, :title, :groupPath) } + it { is_expected.to have_graphql_arguments(:clientMutationId, :boardId, :listId, :title, :groupPath) } it { is_expected.to have_graphql_fields(:epic).at_least } end diff --git a/lib/gitlab/graphql/queries.rb b/lib/gitlab/graphql/queries.rb index fc569bdc5dc06d28f37622864e8b44c79bd91713..72a74c93257f4616dc1a7cb2b5624f88e5cee96b 100644 --- a/lib/gitlab/graphql/queries.rb +++ b/lib/gitlab/graphql/queries.rb @@ -69,12 +69,16 @@ def print_fragment_spread(fragment_spread, indent: "") def print_operation_definition(op, indent: "") @in_operation = true - out = +"#{indent}#{op.operation_type}" - out << " #{op.name}" if op.name + print_string("#{indent}#{op.operation_type}") + print_string(" #{op.name}") if op.name - # Do these first, so that we detect any skipped arguments - dirs = print_directives(op.directives) - sels = print_selections(op.selections, indent: indent) + # Do these on a temp instance, so that we detect any skipped arguments + # without actually printing the output to the current buffer + temp_printer = self.class.new + op.directives.each { |d| temp_printer.print(d) } + op.selections.each { |s| temp_printer.print(s) } + @skipped_arguments |= temp_printer.skipped_arguments + @printed_arguments |= temp_printer.printed_arguments # remove variable definitions only used in skipped (client) fields vars = op.variables.reject do |v| @@ -82,10 +86,16 @@ def print_operation_definition(op, indent: "") end if vars.any? - out << "(#{vars.map { |v| print_variable_definition(v) }.join(", ")})" + print_string("(") + vars.each_with_index do |v, i| + print_variable_definition(v) + print_string(", ") if i < vars.size - 1 + end + print_string(")") end - out + dirs + sels + print_directives(op.directives) + print_selections(op.selections, indent: indent) ensure @in_operation = false end @@ -94,24 +104,21 @@ def print_field(field, indent: '') if skips? && (field.directives.any? { |d| d.name == 'client' || d.name == 'persist' } || field.name == '__persist') skipped = self.class.new(false) - - skipped.print_node(field) + skipped.print(field) @skipped_fragments |= skipped.used_fragments @skipped_arguments |= skipped.printed_arguments - return '' + return end - ret = super - - @fields_printed += 1 if @in_operation && ret != '' + super - ret + @fields_printed += 1 if @in_operation end def print_fragment_definition(fragment_def, indent: "") if skips? && @skipped_fragments.include?(fragment_def.name) && !@used_fragments.include?(fragment_def.name) - return '' + return end super diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index 885bbc82ecc57a3fce766a6d1fd7d4a63e379382..c9ae3dc987ed764abe975fc5525f95b73a11b318 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -196,6 +196,39 @@ def initialize(id) end end + describe '.resolve_type' do + let(:object) { build(:user) } + + let(:object_type) { Class.new(Types::BaseObject) } + let(:union_type) { Class.new(Types::BaseUnion) } + + it 'returns the type for object types' do + expect(described_class.resolve_type(object_type, object, {})).to eq([object_type, object]) + end + + it 'raises an exception for non-object types' do + expect { described_class.resolve_type(union_type, object, {}) }.to raise_error(GraphQL::RequiredImplementationMissingError) + end + + context 'when accepts is defined' do + let(:object_type) do + Class.new(Types::BaseObject) do + accepts User + end + end + + it 'returns the type if the object is accepted' do + expect(described_class.resolve_type(object_type, object, {})).to eq([object_type, object]) + end + + it 'returns nil when object is not accepted' do + project = build(:project) + + expect(described_class.resolve_type(object_type, project, {})).to eq([nil, project]) + end + end + end + describe 'validate_max_errors' do it 'reports at most 5 errors' do query = <<~GQL diff --git a/spec/graphql/mutations/custom_emoji/destroy_spec.rb b/spec/graphql/mutations/custom_emoji/destroy_spec.rb index 4667812cc80a9d221f24e937d9b1bb4081670fb3..d9fc305cf0c51fcc7dc3bd98d7c93dc0c7138528 100644 --- a/spec/graphql/mutations/custom_emoji/destroy_spec.rb +++ b/spec/graphql/mutations/custom_emoji/destroy_spec.rb @@ -13,7 +13,7 @@ context 'field tests' do subject { described_class } - it { is_expected.to have_graphql_arguments(:id) } + it { is_expected.to have_graphql_arguments(:clientMutationId, :id) } it { is_expected.to have_graphql_field(:custom_emoji) } end diff --git a/spec/lib/gitlab/graphql/queries_spec.rb b/spec/lib/gitlab/graphql/queries_spec.rb index c556f50787655b635265dcbc63e25d59edd7cf21..6365cec51f6f6f4c71b4c3b544e1784e1fc1c0a8 100644 --- a/spec/lib/gitlab/graphql/queries_spec.rb +++ b/spec/lib/gitlab/graphql/queries_spec.rb @@ -343,7 +343,7 @@ def definition_of(path) it_behaves_like 'an invalid GraphQL query for the blog schema' do let(:errors) do contain_exactly( - have_attributes(message: include('Parse error')) + have_attributes(message: include('Expected LCURLY, actual: RCURLY ("}") at [1, 7]')) ) end end