diff options
Diffstat (limited to 'app/graphql')
134 files changed, 1339 insertions, 786 deletions
diff --git a/app/graphql/mutations/ci/pipeline/retry.rb b/app/graphql/mutations/ci/pipeline/retry.rb index ee93f99703e..895397a96ab 100644 --- a/app/graphql/mutations/ci/pipeline/retry.rb +++ b/app/graphql/mutations/ci/pipeline/retry.rb @@ -17,10 +17,11 @@ module Mutations pipeline = authorized_find!(id: id) project = pipeline.project - ::Ci::RetryPipelineService.new(project, current_user).execute(pipeline) + service_response = ::Ci::RetryPipelineService.new(project, current_user).execute(pipeline) + { pipeline: pipeline, - errors: errors_on_object(pipeline) + errors: errors_on_object(pipeline) + service_response.errors } end end diff --git a/app/graphql/mutations/ci/runner/delete.rb b/app/graphql/mutations/ci/runner/delete.rb index 21c3d55881c..1713ec0bf6d 100644 --- a/app/graphql/mutations/ci/runner/delete.rb +++ b/app/graphql/mutations/ci/runner/delete.rb @@ -17,20 +17,11 @@ module Mutations def resolve(id:, **runner_attrs) runner = authorized_find!(id) - error = authenticate_delete_runner!(runner) - return { errors: [error] } if error - - ::Ci::UnregisterRunnerService.new(runner).execute + ::Ci::Runners::UnregisterRunnerService.new(runner, current_user).execute { errors: runner.errors.full_messages } end - def authenticate_delete_runner!(runner) - return if current_user.can_admin_all_resources? - - "Runner #{runner.to_global_id} associated with more than one project" if runner.runner_projects.count > 1 - end - def find_object(id) # TODO: remove this line when the compatibility layer is removed # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb index e6123b4283a..3432840f60f 100644 --- a/app/graphql/mutations/ci/runner/update.rb +++ b/app/graphql/mutations/ci/runner/update.rb @@ -53,7 +53,7 @@ module Mutations def resolve(id:, **runner_attrs) runner = authorized_find!(id) - unless ::Ci::UpdateRunnerService.new(runner).update(runner_attrs) + unless ::Ci::Runners::UpdateRunnerService.new(runner).update(runner_attrs) return { runner: nil, errors: runner.errors.full_messages } end diff --git a/app/graphql/mutations/ci/runners_registration_token/reset.rb b/app/graphql/mutations/ci/runners_registration_token/reset.rb index 7976e8fb70d..29ef7aa2e81 100644 --- a/app/graphql/mutations/ci/runners_registration_token/reset.rb +++ b/app/graphql/mutations/ci/runners_registration_token/reset.rb @@ -45,20 +45,19 @@ module Mutations def reset_token(type:, **args) id = args[:id] + scope = nil case type when 'instance_type' raise Gitlab::Graphql::Errors::ArgumentError, "id must not be specified for '#{type}' scope" if id.present? - authorize!(:global) - - ApplicationSetting.current.reset_runners_registration_token! - ApplicationSetting.current_without_cache.runners_registration_token + scope = ApplicationSetting.current + authorize!(scope) when 'group_type', 'project_type' - project_or_group = authorized_find!(type: type, id: id) - project_or_group.reset_runners_token! - project_or_group.runners_token + scope = authorized_find!(type: type, id: id) end + + ::Ci::Runners::ResetRegistrationTokenService.new(scope, current_user).execute if scope end end end diff --git a/app/graphql/mutations/concerns/mutations/spam_protection.rb b/app/graphql/mutations/concerns/mutations/spam_protection.rb index 341067710b2..e61f66c02a5 100644 --- a/app/graphql/mutations/concerns/mutations/spam_protection.rb +++ b/app/graphql/mutations/concerns/mutations/spam_protection.rb @@ -16,30 +16,16 @@ module Mutations private - def spam_action_response(object) - fields = spam_action_response_fields(object) - - # If the SpamActionService detected something as spam, - # this is non-recoverable and the needs_captcha_response - # should not be considered - kind = if fields[:spam] - :spam - elsif fields[:needs_captcha_response] - :needs_captcha_response - end - - [kind, fields] - end - def check_spam_action_response!(object) - kind, fields = spam_action_response(object) + fields = spam_action_response_fields(object) - case kind - when :needs_captcha_response + if fields[:spam] + # If the SpamActionService detected something as spam, this is non-recoverable and the + # needs_captcha_response and other CAPTCHA-related fields should not be returned + raise SpamDisallowedError.new(SPAM_DISALLOWED_MESSAGE, extensions: { spam: true }) + elsif fields[:needs_captcha_response] fields.delete :spam raise NeedsCaptchaResponseError.new(NEEDS_CAPTCHA_RESPONSE_MESSAGE, extensions: fields) - when :spam - raise SpamDisallowedError.new(SPAM_DISALLOWED_MESSAGE, extensions: { spam: true }) else nil end diff --git a/app/graphql/mutations/notes/base.rb b/app/graphql/mutations/notes/base.rb index d6c8121eee7..65bb9e4644c 100644 --- a/app/graphql/mutations/notes/base.rb +++ b/app/graphql/mutations/notes/base.rb @@ -3,6 +3,12 @@ module Mutations module Notes class Base < BaseMutation + QUICK_ACTION_ONLY_WARNING = <<~NB + If the body of the Note contains only quick actions, + the Note will be destroyed during an update, and no Note will be + returned. + NB + field :note, Types::Notes::NoteType, null: true, diff --git a/app/graphql/mutations/notes/create/note.rb b/app/graphql/mutations/notes/create/note.rb index 5a5d62a8c20..1cfc11c6b11 100644 --- a/app/graphql/mutations/notes/create/note.rb +++ b/app/graphql/mutations/notes/create/note.rb @@ -5,12 +5,18 @@ module Mutations module Create class Note < Base graphql_name 'CreateNote' + description "Creates a Note.\n#{QUICK_ACTION_ONLY_WARNING}" argument :discussion_id, ::Types::GlobalIDType[::Discussion], required: false, description: 'Global ID of the discussion this note is in reply to.' + argument :merge_request_diff_head_sha, + GraphQL::Types::String, + required: false, + description: 'SHA of the head commit which is used to ensure that the merge request has not been updated since the request was sent.' + private def create_note_params(noteable, args) @@ -28,7 +34,8 @@ module Mutations end super(noteable, args).merge({ - in_reply_to_discussion_id: discussion_id + in_reply_to_discussion_id: discussion_id, + merge_request_diff_head_sha: args[:merge_request_diff_head_sha] }) end diff --git a/app/graphql/mutations/notes/update/base.rb b/app/graphql/mutations/notes/update/base.rb index 2dfa7b815a1..4c6df2776cc 100644 --- a/app/graphql/mutations/notes/update/base.rb +++ b/app/graphql/mutations/notes/update/base.rb @@ -6,12 +6,6 @@ module Mutations # This is a Base class for the Note update mutations and is not # mounted as a GraphQL mutation itself. class Base < Mutations::Notes::Base - QUICK_ACTION_ONLY_WARNING = <<~NB - If the body of the Note contains only quick actions, - the Note will be destroyed during the update, and no Note will be - returned. - NB - authorize :admin_note argument :id, diff --git a/app/graphql/mutations/saved_replies/base.rb b/app/graphql/mutations/saved_replies/base.rb new file mode 100644 index 00000000000..468263b0f9d --- /dev/null +++ b/app/graphql/mutations/saved_replies/base.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Mutations + module SavedReplies + class Base < BaseMutation + field :saved_reply, Types::SavedReplyType, + null: true, + description: 'Updated saved reply.' + + private + + def present_result(result) + if result.success? + { + saved_reply: result[:saved_reply], + errors: [] + } + else + { + saved_reply: nil, + errors: result.message + } + end + end + + def feature_enabled? + Feature.enabled?(:saved_replies, current_user, default_enabled: :yaml) + end + + def find_object(id) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::Users::SavedReply].coerce_isolated_input(id) + + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/mutations/saved_replies/create.rb b/app/graphql/mutations/saved_replies/create.rb new file mode 100644 index 00000000000..d97461a1c2a --- /dev/null +++ b/app/graphql/mutations/saved_replies/create.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Mutations + module SavedReplies + class Create < Base + graphql_name 'SavedReplyCreate' + + authorize :create_saved_replies + + argument :name, GraphQL::Types::String, + required: true, + description: copy_field_description(Types::SavedReplyType, :name) + + argument :content, GraphQL::Types::String, + required: true, + description: copy_field_description(Types::SavedReplyType, :content) + + def resolve(name:, content:) + raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless feature_enabled? + + result = ::Users::SavedReplies::CreateService.new(current_user: current_user, name: name, content: content).execute + present_result(result) + end + end + end +end diff --git a/app/graphql/mutations/saved_replies/update.rb b/app/graphql/mutations/saved_replies/update.rb new file mode 100644 index 00000000000..bacc6ceb39e --- /dev/null +++ b/app/graphql/mutations/saved_replies/update.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Mutations + module SavedReplies + class Update < Base + graphql_name 'SavedReplyUpdate' + + authorize :update_saved_replies + + argument :id, Types::GlobalIDType[::Users::SavedReply], + required: true, + description: copy_field_description(Types::SavedReplyType, :id) + + argument :name, GraphQL::Types::String, + required: true, + description: copy_field_description(Types::SavedReplyType, :name) + + argument :content, GraphQL::Types::String, + required: true, + description: copy_field_description(Types::SavedReplyType, :content) + + def resolve(id:, name:, content:) + raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless feature_enabled? + + saved_reply = authorized_find!(id) + result = ::Users::SavedReplies::UpdateService.new(current_user: current_user, saved_reply: saved_reply, name: name, content: content).execute + present_result(result) + end + end + end +end diff --git a/app/graphql/mutations/work_items/create.rb b/app/graphql/mutations/work_items/create.rb index 81454db62b1..48f0f470988 100644 --- a/app/graphql/mutations/work_items/create.rb +++ b/app/graphql/mutations/work_items/create.rb @@ -33,7 +33,7 @@ module Mutations def resolve(project_path:, **attributes) project = authorized_find!(project_path) - unless Feature.enabled?(:work_items, project) + unless Feature.enabled?(:work_items, project, default_enabled: :yaml) return { errors: ['`work_items` feature flag disabled for this project'] } end diff --git a/app/graphql/mutations/work_items/create_from_task.rb b/app/graphql/mutations/work_items/create_from_task.rb new file mode 100644 index 00000000000..16d1e646167 --- /dev/null +++ b/app/graphql/mutations/work_items/create_from_task.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + class CreateFromTask < BaseMutation + graphql_name 'WorkItemCreateFromTask' + + include Mutations::SpamProtection + + description "Creates a work item from a task in another work item's description." \ + " Available only when feature flag `work_items` is enabled. This feature is experimental and is subject to change without notice." + + authorize :update_work_item + + argument :id, ::Types::GlobalIDType[::WorkItem], + required: true, + description: 'Global ID of the work item.' + argument :work_item_data, ::Types::WorkItems::ConvertTaskInputType, + required: true, + description: 'Arguments necessary to convert a task into a work item.', + prepare: ->(attributes, _ctx) { attributes.to_h } + + field :work_item, Types::WorkItemType, + null: true, + description: 'Updated work item.' + + field :new_work_item, Types::WorkItemType, + null: true, + description: 'New work item created from task.' + + def resolve(id:, work_item_data:) + work_item = authorized_find!(id: id) + + unless Feature.enabled?(:work_items, work_item.project, default_enabled: :yaml) + return { errors: ['`work_items` feature flag disabled for this project'] } + end + + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + + result = ::WorkItems::CreateFromTaskService.new( + work_item: work_item, + current_user: current_user, + work_item_params: work_item_data, + spam_params: spam_params + ).execute + + check_spam_action_response!(result[:work_item]) if result[:work_item] + + response = { errors: result.errors } + response.merge!(work_item: work_item, new_work_item: result[:work_item]) if result.success? + + response + end + + private + + def find_object(id:) + # TODO: Remove coercion when working on https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::WorkItem].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/mutations/work_items/delete.rb b/app/graphql/mutations/work_items/delete.rb index 71792a802c0..f32354878ec 100644 --- a/app/graphql/mutations/work_items/delete.rb +++ b/app/graphql/mutations/work_items/delete.rb @@ -20,7 +20,7 @@ module Mutations def resolve(id:) work_item = authorized_find!(id: id) - unless Feature.enabled?(:work_items, work_item.project) + unless Feature.enabled?(:work_items, work_item.project, default_enabled: :yaml) return { errors: ['`work_items` feature flag disabled for this project'] } end diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb index 3ab9ba2d502..2700cbdb709 100644 --- a/app/graphql/mutations/work_items/update.rb +++ b/app/graphql/mutations/work_items/update.rb @@ -28,7 +28,7 @@ module Mutations def resolve(id:, **attributes) work_item = authorized_find!(id: id) - unless Feature.enabled?(:work_items, work_item.project) + unless Feature.enabled?(:work_items, work_item.project, default_enabled: :yaml) return { errors: ['`work_items` feature flag disabled for this project'] } end diff --git a/app/graphql/queries/burndown_chart/burnup.query.graphql b/app/graphql/queries/burndown_chart/burnup.query.graphql index 7a389a6def5..0795645f8b7 100644 --- a/app/graphql/queries/burndown_chart/burnup.query.graphql +++ b/app/graphql/queries/burndown_chart/burnup.query.graphql @@ -1,4 +1,9 @@ -query BurnupTimesSeriesData($id: ID!, $isIteration: Boolean = false, $weight: Boolean = false) { +query BurnupTimesSeriesData( + $id: ID! + $isIteration: Boolean = false + $weight: Boolean = false + $fullPath: String +) { milestone(id: $id) @skip(if: $isIteration) { __typename id @@ -37,7 +42,7 @@ query BurnupTimesSeriesData($id: ID!, $isIteration: Boolean = false, $weight: Bo __typename id title - report { + report(fullPath: $fullPath) { __typename burnupTimeSeries { __typename diff --git a/app/graphql/resolvers/blobs_resolver.rb b/app/graphql/resolvers/blobs_resolver.rb index d0eb2deaf48..0704a845bb0 100644 --- a/app/graphql/resolvers/blobs_resolver.rb +++ b/app/graphql/resolvers/blobs_resolver.rb @@ -30,8 +30,17 @@ module Resolvers return [] if repository.empty? ref ||= repository.root_ref + validate_ref(ref) repository.blobs_at(paths.map { |path| [ref, path] }) end + + private + + def validate_ref(ref) + unless Gitlab::GitRefValidator.validate(ref) + raise Gitlab::Graphql::Errors::ArgumentError, 'Ref is not valid' + end + end end end diff --git a/app/graphql/resolvers/ci/config_resolver.rb b/app/graphql/resolvers/ci/config_resolver.rb index 387185b5171..f9d60650443 100644 --- a/app/graphql/resolvers/ci/config_resolver.rb +++ b/app/graphql/resolvers/ci/config_resolver.rb @@ -38,6 +38,8 @@ module Resolvers .validate(content, dry_run: dry_run) response(result).merge(merged_yaml: result.merged_yaml) + rescue GRPC::InvalidArgument => error + Gitlab::ErrorTracking.track_and_raise_exception(error, sha: sha) end private diff --git a/app/graphql/resolvers/concerns/group_issuable_resolver.rb b/app/graphql/resolvers/concerns/group_issuable_resolver.rb index 542ff5374ff..92d22409ff2 100644 --- a/app/graphql/resolvers/concerns/group_issuable_resolver.rb +++ b/app/graphql/resolvers/concerns/group_issuable_resolver.rb @@ -3,12 +3,21 @@ module GroupIssuableResolver extend ActiveSupport::Concern - class_methods do - def include_subgroups(name_of_things) - argument :include_subgroups, GraphQL::Types::Boolean, - required: false, - default_value: false, - description: "Include #{name_of_things} belonging to subgroups" - end + included do + argument :include_subgroups, GraphQL::Types::Boolean, + required: false, + default_value: false, + description: "Include #{issuable_collection_name} belonging to subgroups" + + argument :include_archived, GraphQL::Types::Boolean, + required: false, + default_value: false, + description: "Return #{issuable_collection_name} from archived projects" + end + + def resolve(**args) + args[:non_archived] = !args.delete(:include_archived) + + super end end diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb index 75f1ee478a8..a72b9a09118 100644 --- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb +++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb @@ -51,7 +51,8 @@ module ResolvesMergeRequests milestone: [:milestone], security_auto_fix: [:author], head_pipeline: [:merge_request_diff, { head_pipeline: [:merge_request] }], - timelogs: [:timelogs] + timelogs: [:timelogs], + committers: [merge_request_diff: [:merge_request_diff_commits]] } end end diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb index 42c4c22a938..764ed9b15fd 100644 --- a/app/graphql/resolvers/concerns/resolves_pipelines.rb +++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb @@ -20,11 +20,22 @@ module ResolvesPipelines GraphQL::Types::String, required: false, description: "Filter pipelines by the sha of the commit they are run for." - argument :source, GraphQL::Types::String, required: false, description: "Filter pipelines by their source." + + argument :updated_after, Types::TimeType, + required: false, + description: 'Pipelines updated after this date.' + argument :updated_before, Types::TimeType, + required: false, + description: 'Pipelines updated before this date.' + + argument :username, + GraphQL::Types::String, + required: false, + description: "Filter pipelines by the user that triggered the pipeline." end class_methods do diff --git a/app/graphql/resolvers/group_issues_resolver.rb b/app/graphql/resolvers/group_issues_resolver.rb index 28f9266974f..05c5e803539 100644 --- a/app/graphql/resolvers/group_issues_resolver.rb +++ b/app/graphql/resolvers/group_issues_resolver.rb @@ -3,9 +3,11 @@ module Resolvers class GroupIssuesResolver < BaseIssuesResolver - include GroupIssuableResolver + def self.issuable_collection_name + 'issues' + end - include_subgroups 'issues' + include GroupIssuableResolver def ready?(**args) if args.dig(:not, :release_tag).present? diff --git a/app/graphql/resolvers/group_members/notification_email_resolver.rb b/app/graphql/resolvers/group_members/notification_email_resolver.rb new file mode 100644 index 00000000000..6cff4fbf531 --- /dev/null +++ b/app/graphql/resolvers/group_members/notification_email_resolver.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Resolvers + module GroupMembers + class NotificationEmailResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + + type GraphQL::Types::String, null: true + + def resolve + authorize! + + BatchLoader::GraphQL.for(object.user_id).batch do |user_ids, loader| + User.find(user_ids).each do |user| + loader.call(user.id, user.notification_email_for(object.group)) + end + end + end + + def authorize! + raise_resource_not_available_error! unless user_is_admin? + end + + def user_is_admin? + context[:current_user].present? && context[:current_user].can_admin_all_resources? + end + end + end +end diff --git a/app/graphql/resolvers/group_merge_requests_resolver.rb b/app/graphql/resolvers/group_merge_requests_resolver.rb index 34a4c67bc56..da1b6169c07 100644 --- a/app/graphql/resolvers/group_merge_requests_resolver.rb +++ b/app/graphql/resolvers/group_merge_requests_resolver.rb @@ -2,13 +2,16 @@ module Resolvers class GroupMergeRequestsResolver < MergeRequestsResolver + def self.issuable_collection_name + 'merge requests' + end + include GroupIssuableResolver alias_method :group, :object type Types::MergeRequestType.connection_type, null: true - include_subgroups 'merge requests' accept_assignee accept_author diff --git a/app/graphql/resolvers/topics_resolver.rb b/app/graphql/resolvers/topics_resolver.rb index d8199f3d89b..68e2ff69282 100644 --- a/app/graphql/resolvers/topics_resolver.rb +++ b/app/graphql/resolvers/topics_resolver.rb @@ -10,9 +10,9 @@ module Resolvers def resolve(**args) if args[:search].present? - ::Projects::Topic.search(args[:search]).order_by_total_projects_count + ::Projects::Topic.search(args[:search]).order_by_non_private_projects_count else - ::Projects::Topic.order_by_total_projects_count + ::Projects::Topic.order_by_non_private_projects_count end end end diff --git a/app/graphql/resolvers/work_item_resolver.rb b/app/graphql/resolvers/work_item_resolver.rb new file mode 100644 index 00000000000..7cf52339815 --- /dev/null +++ b/app/graphql/resolvers/work_item_resolver.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Resolvers + class WorkItemResolver < BaseResolver + include Gitlab::Graphql::Authorize::AuthorizeResource + + authorize :read_work_item + + type Types::WorkItemType, null: true + + argument :id, ::Types::GlobalIDType[::WorkItem], required: true, description: 'Global ID of the work item.' + + def resolve(id:) + work_item = authorized_find!(id: id) + return unless Feature.enabled?(:work_items, work_item.project, default_enabled: :yaml) + + work_item + end + + 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 = ::Types::GlobalIDType[::WorkItem].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end +end diff --git a/app/graphql/resolvers/work_items/types_resolver.rb b/app/graphql/resolvers/work_items/types_resolver.rb index b7a32e13423..67a9d57d42f 100644 --- a/app/graphql/resolvers/work_items/types_resolver.rb +++ b/app/graphql/resolvers/work_items/types_resolver.rb @@ -5,10 +5,20 @@ module Resolvers class TypesResolver < BaseResolver type Types::WorkItems::TypeType.connection_type, null: true - def resolve + argument :taskable, ::GraphQL::Types::Boolean, + required: false, + description: 'If `true`, only taskable work item types will be returned.' \ + ' Argument is experimental and can be removed in the future without notice.' + + def resolve(taskable: nil) + return unless Feature.enabled?(:work_items, object, default_enabled: :yaml) + # This will require a finder in the future when groups/projects get their work item types # All groups/projects use the default types for now - ::WorkItems::Type.default.order_by_name_asc + base_scope = ::WorkItems::Type.default + base_scope = base_scope.by_type(:task) if taskable + + base_scope.order_by_name_asc end end end diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb index 7495d46179c..43b7bbb419f 100644 --- a/app/graphql/types/alert_management/alert_type.rb +++ b/app/graphql/types/alert_management/alert_type.rb @@ -9,6 +9,7 @@ module Types present_using ::AlertManagement::AlertPresenter implements(Types::Notes::NoteableInterface) + implements(Types::TodoableInterface) authorize :read_alert_management_alert @@ -127,6 +128,12 @@ module Types null: true, description: 'Alert condition for Prometheus.' + field :web_url, + GraphQL::Types::String, + method: :details_url, + null: false, + description: 'URL of the alert.' + def notes object.ordered_notes end diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb index d70236f16f9..0224aeddac6 100644 --- a/app/graphql/types/base_enum.rb +++ b/app/graphql/types/base_enum.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +# rubocop:disable Graphql/GraphqlNamePosition module Types class BaseEnum < GraphQL::Schema::Enum class CustomValue < GraphQL::Schema::EnumValue @@ -37,7 +38,7 @@ module Types description(enum_mod.description) if use_description enum_mod.definition.each do |key, content| - value(key.to_s.upcase, **content) + value(key.to_s.upcase, value: key.to_s, description: content[:description]) end end # rubocop: enable Graphql/Descriptions diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb index 733006369ea..7f4c49df429 100644 --- a/app/graphql/types/board_list_type.rb +++ b/app/graphql/types/board_list_type.rb @@ -14,18 +14,18 @@ module Types null: false, description: 'ID (global ID) of the list.' - field :title, GraphQL::Types::String, null: false, - description: 'Title of the list.' - field :list_type, GraphQL::Types::String, null: false, - description: 'Type of the list.' - field :position, GraphQL::Types::Int, null: true, - description: 'Position of list within the board.' - field :label, Types::LabelType, null: true, - description: 'Label of the list.' field :collapsed, GraphQL::Types::Boolean, null: true, description: 'Indicates if the list is collapsed for this user.' field :issues_count, GraphQL::Types::Int, null: true, description: 'Count of issues in the list.' + field :label, Types::LabelType, null: true, + description: 'Label of the list.' + field :list_type, GraphQL::Types::String, null: false, + description: 'Type of the list.' + field :position, GraphQL::Types::Int, null: true, + description: 'Position of list within the board.' + field :title, GraphQL::Types::String, null: false, + description: 'Title of the list.' field :issues, ::Types::IssueType.connection_type, null: true, description: 'Board issues.', diff --git a/app/graphql/types/ci/analytics_type.rb b/app/graphql/types/ci/analytics_type.rb index f52b9eae229..a77b8026f86 100644 --- a/app/graphql/types/ci/analytics_type.rb +++ b/app/graphql/types/ci/analytics_type.rb @@ -6,28 +6,28 @@ module Types class AnalyticsType < BaseObject graphql_name 'PipelineAnalytics' - field :week_pipelines_totals, [GraphQL::Types::Int], null: true, - description: 'Total weekly pipeline count.' - field :week_pipelines_successful, [GraphQL::Types::Int], null: true, - description: 'Total weekly successful pipeline count.' - field :week_pipelines_labels, [GraphQL::Types::String], null: true, - description: 'Labels for the weekly pipeline count.' - field :month_pipelines_totals, [GraphQL::Types::Int], null: true, - description: 'Total monthly pipeline count.' - field :month_pipelines_successful, [GraphQL::Types::Int], null: true, - description: 'Total monthly successful pipeline count.' field :month_pipelines_labels, [GraphQL::Types::String], null: true, description: 'Labels for the monthly pipeline count.' - field :year_pipelines_totals, [GraphQL::Types::Int], null: true, - description: 'Total yearly pipeline count.' - field :year_pipelines_successful, [GraphQL::Types::Int], null: true, - description: 'Total yearly successful pipeline count.' - field :year_pipelines_labels, [GraphQL::Types::String], null: true, - description: 'Labels for the yearly pipeline count.' - field :pipeline_times_values, [GraphQL::Types::Int], null: true, - description: 'Pipeline times.' + field :month_pipelines_successful, [GraphQL::Types::Int], null: true, + description: 'Total monthly successful pipeline count.' + field :month_pipelines_totals, [GraphQL::Types::Int], null: true, + description: 'Total monthly pipeline count.' field :pipeline_times_labels, [GraphQL::Types::String], null: true, description: 'Pipeline times labels.' + field :pipeline_times_values, [GraphQL::Types::Int], null: true, + description: 'Pipeline times.' + field :week_pipelines_labels, [GraphQL::Types::String], null: true, + description: 'Labels for the weekly pipeline count.' + field :week_pipelines_successful, [GraphQL::Types::Int], null: true, + description: 'Total weekly successful pipeline count.' + field :week_pipelines_totals, [GraphQL::Types::Int], null: true, + description: 'Total weekly pipeline count.' + field :year_pipelines_labels, [GraphQL::Types::String], null: true, + description: 'Labels for the yearly pipeline count.' + field :year_pipelines_successful, [GraphQL::Types::Int], null: true, + description: 'Total yearly successful pipeline count.' + field :year_pipelines_totals, [GraphQL::Types::Int], null: true, + description: 'Total yearly pipeline count.' end end end diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb index 790deab8f68..e43af6f3e78 100644 --- a/app/graphql/types/ci/ci_cd_setting_type.rb +++ b/app/graphql/types/ci/ci_cd_setting_type.rb @@ -7,18 +7,18 @@ module Types authorize :admin_project + field :job_token_scope_enabled, GraphQL::Types::Boolean, null: true, + description: 'Indicates CI job tokens generated in this project have restricted access to resources.', + method: :job_token_scope_enabled? + field :keep_latest_artifact, GraphQL::Types::Boolean, null: true, + description: 'Whether to keep the latest builds artifacts.', + method: :keep_latest_artifacts_available? field :merge_pipelines_enabled, GraphQL::Types::Boolean, null: true, description: 'Whether merge pipelines are enabled.', method: :merge_pipelines_enabled? field :merge_trains_enabled, GraphQL::Types::Boolean, null: true, description: 'Whether merge trains are enabled.', method: :merge_trains_enabled? - field :keep_latest_artifact, GraphQL::Types::Boolean, null: true, - description: 'Whether to keep the latest builds artifacts.', - method: :keep_latest_artifacts_available? - field :job_token_scope_enabled, GraphQL::Types::Boolean, null: true, - description: 'Indicates CI job tokens generated in this project have restricted access to resources.', - method: :job_token_scope_enabled? field :project, Types::ProjectType, null: true, description: 'Project the CI/CD settings belong to.' end diff --git a/app/graphql/types/ci/config/group_type.rb b/app/graphql/types/ci/config/group_type.rb index e5cb0d4e72f..19076fe9c20 100644 --- a/app/graphql/types/ci/config/group_type.rb +++ b/app/graphql/types/ci/config/group_type.rb @@ -7,10 +7,10 @@ module Types class GroupType < BaseObject graphql_name 'CiConfigGroup' - field :name, GraphQL::Types::String, null: true, - description: 'Name of the job group.' field :jobs, Types::Ci::Config::JobType.connection_type, null: true, description: 'Jobs in group.' + field :name, GraphQL::Types::String, null: true, + description: 'Name of the job group.' field :size, GraphQL::Types::Int, null: true, description: 'Size of the job group.' end diff --git a/app/graphql/types/ci/config/job_type.rb b/app/graphql/types/ci/config/job_type.rb index 4cf6780ef60..20279143635 100644 --- a/app/graphql/types/ci/config/job_type.rb +++ b/app/graphql/types/ci/config/job_type.rb @@ -7,33 +7,33 @@ module Types class JobType < BaseObject graphql_name 'CiConfigJob' - field :name, GraphQL::Types::String, null: true, - description: 'Name of the job.' - field :group_name, GraphQL::Types::String, null: true, - description: 'Name of the job group.' - field :stage, GraphQL::Types::String, null: true, - description: 'Name of the job stage.' - field :needs, Types::Ci::Config::NeedType.connection_type, null: true, - description: 'Builds that must complete before the jobs run.' + field :after_script, [GraphQL::Types::String], null: true, + description: 'Override a set of commands that are executed after the job.' field :allow_failure, GraphQL::Types::Boolean, null: true, description: 'Allow job to fail.' field :before_script, [GraphQL::Types::String], null: true, description: 'Override a set of commands that are executed before the job.' - field :script, [GraphQL::Types::String], null: true, - description: 'Shell script that is executed by a runner.' - field :after_script, [GraphQL::Types::String], null: true, - description: 'Override a set of commands that are executed after the job.' - field :when, GraphQL::Types::String, null: true, - description: 'When to run the job.', - resolver_method: :restrict_when_to_run_jobs field :environment, GraphQL::Types::String, null: true, description: 'Name of an environment to which the job deploys.' field :except, Types::Ci::Config::JobRestrictionType, null: true, description: 'Limit when jobs are not created.' + field :group_name, GraphQL::Types::String, null: true, + description: 'Name of the job group.' + field :name, GraphQL::Types::String, null: true, + description: 'Name of the job.' + field :needs, Types::Ci::Config::NeedType.connection_type, null: true, + description: 'Builds that must complete before the jobs run.' field :only, Types::Ci::Config::JobRestrictionType, null: true, description: 'Jobs are created when these conditions do not apply.' + field :script, [GraphQL::Types::String], null: true, + description: 'Shell script that is executed by a runner.' + field :stage, GraphQL::Types::String, null: true, + description: 'Name of the job stage.' field :tags, [GraphQL::Types::String], null: true, description: 'List of tags that are used to select a runner.' + field :when, GraphQL::Types::String, null: true, + description: 'When to run the job.', + resolver_method: :restrict_when_to_run_jobs def restrict_when_to_run_jobs object[:when] diff --git a/app/graphql/types/ci/config/stage_type.rb b/app/graphql/types/ci/config/stage_type.rb index 7e2aa9470f2..5b1163edac2 100644 --- a/app/graphql/types/ci/config/stage_type.rb +++ b/app/graphql/types/ci/config/stage_type.rb @@ -7,10 +7,10 @@ module Types class StageType < BaseObject graphql_name 'CiConfigStage' - field :name, GraphQL::Types::String, null: true, - description: 'Name of the stage.' field :groups, Types::Ci::Config::GroupType.connection_type, null: true, description: 'Groups of jobs for the stage.' + field :name, GraphQL::Types::String, null: true, + description: 'Name of the stage.' end end end diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb index 4433e921971..e3413551a3f 100644 --- a/app/graphql/types/ci/detailed_status_type.rb +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -6,20 +6,23 @@ module Types class DetailedStatusType < BaseObject graphql_name 'DetailedStatus' - field :id, GraphQL::Types::String, null: false, - description: 'ID for a detailed status.', - extras: [:parent] - field :group, GraphQL::Types::String, null: true, - description: 'Group of the status.' - field :icon, GraphQL::Types::String, null: true, - description: 'Icon of the status.' - field :favicon, GraphQL::Types::String, null: true, - description: 'Favicon of the status.' + field :action, Types::Ci::StatusActionType, null: true, + calls_gitaly: true, + description: 'Action information for the status. This includes method, button title, icon, path, and title.' field :details_path, GraphQL::Types::String, null: true, description: 'Path of the details for the status.' + field :favicon, GraphQL::Types::String, null: true, + description: 'Favicon of the status.' + field :group, GraphQL::Types::String, null: true, + description: 'Group of the status.' field :has_details, GraphQL::Types::Boolean, null: true, description: 'Indicates if the status has further details.', method: :has_details? + field :icon, GraphQL::Types::String, null: true, + description: 'Icon of the status.' + field :id, GraphQL::Types::String, null: false, + description: 'ID for a detailed status.', + extras: [:parent] field :label, GraphQL::Types::String, null: true, calls_gitaly: true, description: 'Label of the status.' @@ -28,9 +31,6 @@ module Types field :tooltip, GraphQL::Types::String, null: true, description: 'Tooltip associated with the status.', method: :status_tooltip - field :action, Types::Ci::StatusActionType, null: true, - calls_gitaly: true, - description: 'Action information for the status. This includes method, button title, icon, path, and title.' def id(parent:) "#{object.id}-#{parent.object.object.id}" diff --git a/app/graphql/types/ci/group_type.rb b/app/graphql/types/ci/group_type.rb index 3ae23ba9bd4..c3c73ef170c 100644 --- a/app/graphql/types/ci/group_type.rb +++ b/app/graphql/types/ci/group_type.rb @@ -6,16 +6,16 @@ module Types class GroupType < BaseObject graphql_name 'CiGroup' + field :detailed_status, Types::Ci::DetailedStatusType, null: true, + description: 'Detailed status of the group.' field :id, GraphQL::Types::String, null: false, description: 'ID for a group.' + field :jobs, Ci::JobType.connection_type, null: true, + description: 'Jobs in group.' field :name, GraphQL::Types::String, null: true, description: 'Name of the job group.' field :size, GraphQL::Types::Int, null: true, description: 'Size of the group.' - field :jobs, Ci::JobType.connection_type, null: true, - description: 'Jobs in group.' - field :detailed_status, Types::Ci::DetailedStatusType, null: true, - description: 'Detailed status of the group.' def detailed_status object.detailed_status(context[:current_user]) diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index 1320b96907e..83054553bd8 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -11,38 +11,38 @@ module Types expose_permissions Types::PermissionTypes::Ci::Job + field :allow_failure, ::GraphQL::Types::Boolean, null: false, + description: 'Whether the job is allowed to fail.' + field :duration, GraphQL::Types::Int, null: true, + description: 'Duration of the job in seconds.' field :id, ::Types::GlobalIDType[::CommitStatus].as('JobID'), null: true, description: 'ID of the job.' - field :pipeline, Types::Ci::PipelineType, null: true, - description: 'Pipeline the job belongs to.' field :name, GraphQL::Types::String, null: true, description: 'Name of the job.' field :needs, BuildNeedType.connection_type, null: true, description: 'References to builds that must complete before the jobs run.' + field :pipeline, Types::Ci::PipelineType, null: true, + description: 'Pipeline the job belongs to.' + field :stage, Types::Ci::StageType, null: true, + description: 'Stage of the job.' field :status, type: ::Types::Ci::JobStatusEnum, null: true, description: "Status of the job." - field :stage, Types::Ci::StageType, null: true, - description: 'Stage of the job.' - field :allow_failure, ::GraphQL::Types::Boolean, null: false, - description: 'Whether the job is allowed to fail.' - field :duration, GraphQL::Types::Int, null: true, - description: 'Duration of the job in seconds.' field :tags, [GraphQL::Types::String], null: true, description: 'Tags for the current job.' # Life-cycle timestamps: field :created_at, Types::TimeType, null: false, description: "When the job was created." - field :queued_at, Types::TimeType, null: true, - description: 'When the job was enqueued and marked as pending.' - field :started_at, Types::TimeType, null: true, - description: 'When the job was started.' field :finished_at, Types::TimeType, null: true, description: 'When a job has finished running.' + field :queued_at, Types::TimeType, null: true, + description: 'When the job was enqueued and marked as pending.' field :scheduled_at, Types::TimeType, null: true, description: 'Schedule for the build.' + field :started_at, Types::TimeType, null: true, + description: 'When the job was started.' # Life-cycle durations: field :queued_duration, @@ -50,40 +50,40 @@ module Types null: true, description: 'How long the job was enqueued before starting.' - field :downstream_pipeline, Types::Ci::PipelineType, null: true, - description: 'Downstream pipeline for a bridge.' - field :previous_stage_jobs_or_needs, Types::Ci::JobNeedUnion.connection_type, null: true, - description: 'Jobs that must complete before the job runs. Returns `BuildNeed`, which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.' - field :detailed_status, Types::Ci::DetailedStatusType, null: true, - description: 'Detailed status of the job.' + field :active, GraphQL::Types::Boolean, null: false, method: :active?, + description: 'Indicates the job is active.' field :artifacts, Types::Ci::JobArtifactType.connection_type, null: true, description: 'Artifacts generated by the job.' - field :short_sha, type: GraphQL::Types::String, null: false, - description: 'Short SHA1 ID of the commit.' - field :scheduling_type, GraphQL::Types::String, null: true, - description: 'Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise.' + field :cancelable, GraphQL::Types::Boolean, null: false, method: :cancelable?, + description: 'Indicates the job can be canceled.' field :commit_path, GraphQL::Types::String, null: true, description: 'Path to the commit that triggered the job.' + field :coverage, GraphQL::Types::Float, null: true, + description: 'Coverage level of the job.' + field :created_by_tag, GraphQL::Types::Boolean, null: false, + description: 'Whether the job was created by a tag.', method: :tag? + field :detailed_status, Types::Ci::DetailedStatusType, null: true, + description: 'Detailed status of the job.' + field :downstream_pipeline, Types::Ci::PipelineType, null: true, + description: 'Downstream pipeline for a bridge.' + field :manual_job, GraphQL::Types::Boolean, null: true, + description: 'Whether the job has a manual action.' + field :playable, GraphQL::Types::Boolean, null: false, method: :playable?, + description: 'Indicates the job can be played.' + field :previous_stage_jobs_or_needs, Types::Ci::JobNeedUnion.connection_type, null: true, + description: 'Jobs that must complete before the job runs. Returns `BuildNeed`, which is the needed jobs if the job uses the `needs` keyword, or the previous stage jobs otherwise.' field :ref_name, GraphQL::Types::String, null: true, description: 'Ref name of the job.' field :ref_path, GraphQL::Types::String, null: true, description: 'Path to the ref.' - field :playable, GraphQL::Types::Boolean, null: false, method: :playable?, - description: 'Indicates the job can be played.' field :retryable, GraphQL::Types::Boolean, null: false, method: :retryable?, description: 'Indicates the job can be retried.' - field :cancelable, GraphQL::Types::Boolean, null: false, method: :cancelable?, - description: 'Indicates the job can be canceled.' - field :active, GraphQL::Types::Boolean, null: false, method: :active?, - description: 'Indicates the job is active.' + field :scheduling_type, GraphQL::Types::String, null: true, + description: 'Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise.' + field :short_sha, type: GraphQL::Types::String, null: false, + description: 'Short SHA1 ID of the commit.' field :stuck, GraphQL::Types::Boolean, null: false, method: :stuck?, description: 'Indicates the job is stuck.' - field :coverage, GraphQL::Types::Float, null: true, - description: 'Coverage level of the job.' - field :created_by_tag, GraphQL::Types::Boolean, null: false, - description: 'Whether the job was created by a tag.' - field :manual_job, GraphQL::Types::Boolean, null: true, - description: 'Whether the job has a manual action.' field :triggered, GraphQL::Types::Boolean, null: true, description: 'Whether the job was triggered.' @@ -173,10 +173,6 @@ module Types object&.coverage end - def created_by_tag - object.tag? - end - def manual_job object.try(:action?) end diff --git a/app/graphql/types/ci/runner_architecture_type.rb b/app/graphql/types/ci/runner_architecture_type.rb index 08d3f98592b..eb576cf09ce 100644 --- a/app/graphql/types/ci/runner_architecture_type.rb +++ b/app/graphql/types/ci/runner_architecture_type.rb @@ -6,10 +6,10 @@ module Types class RunnerArchitectureType < BaseObject graphql_name 'RunnerArchitecture' - field :name, GraphQL::Types::String, null: false, - description: 'Name of the runner platform architecture.' field :download_location, GraphQL::Types::String, null: false, description: 'Download location for the runner for the platform architecture.' + field :name, GraphQL::Types::String, null: false, + description: 'Name of the runner platform architecture.' end end end diff --git a/app/graphql/types/ci/runner_platform_type.rb b/app/graphql/types/ci/runner_platform_type.rb index ffcf6364968..3c893615b20 100644 --- a/app/graphql/types/ci/runner_platform_type.rb +++ b/app/graphql/types/ci/runner_platform_type.rb @@ -6,12 +6,12 @@ module Types class RunnerPlatformType < BaseObject graphql_name 'RunnerPlatform' - field :name, GraphQL::Types::String, null: false, - description: 'Name slug of the runner platform.' - field :human_readable_name, GraphQL::Types::String, null: false, - description: 'Human readable name of the runner platform.' field :architectures, Types::Ci::RunnerArchitectureType.connection_type, null: true, description: 'Runner architectures supported for the platform.' + field :human_readable_name, GraphQL::Types::String, null: false, + description: 'Human readable name of the runner platform.' + field :name, GraphQL::Types::String, null: false, + description: 'Name slug of the runner platform.' end end end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index 9094c6b96e4..a7f0730f07e 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -16,54 +16,20 @@ module Types alias_method :runner, :object - field :id, ::Types::GlobalIDType[::Ci::Runner], null: false, - description: 'ID of the runner.' - field :description, GraphQL::Types::String, null: true, - description: 'Description of the runner.' - field :created_at, Types::TimeType, null: true, - description: 'Timestamp of creation of this runner.' - field :contacted_at, Types::TimeType, null: true, - description: 'Timestamp of last contact from this runner.', - method: :contacted_at - field :token_expires_at, Types::TimeType, null: true, - description: 'Runner token expiration time.', - method: :token_expires_at - field :maximum_timeout, GraphQL::Types::Int, null: true, - description: 'Maximum timeout (in seconds) for jobs processed by the runner.' field :access_level, ::Types::Ci::RunnerAccessLevelEnum, null: false, description: 'Access level of the runner.' field :active, GraphQL::Types::Boolean, null: false, description: 'Indicates the runner is allowed to receive jobs.', deprecated: { reason: 'Use paused', milestone: '14.8' } - field :paused, GraphQL::Types::Boolean, null: false, - description: 'Indicates the runner is paused and not available to run jobs.' - field :status, - Types::Ci::RunnerStatusEnum, - null: false, - description: 'Status of the runner.', - resolver: ::Resolvers::Ci::RunnerStatusResolver - field :version, GraphQL::Types::String, null: true, - description: 'Version of the runner.' - field :short_sha, GraphQL::Types::String, null: true, - description: %q(First eight characters of the runner's token used to authenticate new job requests. Used as the runner's unique ID.) - field :revision, GraphQL::Types::String, null: true, - description: 'Revision of the runner.' - field :locked, GraphQL::Types::Boolean, null: true, - description: 'Indicates the runner is locked.' - field :run_untagged, GraphQL::Types::Boolean, null: false, - description: 'Indicates the runner is able to run untagged jobs.' - field :ip_address, GraphQL::Types::String, null: true, - description: 'IP address of the runner.' - field :runner_type, ::Types::Ci::RunnerTypeEnum, null: false, - description: 'Type of the runner.' - field :tag_list, [GraphQL::Types::String], null: true, - description: 'Tags associated with the runner.' - field :project_count, GraphQL::Types::Int, null: true, - description: 'Number of projects that the runner is associated with.' - field :job_count, GraphQL::Types::Int, null: true, - description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)." field :admin_url, GraphQL::Types::String, null: true, description: 'Admin URL of the runner. Only available for administrators.' + field :contacted_at, Types::TimeType, null: true, + description: 'Timestamp of last contact from this runner.', + method: :contacted_at + field :created_at, Types::TimeType, null: true, + description: 'Timestamp of creation of this runner.' + field :description, GraphQL::Types::String, null: true, + description: 'Description of the runner.' field :edit_admin_url, GraphQL::Types::String, null: true, description: 'Admin form URL of the runner. Only available for administrators.' field :executor_name, GraphQL::Types::String, null: true, @@ -72,12 +38,46 @@ module Types feature_flag: :graphql_ci_runner_executor field :groups, ::Types::GroupType.connection_type, null: true, description: 'Groups the runner is associated with. For group runners only.' - field :projects, ::Types::ProjectType.connection_type, null: true, - description: 'Projects the runner is associated with. For project runners only.' + field :id, ::Types::GlobalIDType[::Ci::Runner], null: false, + description: 'ID of the runner.' + field :ip_address, GraphQL::Types::String, null: true, + description: 'IP address of the runner.' + field :job_count, GraphQL::Types::Int, null: true, + description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)." field :jobs, ::Types::Ci::JobType.connection_type, null: true, description: 'Jobs assigned to the runner.', authorize: :read_builds, resolver: ::Resolvers::Ci::RunnerJobsResolver + field :locked, GraphQL::Types::Boolean, null: true, + description: 'Indicates the runner is locked.' + field :maximum_timeout, GraphQL::Types::Int, null: true, + description: 'Maximum timeout (in seconds) for jobs processed by the runner.' + field :paused, GraphQL::Types::Boolean, null: false, + description: 'Indicates the runner is paused and not available to run jobs.' + field :project_count, GraphQL::Types::Int, null: true, + description: 'Number of projects that the runner is associated with.' + field :projects, ::Types::ProjectType.connection_type, null: true, + description: 'Projects the runner is associated with. For project runners only.' + field :revision, GraphQL::Types::String, null: true, + description: 'Revision of the runner.' + field :run_untagged, GraphQL::Types::Boolean, null: false, + description: 'Indicates the runner is able to run untagged jobs.' + field :runner_type, ::Types::Ci::RunnerTypeEnum, null: false, + description: 'Type of the runner.' + field :short_sha, GraphQL::Types::String, null: true, + description: %q(First eight characters of the runner's token used to authenticate new job requests. Used as the runner's unique ID.) + field :status, + Types::Ci::RunnerStatusEnum, + null: false, + description: 'Status of the runner.', + resolver: ::Resolvers::Ci::RunnerStatusResolver + field :tag_list, [GraphQL::Types::String], null: true, + description: 'Tags associated with the runner.' + field :token_expires_at, Types::TimeType, null: true, + description: 'Runner token expiration time.', + method: :token_expires_at + field :version, GraphQL::Types::String, null: true, + description: 'Version of the runner.' def job_count # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT diff --git a/app/graphql/types/ci/runner_web_url_edge.rb b/app/graphql/types/ci/runner_web_url_edge.rb index 368e16f972c..035d75c22c6 100644 --- a/app/graphql/types/ci/runner_web_url_edge.rb +++ b/app/graphql/types/ci/runner_web_url_edge.rb @@ -6,6 +6,9 @@ module Types class RunnerWebUrlEdge < ::Types::BaseEdge include FindClosest + field :edit_url, GraphQL::Types::String, null: true, + description: 'Web URL of the runner edit page. The value depends on where you put this field in the query. You can use it for projects or groups.', + extras: [:parent] field :web_url, GraphQL::Types::String, null: true, description: 'Web URL of the runner. The value depends on where you put this field in the query. You can use it for projects or groups.', extras: [:parent] @@ -16,14 +19,26 @@ module Types @runner = node.node end + def edit_url(parent:) + runner_url(parent: parent, url_type: :edit_url) + end + def web_url(parent:) + runner_url(parent: parent, url_type: :default) + end + + private + + def runner_url(parent:, url_type: :default) owner = closest_parent([::Types::ProjectType, ::Types::GroupType], parent) + # Only ::Group is supported at the moment, future iterations will include ::Project. + # See https://gitlab.com/gitlab-org/gitlab/-/issues/16338 case owner when ::Group + return Gitlab::Routing.url_helpers.edit_group_runner_url(owner, @runner) if url_type == :edit_url + Gitlab::Routing.url_helpers.group_runner_url(owner, @runner) - when ::Project - Gitlab::Routing.url_helpers.project_runner_url(owner, @runner) end end end diff --git a/app/graphql/types/ci/stage_type.rb b/app/graphql/types/ci/stage_type.rb index 70e78e391a7..dcb3092d15a 100644 --- a/app/graphql/types/ci/stage_type.rb +++ b/app/graphql/types/ci/stage_type.rb @@ -6,17 +6,17 @@ module Types graphql_name 'CiStage' authorize :read_build - field :id, GraphQL::Types::ID, null: false, - description: 'ID of the stage.' - field :name, type: GraphQL::Types::String, null: true, - description: 'Name of the stage.' + field :detailed_status, Types::Ci::DetailedStatusType, null: true, + description: 'Detailed status of the stage.' field :groups, type: Ci::GroupType.connection_type, null: true, extras: [:lookahead], description: 'Group of jobs for the stage.' - field :detailed_status, Types::Ci::DetailedStatusType, null: true, - description: 'Detailed status of the stage.' + field :id, GraphQL::Types::ID, null: false, + description: 'ID of the stage.' field :jobs, Types::Ci::JobType.connection_type, null: true, description: 'Jobs for the stage.' + field :name, type: GraphQL::Types::String, null: true, + description: 'Name of the stage.' field :status, GraphQL::Types::String, null: true, description: 'Status of the pipeline stage.' diff --git a/app/graphql/types/ci/status_action_type.rb b/app/graphql/types/ci/status_action_type.rb index 15e5344e130..26ca3c1438a 100644 --- a/app/graphql/types/ci/status_action_type.rb +++ b/app/graphql/types/ci/status_action_type.rb @@ -5,13 +5,13 @@ module Types class StatusActionType < BaseObject graphql_name 'StatusAction' - field :id, GraphQL::Types::String, null: false, - description: 'ID for a status action.', - extras: [:parent] field :button_title, GraphQL::Types::String, null: true, description: 'Title for the button, for example: Retry this job.' field :icon, GraphQL::Types::String, null: true, description: 'Icon used in the action button.' + field :id, GraphQL::Types::String, null: false, + description: 'ID for a status action.', + extras: [:parent] field :method, GraphQL::Types::String, null: true, description: 'Method for the action, for example: :post.', resolver_method: :action_method diff --git a/app/graphql/types/ci/template_type.rb b/app/graphql/types/ci/template_type.rb index 7e7ee44025f..4f1ec6436de 100644 --- a/app/graphql/types/ci/template_type.rb +++ b/app/graphql/types/ci/template_type.rb @@ -7,10 +7,10 @@ module Types graphql_name 'CiTemplate' description 'GitLab CI/CD configuration template.' - field :name, GraphQL::Types::String, null: false, - description: 'Name of the CI template.' field :content, GraphQL::Types::String, null: false, description: 'Contents of the CI template.' + field :name, GraphQL::Types::String, null: false, + description: 'Name of the CI template.' end end end diff --git a/app/graphql/types/commit_action_type.rb b/app/graphql/types/commit_action_type.rb index 6f6d6a418dc..1aa3a4e7ee1 100644 --- a/app/graphql/types/commit_action_type.rb +++ b/app/graphql/types/commit_action_type.rb @@ -4,17 +4,17 @@ module Types class CommitActionType < BaseInputObject argument :action, type: Types::CommitActionModeEnum, required: true, description: 'Action to perform: create, delete, move, update, or chmod.' - argument :file_path, type: GraphQL::Types::String, required: true, - description: 'Full path to the file.' argument :content, type: GraphQL::Types::String, required: false, description: 'Content of the file.' - argument :previous_path, type: GraphQL::Types::String, required: false, - description: 'Original full path to the file being moved.' - argument :last_commit_id, type: GraphQL::Types::String, required: false, - description: 'Last known file commit ID.' - argument :execute_filemode, type: GraphQL::Types::Boolean, required: false, - description: 'Enables/disables the execute flag on the file.' argument :encoding, type: Types::CommitEncodingEnum, required: false, description: 'Encoding of the file. Default is text.' + argument :execute_filemode, type: GraphQL::Types::Boolean, required: false, + description: 'Enables/disables the execute flag on the file.' + argument :file_path, type: GraphQL::Types::String, required: true, + description: 'Full path to the file.' + argument :last_commit_id, type: GraphQL::Types::String, required: false, + description: 'Last known file commit ID.' + argument :previous_path, type: GraphQL::Types::String, required: false, + description: 'Original full path to the file being moved.' end end diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index 8bc00359ccb..c3a6d6f7faa 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -8,6 +8,8 @@ module Types present_using CommitPresenter + implements(Types::TodoableInterface) + field :id, type: GraphQL::Types::ID, null: false, description: 'ID (global ID) of the commit.' @@ -41,12 +43,12 @@ module Types field :signature_html, type: GraphQL::Types::String, null: true, calls_gitaly: true, description: 'Rendered HTML of the commit signature.' - field :author_name, type: GraphQL::Types::String, null: true, - description: 'Commit authors name.' field :author_email, type: GraphQL::Types::String, null: true, description: "Commit author's email." field :author_gravatar, type: GraphQL::Types::String, null: true, description: 'Commit authors gravatar.' + field :author_name, type: GraphQL::Types::String, null: true, + description: 'Commit authors name.' # models/commit lazy loads the author by email field :author, type: Types::UserType, null: true, diff --git a/app/graphql/types/container_expiration_policy_type.rb b/app/graphql/types/container_expiration_policy_type.rb index 6d6df21fe3f..0e9534be684 100644 --- a/app/graphql/types/container_expiration_policy_type.rb +++ b/app/graphql/types/container_expiration_policy_type.rb @@ -8,14 +8,14 @@ module Types authorize :destroy_container_image + field :cadence, Types::ContainerExpirationPolicyCadenceEnum, null: false, description: 'This container expiration policy schedule.' field :created_at, Types::TimeType, null: false, description: 'Timestamp of when the container expiration policy was created.' - field :updated_at, Types::TimeType, null: false, description: 'Timestamp of when the container expiration policy was updated.' field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether this container expiration policy is enabled.' - field :older_than, Types::ContainerExpirationPolicyOlderThanEnum, null: true, description: 'Tags older that this will expire.' - field :cadence, Types::ContainerExpirationPolicyCadenceEnum, null: false, description: 'This container expiration policy schedule.' field :keep_n, Types::ContainerExpirationPolicyKeepEnum, null: true, description: 'Number of tags to retain.' field :name_regex, Types::UntrustedRegexp, null: true, description: 'Tags with names matching this regex pattern will expire.' field :name_regex_keep, Types::UntrustedRegexp, null: true, description: 'Tags with names matching this regex pattern will be preserved.' field :next_run_at, Types::TimeType, null: true, description: 'Next time that this container expiration policy will get executed.' + field :older_than, Types::ContainerExpirationPolicyOlderThanEnum, null: true, description: 'Tags older that this will expire.' + field :updated_at, Types::TimeType, null: false, description: 'Timestamp of when the container expiration policy was updated.' end end diff --git a/app/graphql/types/container_repository_details_type.rb b/app/graphql/types/container_repository_details_type.rb index e713aaebe36..1ee9e76a1c8 100644 --- a/app/graphql/types/container_repository_details_type.rb +++ b/app/graphql/types/container_repository_details_type.rb @@ -15,8 +15,19 @@ module Types max_page_size: 20, resolver: Resolvers::ContainerRepositoryTagsResolver + field :size, + GraphQL::Types::Float, + null: true, + description: 'Deduplicated size of the image repository in bytes. This is only available on GitLab.com for repositories created after `2021-11-04`.' + def can_delete Ability.allowed?(current_user, :destroy_container_image, object) end + + def size + object.size + rescue Faraday::Error + raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, "Can't connect to the Container Registry. If this error persists, please review the troubleshooting documentation." + end end end diff --git a/app/graphql/types/container_repository_tag_type.rb b/app/graphql/types/container_repository_tag_type.rb index 206d6a3426c..d9665175449 100644 --- a/app/graphql/types/container_repository_tag_type.rb +++ b/app/graphql/types/container_repository_tag_type.rb @@ -8,15 +8,15 @@ module Types authorize :read_container_image + field :can_delete, GraphQL::Types::Boolean, null: false, description: 'Can the current user delete this tag.' + field :created_at, Types::TimeType, null: true, description: 'Timestamp when the tag was created.' + field :digest, GraphQL::Types::String, null: true, description: 'Digest of the tag.' + field :location, GraphQL::Types::String, null: false, description: 'URL of the tag.' field :name, GraphQL::Types::String, null: false, description: 'Name of the tag.' field :path, GraphQL::Types::String, null: false, description: 'Path of the tag.' - field :location, GraphQL::Types::String, null: false, description: 'URL of the tag.' - field :digest, GraphQL::Types::String, null: true, description: 'Digest of the tag.' field :revision, GraphQL::Types::String, null: true, description: 'Revision of the tag.' field :short_revision, GraphQL::Types::String, null: true, description: 'Short revision of the tag.' field :total_size, GraphQL::Types::BigInt, null: true, description: 'Size of the tag.' - field :created_at, Types::TimeType, null: true, description: 'Timestamp when the tag was created.' - field :can_delete, GraphQL::Types::Boolean, null: false, description: 'Can the current user delete this tag.' def can_delete Ability.allowed?(current_user, :destroy_container_image, object) diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb index 1fe5cf112f0..3cd3730010b 100644 --- a/app/graphql/types/container_repository_type.rb +++ b/app/graphql/types/container_repository_type.rb @@ -8,18 +8,18 @@ module Types authorize :read_container_image + field :can_delete, GraphQL::Types::Boolean, null: false, description: 'Can the current user delete the container repository.' + field :created_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was created.' + field :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'Tags cleanup status for the container repository.' + field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.' field :id, GraphQL::Types::ID, null: false, description: 'ID of the container repository.' + field :location, GraphQL::Types::String, null: false, description: 'URL of the container repository.' field :name, GraphQL::Types::String, null: false, description: 'Name of the container repository.' field :path, GraphQL::Types::String, null: false, description: 'Path of the container repository.' - field :location, GraphQL::Types::String, null: false, description: 'URL of the container repository.' - field :created_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was created.' - field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.' - field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.' - field :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'Tags cleanup status for the container repository.' + field :project, Types::ProjectType, null: false, description: 'Project of the container registry.' field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.' field :tags_count, GraphQL::Types::Int, null: false, description: 'Number of tags associated with this image.' - field :can_delete, GraphQL::Types::Boolean, null: false, description: 'Can the current user delete the container repository.' - field :project, Types::ProjectType, null: false, description: 'Project of the container registry.' + field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.' def can_delete Ability.allowed?(current_user, :update_container_image, object) diff --git a/app/graphql/types/dependency_proxy/blob_type.rb b/app/graphql/types/dependency_proxy/blob_type.rb index f5a78fbb3ba..b5cebe516aa 100644 --- a/app/graphql/types/dependency_proxy/blob_type.rb +++ b/app/graphql/types/dependency_proxy/blob_type.rb @@ -9,8 +9,8 @@ module Types authorize :read_dependency_proxy field :created_at, Types::TimeType, null: false, description: 'Date of creation.' - field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' field :file_name, GraphQL::Types::String, null: false, description: 'Name of the blob.' field :size, GraphQL::Types::String, null: false, description: 'Size of the blob file.' + field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' end end diff --git a/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb b/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb index 29bba7122d0..9ab7c50998d 100644 --- a/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb +++ b/app/graphql/types/dependency_proxy/image_ttl_group_policy_type.rb @@ -8,9 +8,9 @@ module Types authorize :read_dependency_proxy + field :created_at, Types::TimeType, null: true, description: 'Timestamp of creation.' field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether the policy is enabled or disabled.' field :ttl, GraphQL::Types::Int, null: true, description: 'Number of days to retain a cached image file.' - field :created_at, Types::TimeType, null: true, description: 'Timestamp of creation.' field :updated_at, Types::TimeType, null: true, description: 'Timestamp of the most recent update.' end end diff --git a/app/graphql/types/dependency_proxy/manifest_type.rb b/app/graphql/types/dependency_proxy/manifest_type.rb index ef9f730df43..ab22f540f48 100644 --- a/app/graphql/types/dependency_proxy/manifest_type.rb +++ b/app/graphql/types/dependency_proxy/manifest_type.rb @@ -8,13 +8,13 @@ module Types authorize :read_dependency_proxy - field :id, ::Types::GlobalIDType[::DependencyProxy::Manifest], null: false, description: 'ID of the manifest.' field :created_at, Types::TimeType, null: false, description: 'Date of creation.' - field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' + field :digest, GraphQL::Types::String, null: false, description: 'Digest of the manifest.' field :file_name, GraphQL::Types::String, null: false, description: 'Name of the manifest.' + field :id, ::Types::GlobalIDType[::DependencyProxy::Manifest], null: false, description: 'ID of the manifest.' field :image_name, GraphQL::Types::String, null: false, description: 'Name of the image.' field :size, GraphQL::Types::String, null: false, description: 'Size of the manifest file.' - field :digest, GraphQL::Types::String, null: false, description: 'Digest of the manifest.' + field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' def image_name object.file_name.chomp(File.extname(object.file_name)) diff --git a/app/graphql/types/design_management/design_collection_type.rb b/app/graphql/types/design_management/design_collection_type.rb index 570eac907f3..91978aa37b0 100644 --- a/app/graphql/types/design_management/design_collection_type.rb +++ b/app/graphql/types/design_management/design_collection_type.rb @@ -8,10 +8,10 @@ module Types authorize :read_design - field :project, Types::ProjectType, null: false, - description: 'Project associated with the design collection.' field :issue, Types::IssueType, null: false, description: 'Issue associated with the design collection.' + field :project, Types::ProjectType, null: false, + description: 'Project associated with the design collection.' field :designs, Types::DesignManagement::DesignType.connection_type, diff --git a/app/graphql/types/design_management/design_fields.rb b/app/graphql/types/design_management/design_fields.rb index 75f1aaa8c60..364f72a519f 100644 --- a/app/graphql/types/design_management/design_fields.rb +++ b/app/graphql/types/design_management/design_fields.rb @@ -62,7 +62,7 @@ module Types def cached_actions_for_version(version) Gitlab::SafeRequestStore.fetch(['DesignFields', 'actions_for_version', version.id]) do - version.actions.to_h { |dv| [dv.design_id, dv] } + version.actions.index_by(&:design_id) end end diff --git a/app/graphql/types/design_management/design_type.rb b/app/graphql/types/design_management/design_type.rb index 2f40bf5ebfd..4c0b1162306 100644 --- a/app/graphql/types/design_management/design_type.rb +++ b/app/graphql/types/design_management/design_type.rb @@ -13,6 +13,12 @@ module Types implements(Types::Notes::NoteableInterface) implements(Types::DesignManagement::DesignFields) implements(Types::CurrentUserTodos) + implements(Types::TodoableInterface) + + field :web_url, + GraphQL::Types::String, + null: false, + description: 'URL of the design.' field :versions, Types::DesignManagement::VersionType.connection_type, @@ -40,6 +46,10 @@ module Types def request_cache_base_key self.class.name end + + def web_url + Gitlab::UrlBuilder.build(object) + end end end end diff --git a/app/graphql/types/diff_paths_input_type.rb b/app/graphql/types/diff_paths_input_type.rb index cdcff1a7e34..c5c75105fda 100644 --- a/app/graphql/types/diff_paths_input_type.rb +++ b/app/graphql/types/diff_paths_input_type.rb @@ -2,9 +2,9 @@ module Types class DiffPathsInputType < BaseInputObject - argument :old_path, GraphQL::Types::String, required: false, - description: 'Path of the file on the start SHA.' argument :new_path, GraphQL::Types::String, required: false, description: 'Path of the file on the HEAD SHA.' + argument :old_path, GraphQL::Types::String, required: false, + description: 'Path of the file on the start SHA.' end end diff --git a/app/graphql/types/diff_refs_type.rb b/app/graphql/types/diff_refs_type.rb index b19d09c789c..a03d72a4dc2 100644 --- a/app/graphql/types/diff_refs_type.rb +++ b/app/graphql/types/diff_refs_type.rb @@ -6,10 +6,10 @@ module Types class DiffRefsType < BaseObject graphql_name 'DiffRefs' - field :head_sha, GraphQL::Types::String, null: false, - description: 'SHA of the HEAD at the time the comment was made.' field :base_sha, GraphQL::Types::String, null: true, description: 'Merge base of the branch the comment was made on.' + field :head_sha, GraphQL::Types::String, null: false, + description: 'SHA of the HEAD at the time the comment was made.' field :start_sha, GraphQL::Types::String, null: false, description: 'SHA of the branch being compared against.' end diff --git a/app/graphql/types/diff_stats_summary_type.rb b/app/graphql/types/diff_stats_summary_type.rb index 079c73d0759..95705ddecf3 100644 --- a/app/graphql/types/diff_stats_summary_type.rb +++ b/app/graphql/types/diff_stats_summary_type.rb @@ -10,10 +10,10 @@ module Types field :additions, GraphQL::Types::Int, null: false, description: 'Number of lines added.' - field :deletions, GraphQL::Types::Int, null: false, - description: 'Number of lines deleted.' field :changes, GraphQL::Types::Int, null: false, description: 'Number of lines changed.' + field :deletions, GraphQL::Types::Int, null: false, + description: 'Number of lines deleted.' field :file_count, GraphQL::Types::Int, null: false, description: 'Number of files changed.' diff --git a/app/graphql/types/diff_stats_type.rb b/app/graphql/types/diff_stats_type.rb index 60aacca8ce5..da366fec8c3 100644 --- a/app/graphql/types/diff_stats_type.rb +++ b/app/graphql/types/diff_stats_type.rb @@ -8,12 +8,12 @@ module Types description 'Changes to a single file' - field :path, GraphQL::Types::String, null: false, - description: 'File path, relative to repository root.' field :additions, GraphQL::Types::Int, null: false, description: 'Number of lines added to this file.' field :deletions, GraphQL::Types::Int, null: false, description: 'Number of lines deleted from this file.' + field :path, GraphQL::Types::String, null: false, + description: 'File path, relative to repository root.' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb index 826ae61a1a3..b19ab80f96d 100644 --- a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb +++ b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb @@ -10,46 +10,68 @@ module Types authorize :read_sentry_issue - field :id, GraphQL::Types::ID, - null: false, - description: 'ID (global ID) of the error.' - field :integrated, GraphQL::Types::Boolean, - null: true, - description: 'Error tracking backend.' - field :sentry_id, GraphQL::Types::String, - method: :id, - null: false, - description: 'ID (Sentry ID) of the error.' - field :title, GraphQL::Types::String, + field :count, GraphQL::Types::Int, null: false, - description: 'Title of the error.' - field :type, GraphQL::Types::String, + description: 'Count of occurrences.' + field :culprit, GraphQL::Types::String, null: false, - description: 'Type of the error.' - field :user_count, GraphQL::Types::Int, + description: 'Culprit of the error.' + field :external_base_url, GraphQL::Types::String, null: false, - description: 'Count of users affected by the error.' - field :count, GraphQL::Types::Int, + description: 'External Base URL of the Sentry Instance.' + field :external_url, GraphQL::Types::String, null: false, - description: 'Count of occurrences.' + description: 'External URL of the error.' + field :first_release_last_commit, GraphQL::Types::String, + null: true, + description: 'Commit the error was first seen.' + field :first_release_short_version, GraphQL::Types::String, + null: true, + description: 'Release short version the error was first seen.' + field :first_release_version, GraphQL::Types::String, + null: true, + description: 'Release version the error was first seen.' field :first_seen, Types::TimeType, null: false, description: 'Timestamp when the error was first seen.' + field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType], + null: false, + description: 'Last 24hr stats of the error.' + field :gitlab_commit, GraphQL::Types::String, + null: true, + description: 'GitLab commit SHA attributed to the Error based on the release version.' + field :gitlab_commit_path, GraphQL::Types::String, + null: true, + description: 'Path to the GitLab page for the GitLab commit attributed to the error.' + field :gitlab_issue_path, GraphQL::Types::String, + method: :gitlab_issue, + null: true, + description: 'URL of GitLab Issue.' + field :id, GraphQL::Types::ID, + null: false, + description: 'ID (global ID) of the error.' + field :integrated, GraphQL::Types::Boolean, + null: true, + description: 'Error tracking backend.' + field :last_release_last_commit, GraphQL::Types::String, + null: true, + description: 'Commit the error was last seen.' + field :last_release_short_version, GraphQL::Types::String, + null: true, + description: 'Release short version the error was last seen.' + field :last_release_version, GraphQL::Types::String, + null: true, + description: 'Release version the error was last seen.' field :last_seen, Types::TimeType, null: false, description: 'Timestamp when the error was last seen.' field :message, GraphQL::Types::String, null: true, description: 'Sentry metadata message of the error.' - field :culprit, GraphQL::Types::String, - null: false, - description: 'Culprit of the error.' - field :external_base_url, GraphQL::Types::String, - null: false, - description: 'External Base URL of the Sentry Instance.' - field :external_url, GraphQL::Types::String, + field :sentry_id, GraphQL::Types::String, + method: :id, null: false, - description: 'External URL of the error.' + description: 'ID (Sentry ID) of the error.' field :sentry_project_id, GraphQL::Types::ID, method: :project_id, null: false, @@ -68,40 +90,18 @@ module Types field :status, Types::ErrorTracking::SentryErrorStatusEnum, null: false, description: 'Status of the error.' - field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType], - null: false, - description: 'Last 24hr stats of the error.' - field :first_release_last_commit, GraphQL::Types::String, - null: true, - description: 'Commit the error was first seen.' - field :last_release_last_commit, GraphQL::Types::String, - null: true, - description: 'Commit the error was last seen.' - field :first_release_short_version, GraphQL::Types::String, - null: true, - description: 'Release short version the error was first seen.' - field :last_release_short_version, GraphQL::Types::String, - null: true, - description: 'Release short version the error was last seen.' - field :first_release_version, GraphQL::Types::String, - null: true, - description: 'Release version the error was first seen.' - field :last_release_version, GraphQL::Types::String, - null: true, - description: 'Release version the error was last seen.' - field :gitlab_commit, GraphQL::Types::String, - null: true, - description: 'GitLab commit SHA attributed to the Error based on the release version.' - field :gitlab_commit_path, GraphQL::Types::String, - null: true, - description: 'Path to the GitLab page for the GitLab commit attributed to the error.' - field :gitlab_issue_path, GraphQL::Types::String, - method: :gitlab_issue, - null: true, - description: 'URL of GitLab Issue.' field :tags, Types::ErrorTracking::SentryErrorTagsType, null: false, description: 'Tags associated with the Sentry Error.' + field :title, GraphQL::Types::String, + null: false, + description: 'Title of the error.' + field :type, GraphQL::Types::String, + null: false, + description: 'Type of the error.' + field :user_count, GraphQL::Types::Int, + null: false, + description: 'Count of users affected by the error.' end end end diff --git a/app/graphql/types/error_tracking/sentry_error_collection_type.rb b/app/graphql/types/error_tracking/sentry_error_collection_type.rb index 2d8c3d3d326..9790560929b 100644 --- a/app/graphql/types/error_tracking/sentry_error_collection_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_collection_type.rb @@ -8,15 +8,15 @@ module Types authorize :read_sentry_issue - field :errors, - description: "Collection of Sentry Errors.", - resolver: Resolvers::ErrorTracking::SentryErrorsResolver field :detailed_error, description: 'Detailed version of a Sentry error on the project.', resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver field :error_stack_trace, description: 'Stack Trace of Sentry Error.', resolver: Resolvers::ErrorTracking::SentryErrorStackTraceResolver + field :errors, + description: "Collection of Sentry Errors.", + resolver: Resolvers::ErrorTracking::SentryErrorsResolver field :external_url, GraphQL::Types::String, null: true, diff --git a/app/graphql/types/error_tracking/sentry_error_frequency_type.rb b/app/graphql/types/error_tracking/sentry_error_frequency_type.rb index 49a1b1e0476..f67becb3774 100644 --- a/app/graphql/types/error_tracking/sentry_error_frequency_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_frequency_type.rb @@ -6,12 +6,12 @@ module Types class SentryErrorFrequencyType < ::Types::BaseObject graphql_name 'SentryErrorFrequency' - field :time, Types::TimeType, - null: false, - description: "Time the error frequency stats were recorded." field :count, GraphQL::Types::Int, null: false, description: "Count of errors received since the previously recorded time." + field :time, Types::TimeType, + null: false, + description: "Time the error frequency stats were recorded." end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb index ad31854b30c..d4b806c4e1e 100644 --- a/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_context_type.rb @@ -7,14 +7,14 @@ module Types graphql_name 'SentryErrorStackTraceContext' description 'An object context for a Sentry error stack trace' - field :line, - GraphQL::Types::Int, - null: false, - description: 'Line number of the context.' field :code, GraphQL::Types::String, null: false, description: 'Code number of the context.' + field :line, + GraphQL::Types::Int, + null: false, + description: 'Line number of the context.' def line object[0] diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb index e8f78004569..c33baa06052 100644 --- a/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb @@ -7,18 +7,18 @@ module Types graphql_name 'SentryErrorStackTraceEntry' description 'An object containing a stack trace entry for a Sentry error' - field :function, GraphQL::Types::String, + field :col, GraphQL::Types::String, null: true, description: 'Function in which the Sentry error occurred.' - field :col, GraphQL::Types::String, + field :file_name, GraphQL::Types::String, + null: true, + description: 'File in which the Sentry error occurred.' + field :function, GraphQL::Types::String, null: true, description: 'Function in which the Sentry error occurred.' field :line, GraphQL::Types::String, null: true, description: 'Function in which the Sentry error occurred.' - field :file_name, GraphQL::Types::String, - null: true, - description: 'File in which the Sentry error occurred.' field :trace_context, [Types::ErrorTracking::SentryErrorStackTraceContextType], null: true, description: 'Context of the Sentry error.' diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb index dff52d77109..5c7aecf16ee 100644 --- a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb @@ -8,12 +8,12 @@ module Types authorize :read_sentry_issue - field :issue_id, GraphQL::Types::String, - null: false, - description: 'ID of the Sentry error.' field :date_received, GraphQL::Types::String, null: false, description: 'Time the stack trace was received by Sentry.' + field :issue_id, GraphQL::Types::String, + null: false, + description: 'ID of the Sentry error.' field :stack_trace_entries, [Types::ErrorTracking::SentryErrorStackTraceEntryType], null: false, description: 'Stack trace entries for the Sentry error.' diff --git a/app/graphql/types/error_tracking/sentry_error_type.rb b/app/graphql/types/error_tracking/sentry_error_type.rb index aaa6cbfb28f..5f871155737 100644 --- a/app/graphql/types/error_tracking/sentry_error_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_type.rb @@ -9,49 +9,34 @@ module Types present_using SentryErrorPresenter - field :id, GraphQL::Types::ID, - null: false, - description: 'ID (global ID) of the error.' - field :sentry_id, GraphQL::Types::String, - method: :id, - null: false, - description: 'ID (Sentry ID) of the error.' - field :first_seen, Types::TimeType, - null: false, - description: 'Timestamp when the error was first seen.' - field :last_seen, Types::TimeType, - null: false, - description: 'Timestamp when the error was last seen.' - field :title, GraphQL::Types::String, - null: false, - description: 'Title of the error.' - field :type, GraphQL::Types::String, - null: false, - description: 'Type of the error.' - field :user_count, GraphQL::Types::Int, - null: false, - description: 'Count of users affected by the error.' field :count, GraphQL::Types::Int, null: false, description: 'Count of occurrences.' - field :message, GraphQL::Types::String, - null: true, - description: 'Sentry metadata message of the error.' field :culprit, GraphQL::Types::String, null: false, description: 'Culprit of the error.' field :external_url, GraphQL::Types::String, null: false, description: 'External URL of the error.' - field :short_id, GraphQL::Types::String, - null: false, - description: 'Short ID (Sentry ID) of the error.' - field :status, Types::ErrorTracking::SentryErrorStatusEnum, + field :first_seen, Types::TimeType, null: false, - description: 'Status of the error.' + description: 'Timestamp when the error was first seen.' field :frequency, [Types::ErrorTracking::SentryErrorFrequencyType], null: false, description: 'Last 24hr stats of the error.' + field :id, GraphQL::Types::ID, + null: false, + description: 'ID (global ID) of the error.' + field :last_seen, Types::TimeType, + null: false, + description: 'Timestamp when the error was last seen.' + field :message, GraphQL::Types::String, + null: true, + description: 'Sentry metadata message of the error.' + field :sentry_id, GraphQL::Types::String, + method: :id, + null: false, + description: 'ID (Sentry ID) of the error.' field :sentry_project_id, GraphQL::Types::ID, method: :project_id, null: false, @@ -64,6 +49,21 @@ module Types method: :project_slug, null: false, description: 'Slug of the project affected by the error.' + field :short_id, GraphQL::Types::String, + null: false, + description: 'Short ID (Sentry ID) of the error.' + field :status, Types::ErrorTracking::SentryErrorStatusEnum, + null: false, + description: 'Status of the error.' + field :title, GraphQL::Types::String, + null: false, + description: 'Title of the error.' + field :type, GraphQL::Types::String, + null: false, + description: 'Type of the error.' + field :user_count, GraphQL::Types::Int, + null: false, + description: 'Count of users affected by the error.' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/evidence_type.rb b/app/graphql/types/evidence_type.rb index 33f46c712f1..ed644a4b2c6 100644 --- a/app/graphql/types/evidence_type.rb +++ b/app/graphql/types/evidence_type.rb @@ -9,13 +9,13 @@ module Types present_using Releases::EvidencePresenter + field :collected_at, Types::TimeType, null: true, + description: 'Timestamp when the evidence was collected.' + field :filepath, GraphQL::Types::String, null: true, + description: 'URL from where the evidence can be downloaded.' field :id, GraphQL::Types::ID, null: false, description: 'ID of the evidence.' field :sha, GraphQL::Types::String, null: true, description: 'SHA1 ID of the evidence hash.' - field :filepath, GraphQL::Types::String, null: true, - description: 'URL from where the evidence can be downloaded.' - field :collected_at, Types::TimeType, null: true, - description: 'Timestamp when the evidence was collected.' end end diff --git a/app/graphql/types/global_id_type.rb b/app/graphql/types/global_id_type.rb index c44c268b43f..4f92b5e8cc2 100644 --- a/app/graphql/types/global_id_type.rb +++ b/app/graphql/types/global_id_type.rb @@ -49,7 +49,11 @@ module Types # Construct a restricted type, that can only be inhabited by an ID of # a given model class. def self.[](model_class) - @id_types ||= {} + @id_types ||= { + # WorkItem has a special class as we want to allow IssueID + # on WorkItemID while we transition into work items + ::WorkItem => ::Types::WorkItemIdType + } @id_types[model_class] ||= Class.new(self) do model_name = model_class.name diff --git a/app/graphql/types/grafana_integration_type.rb b/app/graphql/types/grafana_integration_type.rb index 26fefd51e08..2bbc0d34db6 100644 --- a/app/graphql/types/grafana_integration_type.rb +++ b/app/graphql/types/grafana_integration_type.rb @@ -6,14 +6,14 @@ module Types authorize :admin_operations - field :id, GraphQL::Types::ID, null: false, - description: 'Internal ID of the Grafana integration.' - field :grafana_url, GraphQL::Types::String, null: false, - description: 'URL for the Grafana host for the Grafana integration.' - field :enabled, GraphQL::Types::Boolean, null: false, - description: 'Indicates whether Grafana integration is enabled.' field :created_at, Types::TimeType, null: false, description: 'Timestamp of the issue\'s creation.' + field :enabled, GraphQL::Types::Boolean, null: false, + description: 'Indicates whether Grafana integration is enabled.' + field :grafana_url, GraphQL::Types::String, null: false, + description: 'URL for the Grafana host for the Grafana integration.' + field :id, GraphQL::Types::ID, null: false, + description: 'Internal ID of the Grafana integration.' field :updated_at, Types::TimeType, null: false, description: 'Timestamp of the issue\'s last activity.' end diff --git a/app/graphql/types/group_member_type.rb b/app/graphql/types/group_member_type.rb index d68abc11bba..18242f7b8b1 100644 --- a/app/graphql/types/group_member_type.rb +++ b/app/graphql/types/group_member_type.rb @@ -13,6 +13,10 @@ module Types field :group, Types::GroupType, null: true, description: 'Group that a User is a member of.' + field :notification_email, + resolver: Resolvers::GroupMembers::NotificationEmailResolver, + description: "Group notification email for User. Only availble for admins." + def group Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, object.source_id).find end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 5f63aa20953..a94cd6fad20 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -209,8 +209,9 @@ module Types field :work_item_types, Types::WorkItems::TypeType.connection_type, resolver: Resolvers::WorkItems::TypesResolver, - description: 'Work item types available to the group.', - feature_flag: :work_items + description: 'Work item types available to the group.' \ + ' Returns `null` if `work_items` feature flag is disabled.' \ + ' This flag is disabled by default, because the feature is experimental and is subject to change without notice.' def label(title:) BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index ee57961ee4a..07450c38616 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -8,6 +8,7 @@ module Types implements(Types::Notes::NoteableInterface) implements(Types::CurrentUserTodos) + implements(Types::TodoableInterface) authorize :read_issue @@ -15,16 +16,16 @@ module Types present_using IssuePresenter + field :description, GraphQL::Types::String, null: true, + description: 'Description of the issue.' field :id, GraphQL::Types::ID, null: false, description: "ID of the issue." field :iid, GraphQL::Types::ID, null: false, description: "Internal ID of the issue." - field :title, GraphQL::Types::String, null: false, - description: 'Title of the issue.' - field :description, GraphQL::Types::String, null: true, - description: 'Description of the issue.' field :state, IssueStateEnum, null: false, description: 'State of the issue.' + field :title, GraphQL::Types::String, null: false, + description: 'Title of the issue.' field :reference, GraphQL::Types::String, null: false, description: 'Internal reference of the issue. Returned in shortened format by default.', @@ -47,52 +48,52 @@ module Types field :milestone, Types::MilestoneType, null: true, description: 'Milestone of the issue.' - field :due_date, Types::TimeType, null: true, - description: 'Due date of the issue.' field :confidential, GraphQL::Types::Boolean, null: false, description: 'Indicates the issue is confidential.' + field :discussion_locked, GraphQL::Types::Boolean, null: false, + description: 'Indicates discussion is locked on the issue.' + field :due_date, Types::TimeType, null: true, + description: 'Due date of the issue.' field :hidden, GraphQL::Types::Boolean, null: true, resolver_method: :hidden?, description: 'Indicates the issue is hidden because the author has been banned. ' \ 'Will always return `null` if `ban_user_feature_flag` feature flag is disabled.' - field :discussion_locked, GraphQL::Types::Boolean, null: false, - description: 'Indicates discussion is locked on the issue.' - field :upvotes, GraphQL::Types::Int, null: false, - description: 'Number of upvotes the issue has received.' field :downvotes, GraphQL::Types::Int, null: false, description: 'Number of downvotes the issue has received.' field :merge_requests_count, GraphQL::Types::Int, null: false, description: 'Number of merge requests that close the issue on merge.', resolver: Resolvers::MergeRequestsCountResolver - field :user_notes_count, GraphQL::Types::Int, null: false, - description: 'Number of user notes of the issue.', - resolver: Resolvers::UserNotesCountResolver + field :relative_position, GraphQL::Types::Int, null: true, + description: 'Relative position of the issue (used for positioning in epic tree and issue boards).' + field :upvotes, GraphQL::Types::Int, null: false, + description: 'Number of upvotes the issue has received.' field :user_discussions_count, GraphQL::Types::Int, null: false, description: 'Number of user discussions in the issue.', resolver: Resolvers::UserDiscussionsCountResolver + field :user_notes_count, GraphQL::Types::Int, null: false, + description: 'Number of user notes of the issue.', + resolver: Resolvers::UserNotesCountResolver field :web_path, GraphQL::Types::String, null: false, method: :issue_path, description: 'Web path of the issue.' field :web_url, GraphQL::Types::String, null: false, description: 'Web URL of the issue.' - field :relative_position, GraphQL::Types::Int, null: true, - description: 'Relative position of the issue (used for positioning in epic tree and issue boards).' - field :participants, Types::UserType.connection_type, null: true, complexity: 5, - description: 'List of participants in the issue.', - resolver: Resolvers::Users::ParticipantsResolver field :emails_disabled, GraphQL::Types::Boolean, null: false, method: :project_emails_disabled?, description: 'Indicates if a project has email notifications disabled: `true` if email notifications are disabled.' + field :human_time_estimate, GraphQL::Types::String, null: true, + description: 'Human-readable time estimate of the issue.' + field :human_total_time_spent, GraphQL::Types::String, null: true, + description: 'Human-readable total time reported as spent on the issue.' + field :participants, Types::UserType.connection_type, null: true, complexity: 5, + description: 'List of participants in the issue.', + resolver: Resolvers::Users::ParticipantsResolver field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5, description: 'Indicates the currently logged in user is subscribed to the issue.' field :time_estimate, GraphQL::Types::Int, null: false, description: 'Time estimate of the issue.' field :total_time_spent, GraphQL::Types::Int, null: false, description: 'Total time reported as spent on the issue.' - field :human_time_estimate, GraphQL::Types::String, null: true, - description: 'Human-readable time estimate of the issue.' - field :human_total_time_spent, GraphQL::Types::String, null: true, - description: 'Human-readable total time reported as spent on the issue.' field :closed_at, Types::TimeType, null: true, description: 'Timestamp of when the issue was closed.' diff --git a/app/graphql/types/issues/negated_issue_filter_input_type.rb b/app/graphql/types/issues/negated_issue_filter_input_type.rb index 73e090a4802..fc39efd2493 100644 --- a/app/graphql/types/issues/negated_issue_filter_input_type.rb +++ b/app/graphql/types/issues/negated_issue_filter_input_type.rb @@ -5,6 +5,15 @@ module Types class NegatedIssueFilterInputType < BaseInputObject graphql_name 'NegatedIssueFilterInput' + argument :assignee_id, GraphQL::Types::String, + required: false, + description: 'ID of a user not assigned to the issues.' + argument :assignee_usernames, [GraphQL::Types::String], + required: false, + description: 'Usernames of users not assigned to the issue.' + argument :author_username, GraphQL::Types::String, + required: false, + description: "Username of a user who didn't author the issue." argument :iids, [GraphQL::Types::String], required: false, description: 'List of IIDs of issues to exclude. For example, `[1, 2]`.' @@ -14,24 +23,15 @@ module Types argument :milestone_title, [GraphQL::Types::String], required: false, description: 'Milestone not applied to this issue.' - argument :release_tag, [GraphQL::Types::String], - required: false, - description: "Release tag not associated with the issue's milestone. Ignored when parent is a group." - argument :author_username, GraphQL::Types::String, - required: false, - description: "Username of a user who didn't author the issue." - argument :assignee_usernames, [GraphQL::Types::String], - required: false, - description: 'Usernames of users not assigned to the issue.' - argument :assignee_id, GraphQL::Types::String, - required: false, - description: 'ID of a user not assigned to the issues.' argument :milestone_wildcard_id, ::Types::NegatedMilestoneWildcardIdEnum, required: false, description: 'Filter by negated milestone wildcard values.' argument :my_reaction_emoji, GraphQL::Types::String, required: false, description: 'Filter by reaction emoji applied by the current user.' + argument :release_tag, [GraphQL::Types::String], + required: false, + description: "Release tag not associated with the issue's milestone. Ignored when parent is a group." argument :types, [Types::IssueTypeEnum], as: :issue_types, description: 'Filters out issues by the given issue types.', diff --git a/app/graphql/types/jira_import_type.rb b/app/graphql/types/jira_import_type.rb index 0cdfc178350..8477f0b97f0 100644 --- a/app/graphql/types/jira_import_type.rb +++ b/app/graphql/types/jira_import_type.rb @@ -8,16 +8,16 @@ module Types field :created_at, Types::TimeType, null: true, description: 'Timestamp of when the Jira import was created.' + field :failed_to_import_count, GraphQL::Types::Int, null: false, + description: 'Count of issues that failed to import.' + field :imported_issues_count, GraphQL::Types::Int, null: false, + description: 'Count of issues that were successfully imported.' + field :jira_project_key, GraphQL::Types::String, null: false, + description: 'Project key for the imported Jira project.' field :scheduled_at, Types::TimeType, null: true, description: 'Timestamp of when the Jira import was scheduled.' field :scheduled_by, Types::UserType, null: true, description: 'User that started the Jira import.' - field :jira_project_key, GraphQL::Types::String, null: false, - description: 'Project key for the imported Jira project.' - field :imported_issues_count, GraphQL::Types::Int, null: false, - description: 'Count of issues that were successfully imported.' - field :failed_to_import_count, GraphQL::Types::Int, null: false, - description: 'Count of issues that failed to import.' field :total_issue_count, GraphQL::Types::Int, null: false, description: 'Total count of issues that were attempted to import.' end diff --git a/app/graphql/types/jira_user_type.rb b/app/graphql/types/jira_user_type.rb index 6e1c349726c..aba05385ece 100644 --- a/app/graphql/types/jira_user_type.rb +++ b/app/graphql/types/jira_user_type.rb @@ -6,18 +6,18 @@ module Types class JiraUserType < BaseObject graphql_name 'JiraUser' + field :gitlab_id, GraphQL::Types::Int, null: true, + description: 'ID of the matched GitLab user.' + field :gitlab_name, GraphQL::Types::String, null: true, + description: 'Name of the matched GitLab user.' + field :gitlab_username, GraphQL::Types::String, null: true, + description: 'Username of the matched GitLab user.' field :jira_account_id, GraphQL::Types::String, null: false, description: 'Account ID of the Jira user.' field :jira_display_name, GraphQL::Types::String, null: false, description: 'Display name of the Jira user.' field :jira_email, GraphQL::Types::String, null: true, description: 'Email of the Jira user, returned only for users with public emails.' - field :gitlab_id, GraphQL::Types::Int, null: true, - description: 'ID of the matched GitLab user.' - field :gitlab_username, GraphQL::Types::String, null: true, - description: 'Username of the matched GitLab user.' - field :gitlab_name, GraphQL::Types::String, null: true, - description: 'Name of the matched GitLab user.' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/jira_users_mapping_input_type.rb b/app/graphql/types/jira_users_mapping_input_type.rb index 37fd05370c0..4df2e27b45a 100644 --- a/app/graphql/types/jira_users_mapping_input_type.rb +++ b/app/graphql/types/jira_users_mapping_input_type.rb @@ -4,13 +4,13 @@ module Types class JiraUsersMappingInputType < BaseInputObject graphql_name 'JiraUsersMappingInputType' - argument :jira_account_id, - GraphQL::Types::String, - required: true, - description: 'Jira account ID of the user.' argument :gitlab_id, GraphQL::Types::Int, required: false, description: 'ID of the GitLab user.' + argument :jira_account_id, + GraphQL::Types::String, + required: true, + description: 'Jira account ID of the user.' end end diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb index 5a10bcfee74..b5b3e20bcbc 100644 --- a/app/graphql/types/label_type.rb +++ b/app/graphql/types/label_type.rb @@ -8,18 +8,18 @@ module Types authorize :read_label - field :id, GraphQL::Types::ID, null: false, - description: 'Label ID.' - field :description, GraphQL::Types::String, null: true, - description: 'Description of the label (Markdown rendered as HTML for caching).' - field :title, GraphQL::Types::String, null: false, - description: 'Content of the label.' field :color, GraphQL::Types::String, null: false, description: 'Background color of the label.' - field :text_color, GraphQL::Types::String, null: false, - description: 'Text color of the label.' field :created_at, Types::TimeType, null: false, description: 'When this label was created.' + field :description, GraphQL::Types::String, null: true, + description: 'Description of the label (Markdown rendered as HTML for caching).' + field :id, GraphQL::Types::ID, null: false, + description: 'Label ID.' + field :text_color, GraphQL::Types::String, null: false, + description: 'Text color of the label.' + field :title, GraphQL::Types::String, null: false, + description: 'Content of the label.' field :updated_at, Types::TimeType, null: false, description: 'When this label was last updated.' diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index ea05671c79c..af198d03c3f 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -8,6 +8,7 @@ module Types implements(Types::Notes::NoteableInterface) implements(Types::CurrentUserTodos) + implements(Types::TodoableInterface) authorize :read_merge_request @@ -15,94 +16,96 @@ module Types present_using MergeRequestPresenter + field :created_at, Types::TimeType, null: false, + description: 'Timestamp of when the merge request was created.' + field :description, GraphQL::Types::String, null: true, + description: 'Description of the merge request (Markdown rendered as HTML for caching).' + field :diff_head_sha, GraphQL::Types::String, null: true, + description: 'Diff head SHA of the merge request.' + field :diff_refs, Types::DiffRefsType, null: true, + description: 'References of the base SHA, the head SHA, and the start SHA for this merge request.' + field :diff_stats, [Types::DiffStatsType], null: true, calls_gitaly: true, + description: 'Details about which files were changed in this merge request.' do + argument :path, GraphQL::Types::String, required: false, description: 'Specific file path.' + end + field :draft, GraphQL::Types::Boolean, method: :draft?, null: false, + description: 'Indicates if the merge request is a draft.' field :id, GraphQL::Types::ID, null: false, description: 'ID of the merge request.' field :iid, GraphQL::Types::String, null: false, description: 'Internal ID of the merge request.' - field :title, GraphQL::Types::String, null: false, - description: 'Title of the merge request.' - field :description, GraphQL::Types::String, null: true, - description: 'Description of the merge request (Markdown rendered as HTML for caching).' - field :state, MergeRequestStateEnum, null: false, - description: 'State of the merge request.' - field :created_at, Types::TimeType, null: false, - description: 'Timestamp of when the merge request was created.' - field :updated_at, Types::TimeType, null: false, - description: 'Timestamp of when the merge request was last updated.' + field :merge_when_pipeline_succeeds, GraphQL::Types::Boolean, null: true, + description: 'Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS).' field :merged_at, Types::TimeType, null: true, complexity: 5, description: 'Timestamp of when the merge request was merged, null if not merged.' - field :source_project, Types::ProjectType, null: true, - description: 'Source project of the merge request.' - field :target_project, Types::ProjectType, null: false, - description: 'Target project of the merge request.' - field :diff_refs, Types::DiffRefsType, null: true, - description: 'References of the base SHA, the head SHA, and the start SHA for this merge request.' field :project, Types::ProjectType, null: false, description: 'Alias for target_project.' field :project_id, GraphQL::Types::Int, null: false, method: :target_project_id, description: 'ID of the merge request project.' - field :source_project_id, GraphQL::Types::Int, null: true, - description: 'ID of the merge request source project.' - field :target_project_id, GraphQL::Types::Int, null: false, - description: 'ID of the merge request target project.' field :source_branch, GraphQL::Types::String, null: false, description: 'Source branch of the merge request.' field :source_branch_protected, GraphQL::Types::Boolean, null: false, calls_gitaly: true, description: 'Indicates if the source branch is protected.' + field :source_project, Types::ProjectType, null: true, + description: 'Source project of the merge request.' + field :source_project_id, GraphQL::Types::Int, null: true, + description: 'ID of the merge request source project.' + field :state, MergeRequestStateEnum, null: false, + description: 'State of the merge request.' field :target_branch, GraphQL::Types::String, null: false, description: 'Target branch of the merge request.' - field :draft, GraphQL::Types::Boolean, method: :draft?, null: false, - description: 'Indicates if the merge request is a draft.' - field :merge_when_pipeline_succeeds, GraphQL::Types::Boolean, null: true, - description: 'Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS).' - field :diff_head_sha, GraphQL::Types::String, null: true, - description: 'Diff head SHA of the merge request.' - field :diff_stats, [Types::DiffStatsType], null: true, calls_gitaly: true, - description: 'Details about which files were changed in this merge request.' do - argument :path, GraphQL::Types::String, required: false, description: 'Specific file path.' - end + field :target_project, Types::ProjectType, null: false, + description: 'Target project of the merge request.' + field :target_project_id, GraphQL::Types::Int, null: false, + description: 'ID of the merge request target project.' + field :title, GraphQL::Types::String, null: false, + description: 'Title of the merge request.' + field :updated_at, Types::TimeType, null: false, + description: 'Timestamp of when the merge request was last updated.' + field :allow_collaboration, GraphQL::Types::Boolean, null: true, + description: 'Indicates if members of the target project can push to the fork.' + field :default_merge_commit_message, GraphQL::Types::String, null: true, calls_gitaly: true, + description: 'Default merge commit message of the merge request.' + field :default_merge_commit_message_with_description, GraphQL::Types::String, null: true, + description: 'Default merge commit message of the merge request with description. Will have the same value as `defaultMergeCommitMessage` when project has `mergeCommitTemplate` set.', + deprecated: { reason: 'Define merge commit template in project and use `defaultMergeCommitMessage`', milestone: '14.5' } + field :default_squash_commit_message, GraphQL::Types::String, null: true, calls_gitaly: true, + description: 'Default squash commit message of the merge request.' field :diff_stats_summary, Types::DiffStatsSummaryType, null: true, calls_gitaly: true, description: 'Summary of which files were changed in this merge request.' - field :merge_commit_sha, GraphQL::Types::String, null: true, - description: 'SHA of the merge request commit (set once merged).' - field :user_notes_count, GraphQL::Types::Int, null: true, - description: 'User notes count of the merge request.', - resolver: Resolvers::UserNotesCountResolver - field :user_discussions_count, GraphQL::Types::Int, null: true, - description: 'Number of user discussions in the merge request.', - resolver: Resolvers::UserDiscussionsCountResolver - field :should_remove_source_branch, GraphQL::Types::Boolean, method: :should_remove_source_branch?, null: true, - description: 'Indicates if the source branch of the merge request will be deleted after merge.' + field :diverged_from_target_branch, GraphQL::Types::Boolean, + null: false, calls_gitaly: true, + method: :diverged_from_target_branch?, + description: 'Indicates if the source branch is behind the target branch.' + field :downvotes, GraphQL::Types::Int, null: false, + description: 'Number of downvotes for the merge request.' field :force_remove_source_branch, GraphQL::Types::Boolean, method: :force_remove_source_branch?, null: true, description: 'Indicates if the project settings will lead to source branch deletion after merge.' + field :in_progress_merge_commit_sha, GraphQL::Types::String, null: true, + description: 'Commit SHA of the merge request if merge is in progress.' + field :merge_commit_sha, GraphQL::Types::String, null: true, + description: 'SHA of the merge request commit (set once merged).' + field :merge_error, GraphQL::Types::String, null: true, + description: 'Error message due to a merge error.' + field :merge_ongoing, GraphQL::Types::Boolean, method: :merge_ongoing?, null: false, + description: 'Indicates if a merge is currently occurring.' field :merge_status, GraphQL::Types::String, method: :public_merge_status, null: true, description: 'Status of the merge request.', deprecated: { reason: :renamed, replacement: 'MergeRequest.mergeStatusEnum', milestone: '14.0' } field :merge_status_enum, ::Types::MergeRequests::MergeStatusEnum, method: :public_merge_status, null: true, description: 'Merge status of the merge request.' - field :in_progress_merge_commit_sha, GraphQL::Types::String, null: true, - description: 'Commit SHA of the merge request if merge is in progress.' - field :merge_error, GraphQL::Types::String, null: true, - description: 'Error message due to a merge error.' - field :allow_collaboration, GraphQL::Types::Boolean, null: true, - description: 'Indicates if members of the target project can push to the fork.' - field :should_be_rebased, GraphQL::Types::Boolean, method: :should_be_rebased?, null: false, calls_gitaly: true, - description: 'Indicates if the merge request will be rebased.' + field :mergeable_discussions_state, GraphQL::Types::Boolean, null: true, + description: 'Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged.' field :rebase_commit_sha, GraphQL::Types::String, null: true, description: 'Rebase commit SHA of the merge request.' field :rebase_in_progress, GraphQL::Types::Boolean, method: :rebase_in_progress?, null: false, calls_gitaly: true, description: 'Indicates if there is a rebase currently in progress for the merge request.' - field :default_merge_commit_message, GraphQL::Types::String, null: true, calls_gitaly: true, - description: 'Default merge commit message of the merge request.' - field :default_merge_commit_message_with_description, GraphQL::Types::String, null: true, - description: 'Default merge commit message of the merge request with description. Will have the same value as `defaultMergeCommitMessage` when project has `mergeCommitTemplate` set.', - deprecated: { reason: 'Define merge commit template in project and use `defaultMergeCommitMessage`', milestone: '14.5' } - field :default_squash_commit_message, GraphQL::Types::String, null: true, calls_gitaly: true, - description: 'Default squash commit message of the merge request.' - field :merge_ongoing, GraphQL::Types::Boolean, method: :merge_ongoing?, null: false, - description: 'Indicates if a merge is currently occurring.' + field :should_be_rebased, GraphQL::Types::Boolean, method: :should_be_rebased?, null: false, calls_gitaly: true, + description: 'Indicates if the merge request will be rebased.' + field :should_remove_source_branch, GraphQL::Types::Boolean, method: :should_remove_source_branch?, null: true, + description: 'Indicates if the source branch of the merge request will be deleted after merge.' field :source_branch_exists, GraphQL::Types::Boolean, null: false, calls_gitaly: true, method: :source_branch_exists?, @@ -111,18 +114,16 @@ module Types null: false, calls_gitaly: true, method: :target_branch_exists?, description: 'Indicates if the target branch of the merge request exists.' - field :diverged_from_target_branch, GraphQL::Types::Boolean, - null: false, calls_gitaly: true, - method: :diverged_from_target_branch?, - description: 'Indicates if the source branch is behind the target branch.' - field :mergeable_discussions_state, GraphQL::Types::Boolean, null: true, - description: 'Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged.' - field :web_url, GraphQL::Types::String, null: true, - description: 'Web URL of the merge request.' field :upvotes, GraphQL::Types::Int, null: false, description: 'Number of upvotes for the merge request.' - field :downvotes, GraphQL::Types::Int, null: false, - description: 'Number of downvotes for the merge request.' + field :user_discussions_count, GraphQL::Types::Int, null: true, + description: 'Number of user discussions in the merge request.', + resolver: Resolvers::UserDiscussionsCountResolver + field :user_notes_count, GraphQL::Types::Int, null: true, + description: 'User notes count of the merge request.', + resolver: Resolvers::UserNotesCountResolver + field :web_url, GraphQL::Types::String, null: true, + description: 'Web URL of the merge request.' field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline, description: 'Pipeline running on the branch HEAD of the merge request.' @@ -131,84 +132,82 @@ module Types description: 'Pipelines for the merge request. Note: for performance reasons, no more than the most recent 500 pipelines will be returned.', resolver: Resolvers::MergeRequestPipelinesResolver - field :milestone, Types::MilestoneType, null: true, - description: 'Milestone of the merge request.' field :assignees, type: Types::MergeRequests::AssigneeType.connection_type, null: true, complexity: 5, description: 'Assignees of the merge request.' - field :reviewers, - type: Types::MergeRequests::ReviewerType.connection_type, - null: true, - complexity: 5, - description: 'Users from whom a review has been requested.' - field :author, Types::UserType, null: true, + field :author, Types::MergeRequests::AuthorType, null: true, description: 'User who created this merge request.' - field :participants, Types::UserType.connection_type, null: true, complexity: 15, - description: 'Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes.', - resolver: Resolvers::Users::ParticipantsResolver - field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5, - description: 'Indicates if the currently logged in user is subscribed to this merge request.' - field :labels, Types::LabelType.connection_type, null: true, complexity: 5, - description: 'Labels of the merge request.' field :discussion_locked, GraphQL::Types::Boolean, description: 'Indicates if comments on the merge request are locked to members only.', null: false - field :time_estimate, GraphQL::Types::Int, null: false, - description: 'Time estimate of the merge request.' - field :total_time_spent, GraphQL::Types::Int, null: false, - description: 'Total time reported as spent on the merge request.' field :human_time_estimate, GraphQL::Types::String, null: true, description: 'Human-readable time estimate of the merge request.' field :human_total_time_spent, GraphQL::Types::String, null: true, description: 'Human-readable total time reported as spent on the merge request.' + field :labels, Types::LabelType.connection_type, null: true, complexity: 5, + description: 'Labels of the merge request.' + field :milestone, Types::MilestoneType, null: true, + description: 'Milestone of the merge request.' + field :participants, Types::MergeRequests::ParticipantType.connection_type, null: true, complexity: 15, + description: 'Participants in the merge request. This includes the author, assignees, reviewers, and users mentioned in notes.', + resolver: Resolvers::Users::ParticipantsResolver field :reference, GraphQL::Types::String, null: false, method: :to_reference, description: 'Internal reference of the merge request. Returned in shortened format by default.' do argument :full, GraphQL::Types::Boolean, required: false, default_value: false, description: 'Boolean option specifying whether the reference should be returned in full.' end - field :task_completion_status, Types::TaskCompletionStatus, null: false, - description: Types::TaskCompletionStatus.description + field :auto_merge_enabled, GraphQL::Types::Boolean, null: false, + description: 'Indicates if auto merge is enabled for the merge request.' field :commit_count, GraphQL::Types::Int, null: true, method: :commits_count, description: 'Number of commits in the merge request.' field :conflicts, GraphQL::Types::Boolean, null: false, method: :cannot_be_merged?, description: 'Indicates if the merge request has conflicts.' - field :auto_merge_enabled, GraphQL::Types::Boolean, null: false, - description: 'Indicates if auto merge is enabled for the merge request.' + field :reviewers, + type: Types::MergeRequests::ReviewerType.connection_type, + null: true, + complexity: 5, + description: 'Users from whom a review has been requested.' + field :subscribed, GraphQL::Types::Boolean, method: :subscribed?, null: false, complexity: 5, + description: 'Indicates if the currently logged in user is subscribed to this merge request.' + field :task_completion_status, Types::TaskCompletionStatus, null: false, + description: Types::TaskCompletionStatus.description + field :time_estimate, GraphQL::Types::Int, null: false, + description: 'Time estimate of the merge request.' + field :total_time_spent, GraphQL::Types::Int, null: false, + description: 'Total time reported as spent on the merge request.' field :approved_by, Types::UserType.connection_type, null: true, - description: 'Users who approved the merge request.' - field :squash_on_merge, GraphQL::Types::Boolean, null: false, method: :squash_on_merge?, - description: 'Indicates if squash on merge is enabled.' - field :squash, GraphQL::Types::Boolean, null: false, - description: 'Indicates if squash on merge is enabled.' + description: 'Users who approved the merge request.', method: :approved_by_users + field :auto_merge_strategy, GraphQL::Types::String, null: true, + description: 'Selected auto merge strategy.' field :available_auto_merge_strategies, [GraphQL::Types::String], null: true, calls_gitaly: true, description: 'Array of available auto merge strategies.' - field :has_ci, GraphQL::Types::Boolean, null: false, method: :has_ci?, - description: 'Indicates if the merge request has CI.' - field :mergeable, GraphQL::Types::Boolean, null: false, method: :mergeable?, calls_gitaly: true, - description: 'Indicates if the merge request is mergeable.' field :commits, Types::CommitType.connection_type, null: true, calls_gitaly: true, description: 'Merge request commits.' + field :committers, Types::UserType.connection_type, null: true, complexity: 5, + calls_gitaly: true, description: 'Users who have added commits to the merge request.' field :commits_without_merge_commits, Types::CommitType.connection_type, null: true, calls_gitaly: true, description: 'Merge request commits excluding merge commits.' - field :security_auto_fix, GraphQL::Types::Boolean, null: true, - description: 'Indicates if the merge request is created by @GitLab-Security-Bot.' - field :auto_merge_strategy, GraphQL::Types::String, null: true, - description: 'Selected auto merge strategy.' + field :has_ci, GraphQL::Types::Boolean, null: false, method: :has_ci?, + description: 'Indicates if the merge request has CI.' field :merge_user, Types::UserType, null: true, description: 'User who merged this merge request or set it to merge when pipeline succeeds.' + field :mergeable, GraphQL::Types::Boolean, null: false, method: :mergeable?, calls_gitaly: true, + description: 'Indicates if the merge request is mergeable.' + field :security_auto_fix, GraphQL::Types::Boolean, null: true, + description: 'Indicates if the merge request is created by @GitLab-Security-Bot.' + field :squash, GraphQL::Types::Boolean, null: false, + description: 'Indicates if squash on merge is enabled.' + field :squash_on_merge, GraphQL::Types::Boolean, null: false, method: :squash_on_merge?, + description: 'Indicates if squash on merge is enabled.' field :timelogs, Types::TimelogType.connection_type, null: false, description: 'Timelogs on the merge request.' markdown_field :title_html, null: true markdown_field :description_html, null: true - def approved_by - object.approved_by_users - end - def user_notes_count BatchLoader::GraphQL.for(object.id).batch(key: :merge_request_user_notes_count) do |ids, loader, args| counts = Note.count_for_collection(ids, 'MergeRequest').index_by(&:noteable_id) @@ -279,10 +278,6 @@ module Types object.author == User.security_bot end - def reviewers - object.reviewers - end - def merge_user object.metrics&.merged_by || object.merge_user end diff --git a/app/graphql/types/merge_requests/assignee_type.rb b/app/graphql/types/merge_requests/assignee_type.rb index 24321d057a3..a0ba74597ba 100644 --- a/app/graphql/types/merge_requests/assignee_type.rb +++ b/app/graphql/types/merge_requests/assignee_type.rb @@ -6,7 +6,6 @@ module Types graphql_name 'MergeRequestAssignee' description 'A user assigned to a merge request.' - include FindClosest include ::Types::MergeRequests::InteractsWithMergeRequest authorize :read_user diff --git a/app/graphql/types/merge_requests/author_type.rb b/app/graphql/types/merge_requests/author_type.rb new file mode 100644 index 00000000000..56ad3190547 --- /dev/null +++ b/app/graphql/types/merge_requests/author_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + module MergeRequests + class AuthorType < ::Types::UserType + graphql_name 'MergeRequestAuthor' + description 'The author of the merge request.' + + include ::Types::MergeRequests::InteractsWithMergeRequest + + authorize :read_user + end + end +end diff --git a/app/graphql/types/merge_requests/participant_type.rb b/app/graphql/types/merge_requests/participant_type.rb new file mode 100644 index 00000000000..86d627097b2 --- /dev/null +++ b/app/graphql/types/merge_requests/participant_type.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + module MergeRequests + class ParticipantType < ::Types::UserType + graphql_name 'MergeRequestParticipant' + description 'A user participating in a merge request.' + + include ::Types::MergeRequests::InteractsWithMergeRequest + + authorize :read_user + end + end +end diff --git a/app/graphql/types/merge_requests/reviewer_type.rb b/app/graphql/types/merge_requests/reviewer_type.rb index 11f7ceaf461..e5bc5812816 100644 --- a/app/graphql/types/merge_requests/reviewer_type.rb +++ b/app/graphql/types/merge_requests/reviewer_type.rb @@ -6,7 +6,6 @@ module Types graphql_name 'MergeRequestReviewer' description 'A user assigned to a merge request as a reviewer.' - include FindClosest include ::Types::MergeRequests::InteractsWithMergeRequest authorize :read_user diff --git a/app/graphql/types/metadata/kas_type.rb b/app/graphql/types/metadata/kas_type.rb index 54a8a6ec40d..6a8d54b6c7d 100644 --- a/app/graphql/types/metadata/kas_type.rb +++ b/app/graphql/types/metadata/kas_type.rb @@ -9,10 +9,10 @@ module Types field :enabled, GraphQL::Types::Boolean, null: false, description: 'Indicates whether the Kubernetes Agent Server is enabled.' - field :version, GraphQL::Types::String, null: true, - description: 'KAS version.' field :external_url, GraphQL::Types::String, null: true, description: 'URL used by the Agents to communicate with KAS.' + field :version, GraphQL::Types::String, null: true, + description: 'KAS version.' end end end diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb index ed1e697711d..6fb141a50c9 100644 --- a/app/graphql/types/metadata_type.rb +++ b/app/graphql/types/metadata_type.rb @@ -6,11 +6,11 @@ module Types authorize :read_instance_metadata - field :version, GraphQL::Types::String, null: false, - description: 'Version.' - field :revision, GraphQL::Types::String, null: false, - description: 'Revision.' field :kas, ::Types::Metadata::KasType, null: false, description: 'Metadata about KAS.' + field :revision, GraphQL::Types::String, null: false, + description: 'Revision.' + field :version, GraphQL::Types::String, null: false, + description: 'Version.' end end diff --git a/app/graphql/types/metrics/dashboards/annotation_type.rb b/app/graphql/types/metrics/dashboards/annotation_type.rb index 0c787476f54..0621cf4d674 100644 --- a/app/graphql/types/metrics/dashboards/annotation_type.rb +++ b/app/graphql/types/metrics/dashboards/annotation_type.rb @@ -14,17 +14,14 @@ module Types description: 'ID of the annotation.' field :panel_id, GraphQL::Types::String, null: true, - description: 'ID of a dashboard panel to which the annotation should be scoped.' + description: 'ID of a dashboard panel to which the annotation should be scoped.', + method: :panel_xid field :starting_at, Types::TimeType, null: true, description: 'Timestamp marking start of annotated time span.' field :ending_at, Types::TimeType, null: true, description: 'Timestamp marking end of annotated time span.' - - def panel_id - object.panel_xid - end end end end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 3c735231595..e6072820eea 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -126,8 +126,11 @@ module Types mount_mutation Mutations::Packages::DestroyFile mount_mutation Mutations::Echo mount_mutation Mutations::WorkItems::Create + mount_mutation Mutations::WorkItems::CreateFromTask mount_mutation Mutations::WorkItems::Delete mount_mutation Mutations::WorkItems::Update + mount_mutation Mutations::SavedReplies::Create + mount_mutation Mutations::SavedReplies::Update end end diff --git a/app/graphql/types/namespace/package_settings_type.rb b/app/graphql/types/namespace/package_settings_type.rb index d573cc9ded5..cb546bbf3ec 100644 --- a/app/graphql/types/namespace/package_settings_type.rb +++ b/app/graphql/types/namespace/package_settings_type.rb @@ -8,9 +8,9 @@ module Types authorize :read_package_settings - field :maven_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' - field :maven_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' - field :generic_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate generic packages are allowed for this namespace.' field :generic_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When generic_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' + field :generic_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate generic packages are allowed for this namespace.' + field :maven_duplicate_exception_regex, Types::UntrustedRegexp, null: true, description: 'When maven_duplicates_allowed is false, you can publish duplicate packages with names that match this regex. Otherwise, this setting has no effect.' + field :maven_duplicates_allowed, GraphQL::Types::Boolean, null: false, description: 'Indicates whether duplicate Maven packages are allowed for this namespace.' end end diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index ba90fb06cb2..de6a078c6ef 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -9,24 +9,28 @@ module Types field :id, GraphQL::Types::ID, null: false, description: 'ID of the namespace.' - field :name, GraphQL::Types::String, null: false, - description: 'Name of the namespace.' - field :path, GraphQL::Types::String, null: false, - description: 'Path of the namespace.' field :full_name, GraphQL::Types::String, null: false, description: 'Full name of the namespace.' field :full_path, GraphQL::Types::ID, null: false, description: 'Full path of the namespace.' + field :name, GraphQL::Types::String, null: false, + description: 'Name of the namespace.' + field :path, GraphQL::Types::String, null: false, + description: 'Path of the namespace.' + + field :cross_project_pipeline_available, GraphQL::Types::Boolean, null: false, + resolver_method: :cross_project_pipeline_available?, + description: 'Indicates if the cross_project_pipeline feature is available for the namespace.' field :description, GraphQL::Types::String, null: true, description: 'Description of the namespace.' - field :visibility, GraphQL::Types::String, null: true, - description: 'Visibility of the namespace.' field :lfs_enabled, GraphQL::Types::Boolean, null: true, method: :lfs_enabled?, description: 'Indicates if Large File Storage (LFS) is enabled for namespace.' field :request_access_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if users can request access to namespace.' + field :visibility, GraphQL::Types::String, null: true, + description: 'Visibility of the namespace.' field :root_storage_statistics, Types::RootStorageStatisticsType, null: true, @@ -48,6 +52,10 @@ module Types markdown_field :description_html, null: true + def cross_project_pipeline_available? + object.licensed_feature_available?(:cross_project_pipelines) + end + def root_storage_statistics Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(object.id).find end diff --git a/app/graphql/types/notes/diff_image_position_input_type.rb b/app/graphql/types/notes/diff_image_position_input_type.rb index d56c67bbec8..d535dea2e07 100644 --- a/app/graphql/types/notes/diff_image_position_input_type.rb +++ b/app/graphql/types/notes/diff_image_position_input_type.rb @@ -5,14 +5,14 @@ module Types class DiffImagePositionInputType < DiffPositionBaseInputType graphql_name 'DiffImagePositionInput' + argument :height, GraphQL::Types::Int, required: true, + description: copy_field_description(Types::Notes::DiffPositionType, :height) + argument :width, GraphQL::Types::Int, required: true, + description: copy_field_description(Types::Notes::DiffPositionType, :width) argument :x, GraphQL::Types::Int, required: true, description: copy_field_description(Types::Notes::DiffPositionType, :x) argument :y, GraphQL::Types::Int, required: true, description: copy_field_description(Types::Notes::DiffPositionType, :y) - argument :width, GraphQL::Types::Int, required: true, - description: copy_field_description(Types::Notes::DiffPositionType, :width) - argument :height, GraphQL::Types::Int, required: true, - description: copy_field_description(Types::Notes::DiffPositionType, :height) end end end diff --git a/app/graphql/types/notes/diff_position_base_input_type.rb b/app/graphql/types/notes/diff_position_base_input_type.rb index e773fbbc8a1..2780dbab573 100644 --- a/app/graphql/types/notes/diff_position_base_input_type.rb +++ b/app/graphql/types/notes/diff_position_base_input_type.rb @@ -3,10 +3,10 @@ module Types module Notes class DiffPositionBaseInputType < BaseInputObject + argument :base_sha, GraphQL::Types::String, required: false, + description: copy_field_description(Types::DiffRefsType, :base_sha) argument :head_sha, GraphQL::Types::String, required: true, description: copy_field_description(Types::DiffRefsType, :head_sha) - argument :base_sha, GraphQL::Types::String, required: false, - description: copy_field_description(Types::DiffRefsType, :base_sha) argument :start_sha, GraphQL::Types::String, required: true, description: copy_field_description(Types::DiffRefsType, :start_sha) diff --git a/app/graphql/types/notes/diff_position_input_type.rb b/app/graphql/types/notes/diff_position_input_type.rb index 18ce6672d14..ccde4188f29 100644 --- a/app/graphql/types/notes/diff_position_input_type.rb +++ b/app/graphql/types/notes/diff_position_input_type.rb @@ -5,10 +5,10 @@ module Types class DiffPositionInputType < DiffPositionBaseInputType graphql_name 'DiffPositionInput' - argument :old_line, GraphQL::Types::Int, required: false, - description: copy_field_description(Types::Notes::DiffPositionType, :old_line) argument :new_line, GraphQL::Types::Int, required: false, - description: copy_field_description(Types::Notes::DiffPositionType, :new_line) + description: "#{copy_field_description(Types::Notes::DiffPositionType, :new_line)} Please see the [REST API Documentation](https://docs.gitlab.com/ee/api/discussions.html#create-a-new-thread-in-the-merge-request-diff) for more information on how to use this field." + argument :old_line, GraphQL::Types::Int, required: false, + description: "#{copy_field_description(Types::Notes::DiffPositionType, :old_line)} Please see the [REST API Documentation](https://docs.gitlab.com/ee/api/discussions.html#create-a-new-thread-in-the-merge-request-diff) for more information on how to use this field." end end end diff --git a/app/graphql/types/notes/diff_position_type.rb b/app/graphql/types/notes/diff_position_type.rb index 9c756d56b97..531bd0edac0 100644 --- a/app/graphql/types/notes/diff_position_type.rb +++ b/app/graphql/types/notes/diff_position_type.rb @@ -12,28 +12,28 @@ module Types field :file_path, GraphQL::Types::String, null: false, description: 'Path of the file that was changed.' - field :old_path, GraphQL::Types::String, null: true, - description: 'Path of the file on the start SHA.' field :new_path, GraphQL::Types::String, null: true, description: 'Path of the file on the HEAD SHA.' + field :old_path, GraphQL::Types::String, null: true, + description: 'Path of the file on the start SHA.' field :position_type, Types::Notes::PositionTypeEnum, null: false, description: 'Type of file the position refers to.' # Fields for text positions - field :old_line, GraphQL::Types::Int, null: true, - description: 'Line on start SHA that was changed.' field :new_line, GraphQL::Types::Int, null: true, description: 'Line on HEAD SHA that was changed.' + field :old_line, GraphQL::Types::Int, null: true, + description: 'Line on start SHA that was changed.' # Fields for image positions + field :height, GraphQL::Types::Int, null: true, + description: 'Total height of the image.' + field :width, GraphQL::Types::Int, null: true, + description: 'Total width of the image.' field :x, GraphQL::Types::Int, null: true, description: 'X position of the note.' field :y, GraphQL::Types::Int, null: true, description: 'Y position of the note.' - field :width, GraphQL::Types::Int, null: true, - description: 'Total width of the image.' - field :height, GraphQL::Types::Int, null: true, - description: 'Total height of the image.' def old_line object.old_line if object.on_text? diff --git a/app/graphql/types/notes/discussion_type.rb b/app/graphql/types/notes/discussion_type.rb index ffe61c9ff88..89778b2a99a 100644 --- a/app/graphql/types/notes/discussion_type.rb +++ b/app/graphql/types/notes/discussion_type.rb @@ -11,16 +11,16 @@ module Types implements(Types::ResolvableInterface) - field :id, DiscussionID, null: false, - description: "ID of this discussion." - field :reply_id, DiscussionID, null: false, - description: 'ID used to reply to this discussion.' field :created_at, Types::TimeType, null: false, description: "Timestamp of the discussion's creation." - field :notes, Types::Notes::NoteType.connection_type, null: false, - description: 'All notes in the discussion.' + field :id, DiscussionID, null: false, + description: "ID of this discussion." field :noteable, Types::NoteableType, null: true, description: 'Object which the discussion belongs to.' + field :notes, Types::Notes::NoteType.connection_type, null: false, + description: 'All notes in the discussion.' + field :reply_id, DiscussionID, null: false, + description: 'ID used to reply to this discussion.' # DiscussionID.coerce_result is suitable here, but will always mark this # as being a 'Discussion'. Using `GlobalId.build` guarantees that we get diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index 7314c137010..32f3ff7f556 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -33,17 +33,17 @@ module Types method: :note, description: 'Content of the note.' + field :confidential, GraphQL::Types::Boolean, null: true, + description: 'Indicates if this note is confidential.', + method: :confidential? field :created_at, Types::TimeType, null: false, description: 'Timestamp of the note creation.' - field :updated_at, Types::TimeType, null: false, - description: "Timestamp of the note's last activity." field :discussion, Types::Notes::DiscussionType, null: true, description: 'Discussion this note is a part of.' field :position, Types::Notes::DiffPositionType, null: true, description: 'Position of this note on a diff.' - field :confidential, GraphQL::Types::Boolean, null: true, - description: 'Indicates if this note is confidential.', - method: :confidential? + field :updated_at, Types::TimeType, null: false, + description: "Timestamp of the note's last activity." field :url, GraphQL::Types::String, null: true, description: 'URL to view this Note in the Web UI.' diff --git a/app/graphql/types/packages/composer/json_type.rb b/app/graphql/types/packages/composer/json_type.rb index 6c121043301..84f08adb021 100644 --- a/app/graphql/types/packages/composer/json_type.rb +++ b/app/graphql/types/packages/composer/json_type.rb @@ -8,9 +8,9 @@ module Types graphql_name 'PackageComposerJsonType' description 'Represents a composer JSON file' + field :license, GraphQL::Types::String, null: true, description: 'License set in the Composer JSON file.' field :name, GraphQL::Types::String, null: true, description: 'Name set in the Composer JSON file.' field :type, GraphQL::Types::String, null: true, description: 'Type set in the Composer JSON file.' - field :license, GraphQL::Types::String, null: true, description: 'License set in the Composer JSON file.' field :version, GraphQL::Types::String, null: true, description: 'Version set in the Composer JSON file.' end end diff --git a/app/graphql/types/packages/composer/metadatum_type.rb b/app/graphql/types/packages/composer/metadatum_type.rb index 092e729ec56..d28ee87b878 100644 --- a/app/graphql/types/packages/composer/metadatum_type.rb +++ b/app/graphql/types/packages/composer/metadatum_type.rb @@ -9,8 +9,8 @@ module Types authorize :read_package - field :target_sha, GraphQL::Types::String, null: false, description: 'Target SHA of the package.' field :composer_json, Types::Packages::Composer::JsonType, null: false, description: 'Data of the Composer JSON file.' + field :target_sha, GraphQL::Types::String, null: false, description: 'Target SHA of the package.' end end end diff --git a/app/graphql/types/packages/conan/file_metadatum_type.rb b/app/graphql/types/packages/conan/file_metadatum_type.rb index 9a26fd5de51..012e03ece8f 100644 --- a/app/graphql/types/packages/conan/file_metadatum_type.rb +++ b/app/graphql/types/packages/conan/file_metadatum_type.rb @@ -11,11 +11,11 @@ module Types authorize :read_package + field :conan_file_type, ::Types::Packages::Conan::MetadatumFileTypeEnum, null: false, description: 'Type of the Conan file.' + field :conan_package_reference, GraphQL::Types::String, null: true, description: 'Reference of the Conan package.' field :id, ::Types::GlobalIDType[::Packages::Conan::FileMetadatum], null: false, description: 'ID of the metadatum.' - field :recipe_revision, GraphQL::Types::String, null: false, description: 'Revision of the Conan recipe.' field :package_revision, GraphQL::Types::String, null: true, description: 'Revision of the package.' - field :conan_package_reference, GraphQL::Types::String, null: true, description: 'Reference of the Conan package.' - field :conan_file_type, ::Types::Packages::Conan::MetadatumFileTypeEnum, null: false, description: 'Type of the Conan file.' + field :recipe_revision, GraphQL::Types::String, null: false, description: 'Revision of the Conan recipe.' end end end diff --git a/app/graphql/types/packages/conan/metadatum_type.rb b/app/graphql/types/packages/conan/metadatum_type.rb index cdfd0aa4483..d410d6d6d33 100644 --- a/app/graphql/types/packages/conan/metadatum_type.rb +++ b/app/graphql/types/packages/conan/metadatum_type.rb @@ -9,13 +9,13 @@ module Types authorize :read_package - field :id, ::Types::GlobalIDType[::Packages::Conan::Metadatum], null: false, description: 'ID of the metadatum.' field :created_at, Types::TimeType, null: false, description: 'Date of creation.' - field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' - field :package_username, GraphQL::Types::String, null: false, description: 'Username of the Conan package.' + field :id, ::Types::GlobalIDType[::Packages::Conan::Metadatum], null: false, description: 'ID of the metadatum.' field :package_channel, GraphQL::Types::String, null: false, description: 'Channel of the Conan package.' + field :package_username, GraphQL::Types::String, null: false, description: 'Username of the Conan package.' field :recipe, GraphQL::Types::String, null: false, description: 'Recipe of the Conan package.' field :recipe_path, GraphQL::Types::String, null: false, description: 'Recipe path of the Conan package.' + field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' end end end diff --git a/app/graphql/types/packages/helm/dependency_type.rb b/app/graphql/types/packages/helm/dependency_type.rb index 35598c2b1d7..72a47d0af51 100644 --- a/app/graphql/types/packages/helm/dependency_type.rb +++ b/app/graphql/types/packages/helm/dependency_type.rb @@ -9,14 +9,14 @@ module Types description 'Represents a Helm dependency' # Need to be synced with app/validators/json_schemas/helm_metadata.json#dependencies - field :name, GraphQL::Types::String, null: true, description: 'Name of the dependency.' - field :version, GraphQL::Types::String, null: true, description: 'Version of the dependency.' - field :repository, GraphQL::Types::String, null: true, description: 'Repository of the dependency.' + field :alias, GraphQL::Types::String, null: true, description: 'Alias of the dependency.', resolver_method: :resolve_alias field :condition, GraphQL::Types::String, null: true, description: 'Condition of the dependency.' - field :tags, [GraphQL::Types::String], null: true, description: 'Tags of the dependency.' field :enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates the dependency is enabled.' field :import_values, [GraphQL::Types::JSON], null: true, description: 'Import-values of the dependency.', hash_key: "import-values" # rubocop:disable Graphql/JSONType - field :alias, GraphQL::Types::String, null: true, description: 'Alias of the dependency.', resolver_method: :resolve_alias + field :name, GraphQL::Types::String, null: true, description: 'Name of the dependency.' + field :repository, GraphQL::Types::String, null: true, description: 'Repository of the dependency.' + field :tags, [GraphQL::Types::String], null: true, description: 'Tags of the dependency.' + field :version, GraphQL::Types::String, null: true, description: 'Version of the dependency.' # field :alias` conflicts with a built-in method def resolve_alias diff --git a/app/graphql/types/packages/helm/maintainer_type.rb b/app/graphql/types/packages/helm/maintainer_type.rb index 6d25a26c46b..e029ff6fd94 100644 --- a/app/graphql/types/packages/helm/maintainer_type.rb +++ b/app/graphql/types/packages/helm/maintainer_type.rb @@ -9,8 +9,8 @@ module Types description 'Represents a Helm maintainer' # Need to be synced with app/validators/json_schemas/helm_metadata.json#maintainers - field :name, GraphQL::Types::String, null: true, description: 'Name of the maintainer.' field :email, GraphQL::Types::String, null: true, description: 'Email of the maintainer.' + field :name, GraphQL::Types::String, null: true, description: 'Name of the maintainer.' field :url, GraphQL::Types::String, null: true, description: 'URL of the maintainer.' end end diff --git a/app/graphql/types/packages/helm/metadata_type.rb b/app/graphql/types/packages/helm/metadata_type.rb index eeb3e8087a8..ccc5a3029cd 100644 --- a/app/graphql/types/packages/helm/metadata_type.rb +++ b/app/graphql/types/packages/helm/metadata_type.rb @@ -9,23 +9,23 @@ module Types description 'Represents the contents of a Helm Chart.yml file' # Need to be synced with app/validators/json_schemas/helm_metadata.json - field :name, GraphQL::Types::String, null: false, description: 'Name of the chart.' - field :home, GraphQL::Types::String, null: true, description: 'URL of the home page.' - field :sources, [GraphQL::Types::String], null: true, description: 'URLs of the source code for the chart.' - field :version, GraphQL::Types::String, null: false, description: 'Version of the chart.' - field :description, GraphQL::Types::String, null: true, description: 'Description of the chart.' - field :keywords, [GraphQL::Types::String], null: true, description: 'Keywords for the chart.' - field :maintainers, [Types::Packages::Helm::MaintainerType], null: true, description: 'Maintainers of the chart.' - field :icon, GraphQL::Types::String, null: true, description: 'URL to an SVG or PNG image for the chart.' + field :annotations, GraphQL::Types::JSON, null: true, description: 'Annotations for the chart.' # rubocop:disable Graphql/JSONType field :api_version, GraphQL::Types::String, null: false, description: 'API version of the chart.', hash_key: "apiVersion" - field :condition, GraphQL::Types::String, null: true, description: 'Condition for the chart.' - field :tags, GraphQL::Types::String, null: true, description: 'Tags for the chart.' field :app_version, GraphQL::Types::String, null: true, description: 'App version of the chart.', hash_key: "appVersion" + field :condition, GraphQL::Types::String, null: true, description: 'Condition for the chart.' + field :dependencies, [Types::Packages::Helm::DependencyType], null: true, description: 'Dependencies of the chart.' field :deprecated, GraphQL::Types::Boolean, null: true, description: 'Indicates if the chart is deprecated.' - field :annotations, GraphQL::Types::JSON, null: true, description: 'Annotations for the chart.' # rubocop:disable Graphql/JSONType + field :description, GraphQL::Types::String, null: true, description: 'Description of the chart.' + field :home, GraphQL::Types::String, null: true, description: 'URL of the home page.' + field :icon, GraphQL::Types::String, null: true, description: 'URL to an SVG or PNG image for the chart.' + field :keywords, [GraphQL::Types::String], null: true, description: 'Keywords for the chart.' field :kube_version, GraphQL::Types::String, null: true, description: 'Kubernetes versions for the chart.', hash_key: "kubeVersion" - field :dependencies, [Types::Packages::Helm::DependencyType], null: true, description: 'Dependencies of the chart.' + field :maintainers, [Types::Packages::Helm::MaintainerType], null: true, description: 'Maintainers of the chart.' + field :name, GraphQL::Types::String, null: false, description: 'Name of the chart.' + field :sources, [GraphQL::Types::String], null: true, description: 'URLs of the source code for the chart.' + field :tags, GraphQL::Types::String, null: true, description: 'Tags for the chart.' field :type, GraphQL::Types::String, null: true, description: 'Type of the chart.', hash_key: "appVersion" + field :version, GraphQL::Types::String, null: false, description: 'Version of the chart.' end end end diff --git a/app/graphql/types/packages/maven/metadatum_type.rb b/app/graphql/types/packages/maven/metadatum_type.rb index eb3829648d1..b59f5235d7b 100644 --- a/app/graphql/types/packages/maven/metadatum_type.rb +++ b/app/graphql/types/packages/maven/metadatum_type.rb @@ -9,13 +9,13 @@ module Types authorize :read_package - field :id, ::Types::GlobalIDType[::Packages::Maven::Metadatum], null: false, description: 'ID of the metadatum.' - field :created_at, Types::TimeType, null: false, description: 'Date of creation.' - field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' - field :path, GraphQL::Types::String, null: false, description: 'Path of the Maven package.' field :app_group, GraphQL::Types::String, null: false, description: 'App group of the Maven package.' - field :app_version, GraphQL::Types::String, null: true, description: 'App version of the Maven package.' field :app_name, GraphQL::Types::String, null: false, description: 'App name of the Maven package.' + field :app_version, GraphQL::Types::String, null: true, description: 'App version of the Maven package.' + field :created_at, Types::TimeType, null: false, description: 'Date of creation.' + field :id, ::Types::GlobalIDType[::Packages::Maven::Metadatum], null: false, description: 'ID of the metadatum.' + field :path, GraphQL::Types::String, null: false, description: 'Path of the Maven package.' + field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' end end end diff --git a/app/graphql/types/packages/nuget/metadatum_type.rb b/app/graphql/types/packages/nuget/metadatum_type.rb index b58fd954a74..fd9f1039d3c 100644 --- a/app/graphql/types/packages/nuget/metadatum_type.rb +++ b/app/graphql/types/packages/nuget/metadatum_type.rb @@ -9,10 +9,10 @@ module Types authorize :read_package + field :icon_url, GraphQL::Types::String, null: true, description: 'Icon URL of the Nuget package.' field :id, ::Types::GlobalIDType[::Packages::Nuget::Metadatum], null: false, description: 'ID of the metadatum.' field :license_url, GraphQL::Types::String, null: true, description: 'License URL of the Nuget package.' field :project_url, GraphQL::Types::String, null: true, description: 'Project URL of the Nuget package.' - field :icon_url, GraphQL::Types::String, null: true, description: 'Icon URL of the Nuget package.' end end end diff --git a/app/graphql/types/packages/package_dependency_link_type.rb b/app/graphql/types/packages/package_dependency_link_type.rb index eceb8319748..8b1d4abf3ba 100644 --- a/app/graphql/types/packages/package_dependency_link_type.rb +++ b/app/graphql/types/packages/package_dependency_link_type.rb @@ -7,9 +7,9 @@ module Types description 'Represents a package dependency link' authorize :read_package - field :id, ::Types::GlobalIDType[::Packages::DependencyLink], null: false, description: 'ID of the dependency link.' - field :dependency_type, Types::Packages::PackageDependencyTypeEnum, null: false, description: 'Dependency type.' field :dependency, Types::Packages::PackageDependencyType, null: true, description: 'Dependency.' + field :dependency_type, Types::Packages::PackageDependencyTypeEnum, null: false, description: 'Dependency type.' + field :id, ::Types::GlobalIDType[::Packages::DependencyLink], null: false, description: 'ID of the dependency link.' field :metadata, Types::Packages::DependencyLinkMetadataType, null: true, description: 'Dependency link metadata.' # NOTE: This method must be kept in sync with the union diff --git a/app/graphql/types/packages/package_file_type.rb b/app/graphql/types/packages/package_file_type.rb index f90a0992bf8..b058dc0ab0d 100644 --- a/app/graphql/types/packages/package_file_type.rb +++ b/app/graphql/types/packages/package_file_type.rb @@ -7,17 +7,17 @@ module Types description 'Represents a package file' authorize :read_package - field :id, ::Types::GlobalIDType[::Packages::PackageFile], null: false, description: 'ID of the file.' field :created_at, Types::TimeType, null: false, description: 'Created date.' - field :updated_at, Types::TimeType, null: false, description: 'Updated date.' - field :size, GraphQL::Types::String, null: false, description: 'Size of the package file.' - field :file_name, GraphQL::Types::String, null: false, description: 'Name of the package file.' field :download_path, GraphQL::Types::String, null: false, description: 'Download path of the package file.' field :file_md5, GraphQL::Types::String, null: true, description: 'Md5 of the package file.' - field :file_sha1, GraphQL::Types::String, null: true, description: 'Sha1 of the package file.' - field :file_sha256, GraphQL::Types::String, null: true, description: 'Sha256 of the package file.' field :file_metadata, Types::Packages::FileMetadataType, null: true, description: 'File metadata.' + field :file_name, GraphQL::Types::String, null: false, description: 'Name of the package file.' + field :file_sha1, GraphQL::Types::String, null: true, description: 'Sha1 of the package file.' + field :file_sha256, GraphQL::Types::String, null: true, description: 'Sha256 of the package file.' + field :id, ::Types::GlobalIDType[::Packages::PackageFile], null: false, description: 'ID of the file.' + field :size, GraphQL::Types::String, null: false, description: 'Size of the package file.' + field :updated_at, Types::TimeType, null: false, description: 'Updated date.' # NOTE: This method must be kept in sync with the union # type: `Types::Packages::FileMetadataType`. diff --git a/app/graphql/types/packages/package_tag_type.rb b/app/graphql/types/packages/package_tag_type.rb index f1f96c42e27..9d462e90b6f 100644 --- a/app/graphql/types/packages/package_tag_type.rb +++ b/app/graphql/types/packages/package_tag_type.rb @@ -7,9 +7,9 @@ module Types description 'Represents a package tag' authorize :read_package + field :created_at, Types::TimeType, null: false, description: 'Created date.' field :id, GraphQL::Types::ID, null: false, description: 'ID of the tag.' field :name, GraphQL::Types::String, null: false, description: 'Name of the tag.' - field :created_at, Types::TimeType, null: false, description: 'Created date.' field :updated_at, Types::TimeType, null: false, description: 'Updated date.' end end diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb index d1312cb963d..1155be28e08 100644 --- a/app/graphql/types/packages/package_type.rb +++ b/app/graphql/types/packages/package_type.rb @@ -13,23 +13,23 @@ module Types field :id, ::Types::GlobalIDType[::Packages::Package], null: false, description: 'ID of the package.' - field :name, GraphQL::Types::String, null: false, description: 'Name of the package.' + field :can_destroy, GraphQL::Types::Boolean, null: false, description: 'Whether the user can destroy the package.' field :created_at, Types::TimeType, null: false, description: 'Date of creation.' - field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' - field :version, GraphQL::Types::String, null: true, description: 'Version string.' + field :metadata, Types::Packages::MetadataType, null: true, + description: 'Package metadata.' + field :name, GraphQL::Types::String, null: false, description: 'Name of the package.' field :package_type, Types::Packages::PackageTypeEnum, null: false, description: 'Package type.' - field :tags, Types::Packages::PackageTagType.connection_type, null: true, description: 'Package tags.' - field :project, Types::ProjectType, null: false, description: 'Project where the package is stored.' field :pipelines, Types::Ci::PipelineType.connection_type, null: true, description: 'Pipelines that built the package.', deprecated: { reason: 'Due to scalability concerns, this field is going to be removed', milestone: '14.6' } - field :metadata, Types::Packages::MetadataType, null: true, - description: 'Package metadata.' + field :project, Types::ProjectType, null: false, description: 'Project where the package is stored.' + field :status, Types::Packages::PackageStatusEnum, null: false, description: 'Package status.' + field :tags, Types::Packages::PackageTagType.connection_type, null: true, description: 'Package tags.' + field :updated_at, Types::TimeType, null: false, description: 'Date of most recent update.' + field :version, GraphQL::Types::String, null: true, description: 'Version string.' field :versions, ::Types::Packages::PackageType.connection_type, null: true, description: 'Other versions of the package.', deprecated: { reason: 'This field is now only returned in the PackageDetailsType', milestone: '13.11' } - field :status, Types::Packages::PackageStatusEnum, null: false, description: 'Package status.' - field :can_destroy, GraphQL::Types::Boolean, null: false, description: 'Whether the user can destroy the package.' def project Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find diff --git a/app/graphql/types/project_statistics_type.rb b/app/graphql/types/project_statistics_type.rb index ab2b9c2a3af..1146774b43c 100644 --- a/app/graphql/types/project_statistics_type.rb +++ b/app/graphql/types/project_statistics_type.rb @@ -9,23 +9,23 @@ module Types field :commit_count, GraphQL::Types::Float, null: false, description: 'Commit count of the project.' - field :storage_size, GraphQL::Types::Float, null: false, - description: 'Storage size of the project in bytes.' - field :repository_size, GraphQL::Types::Float, null: false, - description: 'Repository size of the project in bytes.' - field :lfs_objects_size, GraphQL::Types::Float, null: false, - description: 'Large File Storage (LFS) object size of the project in bytes.' field :build_artifacts_size, GraphQL::Types::Float, null: false, description: 'Build artifacts size of the project in bytes.' + field :lfs_objects_size, GraphQL::Types::Float, null: false, + description: 'Large File Storage (LFS) object size of the project in bytes.' field :packages_size, GraphQL::Types::Float, null: false, description: 'Packages size of the project in bytes.' - field :wiki_size, GraphQL::Types::Float, null: true, - description: 'Wiki size of the project in bytes.' - field :snippets_size, GraphQL::Types::Float, null: true, - description: 'Snippets size of the project in bytes.' field :pipeline_artifacts_size, GraphQL::Types::Float, null: true, description: 'CI Pipeline artifacts size in bytes.' + field :repository_size, GraphQL::Types::Float, null: false, + description: 'Repository size of the project in bytes.' + field :snippets_size, GraphQL::Types::Float, null: true, + description: 'Snippets size of the project in bytes.' + field :storage_size, GraphQL::Types::Float, null: false, + description: 'Storage size of the project in bytes.' field :uploads_size, GraphQL::Types::Float, null: true, description: 'Uploads size of the project in bytes.' + field :wiki_size, GraphQL::Types::Float, null: true, + description: 'Wiki size of the project in bytes.' end end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index dc428e7bdce..47e9a6c11fc 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -11,43 +11,43 @@ module Types field :id, GraphQL::Types::ID, null: false, description: 'ID of the project.' + field :ci_config_path_or_default, GraphQL::Types::String, null: false, + description: 'Path of the CI configuration file.' field :full_path, GraphQL::Types::ID, null: false, description: 'Full path of the project.' field :path, GraphQL::Types::String, null: false, description: 'Path of the project.' - field :ci_config_path_or_default, GraphQL::Types::String, null: false, - description: 'Path of the CI configuration file.' field :sast_ci_configuration, Types::CiConfiguration::Sast::Type, null: true, calls_gitaly: true, description: 'SAST CI configuration for the project.' - field :name_with_namespace, GraphQL::Types::String, null: false, - description: 'Full name of the project with its namespace.' field :name, GraphQL::Types::String, null: false, description: 'Name of the project (without namespace).' + field :name_with_namespace, GraphQL::Types::String, null: false, + description: 'Full name of the project with its namespace.' field :description, GraphQL::Types::String, null: true, description: 'Short description of the project.' field :tag_list, GraphQL::Types::String, null: true, deprecated: { reason: 'Use `topics`', milestone: '13.12' }, - description: 'List of project topics (not Git tags).' + description: 'List of project topics (not Git tags).', method: :topic_list field :topics, [GraphQL::Types::String], null: true, - description: 'List of project topics.' + description: 'List of project topics.', method: :topic_list - field :ssh_url_to_repo, GraphQL::Types::String, null: true, - description: 'URL to connect to the project via SSH.' field :http_url_to_repo, GraphQL::Types::String, null: true, description: 'URL to connect to the project via HTTPS.' + field :ssh_url_to_repo, GraphQL::Types::String, null: true, + description: 'URL to connect to the project via SSH.' field :web_url, GraphQL::Types::String, null: true, description: 'Web URL of the project.' - field :star_count, GraphQL::Types::Int, null: false, - description: 'Number of times the project has been starred.' field :forks_count, GraphQL::Types::Int, null: false, calls_gitaly: true, # 4 times description: 'Number of times the project has been forked.' + field :star_count, GraphQL::Types::Int, null: false, + description: 'Number of times the project has been starred.' field :created_at, Types::TimeType, null: true, description: 'Timestamp of the project creation.' @@ -60,12 +60,12 @@ module Types field :visibility, GraphQL::Types::String, null: true, description: 'Visibility of the project.' - field :shared_runners_enabled, GraphQL::Types::Boolean, null: true, - description: 'Indicates if shared runners are enabled for the project.' field :lfs_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if the project has Large File Storage (LFS) enabled.' field :merge_requests_ff_only_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.' + field :shared_runners_enabled, GraphQL::Types::Boolean, null: true, + description: 'Indicates if shared runners are enabled for the project.' field :service_desk_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if the project has service desk enabled.' @@ -85,33 +85,35 @@ module Types field :open_issues_count, GraphQL::Types::Int, null: true, description: 'Number of open issues for the project.' + field :allow_merge_on_skipped_pipeline, GraphQL::Types::Boolean, null: true, + description: 'If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of the project can also be merged with skipped jobs.' + field :autoclose_referenced_issues, GraphQL::Types::Boolean, null: true, + description: 'Indicates if issues referenced by merge requests and commits within the default branch are closed automatically.' field :import_status, GraphQL::Types::String, null: true, description: 'Status of import background job of the project.' field :jira_import_status, GraphQL::Types::String, null: true, description: 'Status of Jira import background job of the project.' - field :only_allow_merge_if_pipeline_succeeds, GraphQL::Types::Boolean, null: true, - description: 'Indicates if merge requests of the project can only be merged with successful jobs.' - field :allow_merge_on_skipped_pipeline, GraphQL::Types::Boolean, null: true, - description: 'If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of the project can also be merged with skipped jobs.' - field :request_access_enabled, GraphQL::Types::Boolean, null: true, - description: 'Indicates if users can request member access to the project.' field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::Types::Boolean, null: true, description: 'Indicates if merge requests of the project can only be merged when all the discussions are resolved.' + field :only_allow_merge_if_pipeline_succeeds, GraphQL::Types::Boolean, null: true, + description: 'Indicates if merge requests of the project can only be merged with successful jobs.' field :printing_merge_request_link_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line.' field :remove_source_branch_after_merge, GraphQL::Types::Boolean, null: true, description: 'Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project.' - field :autoclose_referenced_issues, GraphQL::Types::Boolean, null: true, - description: 'Indicates if issues referenced by merge requests and commits within the default branch are closed automatically.' - field :suggestion_commit_message, GraphQL::Types::String, null: true, - description: 'Commit message used to apply merge request suggestions.' + field :request_access_enabled, GraphQL::Types::Boolean, null: true, + description: 'Indicates if users can request member access to the project.' field :squash_read_only, GraphQL::Types::Boolean, null: false, method: :squash_readonly?, description: 'Indicates if `squashReadOnly` is enabled.' + field :suggestion_commit_message, GraphQL::Types::String, null: true, + description: 'Commit message used to apply merge request suggestions.' + # No, the quotes are not a typo. Used to get around circular dependencies. + # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27536#note_871009675 + field :group, 'Types::GroupType', null: true, + description: 'Group of the project.' field :namespace, Types::NamespaceType, null: true, description: 'Namespace of the project.' - field :group, Types::GroupType, null: true, - description: 'Group of the project.' field :statistics, Types::ProjectStatisticsType, null: true, @@ -397,8 +399,9 @@ module Types field :work_item_types, Types::WorkItems::TypeType.connection_type, resolver: Resolvers::WorkItems::TypesResolver, - description: 'Work item types available to the project.', - feature_flag: :work_items + description: 'Work item types available to the project.' \ + ' Returns `null` if `work_items` feature flag is disabled.' \ + ' This flag is disabled by default, because the feature is experimental and is subject to change without notice.' def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| @@ -458,14 +461,6 @@ module Types object.service_desk_address end - def tag_list - object.topic_list - end - - def topics - object.topic_list - end - private def project diff --git a/app/graphql/types/projects/service_type.rb b/app/graphql/types/projects/service_type.rb index 4a9e5dcbfe9..88b7b95aa57 100644 --- a/app/graphql/types/projects/service_type.rb +++ b/app/graphql/types/projects/service_type.rb @@ -10,9 +10,20 @@ module Types # https://gitlab.com/gitlab-org/gitlab/-/issues/213088 field :type, GraphQL::Types::String, null: true, description: 'Class name of the service.' + field :service_type, ::Types::Projects::ServiceTypeEnum, null: true, + description: 'Type of the service.' field :active, GraphQL::Types::Boolean, null: true, description: 'Indicates if the service is active.' + def type + enum = ::Types::Projects::ServiceTypeEnum.coerce_result(service_type, context) + enum.downcase.camelize + end + + def service_type + object.type + end + definition_methods do def resolve_type(object, context) if object.is_a?(::Integrations::Jira) diff --git a/app/graphql/types/projects/service_type_enum.rb b/app/graphql/types/projects/service_type_enum.rb index 027026dc16c..d0cecbfea49 100644 --- a/app/graphql/types/projects/service_type_enum.rb +++ b/app/graphql/types/projects/service_type_enum.rb @@ -5,8 +5,21 @@ module Types class ServiceTypeEnum < BaseEnum graphql_name 'ServiceType' - ::Integration.available_integration_types(include_dev: false).each do |type| - value type.underscore.upcase, value: type, description: "#{type} type" + class << self + private + + def type_description(name, type) + "#{type} type" + end + end + + # This prepend must stay here because the dynamic block below depends on it. + prepend_mod # rubocop: disable Cop/InjectEnterpriseEditionModule + + ::Integration.available_integration_names(include_dev: false).each do |name| + type = "#{name.camelize}Service" + domain_value = Integration.integration_name_to_type(name) + value type.underscore.upcase, value: domain_value, description: type_description(name, type) end end end diff --git a/app/graphql/types/projects/services/jira_project_type.rb b/app/graphql/types/projects/services/jira_project_type.rb index 957ac91db6b..0ff1b9d8903 100644 --- a/app/graphql/types/projects/services/jira_project_type.rb +++ b/app/graphql/types/projects/services/jira_project_type.rb @@ -9,11 +9,11 @@ module Types field :key, GraphQL::Types::String, null: false, description: 'Key of the Jira project.' + field :name, GraphQL::Types::String, null: true, + description: 'Name of the Jira project.' field :project_id, GraphQL::Types::Int, null: false, description: 'ID of the Jira project.', method: :id - field :name, GraphQL::Types::String, null: true, - description: 'Name of the Jira project.' end # rubocop:enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 4a4d6727c3f..cc46c7e86e4 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -87,6 +87,12 @@ module Types argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'Global ID of the issue.' end + field :work_item, Types::WorkItemType, + null: true, + resolver: Resolvers::WorkItemResolver, + description: 'Find a work item. Returns `null` if `work_items` feature flag is disabled.' \ + ' The feature is experimental and is subject to change without notice.' + field :merge_request, Types::MergeRequestType, null: true, description: 'Find a merge request.' do @@ -145,6 +151,10 @@ module Types resolver: Resolvers::TopicsResolver, description: "Find project topics." + field :gitpod_enabled, GraphQL::Types::Boolean, + null: true, + description: "Whether Gitpod is enabled in application settings." + def design_management DesignManagementObject.new(nil) end @@ -189,6 +199,10 @@ module Types Gitlab::CurrentSettings.current_application_settings end + def gitpod_enabled + application_settings.gitpod_enabled + end + def query_complexity context.query end diff --git a/app/graphql/types/release_asset_link_type.rb b/app/graphql/types/release_asset_link_type.rb index 02961f2f73f..33dcb5125e3 100644 --- a/app/graphql/types/release_asset_link_type.rb +++ b/app/graphql/types/release_asset_link_type.rb @@ -7,21 +7,21 @@ module Types authorize :read_release + field :external, GraphQL::Types::Boolean, null: true, method: :external?, + description: 'Indicates the link points to an external resource.' field :id, GraphQL::Types::ID, null: false, description: 'ID of the link.' + field :link_type, Types::ReleaseAssetLinkTypeEnum, null: true, + description: 'Type of the link: `other`, `runbook`, `image`, `package`; defaults to `other`.' field :name, GraphQL::Types::String, null: true, description: 'Name of the link.' field :url, GraphQL::Types::String, null: true, description: 'URL of the link.' - field :link_type, Types::ReleaseAssetLinkTypeEnum, null: true, - description: 'Type of the link: `other`, `runbook`, `image`, `package`; defaults to `other`.' - field :external, GraphQL::Types::Boolean, null: true, method: :external?, - description: 'Indicates the link points to an external resource.' - field :direct_asset_url, GraphQL::Types::String, null: true, - description: 'Direct asset URL of the link.' field :direct_asset_path, GraphQL::Types::String, null: true, method: :filepath, description: 'Relative path for the direct asset link.' + field :direct_asset_url, GraphQL::Types::String, null: true, + description: 'Direct asset URL of the link.' def direct_asset_url return object.url unless object.filepath diff --git a/app/graphql/types/release_links_type.rb b/app/graphql/types/release_links_type.rb index 37ad52ce6d0..b7a1a5a9dbe 100644 --- a/app/graphql/types/release_links_type.rb +++ b/app/graphql/types/release_links_type.rb @@ -10,25 +10,25 @@ module Types present_using ReleasePresenter - field :self_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the release.' + field :closed_issues_url, GraphQL::Types::String, null: true, + description: 'HTTP URL of the issues page, filtered by this release and `state=closed`.', + authorize: :download_code + field :closed_merge_requests_url, GraphQL::Types::String, null: true, + description: 'HTTP URL of the merge request page , filtered by this release and `state=closed`.', + authorize: :download_code field :edit_url, GraphQL::Types::String, null: true, description: "HTTP URL of the release's edit page.", authorize: :update_release - field :opened_merge_requests_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the merge request page, filtered by this release and `state=open`.', - authorize: :download_code field :merged_merge_requests_url, GraphQL::Types::String, null: true, description: 'HTTP URL of the merge request page , filtered by this release and `state=merged`.', authorize: :download_code - field :closed_merge_requests_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the merge request page , filtered by this release and `state=closed`.', - authorize: :download_code field :opened_issues_url, GraphQL::Types::String, null: true, description: 'HTTP URL of the issues page, filtered by this release and `state=open`.', authorize: :download_code - field :closed_issues_url, GraphQL::Types::String, null: true, - description: 'HTTP URL of the issues page, filtered by this release and `state=closed`.', + field :opened_merge_requests_url, GraphQL::Types::String, null: true, + description: 'HTTP URL of the merge request page, filtered by this release and `state=open`.', authorize: :download_code + field :self_url, GraphQL::Types::String, null: true, + description: 'HTTP URL of the release.' end end diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb index fbc3779ea9b..95b6b43bb46 100644 --- a/app/graphql/types/release_type.rb +++ b/app/graphql/types/release_type.rb @@ -13,30 +13,30 @@ module Types present_using ReleasePresenter - field :tag_name, GraphQL::Types::String, null: true, method: :tag, - description: 'Name of the tag associated with the release.' - field :tag_path, GraphQL::Types::String, null: true, - description: 'Relative web path to the tag associated with the release.', - authorize: :download_code + field :assets, Types::ReleaseAssetsType, null: true, method: :itself, + description: 'Assets of the release.' + field :created_at, Types::TimeType, null: true, + description: 'Timestamp of when the release was created.' field :description, GraphQL::Types::String, null: true, description: 'Description (also known as "release notes") of the release.' + field :evidences, Types::EvidenceType.connection_type, null: true, + description: 'Evidence for the release.' + field :links, Types::ReleaseLinksType, null: true, method: :itself, + description: 'Links of the release.' + field :milestones, Types::MilestoneType.connection_type, null: true, + description: 'Milestones associated to the release.', + resolver: ::Resolvers::ReleaseMilestonesResolver field :name, GraphQL::Types::String, null: true, description: 'Name of the release.' - field :created_at, Types::TimeType, null: true, - description: 'Timestamp of when the release was created.' field :released_at, Types::TimeType, null: true, description: 'Timestamp of when the release was released.' + field :tag_name, GraphQL::Types::String, null: true, method: :tag, + description: 'Name of the tag associated with the release.' + field :tag_path, GraphQL::Types::String, null: true, + description: 'Relative web path to the tag associated with the release.', + authorize: :download_code field :upcoming_release, GraphQL::Types::Boolean, null: true, method: :upcoming_release?, description: 'Indicates the release is an upcoming release.' - field :assets, Types::ReleaseAssetsType, null: true, method: :itself, - description: 'Assets of the release.' - field :links, Types::ReleaseLinksType, null: true, method: :itself, - description: 'Links of the release.' - field :milestones, Types::MilestoneType.connection_type, null: true, - description: 'Milestones associated to the release.', - resolver: ::Resolvers::ReleaseMilestonesResolver - field :evidences, Types::EvidenceType.connection_type, null: true, - description: 'Evidence for the release.' field :author, Types::UserType, null: true, description: 'User that created the release.' diff --git a/app/graphql/types/repository/blob_type.rb b/app/graphql/types/repository/blob_type.rb index bfd59763a07..652e2882584 100644 --- a/app/graphql/types/repository/blob_type.rb +++ b/app/graphql/types/repository/blob_type.rb @@ -41,6 +41,9 @@ module Types field :ide_fork_and_edit_path, GraphQL::Types::String, null: true, description: 'Web path to edit this blob in the Web IDE using a forked project.' + field :fork_and_view_path, GraphQL::Types::String, null: true, + description: 'Web path to view this blob using a forked project.' + field :size, GraphQL::Types::Int, null: true, description: 'Size (in bytes) of the blob.' @@ -74,6 +77,9 @@ module Types field :pipeline_editor_path, GraphQL::Types::String, null: true, description: 'Web path to edit .gitlab-ci.yml file.' + field :gitpod_blob_url, GraphQL::Types::String, null: true, + description: 'URL to the blob within Gitpod.' + field :find_file_path, GraphQL::Types::String, null: true, description: 'Web path to find file.' @@ -131,6 +137,12 @@ module Types null: true, calls_gitaly: true + field :code_navigation_path, GraphQL::Types::String, null: true, calls_gitaly: true, + description: 'Web path for code navigation.' + + field :project_blob_path_root, GraphQL::Types::String, null: true, + description: 'Web path for the root of the blob.' + def raw_text_blob object.data unless object.binary? end diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb index fc9860900c9..aa02f0058da 100644 --- a/app/graphql/types/repository_type.rb +++ b/app/graphql/types/repository_type.rb @@ -6,17 +6,6 @@ module Types authorize :download_code - field :root_ref, GraphQL::Types::String, null: true, calls_gitaly: true, - description: 'Default branch of the repository.' - field :empty, GraphQL::Types::Boolean, null: false, method: :empty?, calls_gitaly: true, - description: 'Indicates repository has no visible content.' - field :exists, GraphQL::Types::Boolean, null: false, method: :exists?, calls_gitaly: true, - description: 'Indicates a corresponding Git repository exists on disk.' - field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true, - description: 'Tree of the repository.' - field :paginated_tree, Types::Tree::TreeType.connection_type, null: true, resolver: Resolvers::PaginatedTreeResolver, calls_gitaly: true, - max_page_size: 100, - description: 'Paginated tree of the repository.' field :blobs, Types::Repository::BlobType.connection_type, null: true, resolver: Resolvers::BlobsResolver, calls_gitaly: true, description: 'Blobs contained within the repository' field :branch_names, [GraphQL::Types::String], null: true, calls_gitaly: true, @@ -26,5 +15,16 @@ module Types description: 'Shows a disk path of the repository.', null: true, authorize: :read_storage_disk_path + field :empty, GraphQL::Types::Boolean, null: false, method: :empty?, calls_gitaly: true, + description: 'Indicates repository has no visible content.' + field :exists, GraphQL::Types::Boolean, null: false, method: :exists?, calls_gitaly: true, + description: 'Indicates a corresponding Git repository exists on disk.' + field :paginated_tree, Types::Tree::TreeType.connection_type, null: true, resolver: Resolvers::PaginatedTreeResolver, calls_gitaly: true, + max_page_size: 100, + description: 'Paginated tree of the repository.' + field :root_ref, GraphQL::Types::String, null: true, calls_gitaly: true, + description: 'Default branch of the repository.' + field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true, + description: 'Tree of the repository.' end end diff --git a/app/graphql/types/root_storage_statistics_type.rb b/app/graphql/types/root_storage_statistics_type.rb index 4dcadf1274f..467331c5643 100644 --- a/app/graphql/types/root_storage_statistics_type.rb +++ b/app/graphql/types/root_storage_statistics_type.rb @@ -6,15 +6,15 @@ module Types authorize :read_statistics - field :storage_size, GraphQL::Types::Float, null: false, description: 'Total storage in bytes.' - field :repository_size, GraphQL::Types::Float, null: false, description: 'Git repository size in bytes.' - field :lfs_objects_size, GraphQL::Types::Float, null: false, description: 'LFS objects size in bytes.' field :build_artifacts_size, GraphQL::Types::Float, null: false, description: 'CI artifacts size in bytes.' + field :dependency_proxy_size, GraphQL::Types::Float, null: false, description: 'Dependency Proxy sizes in bytes.' + field :lfs_objects_size, GraphQL::Types::Float, null: false, description: 'LFS objects size in bytes.' field :packages_size, GraphQL::Types::Float, null: false, description: 'Packages size in bytes.' - field :wiki_size, GraphQL::Types::Float, null: false, description: 'Wiki size in bytes.' - field :snippets_size, GraphQL::Types::Float, null: false, description: 'Snippets size in bytes.' field :pipeline_artifacts_size, GraphQL::Types::Float, null: false, description: 'CI pipeline artifacts size in bytes.' + field :repository_size, GraphQL::Types::Float, null: false, description: 'Git repository size in bytes.' + field :snippets_size, GraphQL::Types::Float, null: false, description: 'Snippets size in bytes.' + field :storage_size, GraphQL::Types::Float, null: false, description: 'Total storage in bytes.' field :uploads_size, GraphQL::Types::Float, null: false, description: 'Uploads size in bytes.' - field :dependency_proxy_size, GraphQL::Types::Float, null: false, description: 'Dependency Proxy sizes in bytes.' + field :wiki_size, GraphQL::Types::Float, null: false, description: 'Wiki size in bytes.' end end diff --git a/app/graphql/types/saved_reply_type.rb b/app/graphql/types/saved_reply_type.rb new file mode 100644 index 00000000000..329f431b10e --- /dev/null +++ b/app/graphql/types/saved_reply_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + class SavedReplyType < BaseObject + graphql_name 'SavedReply' + + authorize :read_saved_replies + + field :id, Types::GlobalIDType[::Users::SavedReply], + null: false, + description: 'Global ID of the saved reply.' + + field :content, GraphQL::Types::String, + null: false, + description: 'Content of the saved reply.' + + field :name, GraphQL::Types::String, + null: false, + description: 'Name of the saved reply.' + end +end diff --git a/app/graphql/types/task_completion_status.rb b/app/graphql/types/task_completion_status.rb index 3aa19ff9413..9a979b04d37 100644 --- a/app/graphql/types/task_completion_status.rb +++ b/app/graphql/types/task_completion_status.rb @@ -8,10 +8,10 @@ module Types graphql_name 'TaskCompletionStatus' description 'Completion status of tasks' - field :count, GraphQL::Types::Int, null: false, - description: 'Number of total tasks.' field :completed_count, GraphQL::Types::Int, null: false, description: 'Number of completed tasks.' + field :count, GraphQL::Types::Int, null: false, + description: 'Number of total tasks.' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/todo_type.rb b/app/graphql/types/todo_type.rb index 34ba2c75b5f..f21b2b261a3 100644 --- a/app/graphql/types/todo_type.rb +++ b/app/graphql/types/todo_type.rb @@ -18,7 +18,7 @@ module Types null: true, authorize: :read_project - field :group, Types::GroupType, + field :group, 'Types::GroupType', description: 'Group this to-do item is associated with.', null: true, authorize: :read_group @@ -31,6 +31,11 @@ module Types description: 'Action of the to-do item.', null: false + field :target, Types::TodoableInterface, + description: 'Target of the to-do item.', + calls_gitaly: true, + null: false + field :target_type, Types::TodoTargetEnum, description: 'Target type of the to-do item.', null: false @@ -59,5 +64,28 @@ module Types def author Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find end + + def target + if object.for_commit? + Gitlab::Graphql::Loaders::BatchCommitLoader.new( + container_class: Project, + container_id: object.project_id, + oid: object.commit_id + ).find + else + Gitlab::Graphql::Loaders::BatchModelLoader.new(target_type_class, object.target_id).find + end + end + + private + + def target_type_class + klass = object.target_type.safe_constantize + raise "Invalid target type \"#{object.target_type}\"" unless klass < Todoable + + klass + end end end + +Types::TodoType.prepend_mod diff --git a/app/graphql/types/todoable_interface.rb b/app/graphql/types/todoable_interface.rb new file mode 100644 index 00000000000..7d437973c12 --- /dev/null +++ b/app/graphql/types/todoable_interface.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Types + module TodoableInterface + include Types::BaseInterface + + graphql_name 'Todoable' + + field :web_url, GraphQL::Types::String, null: true, description: 'URL of this object.' + + def self.resolve_type(object, context) + case object + when Issue + Types::IssueType + when MergeRequest + Types::MergeRequestType + when ::DesignManagement::Design + Types::DesignManagement::DesignType + when ::AlertManagement::Alert + Types::AlertManagement::AlertType + when Commit + Types::CommitType + else + raise "Unknown GraphQL type for #{object}" + end + end + end +end + +Types::TodoableInterface.prepend_mod diff --git a/app/graphql/types/tree/blob_type.rb b/app/graphql/types/tree/blob_type.rb index bcff65be652..284542e1d2a 100644 --- a/app/graphql/types/tree/blob_type.rb +++ b/app/graphql/types/tree/blob_type.rb @@ -9,15 +9,15 @@ module Types implements Types::Tree::EntryType present_using BlobPresenter - field :web_url, GraphQL::Types::String, null: true, - description: 'Web URL of the blob.' - field :web_path, GraphQL::Types::String, null: true, - description: 'Web path of the blob.' field :lfs_oid, GraphQL::Types::String, null: true, calls_gitaly: true, description: 'LFS ID of the blob.' field :mode, GraphQL::Types::String, null: true, description: 'Blob mode in numeric format.' + field :web_path, GraphQL::Types::String, null: true, + description: 'Web path of the blob.' + field :web_url, GraphQL::Types::String, null: true, + description: 'Web URL of the blob.' def lfs_oid Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(object.repository, object.id).find diff --git a/app/graphql/types/tree/submodule_type.rb b/app/graphql/types/tree/submodule_type.rb index bc7828dbffa..8f462011f0f 100644 --- a/app/graphql/types/tree/submodule_type.rb +++ b/app/graphql/types/tree/submodule_type.rb @@ -8,10 +8,10 @@ module Types implements Types::Tree::EntryType - field :web_url, type: GraphQL::Types::String, null: true, - description: 'Web URL for the sub-module.' field :tree_url, type: GraphQL::Types::String, null: true, description: 'Tree URL for the sub-module.' + field :web_url, type: GraphQL::Types::String, null: true, + description: 'Web URL for the sub-module.' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/tree/tree_entry_type.rb b/app/graphql/types/tree/tree_entry_type.rb index cdc84c8e318..28024fd010b 100644 --- a/app/graphql/types/tree/tree_entry_type.rb +++ b/app/graphql/types/tree/tree_entry_type.rb @@ -10,10 +10,10 @@ module Types implements Types::Tree::EntryType present_using TreeEntryPresenter - field :web_url, GraphQL::Types::String, null: true, - description: 'Web URL for the tree entry (directory).' field :web_path, GraphQL::Types::String, null: true, description: 'Web path for the tree entry (directory).' + field :web_url, GraphQL::Types::String, null: true, + description: 'Web URL for the tree entry (directory).' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/user_callout_type.rb b/app/graphql/types/user_callout_type.rb index 0ff32d68400..526027322ef 100644 --- a/app/graphql/types/user_callout_type.rb +++ b/app/graphql/types/user_callout_type.rb @@ -4,9 +4,9 @@ module Types class UserCalloutType < BaseObject # rubocop:disable Graphql/AuthorizeTypes graphql_name 'UserCallout' - field :feature_name, UserCalloutFeatureNameEnum, null: true, - description: 'Name of the feature that the callout is for.' field :dismissed_at, Types::TimeType, null: true, description: 'Date when the callout was dismissed.' + field :feature_name, UserCalloutFeatureNameEnum, null: true, + description: 'Name of the feature that the callout is for.' end end diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index 24fca80d5a9..2c9592a7f5a 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -115,6 +115,19 @@ module Types extras: [:lookahead], complexity: 5, resolver: ::Resolvers::TimelogResolver + field :saved_replies, + Types::SavedReplyType.connection_type, + null: true, + description: 'Saved replies authored by the user.' + + field :gitpod_enabled, GraphQL::Types::Boolean, null: true, + description: 'Whether Gitpod is enabled at the user level.' + + field :preferences_gitpod_path, GraphQL::Types::String, null: true, + description: 'Web path to the Gitpod section within user preferences.' + + field :profile_enable_gitpod_path, GraphQL::Types::String, null: true, + description: 'Web path to enable Gitpod for the user.' definition_methods do def resolve_type(object, context) @@ -125,14 +138,7 @@ module Types end def redacted_name - return object.name unless object.project_bot? - - return object.name if context[:current_user]&.can?(:read_project, object.projects.first) - - # If the requester does not have permission to read the project bot name, - # the API returns an arbitrary string. UI changes will be addressed in a follow up issue: - # https://gitlab.com/gitlab-org/gitlab/-/issues/346058 - '****' + object.redacted_name(context[:current_user]) end end end diff --git a/app/graphql/types/user_status_type.rb b/app/graphql/types/user_status_type.rb index 61abec0ba96..68c00bffe48 100644 --- a/app/graphql/types/user_status_type.rb +++ b/app/graphql/types/user_status_type.rb @@ -7,11 +7,11 @@ module Types markdown_field :message_html, null: true, description: 'HTML of the user status message' - field :message, GraphQL::Types::String, null: true, - description: 'User status message.' - field :emoji, GraphQL::Types::String, null: true, - description: 'String representation of emoji.' field :availability, Types::AvailabilityEnum, null: false, description: 'User availability status.' + field :emoji, GraphQL::Types::String, null: true, + description: 'String representation of emoji.' + field :message, GraphQL::Types::String, null: true, + description: 'User status message.' end end diff --git a/app/graphql/types/work_item_id_type.rb b/app/graphql/types/work_item_id_type.rb new file mode 100644 index 00000000000..ddcf3416014 --- /dev/null +++ b/app/graphql/types/work_item_id_type.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Types + # rubocop:disable Graphql/AuthorizeTypes + # TODO: This type should be removed when Work Items become generally available. + # This mechanism is introduced temporarily to make the client implementation easier during this transition. + class WorkItemIdType < GlobalIDType + graphql_name 'WorkItemID' + description <<~DESC + A `WorkItemID` is a global ID. It is encoded as a string. + + An example `WorkItemID` is: `"gid://gitlab/WorkItem/1"`. + + While we transition from Issues into Work Items this type will temporarily support + `IssueID` like: `"gid://gitlab/Issue/1"`. This behavior will be removed without notice in the future. + DESC + + class << self + def coerce_result(gid, ctx) + global_id = ::Gitlab::GlobalId.as_global_id(gid, model_name: 'WorkItem') + + raise GraphQL::CoercionError, "Expected a WorkItem ID, got #{global_id}" unless suitable?(global_id) + + # Always return a WorkItemID even if an Issue is returned by a resolver + work_item_gid(global_id).to_s + end + + def coerce_input(string, ctx) + gid = super + # Always return a WorkItemID even if an Issue Global ID is provided as input + return work_item_gid(gid) if suitable?(gid) + + raise GraphQL::CoercionError, "#{string.inspect} does not represent an instance of WorkItem" + end + + def suitable?(gid) + return false if gid&.model_name&.safe_constantize.blank? + + [::WorkItem, ::Issue].any? { |model_class| gid.model_class == model_class } + end + + private + + def work_item_gid(gid) + GlobalID.new(::Gitlab::GlobalId.build(model_name: 'WorkItem', id: gid.model_id)) + end + end + end + # rubocop:enable Graphql/AuthorizeTypes +end diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb index 15a5557b489..512b9ef64d2 100644 --- a/app/graphql/types/work_item_type.rb +++ b/app/graphql/types/work_item_type.rb @@ -4,7 +4,7 @@ module Types class WorkItemType < BaseObject graphql_name 'WorkItem' - authorize :read_issue + authorize :read_work_item field :description, GraphQL::Types::String, null: true, description: 'Description of the work item.' @@ -12,6 +12,8 @@ module Types description: 'Global ID of the work item.' field :iid, GraphQL::Types::ID, null: false, description: 'Internal ID of the work item.' + field :lock_version, GraphQL::Types::Int, null: false, + description: 'Lock version of the work item. Incremented each time the work item is updated.' field :state, WorkItemStateEnum, null: false, description: 'State of the work item.' field :title, GraphQL::Types::String, null: false, diff --git a/app/graphql/types/work_items/convert_task_input_type.rb b/app/graphql/types/work_items/convert_task_input_type.rb new file mode 100644 index 00000000000..1f142c6815c --- /dev/null +++ b/app/graphql/types/work_items/convert_task_input_type.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module Types + module WorkItems + class ConvertTaskInputType < BaseInputObject + graphql_name 'WorkItemConvertTaskInput' + + argument :line_number_end, GraphQL::Types::Int, + required: true, + description: 'Last line in the Markdown source that defines the list item task.' + argument :line_number_start, GraphQL::Types::Int, + required: true, + description: 'First line in the Markdown source that defines the list item task.' + argument :lock_version, GraphQL::Types::Int, + required: true, + description: 'Current lock version of the work item containing the task in the description.' + argument :title, GraphQL::Types::String, + required: true, + description: 'Full string of the task to be replaced. New title for the created work item.' + argument :work_item_type_id, ::Types::GlobalIDType[::WorkItems::Type], + required: true, + description: 'Global ID of the work item type used to create the new work item.', + prepare: ->(attribute, _ctx) { work_item_type_global_id(attribute) } + + class << self + def work_item_type_global_id(global_id) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + global_id = ::Types::GlobalIDType[::WorkItems::Type].coerce_isolated_input(global_id) + + global_id&.model_id + end + end + end + end +end |