diff options
Diffstat (limited to 'app/graphql')
32 files changed, 337 insertions, 56 deletions
diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb index 577f10545b3..ac5ddc5bd4c 100644 --- a/app/graphql/mutations/base_mutation.rb +++ b/app/graphql/mutations/base_mutation.rb @@ -4,6 +4,7 @@ module Mutations class BaseMutation < GraphQL::Schema::RelayClassicMutation prepend Gitlab::Graphql::Authorize::AuthorizeResource prepend Gitlab::Graphql::CopyFieldDescription + prepend ::Gitlab::Graphql::GlobalIDCompatibility ERROR_MESSAGE = 'You cannot perform write operations on a read-only instance' diff --git a/app/graphql/mutations/boards/lists/destroy.rb b/app/graphql/mutations/boards/lists/destroy.rb new file mode 100644 index 00000000000..61ffae7c047 --- /dev/null +++ b/app/graphql/mutations/boards/lists/destroy.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Mutations + module Boards + module Lists + class Destroy < ::Mutations::BaseMutation + graphql_name 'DestroyBoardList' + + field :list, + Types::BoardListType, + null: true, + description: 'The list after mutation.' + + argument :list_id, ::Types::GlobalIDType[::List], + required: true, + loads: Types::BoardListType, + description: 'Global ID of the list to destroy. Only label lists are accepted.' + + def resolve(list:) + raise_resource_not_available_error! unless can_admin_list?(list) + + response = ::Boards::Lists::DestroyService.new(list.board.resource_parent, current_user) + .execute(list) + + { + list: response.success? ? nil : list, + errors: response.errors + } + end + + private + + def can_admin_list?(list) + return false unless list.present? + + Ability.allowed?(current_user, :admin_list, list.board) + end + end + end + end +end diff --git a/app/graphql/mutations/ci/base.rb b/app/graphql/mutations/ci/base.rb index 09df4487a50..aaece2a3021 100644 --- a/app/graphql/mutations/ci/base.rb +++ b/app/graphql/mutations/ci/base.rb @@ -3,13 +3,18 @@ module Mutations module Ci class Base < BaseMutation - argument :id, ::Types::GlobalIDType[::Ci::Pipeline], + PipelineID = ::Types::GlobalIDType[::Ci::Pipeline] + + argument :id, PipelineID, required: true, description: 'The id of the pipeline to mutate' private def find_object(id:) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = PipelineID.coerce_isolated_input(id) GlobalID::Locator.locate(id) end end diff --git a/app/graphql/mutations/design_management/move.rb b/app/graphql/mutations/design_management/move.rb index 6126af8b68b..43e2e542408 100644 --- a/app/graphql/mutations/design_management/move.rb +++ b/app/graphql/mutations/design_management/move.rb @@ -21,7 +21,7 @@ module Mutations description: "The current state of the collection" def resolve(**args) - service = ::DesignManagement::MoveDesignsService.new(current_user, parameters(args)) + service = ::DesignManagement::MoveDesignsService.new(current_user, parameters(**args)) { design_collection: service.collection, errors: service.execute.errors } end @@ -29,11 +29,18 @@ module Mutations private def parameters(**args) - args.transform_values { |id| GitlabSchema.find_by_gid(id) }.transform_values(&:sync).tap do |hash| + args.transform_values { |id| find_design(id) }.transform_values(&:sync).tap do |hash| hash.each { |k, design| not_found(args[k]) unless current_user.can?(:read_design, design) } end end + def find_design(id) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = DesignID.coerce_isolated_input(id) + GitlabSchema.object_from_id(id) + end + def not_found(gid) raise Gitlab::Graphql::Errors::ResourceNotAvailable, "Resource not available: #{gid}" end diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb index f99688aeac6..6f316e76e2a 100644 --- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb +++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb @@ -80,7 +80,7 @@ module Mutations raise Gitlab::Graphql::Errors::ArgumentError, ANNOTATION_SOURCE_ARGUMENT_ERROR end - super(args) + super(**args) end def find_object(id:) diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb index 791c6eab42f..5d29d0bd437 100644 --- a/app/graphql/resolvers/base_resolver.rb +++ b/app/graphql/resolvers/base_resolver.rb @@ -4,6 +4,7 @@ module Resolvers class BaseResolver < GraphQL::Schema::Resolver extend ::Gitlab::Utils::Override include ::Gitlab::Utils::StrongMemoize + include ::Gitlab::Graphql::GlobalIDCompatibility 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..ccb09e29f07 100644 --- a/app/graphql/resolvers/board_lists_resolver.rb +++ b/app/graphql/resolvers/board_lists_resolver.rb @@ -27,7 +27,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..e42cb427c0c --- /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, GraphQL::ID_TYPE, + 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/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..3d845c8e9df 100644 --- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb +++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb @@ -40,7 +40,7 @@ module ResolvesMergeRequests author: [:author], merged_at: [:metrics], commit_count: [:metrics], - approved_by: [:approver_users], + approved_by: [:approved_by_users], milestone: [:milestone], head_pipeline: [:merge_request_diff, { head_pipeline: [:merge_request] }] } diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb index 3bbadf87a71..f6afe945fe8 100644 --- a/app/graphql/resolvers/projects_resolver.rb +++ b/app/graphql/resolvers/projects_resolver.rb @@ -16,6 +16,10 @@ module Resolvers required: false, description: 'Filter projects by IDs' + argument :search_namespaces, GraphQL::BOOLEAN_TYPE, + required: false, + description: 'Include namespace in project search' + def resolve(**args) ProjectsFinder .new(current_user: current_user, params: project_finder_params(args), project_ids_relation: parse_gids(args[:ids])) @@ -28,7 +32,8 @@ module Resolvers { without_deleted: true, non_public: params[:membership], - search: params[:search] + search: params[:search], + search_namespaces: params[:search_namespaces] }.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 diff --git a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb index 13c67442c2e..b9f7f616e13 100644 --- a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb +++ b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb @@ -14,6 +14,10 @@ module Types value 'MERGE_REQUESTS', 'Merge request count', value: :merge_requests value 'GROUPS', 'Group count', value: :groups value 'PIPELINES', 'Pipeline count', value: :pipelines + value 'PIPELINES_SUCCEEDED', 'Pipeline count with success status', value: :pipelines_succeeded + value 'PIPELINES_FAILED', 'Pipeline count with failed status', value: :pipelines_failed + value 'PIPELINES_CANCELED', 'Pipeline count with canceled status', value: :pipelines_canceled + value 'PIPELINES_SKIPPED', 'Pipeline count with skipped status', value: :pipelines_skipped end end end diff --git a/app/graphql/types/design_management/design_collection_copy_state_enum.rb b/app/graphql/types/design_management/design_collection_copy_state_enum.rb new file mode 100644 index 00000000000..7e7303c50ef --- /dev/null +++ b/app/graphql/types/design_management/design_collection_copy_state_enum.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Types + module DesignManagement + class DesignCollectionCopyStateEnum < BaseEnum + graphql_name 'DesignCollectionCopyState' + description 'Copy state of a DesignCollection' + + DESCRIPTION_VARIANTS = { + in_progress: 'is being copied', + error: 'encountered an error during a copy', + ready: 'has no copy in progress' + }.freeze + + def self.description_variant(copy_state) + DESCRIPTION_VARIANTS[copy_state.to_sym] || + (raise ArgumentError, "Unknown copy state: #{copy_state}") + end + + ::DesignManagement::DesignCollection.state_machines[:copy_state].states.keys.each do |copy_state| + value copy_state.upcase, + value: copy_state.to_s, + description: "The DesignCollection #{description_variant(copy_state)}" + end + end + end +end diff --git a/app/graphql/types/design_management/design_collection_type.rb b/app/graphql/types/design_management/design_collection_type.rb index 904fb270e11..9af1f4db425 100644 --- a/app/graphql/types/design_management/design_collection_type.rb +++ b/app/graphql/types/design_management/design_collection_type.rb @@ -39,6 +39,10 @@ module Types null: true, resolver: ::Resolvers::DesignManagement::DesignResolver, description: 'Find a specific design' + + field :copy_state, ::Types::DesignManagement::DesignCollectionCopyStateEnum, + null: true, + description: 'Copy state of the design collection' end end end diff --git a/app/graphql/types/global_id_type.rb b/app/graphql/types/global_id_type.rb index a3964ba83e1..9ae9ba32c13 100644 --- a/app/graphql/types/global_id_type.rb +++ b/app/graphql/types/global_id_type.rb @@ -1,5 +1,21 @@ # frozen_string_literal: true +module GraphQLExtensions + module ScalarExtensions + # Allow ID to unify with GlobalID Types + def ==(other) + if name == 'ID' && other.is_a?(self.class) && + other.type_class.ancestors.include?(::Types::GlobalIDType) + return true + end + + super + end + end +end + +::GraphQL::ScalarType.prepend(GraphQLExtensions::ScalarExtensions) + module Types class GlobalIDType < BaseScalar graphql_name 'GlobalID' diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 60b2e3c7b6e..9b5fb778f6c 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -64,7 +64,7 @@ module Types Types::BoardType, null: true, description: 'A single board of the group', - resolver: Resolvers::BoardsResolver.single + resolver: Resolvers::BoardResolver field :label, Types::LabelType, diff --git a/app/graphql/types/issue_sort_enum.rb b/app/graphql/types/issue_sort_enum.rb index e458d6e02c5..08762264b1b 100644 --- a/app/graphql/types/issue_sort_enum.rb +++ b/app/graphql/types/issue_sort_enum.rb @@ -8,6 +8,8 @@ module Types value 'DUE_DATE_ASC', 'Due date by ascending order', value: :due_date_asc value 'DUE_DATE_DESC', 'Due date by descending order', value: :due_date_desc value 'RELATIVE_POSITION_ASC', 'Relative position by ascending order', value: :relative_position_asc + value 'SEVERITY_ASC', 'Severity from less critical to more critical', value: :severity_asc + value 'SEVERITY_DESC', 'Severity from more critical to less critical', value: :severity_desc end end diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index d6253f74ce5..487508f448f 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -36,8 +36,7 @@ module Types end field :author, Types::UserType, null: false, - description: 'User that created the issue', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find } + description: 'User that created the issue' field :assignees, Types::UserType.connection_type, null: true, description: 'Assignees of the issue' @@ -45,16 +44,14 @@ module Types field :labels, Types::LabelType.connection_type, null: true, description: 'Labels of the issue' field :milestone, Types::MilestoneType, null: true, - description: 'Milestone of the issue', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } + description: 'Milestone of the issue' field :due_date, Types::TimeType, null: true, description: 'Due date of the issue' field :confidential, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates the issue is confidential' field :discussion_locked, GraphQL::BOOLEAN_TYPE, null: false, - description: 'Indicates discussion is locked on the issue', - resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked } + description: 'Indicates discussion is locked on the issue' field :upvotes, GraphQL::INT_TYPE, null: false, description: 'Number of upvotes the issue has received' @@ -108,6 +105,18 @@ module Types field :severity, Types::IssuableSeverityEnum, null: true, description: 'Severity level of the incident' + + def author + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find + end + + def milestone + Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, object.milestone_id).find + end + + def discussion_locked + !!object.discussion_locked + end end end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 56c88491684..573818b1b7a 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -174,10 +174,6 @@ module Types def commit_count object&.metrics&.commits_count end - - def approvers - object.approver_users - end end end Types::MergeRequestType.prepend_if_ee('::EE::Types::MergeRequestType') diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index b2732d83aac..3a9d5529266 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -18,6 +18,7 @@ module Types mount_mutation Mutations::Boards::Issues::IssueMoveList mount_mutation Mutations::Boards::Lists::Create mount_mutation Mutations::Boards::Lists::Update + mount_mutation Mutations::Boards::Lists::Destroy mount_mutation Mutations::Branches::Create, calls_gitaly: true mount_mutation Mutations::Commits::Create, calls_gitaly: true mount_mutation Mutations::Discussions::ToggleResolve @@ -71,4 +72,5 @@ module Types end ::Types::MutationType.prepend(::Types::DeprecatedMutations) +::Types::MutationType.prepend_if_ee('EE::Types::DeprecatedMutations') ::Types::MutationType.prepend_if_ee('::EE::Types::MutationType') diff --git a/app/graphql/types/notes/noteable_type.rb b/app/graphql/types/notes/noteable_type.rb index 3a16d54f9cd..602634d9292 100644 --- a/app/graphql/types/notes/noteable_type.rb +++ b/app/graphql/types/notes/noteable_type.rb @@ -8,24 +8,24 @@ module Types field :notes, Types::Notes::NoteType.connection_type, null: false, description: "All notes on this noteable" field :discussions, Types::Notes::DiscussionType.connection_type, null: false, description: "All discussions on this noteable" - definition_methods do - def resolve_type(object, context) - case object - when Issue - Types::IssueType - when MergeRequest - Types::MergeRequestType - when Snippet - Types::SnippetType - when ::DesignManagement::Design - Types::DesignManagement::DesignType - when ::AlertManagement::Alert - Types::AlertManagement::AlertType - else - raise "Unknown GraphQL type for #{object}" - end + def self.resolve_type(object, context) + case object + when Issue + Types::IssueType + when MergeRequest + Types::MergeRequestType + when Snippet + Types::SnippetType + when ::DesignManagement::Design + Types::DesignManagement::DesignType + when ::AlertManagement::Alert + Types::AlertManagement::AlertType + else + raise "Unknown GraphQL type for #{object}" end end end end end + +Types::Notes::NoteableType.prepend_if_ee('::EE::Types::Notes::NoteableType') diff --git a/app/graphql/types/project_member_type.rb b/app/graphql/types/project_member_type.rb index f08781238d0..01731531ae2 100644 --- a/app/graphql/types/project_member_type.rb +++ b/app/graphql/types/project_member_type.rb @@ -12,7 +12,10 @@ module Types authorize :read_project field :project, Types::ProjectType, null: true, - description: 'Project that User is a member of', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, obj.source_id).find } + description: 'Project that User is a member of' + + def project + Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.source_id).find + end end end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 0fd54af1538..c7fc193abe8 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -234,7 +234,7 @@ module Types Types::BoardType, null: true, description: 'A single board of the project', - resolver: Resolvers::BoardsResolver.single + resolver: Resolvers::BoardResolver field :jira_imports, Types::JiraImportType.connection_type, @@ -294,6 +294,12 @@ module Types description: 'Title of the label' end + field :terraform_states, + Types::Terraform::StateType.connection_type, + null: true, + description: 'Terraform states associated with the project', + resolver: Resolvers::Terraform::StatesResolver + def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| LabelsFinder diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 447ac63a294..73dd7c57223 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -49,8 +49,7 @@ module Types field :milestone, ::Types::MilestoneType, null: true, - description: 'Find a milestone', - resolve: -> (_obj, args, _ctx) { GitlabSchema.find_by_gid(args[:id]) } do + description: 'Find a milestone' do argument :id, ::Types::GlobalIDType[Milestone], required: true, description: 'Find a milestone by its ID' @@ -86,7 +85,17 @@ module Types end def issue(id:) - GitlabSchema.object_from_id(id, expected_type: ::Issue) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::Issue].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + + def milestone(id:) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[Milestone].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) end end end diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb index db98e62c10a..495c25c1776 100644 --- a/app/graphql/types/snippet_type.rb +++ b/app/graphql/types/snippet_type.rb @@ -24,16 +24,14 @@ module Types field :project, Types::ProjectType, description: 'The project the snippet is associated with', null: true, - authorize: :read_project, - resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, snippet.project_id).find } + authorize: :read_project # Author can be nil in some scenarios. For example, # when the admin setting restricted visibility # level is set to public field :author, Types::UserType, description: 'The owner of the snippet', - null: true, - resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, snippet.author_id).find } + null: true field :file_name, GraphQL::STRING_TYPE, description: 'File Name of the snippet', @@ -69,10 +67,11 @@ module Types null: false, deprecated: { reason: 'Use `blobs`', milestone: '13.3' } - field :blobs, type: [Types::Snippets::BlobType], + field :blobs, type: Types::Snippets::BlobType.connection_type, description: 'Snippet blobs', calls_gitaly: true, - null: false + null: true, + resolver: Resolvers::Snippets::BlobsResolver field :ssh_url_to_repo, type: GraphQL::STRING_TYPE, description: 'SSH URL to the snippet repository', @@ -85,5 +84,13 @@ module Types null: true markdown_field :description_html, null: true, method: :description + + def author + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find + end + + def project + Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find + end end end diff --git a/app/graphql/types/sort_enum.rb b/app/graphql/types/sort_enum.rb index 3245cb33e0d..d0a6eecb672 100644 --- a/app/graphql/types/sort_enum.rb +++ b/app/graphql/types/sort_enum.rb @@ -5,9 +5,16 @@ module Types graphql_name 'Sort' description 'Common sort values' - value 'updated_desc', 'Updated at descending order' - value 'updated_asc', 'Updated at ascending order' - value 'created_desc', 'Created at descending order' - value 'created_asc', 'Created at ascending order' + # Deprecated, as we prefer uppercase enums + # https://gitlab.com/groups/gitlab-org/-/epics/1838 + value 'updated_desc', 'Updated at descending order', deprecated: { reason: 'Use UPDATED_DESC', milestone: '13.5' } + value 'updated_asc', 'Updated at ascending order', deprecated: { reason: 'Use UPDATED_ASC', milestone: '13.5' } + value 'created_desc', 'Created at descending order', deprecated: { reason: 'Use CREATED_DESC', milestone: '13.5' } + value 'created_asc', 'Created at ascending order', deprecated: { reason: 'Use CREATED_ASC', milestone: '13.5' } + + value 'UPDATED_DESC', 'Updated at descending order', value: :updated_desc + value 'UPDATED_ASC', 'Updated at ascending order', value: :updated_asc + value 'CREATED_DESC', 'Created at descending order', value: :created_desc + value 'CREATED_ASC', 'Created at ascending order', value: :created_asc end end diff --git a/app/graphql/types/terraform/state_type.rb b/app/graphql/types/terraform/state_type.rb new file mode 100644 index 00000000000..f25f3a7789b --- /dev/null +++ b/app/graphql/types/terraform/state_type.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Types + module Terraform + class StateType < BaseObject + graphql_name 'TerraformState' + + authorize :read_terraform_state + + field :id, GraphQL::ID_TYPE, + null: false, + description: 'ID of the Terraform state' + + field :name, GraphQL::STRING_TYPE, + null: false, + description: 'Name of the Terraform state' + + field :locked_by_user, Types::UserType, + null: true, + authorize: :read_user, + description: 'The user currently holding a lock on the Terraform state', + resolve: -> (state, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, state.locked_by_user_id).find } + + field :locked_at, Types::TimeType, + null: true, + description: 'Timestamp the Terraform state was locked' + + field :created_at, Types::TimeType, + null: false, + description: 'Timestamp the Terraform state was created' + + field :updated_at, Types::TimeType, + null: false, + description: 'Timestamp the Terraform state was updated' + end + end +end |