diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-06 18:10:28 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-06 18:10:28 +0000 |
commit | 958f41148d08b03a9bbe37adecd6e3b0b10a7219 (patch) | |
tree | 5998b3443f6b425b982857a078b95997f5231309 /app/graphql/resolvers | |
parent | b333706699e505b2a0a4fa9cc64b9d2358f271a5 (diff) | |
download | gitlab-ce-958f41148d08b03a9bbe37adecd6e3b0b10a7219.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/graphql/resolvers')
4 files changed, 110 insertions, 36 deletions
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/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/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 |