diff options
Diffstat (limited to 'app/graphql/resolvers')
24 files changed, 268 insertions, 31 deletions
diff --git a/app/graphql/resolvers/alert_management/alert_resolver.rb b/app/graphql/resolvers/alert_management/alert_resolver.rb index 71a7615685a..dc9b1dbb5f4 100644 --- a/app/graphql/resolvers/alert_management/alert_resolver.rb +++ b/app/graphql/resolvers/alert_management/alert_resolver.rb @@ -22,6 +22,10 @@ module Resolvers description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.', required: false + argument :assignee_username, GraphQL::STRING_TYPE, + required: false, + description: 'Username of a user assigned to the issue' + type Types::AlertManagement::AlertType, null: true def resolve_with_lookahead(**args) 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 a45de21002f..96ea4610aff 100644 --- a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb +++ b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb @@ -9,6 +9,10 @@ module Resolvers description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.', required: false + argument :assignee_username, GraphQL::STRING_TYPE, + required: false, + description: 'Username of a user assigned to the issue' + def resolve(**args) ::Gitlab::AlertManagement::AlertStatusCounts.new(context[:current_user], object, args) end diff --git a/app/graphql/resolvers/assigned_merge_requests_resolver.rb b/app/graphql/resolvers/assigned_merge_requests_resolver.rb index fa08b142a7e..172a8e298ad 100644 --- a/app/graphql/resolvers/assigned_merge_requests_resolver.rb +++ b/app/graphql/resolvers/assigned_merge_requests_resolver.rb @@ -2,6 +2,8 @@ module Resolvers class AssignedMergeRequestsResolver < UserMergeRequestsResolver + accept_author + def user_role :assignee end diff --git a/app/graphql/resolvers/authored_merge_requests_resolver.rb b/app/graphql/resolvers/authored_merge_requests_resolver.rb index e19bc9e8715..bc796f8685a 100644 --- a/app/graphql/resolvers/authored_merge_requests_resolver.rb +++ b/app/graphql/resolvers/authored_merge_requests_resolver.rb @@ -2,6 +2,8 @@ module Resolvers class AuthoredMergeRequestsResolver < UserMergeRequestsResolver + accept_assignee + def user_role :author end diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb index 791c6eab42f..2b8854fb4d0 100644 --- a/app/graphql/resolvers/base_resolver.rb +++ b/app/graphql/resolvers/base_resolver.rb @@ -4,6 +4,9 @@ module Resolvers class BaseResolver < GraphQL::Schema::Resolver extend ::Gitlab::Utils::Override include ::Gitlab::Utils::StrongMemoize + include ::Gitlab::Graphql::GlobalIDCompatibility + + argument_class ::Types::BaseArgument def self.single @single ||= Class.new(self) do diff --git a/app/graphql/resolvers/board_list_issues_resolver.rb b/app/graphql/resolvers/board_list_issues_resolver.rb index dba9f99edeb..3421e1024c0 100644 --- a/app/graphql/resolvers/board_list_issues_resolver.rb +++ b/app/graphql/resolvers/board_list_issues_resolver.rb @@ -14,7 +14,7 @@ module Resolvers def resolve(**args) filter_params = issue_filters(args[:filters]).merge(board_id: list.board.id, id: list.id) - service = Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params) + service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params) Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection.new(service.execute) end diff --git a/app/graphql/resolvers/board_lists_resolver.rb b/app/graphql/resolvers/board_lists_resolver.rb index b1d43934f24..3384b37e2ce 100644 --- a/app/graphql/resolvers/board_lists_resolver.rb +++ b/app/graphql/resolvers/board_lists_resolver.rb @@ -2,6 +2,7 @@ module Resolvers class BoardListsResolver < BaseResolver + include BoardIssueFilterable include Gitlab::Graphql::Authorize::AuthorizeResource type Types::BoardListType, null: true @@ -10,12 +11,17 @@ module Resolvers required: false, description: 'Find a list by its global ID' + argument :issue_filters, Types::Boards::BoardIssueInputType, + required: false, + description: 'Filters applied when getting issue metadata in the board list' + alias_method :board, :object - def resolve(lookahead: nil, id: nil) + def resolve(lookahead: nil, id: nil, issue_filters: {}) authorize!(board) lists = board_lists(id) + context.scoped_set!(:issue_filters, issue_filters(issue_filters)) if load_preferences?(lookahead) List.preload_preferences_for_user(lists, context[:current_user]) @@ -27,7 +33,7 @@ module Resolvers private def board_lists(id) - service = Boards::Lists::ListService.new( + service = ::Boards::Lists::ListService.new( board.resource_parent, context[:current_user], list_id: extract_list_id(id) diff --git a/app/graphql/resolvers/board_resolver.rb b/app/graphql/resolvers/board_resolver.rb new file mode 100644 index 00000000000..517f4e514c9 --- /dev/null +++ b/app/graphql/resolvers/board_resolver.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Resolvers + class BoardResolver < BaseResolver.single + alias_method :parent, :synchronized_object + + type Types::BoardType, null: true + + argument :id, ::Types::GlobalIDType[::Board], + required: true, + description: 'The board\'s ID' + + def resolve(id: nil) + return unless parent + + ::Boards::ListService.new(parent, context[:current_user], board_id: extract_board_id(id)).execute(create_default_board: false).first + rescue ActiveRecord::RecordNotFound + nil + end + + private + + def extract_board_id(gid) + GitlabSchema.parse_gid(gid, expected_type: ::Board).model_id + end + end +end diff --git a/app/graphql/resolvers/boards_resolver.rb b/app/graphql/resolvers/boards_resolver.rb index eceb5b38031..82efd92d33f 100644 --- a/app/graphql/resolvers/boards_resolver.rb +++ b/app/graphql/resolvers/boards_resolver.rb @@ -16,7 +16,7 @@ module Resolvers return Board.none unless parent - Boards::ListService.new(parent, context[:current_user], board_id: extract_board_id(id)).execute(create_default_board: false) + ::Boards::ListService.new(parent, context[:current_user], board_id: extract_board_id(id)).execute(create_default_board: false) rescue ActiveRecord::RecordNotFound Board.none end diff --git a/app/graphql/resolvers/ci/runner_platforms_resolver.rb b/app/graphql/resolvers/ci/runner_platforms_resolver.rb new file mode 100644 index 00000000000..9677c5139b4 --- /dev/null +++ b/app/graphql/resolvers/ci/runner_platforms_resolver.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Resolvers + module Ci + class RunnerPlatformsResolver < BaseResolver + type Types::Ci::RunnerPlatformType, null: false + + def resolve(**args) + runner_instructions.map do |platform, data| + { + name: platform, human_readable_name: data[:human_readable_name], + architectures: parse_architectures(data[:download_locations]) + } + end + end + + private + + def runner_instructions + Gitlab::Ci::RunnerInstructions::OS.merge(Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS) + end + + def parse_architectures(download_locations) + download_locations&.map do |architecture, download_location| + { name: architecture, download_location: download_location } + end + end + end + end +end diff --git a/app/graphql/resolvers/concerns/group_issuable_resolver.rb b/app/graphql/resolvers/concerns/group_issuable_resolver.rb new file mode 100644 index 00000000000..49a79683e9f --- /dev/null +++ b/app/graphql/resolvers/concerns/group_issuable_resolver.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module GroupIssuableResolver + extend ActiveSupport::Concern + + class_methods do + def include_subgroups(name_of_things) + argument :include_subgroups, GraphQL::BOOLEAN_TYPE, + required: false, + default_value: false, + description: "Include #{name_of_things} belonging to subgroups" + end + end +end diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb index 2b14d8275d1..fe6fa0bb262 100644 --- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb +++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb @@ -18,9 +18,15 @@ module IssueResolverArguments argument :milestone_title, GraphQL::STRING_TYPE.to_list_type, required: false, description: 'Milestone applied to this issue' + argument :author_username, GraphQL::STRING_TYPE, + required: false, + description: 'Username of the author of the issue' argument :assignee_username, GraphQL::STRING_TYPE, required: false, description: 'Username of a user assigned to the issue' + argument :assignee_usernames, [GraphQL::STRING_TYPE], + required: false, + 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' diff --git a/app/graphql/resolvers/concerns/looks_ahead.rb b/app/graphql/resolvers/concerns/looks_ahead.rb index e7230287e13..61f23920ebb 100644 --- a/app/graphql/resolvers/concerns/looks_ahead.rb +++ b/app/graphql/resolvers/concerns/looks_ahead.rb @@ -3,8 +3,6 @@ module LooksAhead extend ActiveSupport::Concern - FEATURE_FLAG = :graphql_lookahead_support - included do attr_accessor :lookahead end @@ -16,8 +14,6 @@ module LooksAhead end def apply_lookahead(query) - return query unless Feature.enabled?(FEATURE_FLAG) - selection = node_selection includes = preloads.each.flat_map do |name, requirements| diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb index 0c01efd4f9a..ab83476ddea 100644 --- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb +++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb @@ -12,7 +12,7 @@ module ResolvesMergeRequests def resolve_with_lookahead(**args) mr_finder = MergeRequestsFinder.new(current_user, args.compact) - finder = Gitlab::Graphql::Loaders::IssuableLoader.new(project, mr_finder) + finder = Gitlab::Graphql::Loaders::IssuableLoader.new(mr_parent, mr_finder) select_result(finder.batching_find_all { |query| apply_lookahead(query) }) end @@ -29,6 +29,10 @@ module ResolvesMergeRequests private + def mr_parent + project + end + def unconditional_includes [:target_project] end @@ -40,7 +44,8 @@ module ResolvesMergeRequests author: [:author], merged_at: [:metrics], commit_count: [:metrics], - approved_by: [:approver_users], + diff_stats_summary: [:metrics], + approved_by: [:approved_by_users], milestone: [:milestone], head_pipeline: [:merge_request_diff, { head_pipeline: [:merge_request] }] } diff --git a/app/graphql/resolvers/concerns/time_frame_arguments.rb b/app/graphql/resolvers/concerns/time_frame_arguments.rb index ef333dd05a5..94bfe6f7f9f 100644 --- a/app/graphql/resolvers/concerns/time_frame_arguments.rb +++ b/app/graphql/resolvers/concerns/time_frame_arguments.rb @@ -3,21 +3,33 @@ module TimeFrameArguments extend ActiveSupport::Concern + OVERLAPPING_TIMEFRAME_DESC = 'List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present)' + included do argument :start_date, Types::TimeType, required: false, - description: 'List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)' + description: OVERLAPPING_TIMEFRAME_DESC, + deprecated: { reason: 'Use timeframe.start', milestone: '13.5' } argument :end_date, Types::TimeType, required: false, - description: 'List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)' + description: OVERLAPPING_TIMEFRAME_DESC, + deprecated: { reason: 'Use timeframe.end', milestone: '13.5' } + + argument :timeframe, Types::TimeframeInputType, + required: false, + description: 'List items overlapping the given timeframe' end + # TODO: remove when the start_date and end_date arguments are removed def validate_timeframe_params!(args) - return unless args[:start_date].present? || args[:end_date].present? + return unless %i[start_date end_date timeframe].any? { |k| args[k].present? } + return if args[:timeframe] && %i[start_date end_date].all? { |k| args[k].nil? } error_message = - if args[:start_date].nil? || args[:end_date].nil? + if args[:timeframe].present? + "startDate and endDate are deprecated in favor of timeframe. Please use only timeframe." + elsif args[:start_date].nil? || args[:end_date].nil? "Both startDate and endDate must be present." elsif args[:start_date] > args[:end_date] "startDate is after endDate" diff --git a/app/graphql/resolvers/group_issues_resolver.rb b/app/graphql/resolvers/group_issues_resolver.rb index ac51011eea8..1fa6c78e730 100644 --- a/app/graphql/resolvers/group_issues_resolver.rb +++ b/app/graphql/resolvers/group_issues_resolver.rb @@ -2,9 +2,8 @@ module Resolvers class GroupIssuesResolver < IssuesResolver - argument :include_subgroups, GraphQL::BOOLEAN_TYPE, - required: false, - default_value: false, - description: 'Include issues belonging to subgroups.' + include GroupIssuableResolver + + include_subgroups 'issues' end end diff --git a/app/graphql/resolvers/group_merge_requests_resolver.rb b/app/graphql/resolvers/group_merge_requests_resolver.rb new file mode 100644 index 00000000000..5ee72e3f781 --- /dev/null +++ b/app/graphql/resolvers/group_merge_requests_resolver.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Resolvers + class GroupMergeRequestsResolver < MergeRequestsResolver + include GroupIssuableResolver + + alias_method :group, :synchronized_object + + include_subgroups 'merge requests' + accept_assignee + accept_author + + def project + nil + end + + def mr_parent + group + end + + def no_results_possible?(args) + group.nil? || some_argument_is_empty?(args) + end + end +end diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb index 677f84e5795..cb4a76243ae 100644 --- a/app/graphql/resolvers/merge_requests_resolver.rb +++ b/app/graphql/resolvers/merge_requests_resolver.rb @@ -6,6 +6,18 @@ module Resolvers alias_method :project, :synchronized_object + def self.accept_assignee + argument :assignee_username, GraphQL::STRING_TYPE, + required: false, + description: 'Username of the assignee' + end + + def self.accept_author + argument :author_username, GraphQL::STRING_TYPE, + required: false, + description: 'Username of the author' + end + argument :iids, [GraphQL::STRING_TYPE], required: false, description: 'Array of IIDs of merge requests, for example `[1, 2]`' diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb index 5f80506c01b..84712b674db 100644 --- a/app/graphql/resolvers/milestones_resolver.rb +++ b/app/graphql/resolvers/milestones_resolver.rb @@ -13,6 +13,18 @@ module Resolvers required: false, description: 'Filter milestones by state' + argument :title, GraphQL::STRING_TYPE, + required: false, + description: 'The title of the milestone' + + argument :search_title, GraphQL::STRING_TYPE, + required: false, + description: 'A search string for the title' + + argument :containing_date, Types::TimeType, + required: false, + description: 'A date that the milestone contains' + type Types::MilestoneType, null: true def resolve(**args) @@ -29,9 +41,18 @@ module Resolvers { ids: parse_gids(args[:ids]), state: args[:state] || 'all', - start_date: args[:start_date], - end_date: args[:end_date] - }.merge(parent_id_parameters(args)) + title: args[:title], + search_title: args[:search_title], + containing_date: args[:containing_date] + }.merge!(timeframe_parameters(args)).merge!(parent_id_parameters(args)) + end + + def timeframe_parameters(args) + if args[:timeframe] + args[:timeframe].transform_keys { |k| :"#{k}_date" } + else + args.slice(:start_date, :end_date) + end end def parent diff --git a/app/graphql/resolvers/project_merge_requests_resolver.rb b/app/graphql/resolvers/project_merge_requests_resolver.rb index 0526ccd315f..ba13cb6e52c 100644 --- a/app/graphql/resolvers/project_merge_requests_resolver.rb +++ b/app/graphql/resolvers/project_merge_requests_resolver.rb @@ -2,11 +2,7 @@ module Resolvers class ProjectMergeRequestsResolver < MergeRequestsResolver - argument :assignee_username, GraphQL::STRING_TYPE, - required: false, - description: 'Username of the assignee' - argument :author_username, GraphQL::STRING_TYPE, - required: false, - description: 'Username of the author' + accept_assignee + accept_author end end diff --git a/app/graphql/resolvers/projects/jira_projects_resolver.rb b/app/graphql/resolvers/projects/jira_projects_resolver.rb index ed382ac82d0..d017f973e17 100644 --- a/app/graphql/resolvers/projects/jira_projects_resolver.rb +++ b/app/graphql/resolvers/projects/jira_projects_resolver.rb @@ -22,7 +22,7 @@ module Resolvers projects_array, # override default max_page_size to whatever the size of the response is, # see https://gitlab.com/gitlab-org/gitlab/-/issues/231394 - args.merge({ max_page_size: projects_array.size }) + **args.merge({ max_page_size: projects_array.size }) ) else raise Gitlab::Graphql::Errors::BaseError, response.message diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb index 3bbadf87a71..69438229a50 100644 --- a/app/graphql/resolvers/projects_resolver.rb +++ b/app/graphql/resolvers/projects_resolver.rb @@ -13,8 +13,16 @@ module Resolvers description: 'Search query for project name, path, or description' argument :ids, [GraphQL::ID_TYPE], - required: false, - description: 'Filter projects by IDs' + required: false, + description: 'Filter projects by IDs' + + argument :search_namespaces, GraphQL::BOOLEAN_TYPE, + required: false, + description: 'Include namespace in project search' + + argument :sort, GraphQL::STRING_TYPE, + required: false, + description: 'Sort order of results' def resolve(**args) ProjectsFinder @@ -28,7 +36,9 @@ module Resolvers { without_deleted: true, non_public: params[:membership], - search: params[:search] + search: params[:search], + search_namespaces: params[:search_namespaces], + sort: params[:sort] }.compact end diff --git a/app/graphql/resolvers/snippets/blobs_resolver.rb b/app/graphql/resolvers/snippets/blobs_resolver.rb new file mode 100644 index 00000000000..dc28358cab6 --- /dev/null +++ b/app/graphql/resolvers/snippets/blobs_resolver.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Resolvers + module Snippets + class BlobsResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + + alias_method :snippet, :object + + argument :paths, [GraphQL::STRING_TYPE], + required: false, + description: 'Paths of the blobs' + + def resolve(**args) + authorize!(snippet) + + return [snippet.blob] if snippet.empty_repo? + + paths = Array(args.fetch(:paths, [])) + + if paths.empty? + snippet.blobs + else + snippet.repository.blobs_at(transformed_blob_paths(paths)) + end + end + + def authorized_resource?(snippet) + Ability.allowed?(context[:current_user], :read_snippet, snippet) + end + + private + + def transformed_blob_paths(paths) + ref = snippet.default_branch + paths.map { |path| [ref, path] } + end + end + end +end diff --git a/app/graphql/resolvers/terraform/states_resolver.rb b/app/graphql/resolvers/terraform/states_resolver.rb new file mode 100644 index 00000000000..38b26a948b1 --- /dev/null +++ b/app/graphql/resolvers/terraform/states_resolver.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Resolvers + module Terraform + class StatesResolver < BaseResolver + type Types::Terraform::StateType, null: true + + alias_method :project, :object + + def resolve(**args) + return ::Terraform::State.none unless can_read_terraform_states? + + project.terraform_states.ordered_by_name + end + + private + + def can_read_terraform_states? + current_user.can?(:read_terraform_state, project) + end + end + end +end |