Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/graphql/resolvers')
-rw-r--r--app/graphql/resolvers/ci/job_token_scope_resolver.rb4
-rw-r--r--app/graphql/resolvers/ci/runner_jobs_resolver.rb10
-rw-r--r--app/graphql/resolvers/ci/runner_owner_project_resolver.rb15
-rw-r--r--app/graphql/resolvers/ci/runner_projects_resolver.rb63
-rw-r--r--app/graphql/resolvers/ci/test_suite_resolver.rb3
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb58
-rw-r--r--app/graphql/resolvers/concerns/looks_ahead.rb8
-rw-r--r--app/graphql/resolvers/concerns/project_search_arguments.rb36
-rw-r--r--app/graphql/resolvers/concerns/search_arguments.rb39
-rw-r--r--app/graphql/resolvers/crm/organization_state_counts_resolver.rb26
-rw-r--r--app/graphql/resolvers/crm/organizations_resolver.rb6
-rw-r--r--app/graphql/resolvers/deployment_resolver.rb20
-rw-r--r--app/graphql/resolvers/deployments_resolver.rb39
-rw-r--r--app/graphql/resolvers/environments/last_deployment_resolver.rb44
-rw-r--r--app/graphql/resolvers/environments_resolver.rb4
-rw-r--r--app/graphql/resolvers/group_packages_resolver.rb10
-rw-r--r--app/graphql/resolvers/members_resolver.rb4
-rw-r--r--app/graphql/resolvers/package_details_resolver.rb10
-rw-r--r--app/graphql/resolvers/project_jobs_resolver.rb10
-rw-r--r--app/graphql/resolvers/projects/branch_rules_resolver.rb15
-rw-r--r--app/graphql/resolvers/projects_resolver.rb32
-rw-r--r--app/graphql/resolvers/work_items_resolver.rb48
22 files changed, 385 insertions, 119 deletions
diff --git a/app/graphql/resolvers/ci/job_token_scope_resolver.rb b/app/graphql/resolvers/ci/job_token_scope_resolver.rb
index ca76a7b94fc..7c6aedad1d6 100644
--- a/app/graphql/resolvers/ci/job_token_scope_resolver.rb
+++ b/app/graphql/resolvers/ci/job_token_scope_resolver.rb
@@ -6,14 +6,12 @@ module Resolvers
include Gitlab::Graphql::Authorize::AuthorizeResource
authorize :admin_project
- description 'Container for resources that can be accessed by a CI job token from the current project. Null if job token scope setting is disabled.'
+ description 'Container for resources that can be accessed by a CI job token from the current project.'
type ::Types::Ci::JobTokenScopeType, null: true
def resolve
authorize!(object)
- return unless object.ci_job_token_scope_enabled?
-
::Ci::JobToken::Scope.new(object)
end
end
diff --git a/app/graphql/resolvers/ci/runner_jobs_resolver.rb b/app/graphql/resolvers/ci/runner_jobs_resolver.rb
index 2f6ca09d031..de00aadaea8 100644
--- a/app/graphql/resolvers/ci/runner_jobs_resolver.rb
+++ b/app/graphql/resolvers/ci/runner_jobs_resolver.rb
@@ -9,6 +9,7 @@ module Resolvers
type ::Types::Ci::JobType.connection_type, null: true
authorize :read_builds
authorizes_object!
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
argument :statuses, [::Types::Ci::JobStatusEnum],
required: false,
@@ -16,15 +17,6 @@ module Resolvers
alias_method :runner, :object
- def ready?(**args)
- context[self.class] ||= { executions: 0 }
- context[self.class][:executions] += 1
-
- raise GraphQL::ExecutionError, "Jobs can be requested for only one runner at a time" if context[self.class][:executions] > 1
-
- super
- end
-
def resolve_with_lookahead(statuses: nil)
jobs = ::Ci::JobsFinder.new(current_user: current_user, runner: runner, params: { scope: statuses }).execute
diff --git a/app/graphql/resolvers/ci/runner_owner_project_resolver.rb b/app/graphql/resolvers/ci/runner_owner_project_resolver.rb
index 14b5f8f90eb..da8fab93619 100644
--- a/app/graphql/resolvers/ci/runner_owner_project_resolver.rb
+++ b/app/graphql/resolvers/ci/runner_owner_project_resolver.rb
@@ -9,7 +9,7 @@ module Resolvers
alias_method :runner, :object
- def resolve_with_lookahead(**args)
+ def resolve_with_lookahead(**_args)
resolve_owner
end
@@ -19,6 +19,8 @@ module Resolvers
}
end
+ private
+
def filtered_preloads
selection = lookahead
@@ -27,8 +29,6 @@ module Resolvers
end
end
- private
-
def resolve_owner
return unless runner.project_type?
@@ -48,14 +48,13 @@ module Resolvers
.transform_values { |runner_projects| runner_projects.first.project_id }
project_ids = owner_project_id_by_runner_id.values.uniq
- all_preloads = unconditional_includes + filtered_preloads
- owner_relation = Project.all
- owner_relation = owner_relation.preload(*all_preloads) if all_preloads.any?
- projects = owner_relation.where(id: project_ids).index_by(&:id)
+ projects = Project.where(id: project_ids)
+ Preloaders::ProjectPolicyPreloader.new(projects, current_user).execute
+ projects_by_id = projects.index_by(&:id)
runner_ids.each do |runner_id|
owner_project_id = owner_project_id_by_runner_id[runner_id]
- loader.call(runner_id, projects[owner_project_id])
+ loader.call(runner_id, projects_by_id[owner_project_id])
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/graphql/resolvers/ci/runner_projects_resolver.rb b/app/graphql/resolvers/ci/runner_projects_resolver.rb
new file mode 100644
index 00000000000..ca3b4ebb797
--- /dev/null
+++ b/app/graphql/resolvers/ci/runner_projects_resolver.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Ci
+ class RunnerProjectsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include LooksAhead
+ include ProjectSearchArguments
+
+ type Types::ProjectType.connection_type, null: true
+ authorize :read_runner
+ authorizes_object!
+
+ alias_method :runner, :object
+
+ argument :sort, GraphQL::Types::String,
+ required: false,
+ default_value: 'id_asc', # TODO: Remove in %16.0 and move :sort to ProjectSearchArguments, see https://gitlab.com/gitlab-org/gitlab/-/issues/372117
+ deprecated: {
+ reason: 'Default sort order will change in 16.0. ' \
+ 'Specify `"id_asc"` if query results\' order is important',
+ milestone: '15.4'
+ },
+ description: "Sort order of results. Format: '<field_name>_<sort_direction>', " \
+ "for example: 'id_desc' or 'name_asc'"
+
+ def resolve_with_lookahead(**args)
+ return unless runner.project_type?
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ BatchLoader::GraphQL.for(runner.id).batch(key: :runner_projects) do |runner_ids, loader|
+ plucked_runner_and_project_ids = ::Ci::RunnerProject
+ .select(:runner_id, :project_id)
+ .where(runner_id: runner_ids)
+ .pluck(:runner_id, :project_id)
+
+ project_ids = plucked_runner_and_project_ids.collect { |_runner_id, project_id| project_id }.uniq
+ projects = ProjectsFinder
+ .new(current_user: current_user,
+ params: project_finder_params(args),
+ project_ids_relation: project_ids)
+ .execute
+ Preloaders::ProjectPolicyPreloader.new(projects, current_user).execute
+ projects_by_id = projects.index_by(&:id)
+
+ # In plucked_runner_and_project_ids, first() represents the runner ID, and second() the project ID,
+ # so let's group the project IDs by runner ID
+ runner_project_ids_by_runner_id =
+ plucked_runner_and_project_ids
+ .group_by(&:first)
+ .transform_values { |values| values.map(&:second).filter_map { |project_id| projects_by_id[project_id] } }
+
+ runner_ids.each do |runner_id|
+ runner_projects = runner_project_ids_by_runner_id[runner_id] || []
+
+ loader.call(runner_id, runner_projects)
+ end
+ end
+ # rubocop:enable CodeReuse/ActiveRecord
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/ci/test_suite_resolver.rb b/app/graphql/resolvers/ci/test_suite_resolver.rb
index f758e217b47..a2d3af9c664 100644
--- a/app/graphql/resolvers/ci/test_suite_resolver.rb
+++ b/app/graphql/resolvers/ci/test_suite_resolver.rb
@@ -28,7 +28,8 @@ module Resolvers
def load_test_suite_data(builds)
suite = builds.sum do |build|
- build.collect_test_reports!(Gitlab::Ci::Reports::TestReport.new)
+ test_report = build.collect_test_reports!(Gitlab::Ci::Reports::TestReport.new)
+ test_report.get_suite(build.test_suite_name)
end
Gitlab::Ci::Reports::TestFailureHistory.new(suite.failed.values, pipeline.project).load!
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index fe213936f55..8295bd58388 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -76,24 +76,11 @@ module IssueResolverArguments
end
def resolve_with_lookahead(**args)
- # The project could have been loaded in batch by `BatchLoader`.
- # At this point we need the `id` of the project to query for issues, so
- # make sure it's loaded and not `nil` before continuing.
- parent = object.respond_to?(:sync) ? object.sync : object
- return Issue.none if parent.nil?
-
- # Will need to be made group & namespace aware with
- # https://gitlab.com/gitlab-org/gitlab-foss/issues/54520
- args[:not] = args[:not].to_h if args[:not].present?
- args[:iids] ||= [args.delete(:iid)].compact if args[:iid]
- args[:attempt_project_search_optimizations] = true if args[:search].present?
+ return Issue.none if resource_parent.nil?
- prepare_assignee_username_params(args)
- prepare_release_tag_params(args)
+ finder = IssuesFinder.new(current_user, prepare_finder_params(args))
- finder = IssuesFinder.new(current_user, args)
-
- continue_issue_resolve(parent, finder, **args)
+ continue_issue_resolve(resource_parent, finder, **args)
end
def ready?(**args)
@@ -103,7 +90,6 @@ module IssueResolverArguments
params_not_mutually_exclusive(args, mutually_exclusive_milestone_args)
params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args)
params_not_mutually_exclusive(args, mutually_exclusive_release_tag_args)
- validate_anonymous_search_access! if args[:search].present?
super
end
@@ -128,6 +114,17 @@ module IssueResolverArguments
private
+ def prepare_finder_params(args)
+ params = super(args)
+ params[:iids] ||= [params.delete(:iid)].compact if params[:iid]
+ params[:attempt_project_search_optimizations] = true if params[:search].present?
+
+ prepare_assignee_username_params(params)
+ prepare_release_tag_params(params)
+
+ params
+ end
+
def prepare_release_tag_params(args)
release_tag_wildcard = args.delete(:release_tag_wildcard_id)
return if release_tag_wildcard.blank?
@@ -135,20 +132,13 @@ module IssueResolverArguments
args[:release_tag] ||= release_tag_wildcard
end
- def mutually_exclusive_release_tag_args
- [:release_tag, :release_tag_wildcard_id]
- end
-
def prepare_assignee_username_params(args)
args[:assignee_username] = args.delete(:assignee_usernames) if args[:assignee_usernames].present?
args[:not][:assignee_username] = args[:not].delete(:assignee_usernames) if args.dig(:not, :assignee_usernames).present?
end
- def params_not_mutually_exclusive(args, mutually_exclusive_args)
- if args.slice(*mutually_exclusive_args).compact.size > 1
- arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
- raise ::Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time."
- end
+ def mutually_exclusive_release_tag_args
+ [:release_tag, :release_tag_wildcard_id]
end
def mutually_exclusive_milestone_args
@@ -158,4 +148,20 @@ module IssueResolverArguments
def mutually_exclusive_assignee_username_args
[:assignee_usernames, :assignee_username]
end
+
+ def params_not_mutually_exclusive(args, mutually_exclusive_args)
+ if args.slice(*mutually_exclusive_args).compact.size > 1
+ arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
+ raise ::Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time."
+ end
+ end
+
+ def resource_parent
+ # The project could have been loaded in batch by `BatchLoader`.
+ # At this point we need the `id` of the project to query for issues, so
+ # make sure it's loaded and not `nil` before continuing.
+ strong_memoize(:resource_parent) do
+ object.respond_to?(:sync) ? object.sync : object
+ end
+ end
end
diff --git a/app/graphql/resolvers/concerns/looks_ahead.rb b/app/graphql/resolvers/concerns/looks_ahead.rb
index 644b2a11460..b548dc1e175 100644
--- a/app/graphql/resolvers/concerns/looks_ahead.rb
+++ b/app/graphql/resolvers/concerns/looks_ahead.rb
@@ -33,10 +33,14 @@ module LooksAhead
end
def filtered_preloads
- selection = node_selection
+ nodes = node_selection
+
+ return [] unless nodes
+
+ selected_fields = nodes.selections.map(&:name)
preloads.each.flat_map do |name, requirements|
- selection&.selects?(name) ? requirements : []
+ selected_fields.include?(name) ? requirements : []
end
end
diff --git a/app/graphql/resolvers/concerns/project_search_arguments.rb b/app/graphql/resolvers/concerns/project_search_arguments.rb
new file mode 100644
index 00000000000..7e03963f412
--- /dev/null
+++ b/app/graphql/resolvers/concerns/project_search_arguments.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module ProjectSearchArguments
+ extend ActiveSupport::Concern
+
+ included do
+ argument :membership, GraphQL::Types::Boolean,
+ required: false,
+ description: 'Return only projects that the current user is a member of.'
+
+ argument :search, GraphQL::Types::String,
+ required: false,
+ description: 'Search query, which can be for the project name, a path, or a description.'
+
+ argument :search_namespaces, GraphQL::Types::Boolean,
+ required: false,
+ description: 'Include namespace in project search.'
+
+ argument :topics, type: [GraphQL::Types::String],
+ required: false,
+ description: 'Filter projects by topics.'
+ end
+
+ private
+
+ def project_finder_params(params)
+ {
+ without_deleted: true,
+ non_public: params[:membership],
+ search: params[:search],
+ search_namespaces: params[:search_namespaces],
+ sort: params[:sort],
+ topic: params[:topics]
+ }.compact
+ end
+end
diff --git a/app/graphql/resolvers/concerns/search_arguments.rb b/app/graphql/resolvers/concerns/search_arguments.rb
index 7f480f9d0b6..95c6dbf7497 100644
--- a/app/graphql/resolvers/concerns/search_arguments.rb
+++ b/app/graphql/resolvers/concerns/search_arguments.rb
@@ -7,12 +7,49 @@ module SearchArguments
argument :search, GraphQL::Types::String,
required: false,
description: 'Search query for title or description.'
+ argument :in, [Types::IssuableSearchableFieldEnum],
+ required: false,
+ description: <<~DESC
+ Specify the fields to perform the search in.
+ Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'
+ DESC
+ end
+
+ def ready?(**args)
+ validate_search_in_params!(args)
+ validate_anonymous_search_access!(args)
+
+ super
end
- def validate_anonymous_search_access!
+ private
+
+ def validate_anonymous_search_access!(args)
+ return unless args[:search].present?
return if current_user.present? || Feature.disabled?(:disable_anonymous_search, type: :ops)
raise ::Gitlab::Graphql::Errors::ArgumentError,
"User must be authenticated to include the `search` argument."
end
+
+ def validate_search_in_params!(args)
+ return unless args[:in].present? && args[:search].blank?
+
+ raise Gitlab::Graphql::Errors::ArgumentError,
+ '`search` should be present when including the `in` argument'
+ end
+
+ def prepare_finder_params(args)
+ prepare_search_params(args)
+ end
+
+ def prepare_search_params(args)
+ return args unless args[:search].present?
+
+ parent_type = resource_parent.is_a?(Project) ? :project : :group
+ args[:"attempt_#{parent_type}_search_optimizations"] = true
+ args[:in] = args[:in].join(',') if args[:in].present?
+
+ args
+ end
end
diff --git a/app/graphql/resolvers/crm/organization_state_counts_resolver.rb b/app/graphql/resolvers/crm/organization_state_counts_resolver.rb
new file mode 100644
index 00000000000..c16a4bd24ea
--- /dev/null
+++ b/app/graphql/resolvers/crm/organization_state_counts_resolver.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Crm
+ class OrganizationStateCountsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorize :read_crm_organization
+ authorizes_object!
+
+ type Types::CustomerRelations::OrganizationStateCountsType, null: true
+
+ argument :search, GraphQL::Types::String,
+ required: false,
+ description: 'Search term to find organizations with.'
+
+ argument :state, Types::CustomerRelations::OrganizationStateEnum,
+ required: false,
+ description: 'State of the organizations to search for.'
+
+ def resolve(**args)
+ ::Crm::OrganizationsFinder.counts_by_state(context[:current_user], args.merge({ group: object }))
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/crm/organizations_resolver.rb b/app/graphql/resolvers/crm/organizations_resolver.rb
index ca0a908ee22..719834f406d 100644
--- a/app/graphql/resolvers/crm/organizations_resolver.rb
+++ b/app/graphql/resolvers/crm/organizations_resolver.rb
@@ -10,6 +10,11 @@ module Resolvers
type Types::CustomerRelations::OrganizationType, null: true
+ argument :sort, Types::CustomerRelations::OrganizationSortEnum,
+ description: 'Criteria to sort organizations by.',
+ required: false,
+ default_value: { field: 'name', direction: :asc }
+
argument :search, GraphQL::Types::String,
required: false,
description: 'Search term used to find organizations with.'
@@ -24,6 +29,7 @@ module Resolvers
def resolve(**args)
args[:ids] = resolve_ids(args.delete(:ids))
+ args.delete(:state) if args[:state] == :all
::Crm::OrganizationsFinder.new(current_user, { group: group }.merge(args)).execute
end
diff --git a/app/graphql/resolvers/deployment_resolver.rb b/app/graphql/resolvers/deployment_resolver.rb
new file mode 100644
index 00000000000..7d9ce0f023c
--- /dev/null
+++ b/app/graphql/resolvers/deployment_resolver.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class DeploymentResolver < BaseResolver
+ argument :iid,
+ GraphQL::Types::ID,
+ required: true,
+ description: 'Project-level internal ID of the Deployment.'
+
+ type Types::DeploymentType, null: true
+
+ alias_method :project, :object
+
+ def resolve(iid:)
+ return unless project.present? && project.is_a?(::Project)
+
+ Deployment.for_iid(project, iid)
+ end
+ end
+end
diff --git a/app/graphql/resolvers/deployments_resolver.rb b/app/graphql/resolvers/deployments_resolver.rb
new file mode 100644
index 00000000000..341d23c2ccb
--- /dev/null
+++ b/app/graphql/resolvers/deployments_resolver.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class DeploymentsResolver < BaseResolver
+ argument :statuses, [Types::DeploymentStatusEnum],
+ description: 'Statuses of the deployments.',
+ required: false,
+ as: :status
+
+ argument :order_by, Types::DeploymentsOrderByInputType,
+ description: 'Order by a specified field.',
+ required: false
+
+ type Types::DeploymentType, null: true
+
+ alias_method :environment, :object
+
+ def resolve(**args)
+ return unless environment.present? && environment.is_a?(::Environment)
+
+ args = transform_args_for_finder(**args)
+
+ # GraphQL BatchLoader shouldn't be used here because pagination query will be inefficient
+ # that fetches thousands of rows before limiting and offsetting.
+ DeploymentsFinder.new(environment: environment.id, **args).execute
+ end
+
+ private
+
+ def transform_args_for_finder(**args)
+ if (order_by = args.delete(:order_by))
+ order_by = order_by.to_h.map { |k, v| { order_by: k.to_s, sort: v } }.first
+ args.merge!(order_by)
+ end
+
+ args
+ end
+ end
+end
diff --git a/app/graphql/resolvers/environments/last_deployment_resolver.rb b/app/graphql/resolvers/environments/last_deployment_resolver.rb
new file mode 100644
index 00000000000..76f80112673
--- /dev/null
+++ b/app/graphql/resolvers/environments/last_deployment_resolver.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Environments
+ class LastDeploymentResolver < BaseResolver
+ argument :status,
+ Types::DeploymentStatusEnum,
+ required: true,
+ description: 'Status of the Deployment.'
+
+ type Types::DeploymentType, null: true
+
+ def resolve(status:)
+ return unless object.present? && object.is_a?(::Environment)
+
+ validate!(status)
+
+ find_last_deployment(status)
+ end
+
+ private
+
+ def find_last_deployment(status)
+ BatchLoader::GraphQL.for(object).batch(key: status) do |environments, loader, args|
+ association_name = "last_#{args[:key]}_deployment".to_sym
+
+ Preloaders::Environments::DeploymentPreloader.new(environments)
+ .execute_with_union(association_name, {})
+
+ environments.each do |environment|
+ loader.call(environment, environment.public_send(association_name)) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+ end
+
+ def validate!(status)
+ unless Deployment::FINISHED_STATUSES.include?(status.to_sym) ||
+ Deployment::UPCOMING_STATUSES.include?(status.to_sym)
+ raise Gitlab::Graphql::Errors::ArgumentError, "\"#{status}\" status is not supported."
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/environments_resolver.rb b/app/graphql/resolvers/environments_resolver.rb
index 934c1ba2738..f265e2183d0 100644
--- a/app/graphql/resolvers/environments_resolver.rb
+++ b/app/graphql/resolvers/environments_resolver.rb
@@ -21,8 +21,8 @@ module Resolvers
def resolve(**args)
return unless project.present?
- Environments::EnvironmentsFinder.new(project, context[:current_user], args).execute
- rescue Environments::EnvironmentsFinder::InvalidStatesError => e
+ ::Environments::EnvironmentsFinder.new(project, context[:current_user], args).execute
+ rescue ::Environments::EnvironmentsFinder::InvalidStatesError => e
raise Gitlab::Graphql::Errors::ArgumentError, e.message
end
end
diff --git a/app/graphql/resolvers/group_packages_resolver.rb b/app/graphql/resolvers/group_packages_resolver.rb
index b48e0b75190..e6a6abb39dd 100644
--- a/app/graphql/resolvers/group_packages_resolver.rb
+++ b/app/graphql/resolvers/group_packages_resolver.rb
@@ -5,6 +5,8 @@ module Resolvers
class GroupPackagesResolver < PackagesBaseResolver
# The GraphQL type is defined in the extended class
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+
argument :sort, Types::Packages::PackageGroupSortEnum,
description: 'Sort packages by this criteria.',
required: false,
@@ -15,14 +17,6 @@ module Resolvers
project_path_asc: { order_by: 'project_path', sort: 'asc' }
}).freeze
- def ready?(**args)
- context[self.class] ||= { executions: 0 }
- context[self.class][:executions] += 1
- raise GraphQL::ExecutionError, "Packages can be requested only for one group at a time" if context[self.class][:executions] > 1
-
- super
- end
-
def resolve(sort:, **filters)
return unless packages_available?
diff --git a/app/graphql/resolvers/members_resolver.rb b/app/graphql/resolvers/members_resolver.rb
index 827db54134a..3d7894fdd6a 100644
--- a/app/graphql/resolvers/members_resolver.rb
+++ b/app/graphql/resolvers/members_resolver.rb
@@ -11,6 +11,10 @@ module Resolvers
required: false,
description: 'Search query.'
+ argument :sort, ::Types::MemberSortEnum,
+ required: false,
+ description: 'sort query.'
+
def resolve_with_lookahead(**args)
authorize!(object)
diff --git a/app/graphql/resolvers/package_details_resolver.rb b/app/graphql/resolvers/package_details_resolver.rb
index 705d3900cd2..b77c6b1112b 100644
--- a/app/graphql/resolvers/package_details_resolver.rb
+++ b/app/graphql/resolvers/package_details_resolver.rb
@@ -2,20 +2,14 @@
module Resolvers
class PackageDetailsResolver < BaseResolver
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
+
type ::Types::Packages::PackageDetailsType, null: true
argument :id, ::Types::GlobalIDType[::Packages::Package],
required: true,
description: 'Global ID of the package.'
- def ready?(**args)
- context[self.class] ||= { executions: 0 }
- context[self.class][:executions] += 1
- raise GraphQL::ExecutionError, "Package details can be requested only for one package at a time" if context[self.class][:executions] > 1
-
- super
- end
-
def resolve(id:)
GitlabSchema.find_by_gid(id)
end
diff --git a/app/graphql/resolvers/project_jobs_resolver.rb b/app/graphql/resolvers/project_jobs_resolver.rb
index b09158d475d..4d13a4a3fae 100644
--- a/app/graphql/resolvers/project_jobs_resolver.rb
+++ b/app/graphql/resolvers/project_jobs_resolver.rb
@@ -8,6 +8,7 @@ module Resolvers
type ::Types::Ci::JobType.connection_type, null: true
authorize :read_build
authorizes_object!
+ extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
argument :statuses, [::Types::Ci::JobStatusEnum],
required: false,
@@ -15,15 +16,6 @@ module Resolvers
alias_method :project, :object
- def ready?(**args)
- context[self.class] ||= { executions: 0 }
- context[self.class][:executions] += 1
-
- raise GraphQL::ExecutionError, "Jobs can be requested for only one project at a time" if context[self.class][:executions] > 1
-
- super
- end
-
def resolve_with_lookahead(statuses: nil)
jobs = ::Ci::JobsFinder.new(current_user: current_user, project: project, params: { scope: statuses }).execute
diff --git a/app/graphql/resolvers/projects/branch_rules_resolver.rb b/app/graphql/resolvers/projects/branch_rules_resolver.rb
new file mode 100644
index 00000000000..6c8b416bcea
--- /dev/null
+++ b/app/graphql/resolvers/projects/branch_rules_resolver.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Projects
+ class BranchRulesResolver < BaseResolver
+ type Types::Projects::BranchRuleType.connection_type, null: false
+
+ alias_method :project, :object
+
+ def resolve(**args)
+ project.protected_branches
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb
index facf8ffe36f..4d1e1b867da 100644
--- a/app/graphql/resolvers/projects_resolver.rb
+++ b/app/graphql/resolvers/projects_resolver.rb
@@ -2,31 +2,18 @@
module Resolvers
class ProjectsResolver < BaseResolver
- type Types::ProjectType, null: true
-
- argument :membership, GraphQL::Types::Boolean,
- required: false,
- description: 'Limit projects that the current user is a member of.'
+ include ProjectSearchArguments
- argument :search, GraphQL::Types::String,
- required: false,
- description: 'Search query for project name, path, or description.'
+ type Types::ProjectType, null: true
argument :ids, [GraphQL::Types::ID],
required: false,
description: 'Filter projects by IDs.'
- argument :search_namespaces, GraphQL::Types::Boolean,
- required: false,
- description: 'Include namespace in project search.'
-
argument :sort, GraphQL::Types::String,
required: false,
- description: 'Sort order of results.'
-
- argument :topics, type: [GraphQL::Types::String],
- required: false,
- description: 'Filters projects by topics.'
+ description: "Sort order of results. Format: '<field_name>_<sort_direction>', " \
+ "for example: 'id_desc' or 'name_asc'"
def resolve(**args)
ProjectsFinder
@@ -36,17 +23,6 @@ module Resolvers
private
- def project_finder_params(params)
- {
- without_deleted: true,
- non_public: params[:membership],
- search: params[:search],
- search_namespaces: params[:search_namespaces],
- sort: params[:sort],
- topic: params[:topics]
- }.compact
- end
-
def parse_gids(gids)
gids&.map { |gid| GitlabSchema.parse_gid(gid, expected_type: ::Project).model_id }
end
diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb
index 055984db3cb..9c7931a4edb 100644
--- a/app/graphql/resolvers/work_items_resolver.rb
+++ b/app/graphql/resolvers/work_items_resolver.rb
@@ -26,27 +26,31 @@ module Resolvers
required: false
def resolve_with_lookahead(**args)
- # The project could have been loaded in batch by `BatchLoader`.
- # At this point we need the `id` of the project to query for issues, so
- # make sure it's loaded and not `nil` before continuing.
- parent = object.respond_to?(:sync) ? object.sync : object
- return WorkItem.none if parent.nil? || !parent.work_items_feature_flag_enabled?
+ return WorkItem.none if resource_parent.nil? || !resource_parent.work_items_feature_flag_enabled?
- args[:iids] ||= [args.delete(:iid)].compact if args[:iid]
- args[:attempt_project_search_optimizations] = true if args[:search].present?
+ finder = ::WorkItems::WorkItemsFinder.new(current_user, prepare_finder_params(args))
- finder = ::WorkItems::WorkItemsFinder.new(current_user, args)
-
- Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all { |q| apply_lookahead(q) }
+ Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all { |q| apply_lookahead(q) }
end
- def ready?(**args)
- validate_anonymous_search_access! if args[:search].present?
+ private
- super
+ def preloads
+ {
+ last_edited_by: :last_edited_by
+ }
end
- private
+ # Allows to apply lookahead for fields
+ # selected from WidgetInterface
+ override :node_selection
+ def node_selection
+ selected_fields = super
+
+ return unless selected_fields
+
+ selected_fields.selection(:widgets)
+ end
def unconditional_includes
[
@@ -56,6 +60,22 @@ module Resolvers
:author
]
end
+
+ def prepare_finder_params(args)
+ params = super(args)
+ params[:iids] ||= [params.delete(:iid)].compact if params[:iid]
+
+ params
+ end
+
+ def resource_parent
+ # The project could have been loaded in batch by `BatchLoader`.
+ # At this point we need the `id` of the project to query for work items, so
+ # make sure it's loaded and not `nil` before continuing.
+ strong_memoize(:resource_parent) do
+ object.respond_to?(:sync) ? object.sync : object
+ end
+ end
end
end