summaryrefslogtreecommitdiff
path: root/app/graphql/resolvers
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 08:27:35 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 08:27:35 +0000
commit7e9c479f7de77702622631cff2628a9c8dcbc627 (patch)
treec8f718a08e110ad7e1894510980d2155a6549197 /app/graphql/resolvers
parente852b0ae16db4052c1c567d9efa4facc81146e88 (diff)
downloadgitlab-ce-7e9c479f7de77702622631cff2628a9c8dcbc627.tar.gz
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'app/graphql/resolvers')
-rw-r--r--app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb12
-rw-r--r--app/graphql/resolvers/alert_management/alert_resolver.rb2
-rw-r--r--app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb2
-rw-r--r--app/graphql/resolvers/alert_management/integrations_resolver.rb29
-rw-r--r--app/graphql/resolvers/assigned_merge_requests_resolver.rb3
-rw-r--r--app/graphql/resolvers/authored_merge_requests_resolver.rb3
-rw-r--r--app/graphql/resolvers/base_resolver.rb86
-rw-r--r--app/graphql/resolvers/board_lists_resolver.rb2
-rw-r--r--app/graphql/resolvers/boards_resolver.rb11
-rw-r--r--app/graphql/resolvers/ci/jobs_resolver.rb24
-rw-r--r--app/graphql/resolvers/ci/runner_setup_resolver.rb64
-rw-r--r--app/graphql/resolvers/commit_pipelines_resolver.rb3
-rw-r--r--app/graphql/resolvers/concerns/caching_array_resolver.rb128
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb2
-rw-r--r--app/graphql/resolvers/concerns/looks_ahead.rb1
-rw-r--r--app/graphql/resolvers/concerns/resolves_pipelines.rb2
-rw-r--r--app/graphql/resolvers/concerns/resolves_project.rb3
-rw-r--r--app/graphql/resolvers/concerns/resolves_snippets.rb21
-rw-r--r--app/graphql/resolvers/container_repositories_resolver.rb19
-rw-r--r--app/graphql/resolvers/design_management/design_at_version_resolver.rb9
-rw-r--r--app/graphql/resolvers/design_management/design_resolver.rb10
-rw-r--r--app/graphql/resolvers/design_management/designs_resolver.rb29
-rw-r--r--app/graphql/resolvers/design_management/version/design_at_version_resolver.rb22
-rw-r--r--app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb18
-rw-r--r--app/graphql/resolvers/design_management/version_in_collection_resolver.rb15
-rw-r--r--app/graphql/resolvers/design_management/version_resolver.rb8
-rw-r--r--app/graphql/resolvers/design_management/versions_resolver.rb20
-rw-r--r--app/graphql/resolvers/echo_resolver.rb7
-rw-r--r--app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb13
-rw-r--r--app/graphql/resolvers/error_tracking/sentry_error_collection_resolver.rb2
-rw-r--r--app/graphql/resolvers/error_tracking/sentry_error_stack_trace_resolver.rb10
-rw-r--r--app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb2
-rw-r--r--app/graphql/resolvers/group_issues_resolver.rb1
-rw-r--r--app/graphql/resolvers/group_members_resolver.rb2
-rw-r--r--app/graphql/resolvers/group_merge_requests_resolver.rb2
-rw-r--r--app/graphql/resolvers/group_milestones_resolver.rb3
-rw-r--r--app/graphql/resolvers/issues_resolver.rb2
-rw-r--r--app/graphql/resolvers/members_resolver.rb2
-rw-r--r--app/graphql/resolvers/merge_request_pipelines_resolver.rb3
-rw-r--r--app/graphql/resolvers/merge_request_resolver.rb2
-rw-r--r--app/graphql/resolvers/metadata_resolver.rb2
-rw-r--r--app/graphql/resolvers/milestones_resolver.rb2
-rw-r--r--app/graphql/resolvers/namespace_projects_resolver.rb9
-rw-r--r--app/graphql/resolvers/project_members_resolver.rb3
-rw-r--r--app/graphql/resolvers/project_merge_requests_resolver.rb1
-rw-r--r--app/graphql/resolvers/project_milestones_resolver.rb3
-rw-r--r--app/graphql/resolvers/project_pipeline_resolver.rb2
-rw-r--r--app/graphql/resolvers/project_pipelines_resolver.rb19
-rw-r--r--app/graphql/resolvers/projects/jira_imports_resolver.rb2
-rw-r--r--app/graphql/resolvers/projects/jira_projects_resolver.rb2
-rw-r--r--app/graphql/resolvers/projects/services_resolver.rb2
-rw-r--r--app/graphql/resolvers/projects/snippets_resolver.rb1
-rw-r--r--app/graphql/resolvers/releases_resolver.rb16
-rw-r--r--app/graphql/resolvers/snippets/blobs_resolver.rb2
-rw-r--r--app/graphql/resolvers/snippets_resolver.rb11
-rw-r--r--app/graphql/resolvers/todo_resolver.rb2
-rw-r--r--app/graphql/resolvers/tree_resolver.rb2
-rw-r--r--app/graphql/resolvers/user_merge_requests_resolver_base.rb (renamed from app/graphql/resolvers/user_merge_requests_resolver.rb)10
-rw-r--r--app/graphql/resolvers/user_resolver.rb2
-rw-r--r--app/graphql/resolvers/users/group_count_resolver.rb25
-rw-r--r--app/graphql/resolvers/users/snippets_resolver.rb1
-rw-r--r--app/graphql/resolvers/users_resolver.rb12
62 files changed, 610 insertions, 120 deletions
diff --git a/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb b/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb
index aea3afa8ec5..9bac9f222ab 100644
--- a/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb
+++ b/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb
@@ -13,10 +13,20 @@ module Resolvers
required: true,
description: 'The type of measurement/statistics to retrieve'
- def resolve(identifier:)
+ argument :recorded_after, Types::TimeType,
+ required: false,
+ description: 'Measurement recorded after this date'
+
+ argument :recorded_before, Types::TimeType,
+ required: false,
+ description: 'Measurement recorded before this date'
+
+ def resolve(identifier:, recorded_before: nil, recorded_after: nil)
authorize!
::Analytics::InstanceStatistics::Measurement
+ .recorded_after(recorded_after)
+ .recorded_before(recorded_before)
.with_identifier(identifier)
.order_by_latest
end
diff --git a/app/graphql/resolvers/alert_management/alert_resolver.rb b/app/graphql/resolvers/alert_management/alert_resolver.rb
index dc9b1dbb5f4..c3219d9cdc3 100644
--- a/app/graphql/resolvers/alert_management/alert_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_resolver.rb
@@ -19,7 +19,7 @@ module Resolvers
required: false
argument :search, GraphQL::STRING_TYPE,
- description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
+ description: 'Search query for title, description, service, or monitoring_tool.',
required: false
argument :assignee_username, GraphQL::STRING_TYPE,
diff --git a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
index 96ea4610aff..8fc0f9fd1ff 100644
--- a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
@@ -6,7 +6,7 @@ module Resolvers
type Types::AlertManagement::AlertStatusCountsType, null: true
argument :search, GraphQL::STRING_TYPE,
- description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
+ description: 'Search query for title, description, service, or monitoring_tool.',
required: false
argument :assignee_username, GraphQL::STRING_TYPE,
diff --git a/app/graphql/resolvers/alert_management/integrations_resolver.rb b/app/graphql/resolvers/alert_management/integrations_resolver.rb
new file mode 100644
index 00000000000..4d1fe367277
--- /dev/null
+++ b/app/graphql/resolvers/alert_management/integrations_resolver.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module AlertManagement
+ class IntegrationsResolver < BaseResolver
+ alias_method :project, :synchronized_object
+
+ type Types::AlertManagement::IntegrationType.connection_type, null: true
+
+ def resolve(**args)
+ http_integrations + prometheus_integrations
+ end
+
+ private
+
+ def prometheus_integrations
+ return [] unless Ability.allowed?(current_user, :admin_project, project)
+
+ Array(project.prometheus_service)
+ end
+
+ def http_integrations
+ return [] unless Ability.allowed?(current_user, :admin_operations, project)
+
+ ::AlertManagement::HttpIntegrationsFinder.new(project, {}).execute
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/assigned_merge_requests_resolver.rb b/app/graphql/resolvers/assigned_merge_requests_resolver.rb
index 172a8e298ad..30415ef5d2d 100644
--- a/app/graphql/resolvers/assigned_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/assigned_merge_requests_resolver.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module Resolvers
- class AssignedMergeRequestsResolver < UserMergeRequestsResolver
+ class AssignedMergeRequestsResolver < UserMergeRequestsResolverBase
+ type ::Types::MergeRequestType.connection_type, null: true
accept_author
def user_role
diff --git a/app/graphql/resolvers/authored_merge_requests_resolver.rb b/app/graphql/resolvers/authored_merge_requests_resolver.rb
index bc796f8685a..1426ca83c06 100644
--- a/app/graphql/resolvers/authored_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/authored_merge_requests_resolver.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module Resolvers
- class AuthoredMergeRequestsResolver < UserMergeRequestsResolver
+ class AuthoredMergeRequestsResolver < UserMergeRequestsResolverBase
+ type ::Types::MergeRequestType.connection_type, null: true
accept_assignee
def user_role
diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb
index 2b8854fb4d0..87a63231b22 100644
--- a/app/graphql/resolvers/base_resolver.rb
+++ b/app/graphql/resolvers/base_resolver.rb
@@ -8,32 +8,81 @@ module Resolvers
argument_class ::Types::BaseArgument
- def self.single
- @single ||= Class.new(self) do
- def ready?(**args)
- ready, early_return = super
- [ready, select_result(early_return)]
- end
+ def self.singular_type
+ return unless type
- def resolve(**args)
- select_result(super)
- end
+ unwrapped = type.unwrap
+
+ %i[node_type relay_node_type of_type itself].reduce(nil) do |t, m|
+ t || unwrapped.try(m)
+ end
+ end
- def single?
- true
+ def self.when_single(&block)
+ as_single << block
+
+ # Have we been called after defining the single version of this resolver?
+ if @single.present?
+ @single.instance_exec(&block)
+ end
+ end
+
+ def self.as_single
+ @as_single ||= []
+ end
+
+ def self.single_definition_blocks
+ ancestors.flat_map { |klass| klass.try(:as_single) || [] }
+ end
+
+ def self.single
+ @single ||= begin
+ parent = self
+ klass = Class.new(self) do
+ type parent.singular_type, null: true
+
+ def ready?(**args)
+ ready, early_return = super
+ [ready, select_result(early_return)]
+ end
+
+ def resolve(**args)
+ select_result(super)
+ end
+
+ def single?
+ true
+ end
+
+ def select_result(results)
+ results&.first
+ end
+
+ define_singleton_method :to_s do
+ "#{parent}.single"
+ end
end
- def select_result(results)
- results&.first
+ single_definition_blocks.each do |definition|
+ klass.instance_exec(&definition)
end
+
+ klass
end
end
def self.last
+ parent = self
@last ||= Class.new(self.single) do
+ type parent.singular_type, null: true
+
def select_result(results)
results&.last
end
+
+ define_singleton_method :to_s do
+ "#{parent}.last"
+ end
end
end
@@ -68,14 +117,13 @@ module Resolvers
end
end
+ # TODO: remove! This should never be necessary
+ # Remove as part of https://gitlab.com/gitlab-org/gitlab/-/issues/13984,
+ # since once we use that authorization approach, the object is guaranteed to
+ # be synchronized before any field.
def synchronized_object
strong_memoize(:synchronized_object) do
- case object
- when BatchLoader::GraphQL
- object.sync
- else
- object
- end
+ ::Gitlab::Graphql::Lazy.force(object)
end
end
diff --git a/app/graphql/resolvers/board_lists_resolver.rb b/app/graphql/resolvers/board_lists_resolver.rb
index 3384b37e2ce..ef12dfa19ff 100644
--- a/app/graphql/resolvers/board_lists_resolver.rb
+++ b/app/graphql/resolvers/board_lists_resolver.rb
@@ -7,7 +7,7 @@ module Resolvers
type Types::BoardListType, null: true
- argument :id, GraphQL::ID_TYPE,
+ argument :id, Types::GlobalIDType[List],
required: false,
description: 'Find a list by its global ID'
diff --git a/app/graphql/resolvers/boards_resolver.rb b/app/graphql/resolvers/boards_resolver.rb
index 82efd92d33f..42b6ce03118 100644
--- a/app/graphql/resolvers/boards_resolver.rb
+++ b/app/graphql/resolvers/boards_resolver.rb
@@ -4,7 +4,7 @@ module Resolvers
class BoardsResolver < BaseResolver
type Types::BoardType, null: true
- argument :id, GraphQL::ID_TYPE,
+ argument :id, ::Types::GlobalIDType[::Board],
required: false,
description: 'Find a board by its ID'
@@ -23,10 +23,13 @@ module Resolvers
private
- def extract_board_id(gid)
- return unless gid.present?
+ def extract_board_id(id)
+ return unless id.present?
- GitlabSchema.parse_gid(gid, expected_type: ::Board).model_id
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = Types::GlobalIDType[Board].coerce_isolated_input(id)
+ id.model_id
end
end
end
diff --git a/app/graphql/resolvers/ci/jobs_resolver.rb b/app/graphql/resolvers/ci/jobs_resolver.rb
new file mode 100644
index 00000000000..8a9ae42b375
--- /dev/null
+++ b/app/graphql/resolvers/ci/jobs_resolver.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Ci
+ class JobsResolver < BaseResolver
+ alias_method :pipeline, :object
+
+ argument :security_report_types, [Types::Security::ReportTypeEnum],
+ required: false,
+ description: 'Filter jobs by the type of security report they produce'
+
+ def resolve(security_report_types: [])
+ if security_report_types.present?
+ ::Security::SecurityJobsFinder.new(
+ pipeline: pipeline,
+ job_types: security_report_types
+ ).execute
+ else
+ pipeline.statuses
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/ci/runner_setup_resolver.rb b/app/graphql/resolvers/ci/runner_setup_resolver.rb
new file mode 100644
index 00000000000..241cd57f74b
--- /dev/null
+++ b/app/graphql/resolvers/ci/runner_setup_resolver.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Ci
+ class RunnerSetupResolver < BaseResolver
+ type Types::Ci::RunnerSetupType, null: true
+
+ argument :platform, GraphQL::STRING_TYPE,
+ required: true,
+ description: 'Platform to generate the instructions for'
+
+ argument :architecture, GraphQL::STRING_TYPE,
+ required: true,
+ description: 'Architecture to generate the instructions for'
+
+ argument :project_id, ::Types::GlobalIDType[::Project],
+ required: false,
+ description: 'Project to register the runner for'
+
+ argument :group_id, ::Types::GlobalIDType[::Group],
+ required: false,
+ description: 'Group to register the runner for'
+
+ def resolve(platform:, architecture:, **args)
+ instructions = Gitlab::Ci::RunnerInstructions.new(
+ { current_user: current_user, os: platform, arch: architecture }.merge(target_param(args))
+ )
+
+ {
+ install_instructions: instructions.install_script || other_install_instructions(platform),
+ register_instructions: instructions.register_command
+ }
+ ensure
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'User is not authorized to register a runner for the specified resource!' if instructions.errors.include?('Gitlab::Access::AccessDeniedError')
+ end
+
+ private
+
+ def other_install_instructions(platform)
+ Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS[platform.to_sym][:installation_instructions_url]
+ end
+
+ def target_param(args)
+ project_param(args[:project_id]) || group_param(args[:group_id]) || {}
+ end
+
+ def project_param(project_id)
+ return unless project_id
+
+ { project: find_object(project_id) }
+ end
+
+ def group_param(group_id)
+ return unless group_id
+
+ { group: find_object(group_id) }
+ end
+
+ def find_object(gid)
+ GlobalID::Locator.locate(gid)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/commit_pipelines_resolver.rb b/app/graphql/resolvers/commit_pipelines_resolver.rb
index 92a83523593..40af392200c 100644
--- a/app/graphql/resolvers/commit_pipelines_resolver.rb
+++ b/app/graphql/resolvers/commit_pipelines_resolver.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
+# rubocop: disable Graphql/ResolverType
module Resolvers
class CommitPipelinesResolver < BaseResolver
+ # The GraphQL type here gets defined in this include
include ::ResolvesPipelines
alias_method :commit, :object
@@ -11,3 +13,4 @@ module Resolvers
end
end
end
+# rubocop: enable Graphql/ResolverType
diff --git a/app/graphql/resolvers/concerns/caching_array_resolver.rb b/app/graphql/resolvers/concerns/caching_array_resolver.rb
new file mode 100644
index 00000000000..4f2c8b98928
--- /dev/null
+++ b/app/graphql/resolvers/concerns/caching_array_resolver.rb
@@ -0,0 +1,128 @@
+# frozen_string_literal: true
+
+# Concern that will eliminate N+1 queries for size-constrained
+# collections of items.
+#
+# **note**: The resolver will never load more items than
+# `@field.max_page_size` if defined, falling back to
+# `context.schema.default_max_page_size`.
+#
+# provided that:
+#
+# - the query can be uniquely determined by the object and the arguments
+# - the model class includes FromUnion
+# - the model class defines a scalar primary key
+#
+# This comes at the cost of returning arrays, not relations, so we don't get
+# any keyset pagination goodness. Consequently, this is only suitable for small-ish
+# result sets, as the full result set will be loaded into memory.
+#
+# To enforce this, the resolver limits the size of result sets to
+# `@field.max_page_size || context.schema.default_max_page_size`.
+#
+# **important**: If the cardinality of your collection is likely to be greater than 100,
+# then you will want to pass `max_page_size:` as part of the field definition
+# or (ideally) as part of the resolver `field_options`.
+#
+# How to implement:
+# --------------------
+#
+# Each including class operates on two generic parameters, A and R:
+# - A is any Object that can be used as a Hash key. Instances of A
+# are returned by `query_input` and then passed to `query_for`.
+# - R is any subclass of ApplicationRecord that includes FromUnion.
+# R must have a single scalar primary_key
+#
+# Classes must implement:
+# - #model_class -> Class[R]. (Must respond to :primary_key, and :from_union)
+# - #query_input(**kwargs) -> A (Must be hashable)
+# - #query_for(A) -> ActiveRecord::Relation[R]
+#
+# Note the relationship between query_input and query_for, one of which
+# consumes the input of the other
+# (i.e. `resolve(**args).sync == query_for(query_input(**args)).to_a`).
+#
+# Classes may implement:
+# - #item_found(A, R) (return value is ignored)
+# - max_union_size Integer (the maximum number of queries to run in any one union)
+module CachingArrayResolver
+ MAX_UNION_SIZE = 50
+
+ def resolve(**args)
+ key = query_input(**args)
+
+ BatchLoader::GraphQL.for(key).batch(**batch) do |keys, loader|
+ if keys.size == 1
+ # We can avoid the union entirely.
+ k = keys.first
+ limit(query_for(k)).each { |item| found(loader, k, item) }
+ else
+ queries = keys.map { |key| query_for(key) }
+
+ queries.in_groups_of(max_union_size, false).each do |group|
+ by_id = model_class
+ .from_union(tag(group), remove_duplicates: false)
+ .group_by { |r| r[primary_key] }
+
+ by_id.values.each do |item_group|
+ item = item_group.first
+ item_group.map(&:union_member_idx).each do |i|
+ found(loader, keys[i], item)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ # Override this to intercept the items once they are found
+ def item_found(query_input, item)
+ end
+
+ def max_union_size
+ MAX_UNION_SIZE
+ end
+
+ private
+
+ def primary_key
+ @primary_key ||= (model_class.primary_key || raise("No primary key for #{model_class}"))
+ end
+
+ def batch
+ { key: self.class, default_value: [] }
+ end
+
+ def found(loader, key, value)
+ loader.call(key) do |vs|
+ item_found(key, value)
+ vs << value
+ end
+ end
+
+ # Tag each row returned from each query with a the index of which query in
+ # the union it comes from. This lets us map the results back to the cache key.
+ def tag(queries)
+ queries.each_with_index.map do |q, i|
+ limit(q.select(all_fields, member_idx(i)))
+ end
+ end
+
+ def limit(query)
+ query.limit(query_limit) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def all_fields
+ model_class.arel_table[Arel.star]
+ end
+
+ # rubocop: disable Graphql/Descriptions (false positive!)
+ def query_limit
+ field&.max_page_size.presence || context.schema.default_max_page_size
+ end
+ # rubocop: enable Graphql/Descriptions
+
+ def member_idx(idx)
+ ::Arel::Nodes::SqlLiteral.new(idx.to_s).as('union_member_idx')
+ end
+end
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index fe6fa0bb262..4715b867ecb 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -29,7 +29,7 @@ module IssueResolverArguments
description: 'Usernames of users assigned to the issue'
argument :assignee_id, GraphQL::STRING_TYPE,
required: false,
- description: 'ID of a user assigned to the issues, "none" and "any" values supported'
+ description: 'ID of a user assigned to the issues, "none" and "any" values are supported'
argument :created_before, Types::TimeType,
required: false,
description: 'Issues created before this date'
diff --git a/app/graphql/resolvers/concerns/looks_ahead.rb b/app/graphql/resolvers/concerns/looks_ahead.rb
index 61f23920ebb..d468047b539 100644
--- a/app/graphql/resolvers/concerns/looks_ahead.rb
+++ b/app/graphql/resolvers/concerns/looks_ahead.rb
@@ -4,6 +4,7 @@ module LooksAhead
extend ActiveSupport::Concern
included do
+ extras [:lookahead]
attr_accessor :lookahead
end
diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb
index 46d9e174deb..f061f5f1606 100644
--- a/app/graphql/resolvers/concerns/resolves_pipelines.rb
+++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb
@@ -4,7 +4,7 @@ module ResolvesPipelines
extend ActiveSupport::Concern
included do
- type [Types::Ci::PipelineType], null: false
+ type Types::Ci::PipelineType.connection_type, null: false
argument :status,
Types::Ci::PipelineStatusEnum,
required: false,
diff --git a/app/graphql/resolvers/concerns/resolves_project.rb b/app/graphql/resolvers/concerns/resolves_project.rb
index 3c5ce3dab01..b2ee7d7e850 100644
--- a/app/graphql/resolvers/concerns/resolves_project.rb
+++ b/app/graphql/resolvers/concerns/resolves_project.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
module ResolvesProject
+ # Accepts EITHER one of
+ # - full_path: String (see Project#full_path)
+ # - project_id: GlobalID. Arguments should be typed as: `::Types::GlobalIDType[Project]`
def resolve_project(full_path: nil, project_id: nil)
unless full_path.present? ^ project_id.present?
raise ::Gitlab::Graphql::Errors::ArgumentError, 'Incompatible arguments: projectId, projectPath.'
diff --git a/app/graphql/resolvers/concerns/resolves_snippets.rb b/app/graphql/resolvers/concerns/resolves_snippets.rb
index 483372bbf63..790ff4f774f 100644
--- a/app/graphql/resolvers/concerns/resolves_snippets.rb
+++ b/app/graphql/resolvers/concerns/resolves_snippets.rb
@@ -4,9 +4,9 @@ module ResolvesSnippets
extend ActiveSupport::Concern
included do
- type Types::SnippetType, null: false
+ type Types::SnippetType.connection_type, null: false
- argument :ids, [GraphQL::ID_TYPE],
+ argument :ids, [::Types::GlobalIDType[::Snippet]],
required: false,
description: 'Array of global snippet ids, e.g., "gid://gitlab/ProjectSnippet/1"'
@@ -32,16 +32,15 @@ module ResolvesSnippets
}.merge(options_by_type(args[:type]))
end
- def resolve_ids(ids)
- Array.wrap(ids).map { |id| resolve_gid(id, :id) }
- end
-
- def resolve_gid(gid, argument)
- return unless gid.present?
+ def resolve_ids(ids, type = ::Types::GlobalIDType[::Snippet])
+ Array.wrap(ids).map do |id|
+ next unless id.present?
- GlobalID.parse(gid)&.model_id.tap do |id|
- raise Gitlab::Graphql::Errors::ArgumentError, "Invalid global id format for param #{argument}" if id.nil?
- end
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = type.coerce_isolated_input(id)
+ id.model_id
+ end.compact
end
def options_by_type(type)
diff --git a/app/graphql/resolvers/container_repositories_resolver.rb b/app/graphql/resolvers/container_repositories_resolver.rb
new file mode 100644
index 00000000000..b4b2893a3b8
--- /dev/null
+++ b/app/graphql/resolvers/container_repositories_resolver.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class ContainerRepositoriesResolver < BaseResolver
+ include ::Mutations::PackageEventable
+
+ type Types::ContainerRepositoryType, null: true
+
+ argument :name, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Filter the container repositories by their name'
+
+ def resolve(name: nil)
+ ContainerRepositoriesFinder.new(user: current_user, subject: object, params: { name: name })
+ .execute
+ .tap { track_event(:list_repositories, :container) }
+ end
+ end
+end
diff --git a/app/graphql/resolvers/design_management/design_at_version_resolver.rb b/app/graphql/resolvers/design_management/design_at_version_resolver.rb
index fd9b349f974..1b69efebe4e 100644
--- a/app/graphql/resolvers/design_management/design_at_version_resolver.rb
+++ b/app/graphql/resolvers/design_management/design_at_version_resolver.rb
@@ -9,7 +9,7 @@ module Resolvers
authorize :read_design
- argument :id, GraphQL::ID_TYPE,
+ argument :id, ::Types::GlobalIDType[::DesignManagement::DesignAtVersion],
required: true,
description: 'The Global ID of the design at this version'
@@ -18,7 +18,10 @@ module Resolvers
end
def find_object(id:)
- dav = GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::DesignAtVersion)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::DesignManagement::DesignAtVersion].coerce_isolated_input(id)
+ dav = GitlabSchema.find_by_gid(id)
return unless consistent?(dav)
dav
@@ -35,7 +38,7 @@ module Resolvers
# that the DesignAtVersion as found by its ID does in fact belong
# to this issue.
def consistent?(dav)
- issue.nil? || (dav&.design&.issue_id == issue.id)
+ issue.nil? || (dav.present? && dav.design&.issue_id == issue.id)
end
def issue
diff --git a/app/graphql/resolvers/design_management/design_resolver.rb b/app/graphql/resolvers/design_management/design_resolver.rb
index 05bdbbbe407..e0a68bae397 100644
--- a/app/graphql/resolvers/design_management/design_resolver.rb
+++ b/app/graphql/resolvers/design_management/design_resolver.rb
@@ -3,7 +3,9 @@
module Resolvers
module DesignManagement
class DesignResolver < BaseResolver
- argument :id, GraphQL::ID_TYPE,
+ type ::Types::DesignManagement::DesignType, null: true
+
+ argument :id, ::Types::GlobalIDType[::DesignManagement::Design],
required: false,
description: 'Find a design by its ID'
@@ -50,7 +52,11 @@ module Resolvers
end
def parse_gid(gid)
- GitlabSchema.parse_gid(gid, expected_type: ::DesignManagement::Design).model_id
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ gid = ::Types::GlobalIDType[::DesignManagement::Design].coerce_isolated_input(gid)
+
+ gid.model_id
end
end
end
diff --git a/app/graphql/resolvers/design_management/designs_resolver.rb b/app/graphql/resolvers/design_management/designs_resolver.rb
index 955ea6304e0..c588142ea6b 100644
--- a/app/graphql/resolvers/design_management/designs_resolver.rb
+++ b/app/graphql/resolvers/design_management/designs_resolver.rb
@@ -3,16 +3,18 @@
module Resolvers
module DesignManagement
class DesignsResolver < BaseResolver
- argument :ids,
- [GraphQL::ID_TYPE],
+ DesignID = ::Types::GlobalIDType[::DesignManagement::Design]
+ VersionID = ::Types::GlobalIDType[::DesignManagement::Version]
+
+ type ::Types::DesignManagement::DesignType.connection_type, null: true
+
+ argument :ids, [DesignID],
required: false,
description: 'Filters designs by their ID'
- argument :filenames,
- [GraphQL::STRING_TYPE],
+ argument :filenames, [GraphQL::STRING_TYPE],
required: false,
description: 'Filters designs by their filename'
- argument :at_version,
- GraphQL::ID_TYPE,
+ argument :at_version, VersionID,
required: false,
description: 'Filters designs to only those that existed at the version. ' \
'If argument is omitted or nil then all designs will reflect the latest version'
@@ -36,11 +38,20 @@ module Resolvers
def version(at_version)
return unless at_version
- GitlabSchema.object_from_id(at_version, expected_type: ::DesignManagement::Version)&.sync
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ at_version = VersionID.coerce_isolated_input(at_version)
+ # TODO: when we get promises use this to make resolve lazy
+ Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(at_version))
end
- def design_ids(ids)
- ids&.map { |id| GlobalID.parse(id, expected_type: ::DesignManagement::Design).model_id }
+ def design_ids(gids)
+ return if gids.nil?
+
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ gids = gids.map { |id| DesignID.coerce_isolated_input(id) }
+ gids.map(&:model_id)
end
def issue
diff --git a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
index 03f7908780c..70021057f71 100644
--- a/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version/design_at_version_resolver.rb
@@ -5,17 +5,20 @@ module Resolvers
module Version
# Resolver for a DesignAtVersion object given an implicit version context
class DesignAtVersionResolver < BaseResolver
+ DesignAtVersionID = ::Types::GlobalIDType[::DesignManagement::DesignAtVersion]
+ DesignID = ::Types::GlobalIDType[::DesignManagement::Design]
+
include Gitlab::Graphql::Authorize::AuthorizeResource
type Types::DesignManagement::DesignAtVersionType, null: true
authorize :read_design
- argument :id, GraphQL::ID_TYPE,
+ argument :id, DesignAtVersionID,
required: false,
as: :design_at_version_id,
description: 'The ID of the DesignAtVersion'
- argument :design_id, GraphQL::ID_TYPE,
+ argument :design_id, DesignID,
required: false,
description: 'The ID of a specific design'
argument :filename, GraphQL::STRING_TYPE,
@@ -29,6 +32,11 @@ module Resolvers
def resolve(design_id: nil, filename: nil, design_at_version_id: nil)
validate_arguments(design_id, filename, design_at_version_id)
+ # TODO: remove this when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ design_id &&= DesignID.coerce_isolated_input(design_id)
+ design_at_version_id &&= DesignAtVersionID.coerce_isolated_input(design_at_version_id)
+
return unless Ability.allowed?(current_user, :read_design, issue)
return specific_design_at_version(design_at_version_id) if design_at_version_id
@@ -49,7 +57,7 @@ module Resolvers
end
def specific_design_at_version(id)
- dav = GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::DesignAtVersion)
+ dav = GitlabSchema.find_by_gid(id)
return unless consistent?(dav)
dav
@@ -65,8 +73,8 @@ module Resolvers
dav.design.visible_in?(version)
end
- def find(id, filename)
- ids = [parse_design_id(id).model_id] if id
+ def find(gid, filename)
+ ids = [gid.model_id] if gid
filenames = [filename] if filename
::DesignManagement::DesignsFinder
@@ -74,10 +82,6 @@ module Resolvers
.execute
end
- def parse_design_id(id)
- GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Design)
- end
-
def issue
version.issue
end
diff --git a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
index 5ccb2f3e311..a129d8620d4 100644
--- a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb
@@ -11,8 +11,9 @@ module Resolvers
authorize :read_design
- argument :ids,
- [GraphQL::ID_TYPE],
+ DesignID = ::Types::GlobalIDType[::DesignManagement::Design]
+
+ argument :ids, [DesignID],
required: false,
description: 'Filters designs by their ID'
argument :filenames,
@@ -31,16 +32,19 @@ module Resolvers
private
def find(ids, filenames)
- ids = ids&.map { |id| parse_design_id(id).model_id }
-
::DesignManagement::DesignsFinder.new(issue, current_user,
- ids: ids,
+ ids: design_ids(ids),
filenames: filenames,
visible_at_version: version)
end
- def parse_design_id(id)
- GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Design)
+ def design_ids(gids)
+ return if gids.nil?
+
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ gids = gids.map { |id| DesignID.coerce_isolated_input(id) }
+ gids.map(&:model_id)
end
def issue
diff --git a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
index 9e729172881..ecd7ab3ee45 100644
--- a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
+++ b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb
@@ -11,20 +11,25 @@ module Resolvers
alias_method :collection, :object
+ VersionID = ::Types::GlobalIDType[::DesignManagement::Version]
+
argument :sha, GraphQL::STRING_TYPE,
required: false,
description: "The SHA256 of a specific version"
- argument :id, GraphQL::ID_TYPE,
+ argument :id, VersionID,
+ as: :version_id,
required: false,
description: 'The Global ID of the version'
- def resolve(id: nil, sha: nil)
- check_args(id, sha)
+ def resolve(version_id: nil, sha: nil)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ version_id &&= VersionID.coerce_isolated_input(version_id)
- gid = GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Version) if id
+ check_args(version_id, sha)
::DesignManagement::VersionsFinder
- .new(collection, current_user, sha: sha, version_id: gid&.model_id)
+ .new(collection, current_user, sha: sha, version_id: version_id&.model_id)
.execute
.first
end
diff --git a/app/graphql/resolvers/design_management/version_resolver.rb b/app/graphql/resolvers/design_management/version_resolver.rb
index b0e0843e6c8..1bc9c1a7cd6 100644
--- a/app/graphql/resolvers/design_management/version_resolver.rb
+++ b/app/graphql/resolvers/design_management/version_resolver.rb
@@ -9,7 +9,7 @@ module Resolvers
authorize :read_design
- argument :id, GraphQL::ID_TYPE,
+ argument :id, ::Types::GlobalIDType[::DesignManagement::Version],
required: true,
description: 'The Global ID of the version'
@@ -18,7 +18,11 @@ module Resolvers
end
def find_object(id:)
- GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::Version)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::DesignManagement::Version].coerce_isolated_input(id)
+
+ GitlabSchema.find_by_gid(id)
end
end
end
diff --git a/app/graphql/resolvers/design_management/versions_resolver.rb b/app/graphql/resolvers/design_management/versions_resolver.rb
index a62258dad5c..23858c8e991 100644
--- a/app/graphql/resolvers/design_management/versions_resolver.rb
+++ b/app/graphql/resolvers/design_management/versions_resolver.rb
@@ -7,12 +7,14 @@ module Resolvers
alias_method :design_or_collection, :object
+ VersionID = ::Types::GlobalIDType[::DesignManagement::Version]
+
argument :earlier_or_equal_to_sha, GraphQL::STRING_TYPE,
as: :sha,
required: false,
description: 'The SHA256 of the most recent acceptable version'
- argument :earlier_or_equal_to_id, GraphQL::ID_TYPE,
+ argument :earlier_or_equal_to_id, VersionID,
as: :id,
required: false,
description: 'The Global ID of the most recent acceptable version'
@@ -23,6 +25,9 @@ module Resolvers
end
def resolve(parent: nil, id: nil, sha: nil)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id &&= VersionID.coerce_isolated_input(id)
version = cutoff(parent, id, sha)
raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'cutoff not found' unless version.present?
@@ -47,8 +52,7 @@ module Resolvers
end
end
- def specific_version(id, sha)
- gid = GitlabSchema.parse_gid(id, expected_type: ::DesignManagement::Version) if id
+ def specific_version(gid, sha)
find(sha: sha, version_id: gid&.model_id).first
end
@@ -58,8 +62,8 @@ module Resolvers
.execute
end
- def by_id(id)
- GitlabSchema.object_from_id(id, expected_type: ::DesignManagement::Version).sync
+ def by_id(gid)
+ ::Gitlab::Graphql::Lazy.force(GitlabSchema.find_by_gid(gid))
end
# Find an `at_version` argument passed to a parent node.
@@ -69,7 +73,11 @@ module Resolvers
# for consistency we should only present versions up to the given
# version here.
def at_version_arg(parent)
- ::Gitlab::Graphql::FindArgumentInParent.find(parent, :at_version, limit_depth: 4)
+ # TODO: remove coercion when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ version_id = ::Gitlab::Graphql::FindArgumentInParent.find(parent, :at_version, limit_depth: 4)
+ version_id &&= VersionID.coerce_isolated_input(version_id)
+ version_id
end
end
end
diff --git a/app/graphql/resolvers/echo_resolver.rb b/app/graphql/resolvers/echo_resolver.rb
index fe0b1893a23..6b85b700712 100644
--- a/app/graphql/resolvers/echo_resolver.rb
+++ b/app/graphql/resolvers/echo_resolver.rb
@@ -2,15 +2,16 @@
module Resolvers
class EchoResolver < BaseResolver
+ type ::GraphQL::STRING_TYPE, null: false
description 'Testing endpoint to validate the API with'
argument :text, GraphQL::STRING_TYPE, required: true,
description: 'Text to echo back'
- def resolve(**args)
- username = context[:current_user]&.username
+ def resolve(text:)
+ username = current_user&.username
- "#{username.inspect} says: #{args[:text]}"
+ "#{username.inspect} says: #{text}"
end
end
end
diff --git a/app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb b/app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb
index 5027403e95c..09e76dba645 100644
--- a/app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb
+++ b/app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb
@@ -3,19 +3,22 @@
module Resolvers
module ErrorTracking
class SentryDetailedErrorResolver < BaseResolver
- argument :id, GraphQL::ID_TYPE,
+ type Types::ErrorTracking::SentryDetailedErrorType, null: true
+
+ argument :id, ::Types::GlobalIDType[::Gitlab::ErrorTracking::DetailedError],
required: true,
description: 'ID of the Sentry issue'
- def resolve(**args)
- current_user = context[:current_user]
- issue_id = GlobalID.parse(args[:id])&.model_id
+ def resolve(id:)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Gitlab::ErrorTracking::DetailedError].coerce_isolated_input(id)
# Get data from Sentry
response = ::ErrorTracking::IssueDetailsService.new(
project,
current_user,
- { issue_id: issue_id }
+ { issue_id: id.model_id }
).execute
issue = response[:issue]
issue.gitlab_project = project if issue
diff --git a/app/graphql/resolvers/error_tracking/sentry_error_collection_resolver.rb b/app/graphql/resolvers/error_tracking/sentry_error_collection_resolver.rb
index e4b4854c273..d47cc2bae56 100644
--- a/app/graphql/resolvers/error_tracking/sentry_error_collection_resolver.rb
+++ b/app/graphql/resolvers/error_tracking/sentry_error_collection_resolver.rb
@@ -3,6 +3,8 @@
module Resolvers
module ErrorTracking
class SentryErrorCollectionResolver < BaseResolver
+ type Types::ErrorTracking::SentryErrorCollectionType, null: true
+
def resolve(**args)
project = object
diff --git a/app/graphql/resolvers/error_tracking/sentry_error_stack_trace_resolver.rb b/app/graphql/resolvers/error_tracking/sentry_error_stack_trace_resolver.rb
index c365baaf475..669b487db10 100644
--- a/app/graphql/resolvers/error_tracking/sentry_error_stack_trace_resolver.rb
+++ b/app/graphql/resolvers/error_tracking/sentry_error_stack_trace_resolver.rb
@@ -3,18 +3,20 @@
module Resolvers
module ErrorTracking
class SentryErrorStackTraceResolver < BaseResolver
- argument :id, GraphQL::ID_TYPE,
+ argument :id, ::Types::GlobalIDType[::Gitlab::ErrorTracking::DetailedError],
required: true,
description: 'ID of the Sentry issue'
- def resolve(**args)
- issue_id = GlobalID.parse(args[:id])&.model_id
+ def resolve(id:)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Gitlab::ErrorTracking::DetailedError].coerce_isolated_input(id)
# Get data from Sentry
response = ::ErrorTracking::IssueLatestEventService.new(
project,
current_user,
- { issue_id: issue_id }
+ { issue_id: id.model_id }
).execute
event = response[:latest_event]
diff --git a/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb b/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb
index 79f99709505..c5cf924ce7f 100644
--- a/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb
+++ b/app/graphql/resolvers/error_tracking/sentry_errors_resolver.rb
@@ -3,6 +3,8 @@
module Resolvers
module ErrorTracking
class SentryErrorsResolver < BaseResolver
+ type Types::ErrorTracking::SentryErrorType.connection_type, null: true
+
def resolve(**args)
args[:cursor] = args.delete(:after)
project = object.project
diff --git a/app/graphql/resolvers/group_issues_resolver.rb b/app/graphql/resolvers/group_issues_resolver.rb
index 1fa6c78e730..1db0ab08e31 100644
--- a/app/graphql/resolvers/group_issues_resolver.rb
+++ b/app/graphql/resolvers/group_issues_resolver.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from IssuesResolver)
module Resolvers
class GroupIssuesResolver < IssuesResolver
diff --git a/app/graphql/resolvers/group_members_resolver.rb b/app/graphql/resolvers/group_members_resolver.rb
index f34c873a8a9..d3aa376c29c 100644
--- a/app/graphql/resolvers/group_members_resolver.rb
+++ b/app/graphql/resolvers/group_members_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class GroupMembersResolver < MembersResolver
+ type Types::GroupMemberType.connection_type, null: true
+
authorize :read_group_member
private
diff --git a/app/graphql/resolvers/group_merge_requests_resolver.rb b/app/graphql/resolvers/group_merge_requests_resolver.rb
index 5ee72e3f781..2bad974daf7 100644
--- a/app/graphql/resolvers/group_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/group_merge_requests_resolver.rb
@@ -6,6 +6,8 @@ module Resolvers
alias_method :group, :synchronized_object
+ type Types::MergeRequestType.connection_type, null: true
+
include_subgroups 'merge requests'
accept_assignee
accept_author
diff --git a/app/graphql/resolvers/group_milestones_resolver.rb b/app/graphql/resolvers/group_milestones_resolver.rb
index 8d34cea4fa1..83b82e2720b 100644
--- a/app/graphql/resolvers/group_milestones_resolver.rb
+++ b/app/graphql/resolvers/group_milestones_resolver.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from MilestonesResolver)
module Resolvers
class GroupMilestonesResolver < MilestonesResolver
@@ -6,6 +7,8 @@ module Resolvers
required: false,
description: 'Also return milestones in all subgroups and subprojects'
+ type Types::MilestoneType.connection_type, null: true
+
private
def parent_id_parameters(args)
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index 396ae02ae13..dd35219454f 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -12,7 +12,7 @@ module Resolvers
required: false,
default_value: 'created_desc'
- type Types::IssueType, null: true
+ type Types::IssueType.connection_type, null: true
NON_STABLE_CURSOR_SORTS = %i[priority_asc priority_desc
label_priority_asc label_priority_desc
diff --git a/app/graphql/resolvers/members_resolver.rb b/app/graphql/resolvers/members_resolver.rb
index 88a1ab71c45..523642e912f 100644
--- a/app/graphql/resolvers/members_resolver.rb
+++ b/app/graphql/resolvers/members_resolver.rb
@@ -5,6 +5,8 @@ module Resolvers
include Gitlab::Graphql::Authorize::AuthorizeResource
include LooksAhead
+ type Types::MemberInterface.connection_type, null: true
+
argument :search, GraphQL::STRING_TYPE,
required: false,
description: 'Search query'
diff --git a/app/graphql/resolvers/merge_request_pipelines_resolver.rb b/app/graphql/resolvers/merge_request_pipelines_resolver.rb
index b95e46d9cff..6590dfdc78c 100644
--- a/app/graphql/resolvers/merge_request_pipelines_resolver.rb
+++ b/app/graphql/resolvers/merge_request_pipelines_resolver.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
+# rubocop: disable Graphql/ResolverType
module Resolvers
class MergeRequestPipelinesResolver < BaseResolver
+ # The GraphQL type here gets defined in this include
include ::ResolvesPipelines
alias_method :merge_request, :object
@@ -18,3 +20,4 @@ module Resolvers
end
end
end
+# rubocop: enable Graphql/ResolverType
diff --git a/app/graphql/resolvers/merge_request_resolver.rb b/app/graphql/resolvers/merge_request_resolver.rb
index a47a128ea32..4cad65fa697 100644
--- a/app/graphql/resolvers/merge_request_resolver.rb
+++ b/app/graphql/resolvers/merge_request_resolver.rb
@@ -6,6 +6,8 @@ module Resolvers
alias_method :project, :synchronized_object
+ type ::Types::MergeRequestType, null: true
+
argument :iid, GraphQL::STRING_TYPE,
required: true,
as: :iids,
diff --git a/app/graphql/resolvers/metadata_resolver.rb b/app/graphql/resolvers/metadata_resolver.rb
index 3a79e6434fb..26bfa81038c 100644
--- a/app/graphql/resolvers/metadata_resolver.rb
+++ b/app/graphql/resolvers/metadata_resolver.rb
@@ -5,7 +5,7 @@ module Resolvers
type Types::MetadataType, null: false
def resolve(**args)
- { version: Gitlab::VERSION, revision: Gitlab.revision }
+ ::InstanceMetadata.new
end
end
end
diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb
index 84712b674db..564e388d571 100644
--- a/app/graphql/resolvers/milestones_resolver.rb
+++ b/app/graphql/resolvers/milestones_resolver.rb
@@ -25,7 +25,7 @@ module Resolvers
required: false,
description: 'A date that the milestone contains'
- type Types::MilestoneType, null: true
+ type Types::MilestoneType.connection_type, null: true
def resolve(**args)
validate_timeframe_params!(args)
diff --git a/app/graphql/resolvers/namespace_projects_resolver.rb b/app/graphql/resolvers/namespace_projects_resolver.rb
index c221cb9aed6..9f57c8f3405 100644
--- a/app/graphql/resolvers/namespace_projects_resolver.rb
+++ b/app/graphql/resolvers/namespace_projects_resolver.rb
@@ -23,7 +23,6 @@ module Resolvers
# The namespace could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` or the `full_path` of the namespace
# to query for projects, so make sure it's loaded and not `nil` before continuing.
- namespace = object.respond_to?(:sync) ? object.sync : object
return Project.none if namespace.nil?
query = include_subgroups ? namespace.all_projects.with_route : namespace.projects.with_route
@@ -41,6 +40,14 @@ module Resolvers
complexity = super
complexity + 10
end
+
+ private
+
+ def namespace
+ strong_memoize(:namespace) do
+ object.respond_to?(:sync) ? object.sync : object
+ end
+ end
end
end
diff --git a/app/graphql/resolvers/project_members_resolver.rb b/app/graphql/resolvers/project_members_resolver.rb
index 1ca4e81f397..e64e8b845a5 100644
--- a/app/graphql/resolvers/project_members_resolver.rb
+++ b/app/graphql/resolvers/project_members_resolver.rb
@@ -1,9 +1,8 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from MembersResolver)
module Resolvers
class ProjectMembersResolver < MembersResolver
- type Types::MemberInterface, null: true
-
authorize :read_project_member
private
diff --git a/app/graphql/resolvers/project_merge_requests_resolver.rb b/app/graphql/resolvers/project_merge_requests_resolver.rb
index ba13cb6e52c..bf082c0b182 100644
--- a/app/graphql/resolvers/project_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/project_merge_requests_resolver.rb
@@ -2,6 +2,7 @@
module Resolvers
class ProjectMergeRequestsResolver < MergeRequestsResolver
+ type ::Types::MergeRequestType.connection_type, null: true
accept_assignee
accept_author
end
diff --git a/app/graphql/resolvers/project_milestones_resolver.rb b/app/graphql/resolvers/project_milestones_resolver.rb
index 976fc300b87..c88c9ce7219 100644
--- a/app/graphql/resolvers/project_milestones_resolver.rb
+++ b/app/graphql/resolvers/project_milestones_resolver.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from MilestonesResolver)
module Resolvers
class ProjectMilestonesResolver < MilestonesResolver
@@ -6,6 +7,8 @@ module Resolvers
required: false,
description: "Also return milestones in the project's parent group and its ancestors"
+ type Types::MilestoneType.connection_type, null: true
+
private
def parent_id_parameters(args)
diff --git a/app/graphql/resolvers/project_pipeline_resolver.rb b/app/graphql/resolvers/project_pipeline_resolver.rb
index 181c1e77109..4cf47dbdc60 100644
--- a/app/graphql/resolvers/project_pipeline_resolver.rb
+++ b/app/graphql/resolvers/project_pipeline_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class ProjectPipelineResolver < BaseResolver
+ type ::Types::Ci::PipelineType, null: true
+
alias_method :project, :object
argument :iid, GraphQL::ID_TYPE,
diff --git a/app/graphql/resolvers/project_pipelines_resolver.rb b/app/graphql/resolvers/project_pipelines_resolver.rb
index 86094c46c2a..0171473a77f 100644
--- a/app/graphql/resolvers/project_pipelines_resolver.rb
+++ b/app/graphql/resolvers/project_pipelines_resolver.rb
@@ -1,13 +1,28 @@
# frozen_string_literal: true
+# The GraphQL type here gets defined in
+# https://gitlab.com/gitlab-org/gitlab/blob/master/app/graphql/resolvers/concerns/resolves_pipelines.rb#L7
+# rubocop: disable Graphql/ResolverType
module Resolvers
class ProjectPipelinesResolver < BaseResolver
+ include LooksAhead
include ResolvesPipelines
alias_method :project, :object
- def resolve(**args)
- resolve_pipelines(project, args)
+ def resolve_with_lookahead(**args)
+ apply_lookahead(resolve_pipelines(project, args))
+ end
+
+ private
+
+ def preloads
+ {
+ jobs: [:statuses],
+ upstream: [:triggered_by_pipeline],
+ downstream: [:triggered_pipelines]
+ }
end
end
end
+# rubocop: enable Graphql/ResolverType
diff --git a/app/graphql/resolvers/projects/jira_imports_resolver.rb b/app/graphql/resolvers/projects/jira_imports_resolver.rb
index aa9b7139f38..efd45c2c465 100644
--- a/app/graphql/resolvers/projects/jira_imports_resolver.rb
+++ b/app/graphql/resolvers/projects/jira_imports_resolver.rb
@@ -3,6 +3,8 @@
module Resolvers
module Projects
class JiraImportsResolver < BaseResolver
+ type Types::JiraImportType.connection_type, null: true
+
include Gitlab::Graphql::Authorize::AuthorizeResource
alias_method :project, :object
diff --git a/app/graphql/resolvers/projects/jira_projects_resolver.rb b/app/graphql/resolvers/projects/jira_projects_resolver.rb
index d017f973e17..31f42d305b0 100644
--- a/app/graphql/resolvers/projects/jira_projects_resolver.rb
+++ b/app/graphql/resolvers/projects/jira_projects_resolver.rb
@@ -5,6 +5,8 @@ module Resolvers
class JiraProjectsResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
+ type Types::Projects::Services::JiraProjectType.connection_type, null: true
+
argument :name,
GraphQL::STRING_TYPE,
required: false,
diff --git a/app/graphql/resolvers/projects/services_resolver.rb b/app/graphql/resolvers/projects/services_resolver.rb
index 40c64c24513..17d81e21c28 100644
--- a/app/graphql/resolvers/projects/services_resolver.rb
+++ b/app/graphql/resolvers/projects/services_resolver.rb
@@ -5,6 +5,8 @@ module Resolvers
class ServicesResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
+ type Types::Projects::ServiceType.connection_type, null: true
+
argument :active,
GraphQL::BOOLEAN_TYPE,
required: false,
diff --git a/app/graphql/resolvers/projects/snippets_resolver.rb b/app/graphql/resolvers/projects/snippets_resolver.rb
index 22895a24054..448918be2f5 100644
--- a/app/graphql/resolvers/projects/snippets_resolver.rb
+++ b/app/graphql/resolvers/projects/snippets_resolver.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from ResolvesSnippets)
module Resolvers
module Projects
diff --git a/app/graphql/resolvers/releases_resolver.rb b/app/graphql/resolvers/releases_resolver.rb
index 85892c2abeb..8e8127cf279 100644
--- a/app/graphql/resolvers/releases_resolver.rb
+++ b/app/graphql/resolvers/releases_resolver.rb
@@ -4,6 +4,10 @@ module Resolvers
class ReleasesResolver < BaseResolver
type Types::ReleaseType.connection_type, null: true
+ argument :sort, Types::ReleaseSortEnum,
+ required: false, default_value: :released_at_desc,
+ description: 'Sort releases by this criteria'
+
alias_method :project, :object
# This resolver has a custom singular resolver
@@ -11,12 +15,20 @@ module Resolvers
Resolvers::ReleaseResolver
end
- def resolve(**args)
+ SORT_TO_PARAMS_MAP = {
+ released_at_desc: { order_by: 'released_at', sort: 'desc' },
+ released_at_asc: { order_by: 'released_at', sort: 'asc' },
+ created_desc: { order_by: 'created_at', sort: 'desc' },
+ created_asc: { order_by: 'created_at', sort: 'asc' }
+ }.freeze
+
+ def resolve(sort:)
return unless Feature.enabled?(:graphql_release_data, project, default_enabled: true)
ReleasesFinder.new(
project,
- current_user
+ current_user,
+ SORT_TO_PARAMS_MAP[sort]
).execute
end
end
diff --git a/app/graphql/resolvers/snippets/blobs_resolver.rb b/app/graphql/resolvers/snippets/blobs_resolver.rb
index dc28358cab6..3a0dcb50faf 100644
--- a/app/graphql/resolvers/snippets/blobs_resolver.rb
+++ b/app/graphql/resolvers/snippets/blobs_resolver.rb
@@ -5,6 +5,8 @@ module Resolvers
class BlobsResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
+ type Types::Snippets::BlobType.connection_type, null: true
+
alias_method :snippet, :object
argument :paths, [GraphQL::STRING_TYPE],
diff --git a/app/graphql/resolvers/snippets_resolver.rb b/app/graphql/resolvers/snippets_resolver.rb
index 530a288a25b..77099565df0 100644
--- a/app/graphql/resolvers/snippets_resolver.rb
+++ b/app/graphql/resolvers/snippets_resolver.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from ResolvesSnippets)
module Resolvers
class SnippetsResolver < BaseResolver
@@ -8,11 +9,11 @@ module Resolvers
alias_method :user, :object
- argument :author_id, GraphQL::ID_TYPE,
+ argument :author_id, ::Types::GlobalIDType[::User],
required: false,
description: 'The ID of an author'
- argument :project_id, GraphQL::ID_TYPE,
+ argument :project_id, ::Types::GlobalIDType[::Project],
required: false,
description: 'The ID of a project'
@@ -36,9 +37,11 @@ module Resolvers
private
def snippet_finder_params(args)
+ # TODO: remove the type arguments when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
super
- .merge(author: resolve_gid(args[:author_id], :author),
- project: resolve_gid(args[:project_id], :project),
+ .merge(author: resolve_ids(args[:author_id], ::Types::GlobalIDType[::User]),
+ project: resolve_ids(args[:project_id], ::Types::GlobalIDType[::Project]),
explore: args[:explore])
end
end
diff --git a/app/graphql/resolvers/todo_resolver.rb b/app/graphql/resolvers/todo_resolver.rb
index bd5f8f274cd..9a8f7a71154 100644
--- a/app/graphql/resolvers/todo_resolver.rb
+++ b/app/graphql/resolvers/todo_resolver.rb
@@ -2,7 +2,7 @@
module Resolvers
class TodoResolver < BaseResolver
- type Types::TodoType, null: true
+ type Types::TodoType.connection_type, null: true
alias_method :target, :object
diff --git a/app/graphql/resolvers/tree_resolver.rb b/app/graphql/resolvers/tree_resolver.rb
index 5aad1c71b40..075a1929c47 100644
--- a/app/graphql/resolvers/tree_resolver.rb
+++ b/app/graphql/resolvers/tree_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class TreeResolver < BaseResolver
+ type Types::Tree::TreeType, null: true
+
argument :path, GraphQL::STRING_TYPE,
required: false,
default_value: '',
diff --git a/app/graphql/resolvers/user_merge_requests_resolver.rb b/app/graphql/resolvers/user_merge_requests_resolver_base.rb
index b0d6e159f73..47967fe69f9 100644
--- a/app/graphql/resolvers/user_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/user_merge_requests_resolver_base.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
module Resolvers
- class UserMergeRequestsResolver < MergeRequestsResolver
+ class UserMergeRequestsResolverBase < MergeRequestsResolver
include ResolvesProject
argument :project_path, GraphQL::STRING_TYPE,
required: false,
description: 'The full-path of the project the authored merge requests should be in. Incompatible with projectId.'
- argument :project_id, GraphQL::ID_TYPE,
+ argument :project_id, ::Types::GlobalIDType[::Project],
required: false,
description: 'The global ID of the project the authored merge requests should be in. Incompatible with projectPath.'
@@ -50,8 +50,10 @@ module Resolvers
end
def load_project(project_path, project_id)
- @project = resolve_project(full_path: project_path, project_id: project_id)
- @project = @project.sync if @project.respond_to?(:sync)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ project_id &&= ::Types::GlobalIDType[::Project].coerce_isolated_input(project_id)
+ @project = ::Gitlab::Graphql::Lazy.force(resolve_project(full_path: project_path, project_id: project_id))
end
def no_results_possible?(args)
diff --git a/app/graphql/resolvers/user_resolver.rb b/app/graphql/resolvers/user_resolver.rb
index a34cecba491..06c1f0cb42d 100644
--- a/app/graphql/resolvers/user_resolver.rb
+++ b/app/graphql/resolvers/user_resolver.rb
@@ -6,7 +6,7 @@ module Resolvers
type Types::UserType, null: true
- argument :id, GraphQL::ID_TYPE,
+ argument :id, Types::GlobalIDType[User],
required: false,
description: 'ID of the User'
diff --git a/app/graphql/resolvers/users/group_count_resolver.rb b/app/graphql/resolvers/users/group_count_resolver.rb
new file mode 100644
index 00000000000..5033c26554a
--- /dev/null
+++ b/app/graphql/resolvers/users/group_count_resolver.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Users
+ class GroupCountResolver < BaseResolver
+ alias_method :user, :object
+
+ def resolve(**args)
+ return unless can_read_group_count?
+
+ BatchLoader::GraphQL.for(user.id).batch do |user_ids, loader|
+ results = UserGroupsCounter.new(user_ids).execute
+
+ results.each do |user_id, count|
+ loader.call(user_id, count)
+ end
+ end
+ end
+
+ def can_read_group_count?
+ current_user&.can?(:read_group_count, user)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/users/snippets_resolver.rb b/app/graphql/resolvers/users/snippets_resolver.rb
index d757640b5ff..c2d42437ffd 100644
--- a/app/graphql/resolvers/users/snippets_resolver.rb
+++ b/app/graphql/resolvers/users/snippets_resolver.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+# rubocop:disable Graphql/ResolverType (inherited from ResolvesSnippets)
module Resolvers
module Users
diff --git a/app/graphql/resolvers/users_resolver.rb b/app/graphql/resolvers/users_resolver.rb
index 110a283b42e..f5838642141 100644
--- a/app/graphql/resolvers/users_resolver.rb
+++ b/app/graphql/resolvers/users_resolver.rb
@@ -4,6 +4,7 @@ module Resolvers
class UsersResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
+ type Types::UserType.connection_type, null: true
description 'Find Users'
argument :ids, [GraphQL::ID_TYPE],
@@ -18,10 +19,14 @@ module Resolvers
required: false,
default_value: 'created_desc'
- def resolve(ids: nil, usernames: nil, sort: nil)
+ argument :search, GraphQL::STRING_TYPE,
+ required: false,
+ description: "Query to search users by name, username, or primary email."
+
+ def resolve(ids: nil, usernames: nil, sort: nil, search: nil)
authorize!
- ::UsersFinder.new(context[:current_user], finder_params(ids, usernames, sort)).execute
+ ::UsersFinder.new(context[:current_user], finder_params(ids, usernames, sort, search)).execute
end
def ready?(**args)
@@ -42,11 +47,12 @@ module Resolvers
private
- def finder_params(ids, usernames, sort)
+ def finder_params(ids, usernames, sort, search)
params = {}
params[:sort] = sort if sort
params[:username] = usernames if usernames
params[:id] = parse_gids(ids) if ids
+ params[:search] = search if search
params
end