diff options
Diffstat (limited to 'app/graphql')
31 files changed, 699 insertions, 234 deletions
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb index 1899278ff3c..a5ddf316572 100644 --- a/app/graphql/gitlab_schema.rb +++ b/app/graphql/gitlab_schema.rb @@ -46,7 +46,7 @@ class GitlabSchema < GraphQL::Schema super(query_str, **kwargs) end - def id_from_object(object) + def id_from_object(object, _type = nil, _ctx = nil) unless object.respond_to?(:to_global_id) # This is an error in our schema and needs to be solved. So raise a # more meaningful error message @@ -57,7 +57,7 @@ class GitlabSchema < GraphQL::Schema object.to_global_id end - def object_from_id(global_id) + def object_from_id(global_id, _ctx = nil) gid = GlobalID.parse(global_id) unless gid diff --git a/app/graphql/mutations/merge_requests/set_assignees.rb b/app/graphql/mutations/merge_requests/set_assignees.rb new file mode 100644 index 00000000000..8f0025f0a58 --- /dev/null +++ b/app/graphql/mutations/merge_requests/set_assignees.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class SetAssignees < Base + graphql_name 'MergeRequestSetAssignees' + + argument :assignee_usernames, + [GraphQL::STRING_TYPE], + required: true, + description: <<~DESC + The usernames to assign to the merge request. Replaces existing assignees by default. + DESC + + argument :operation_mode, + Types::MutationOperationModeEnum, + required: false, + description: <<~DESC + The operation to perform. Defaults to REPLACE. + DESC + + def resolve(project_path:, iid:, assignee_usernames:, operation_mode: Types::MutationOperationModeEnum.enum[:replace]) + Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/issues/36098') + + merge_request = authorized_find!(project_path: project_path, iid: iid) + project = merge_request.project + + assignee_ids = [] + assignee_ids += merge_request.assignees.map(&:id) if Types::MutationOperationModeEnum.enum.values_at(:remove, :append).include?(operation_mode) + user_ids = UsersFinder.new(current_user, username: assignee_usernames).execute.map(&:id) + + if operation_mode == Types::MutationOperationModeEnum.enum[:remove] + assignee_ids -= user_ids + else + assignee_ids |= user_ids + end + + ::MergeRequests::UpdateService.new(project, current_user, assignee_ids: assignee_ids) + .execute(merge_request) + + { + merge_request: merge_request, + errors: merge_request.errors.full_messages + } + end + end + end +end diff --git a/app/graphql/mutations/merge_requests/set_labels.rb b/app/graphql/mutations/merge_requests/set_labels.rb new file mode 100644 index 00000000000..71f7a353bc9 --- /dev/null +++ b/app/graphql/mutations/merge_requests/set_labels.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class SetLabels < Base + graphql_name 'MergeRequestSetLabels' + + argument :label_ids, + [GraphQL::ID_TYPE], + required: true, + description: <<~DESC + The Label IDs to set. Replaces existing labels by default. + DESC + + argument :operation_mode, + Types::MutationOperationModeEnum, + required: false, + description: <<~DESC + Changes the operation mode. Defaults to REPLACE. + DESC + + def resolve(project_path:, iid:, label_ids:, operation_mode: Types::MutationOperationModeEnum.enum[:replace]) + merge_request = authorized_find!(project_path: project_path, iid: iid) + project = merge_request.project + + label_ids = label_ids + .select(&method(:label_descendant?)) + .map { |gid| GlobalID.parse(gid).model_id } # MergeRequests::UpdateService expects integers + + attribute_name = case operation_mode + when Types::MutationOperationModeEnum.enum[:append] + :add_label_ids + when Types::MutationOperationModeEnum.enum[:remove] + :remove_label_ids + else + :label_ids + end + + ::MergeRequests::UpdateService.new(project, current_user, attribute_name => label_ids) + .execute(merge_request) + + { + merge_request: merge_request, + errors: merge_request.errors.full_messages + } + end + + def label_descendant?(gid) + GlobalID.parse(gid)&.model_class&.ancestors&.include?(Label) + end + end + end +end diff --git a/app/graphql/mutations/merge_requests/set_locked.rb b/app/graphql/mutations/merge_requests/set_locked.rb new file mode 100644 index 00000000000..09aaa0b39aa --- /dev/null +++ b/app/graphql/mutations/merge_requests/set_locked.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class SetLocked < Base + graphql_name 'MergeRequestSetLocked' + + argument :locked, + GraphQL::BOOLEAN_TYPE, + required: true, + description: <<~DESC + Whether or not to lock the merge request. + DESC + + def resolve(project_path:, iid:, locked:) + merge_request = authorized_find!(project_path: project_path, iid: iid) + project = merge_request.project + + ::MergeRequests::UpdateService.new(project, current_user, discussion_locked: locked) + .execute(merge_request) + + { + merge_request: merge_request, + errors: merge_request.errors.full_messages + } + end + end + end +end diff --git a/app/graphql/mutations/merge_requests/set_milestone.rb b/app/graphql/mutations/merge_requests/set_milestone.rb new file mode 100644 index 00000000000..707d6677952 --- /dev/null +++ b/app/graphql/mutations/merge_requests/set_milestone.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class SetMilestone < Base + graphql_name 'MergeRequestSetMilestone' + + argument :milestone_id, + GraphQL::ID_TYPE, + required: false, + loads: Types::MilestoneType, + description: <<~DESC + The milestone to assign to the merge request. + DESC + + def resolve(project_path:, iid:, milestone: nil) + merge_request = authorized_find!(project_path: project_path, iid: iid) + project = merge_request.project + + ::MergeRequests::UpdateService.new(project, current_user, milestone: milestone) + .execute(merge_request) + + { + merge_request: merge_request, + errors: merge_request.errors.full_messages + } + end + end + end +end diff --git a/app/graphql/mutations/merge_requests/set_subscription.rb b/app/graphql/mutations/merge_requests/set_subscription.rb new file mode 100644 index 00000000000..86750152775 --- /dev/null +++ b/app/graphql/mutations/merge_requests/set_subscription.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Mutations + module MergeRequests + class SetSubscription < Base + graphql_name 'MergeRequestSetSubscription' + + argument :subscribed_state, + GraphQL::BOOLEAN_TYPE, + required: true, + description: 'The desired state of the subscription' + + def resolve(project_path:, iid:, subscribed_state:) + merge_request = authorized_find!(project_path: project_path, iid: iid) + project = merge_request.project + + merge_request.set_subscription(current_user, subscribed_state, project) + + { + merge_request: merge_request, + errors: merge_request.errors.full_messages + } + end + end + end +end diff --git a/app/graphql/mutations/todos/base.rb b/app/graphql/mutations/todos/base.rb new file mode 100644 index 00000000000..b6c7b320be1 --- /dev/null +++ b/app/graphql/mutations/todos/base.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Mutations + module Todos + class Base < ::Mutations::BaseMutation + private + + def find_object(id:) + GitlabSchema.object_from_id(id) + end + + def to_global_id(id) + ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s + end + end + end +end diff --git a/app/graphql/mutations/todos/mark_done.rb b/app/graphql/mutations/todos/mark_done.rb new file mode 100644 index 00000000000..5483708b5c6 --- /dev/null +++ b/app/graphql/mutations/todos/mark_done.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Mutations + module Todos + class MarkDone < ::Mutations::Todos::Base + graphql_name 'TodoMarkDone' + + authorize :update_todo + + argument :id, + GraphQL::ID_TYPE, + required: true, + description: 'The global id of the todo to mark as done' + + field :todo, Types::TodoType, + null: false, + description: 'The requested todo' + + # rubocop: disable CodeReuse/ActiveRecord + def resolve(id:) + todo = authorized_find!(id: id) + mark_done(Todo.where(id: todo.id)) unless todo.done? + + { + todo: todo.reset, + errors: errors_on_object(todo) + } + end + # rubocop: enable CodeReuse/ActiveRecord + + private + + def mark_done(todo) + TodoService.new.mark_todos_as_done(todo, current_user) + end + end + end +end diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb index 5b7eb57841c..85d6b377934 100644 --- a/app/graphql/resolvers/base_resolver.rb +++ b/app/graphql/resolvers/base_resolver.rb @@ -10,6 +10,14 @@ module Resolvers end end + def self.last + @last ||= Class.new(self) do + def resolve(**args) + super.last + end + end + end + def self.resolver_complexity(args, child_complexity:) complexity = 1 complexity += 1 if args[:sort] diff --git a/app/graphql/resolvers/commit_pipelines_resolver.rb b/app/graphql/resolvers/commit_pipelines_resolver.rb new file mode 100644 index 00000000000..92a83523593 --- /dev/null +++ b/app/graphql/resolvers/commit_pipelines_resolver.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Resolvers + class CommitPipelinesResolver < BaseResolver + include ::ResolvesPipelines + + alias_method :commit, :object + + def resolve(**args) + resolve_pipelines(commit.project, args.merge!({ sha: commit.sha })) + end + end +end diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb index cf43fea45e6..94f6c47e876 100644 --- a/app/graphql/types/base_enum.rb +++ b/app/graphql/types/base_enum.rb @@ -2,5 +2,18 @@ module Types class BaseEnum < GraphQL::Schema::Enum + class << self + def value(*args, **kwargs, &block) + enum[args[0].downcase] = kwargs[:value] || args[0] + + super(*args, **kwargs, &block) + end + + # Returns an indifferent access hash with the key being the downcased name of the attribute + # and the value being the Ruby value (either the explicit `value` passed or the same as the value attr). + def enum + @enum_values ||= {}.with_indifferent_access + end + end end end diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index fe71791f413..87f84ec576f 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -8,25 +8,39 @@ module Types present_using CommitPresenter - field :id, type: GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :sha, type: GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :title, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :description, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :message, type: GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :authored_date, type: Types::TimeType, null: true # rubocop:disable Graphql/Descriptions - field :web_url, type: GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :signature_html, type: GraphQL::STRING_TYPE, - null: true, calls_gitaly: true, description: 'Rendered html for the commit signature' + field :id, type: GraphQL::ID_TYPE, null: false, + description: 'ID (global ID) of the commit' + field :sha, type: GraphQL::STRING_TYPE, null: false, + description: 'SHA1 ID of the commit' + field :title, type: GraphQL::STRING_TYPE, null: true, + description: 'Title of the commit message' + field :description, type: GraphQL::STRING_TYPE, null: true, + description: 'Description of the commit message' + field :message, type: GraphQL::STRING_TYPE, null: true, + description: 'Raw commit message' + field :authored_date, type: Types::TimeType, null: true, + description: 'Timestamp of when the commit was authored' + field :web_url, type: GraphQL::STRING_TYPE, null: false, + description: 'Web URL of the commit' + field :signature_html, type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true, + description: 'Rendered HTML of the commit signature' + field :author_name, type: GraphQL::STRING_TYPE, null: true, + description: 'Commit authors name' # models/commit lazy loads the author by email - field :author, type: Types::UserType, null: true # rubocop:disable Graphql/Descriptions + field :author, type: Types::UserType, null: true, + description: 'Author of the commit' + + field :pipelines, Types::Ci::PipelineType.connection_type, + null: true, + description: 'Pipelines of the commit ordered latest first', + resolver: Resolvers::CommitPipelinesResolver field :latest_pipeline, type: Types::Ci::PipelineType, null: true, - description: "Latest pipeline for this commit", - resolve: -> (obj, ctx, args) do - Gitlab::Graphql::Loaders::PipelineForShaLoader.new(obj.project, obj.sha).find_last - end + description: "Latest pipeline of the commit", + deprecation_reason: 'use pipelines', + resolver: Resolvers::CommitPipelinesResolver.last end end diff --git a/app/graphql/types/extended_issue_type.rb b/app/graphql/types/extended_issue_type.rb deleted file mode 100644 index e007c1109a3..00000000000 --- a/app/graphql/types/extended_issue_type.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -module Types - class ExtendedIssueType < IssueType - graphql_name 'ExtendedIssue' - - authorize :read_issue - expose_permissions Types::PermissionTypes::Issue - present_using IssuePresenter - - field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5, - description: 'Boolean flag for whether the currently logged in user is subscribed to this issue' - end -end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 1e52c0cb147..386ae6ed4a3 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -8,14 +8,17 @@ module Types expose_permissions Types::PermissionTypes::Group - field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :web_url, GraphQL::STRING_TYPE, null: false, + description: 'Web URL of the group' - field :avatar_url, GraphQL::STRING_TYPE, null: true, resolve: -> (group, args, ctx) do # rubocop:disable Graphql/Descriptions - group.avatar_url(only_path: false) - end + field :avatar_url, GraphQL::STRING_TYPE, null: true, + description: 'Avatar URL of the group', + resolve: -> (group, args, ctx) do + group.avatar_url(only_path: false) + end - field :parent, GroupType, # rubocop:disable Graphql/Descriptions - null: true, + field :parent, GroupType, null: true, + description: 'Parent group', resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find } end end diff --git a/app/graphql/types/issue_sort_enum.rb b/app/graphql/types/issue_sort_enum.rb index ad919b55481..48ff5819286 100644 --- a/app/graphql/types/issue_sort_enum.rb +++ b/app/graphql/types/issue_sort_enum.rb @@ -5,6 +5,10 @@ module Types class IssueSortEnum < IssuableSortEnum graphql_name 'IssueSort' description 'Values for sorting issues' + + value 'DUE_DATE_ASC', 'Due date by ascending order', value: 'due_date_asc' + value 'DUE_DATE_DESC', 'Due date by descending order', value: 'due_date_desc' + value 'RELATIVE_POSITION_ASC', 'Relative position by ascending order', value: 'relative_position_asc' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 4965601fe65..4cbb849da3a 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -12,53 +12,79 @@ module Types present_using IssuePresenter - field :iid, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :iid, GraphQL::ID_TYPE, null: false, + description: "Internal ID of the issue" + field :title, GraphQL::STRING_TYPE, null: false, + description: 'Title of the issue' markdown_field :title_html, null: true - field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :description, GraphQL::STRING_TYPE, null: true, + description: 'Description of the issue' markdown_field :description_html, null: true - field :state, IssueStateEnum, null: false # rubocop:disable Graphql/Descriptions - - field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference do # rubocop:disable Graphql/Descriptions - argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false # rubocop:disable Graphql/Descriptions + field :state, IssueStateEnum, null: false, + description: 'State of the issue' + + field :reference, GraphQL::STRING_TYPE, null: false, + description: 'Internal reference of the issue. Returned in shortened format by default', + method: :to_reference do + argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false, + description: 'Boolean option specifying whether the reference should be returned in full' end - field :author, Types::UserType, # rubocop:disable Graphql/Descriptions - null: false, + field :author, Types::UserType, null: false, + description: 'User that created the issue', resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find } # Remove complexity when BatchLoader is used - field :assignees, Types::UserType.connection_type, null: true, complexity: 5 # rubocop:disable Graphql/Descriptions + field :assignees, Types::UserType.connection_type, null: true, complexity: 5, + description: 'Assignees of the issue' # Remove complexity when BatchLoader is used - field :labels, Types::LabelType.connection_type, null: true, complexity: 5 # rubocop:disable Graphql/Descriptions - field :milestone, Types::MilestoneType, # rubocop:disable Graphql/Descriptions - null: true, + field :labels, Types::LabelType.connection_type, null: true, complexity: 5, + description: 'Labels of the issue' + field :milestone, Types::MilestoneType, null: true, + description: 'Milestone of the issue', resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } - field :due_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions - field :confidential, GraphQL::BOOLEAN_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :discussion_locked, GraphQL::BOOLEAN_TYPE, # rubocop:disable Graphql/Descriptions - null: false, + field :due_date, Types::TimeType, null: true, + description: 'Due date of the issue' + field :confidential, GraphQL::BOOLEAN_TYPE, null: false, + description: 'Indicates the issue is confidential' + field :discussion_locked, GraphQL::BOOLEAN_TYPE, null: false, + description: 'Indicates discussion is locked on the issue', resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked } - field :upvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :downvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :user_notes_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path # rubocop:disable Graphql/Descriptions - field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :relative_position, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'List of participants for the issue' - field :time_estimate, GraphQL::INT_TYPE, null: false, description: 'The time estimate on the issue' - field :total_time_spent, GraphQL::INT_TYPE, null: false, description: 'Total time reported as spent on the issue' - - field :closed_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions - - field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions - field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions - - field :task_completion_status, Types::TaskCompletionStatus, null: false # rubocop:disable Graphql/Descriptions + field :upvotes, GraphQL::INT_TYPE, null: false, + description: 'Number of upvotes the issue has received' + field :downvotes, GraphQL::INT_TYPE, null: false, + description: 'Number of downvotes the issue has received' + field :user_notes_count, GraphQL::INT_TYPE, null: false, + description: 'Number of user notes of the issue' + field :web_path, GraphQL::STRING_TYPE, null: false, method: :issue_path, + description: 'Web path of the issue' + field :web_url, GraphQL::STRING_TYPE, null: false, + description: 'Web URL of the issue' + field :relative_position, GraphQL::INT_TYPE, 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' + field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5, + description: 'Boolean flag for whether the currently logged in user is subscribed to this issue' + field :time_estimate, GraphQL::INT_TYPE, null: false, + description: 'Time estimate of the issue' + field :total_time_spent, GraphQL::INT_TYPE, null: false, + description: 'Total time reported as spent on the issue' + + field :closed_at, Types::TimeType, null: true, + description: 'Timestamp of when the issue was closed' + + field :created_at, Types::TimeType, null: false, + description: 'Timestamp of when the issue was created' + field :updated_at, Types::TimeType, null: false, + description: 'Timestamp of when the issue was last updated' + + field :task_completion_status, Types::TaskCompletionStatus, null: false, + description: 'Task completion status of the issue' end end diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb index 384a27df563..d0bcf2068b7 100644 --- a/app/graphql/types/label_type.rb +++ b/app/graphql/types/label_type.rb @@ -6,10 +6,16 @@ module Types authorize :read_label - field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :id, GraphQL::ID_TYPE, null: false, + description: 'Label ID' + field :description, GraphQL::STRING_TYPE, null: true, + description: 'Description of the label (markdown rendered as HTML for caching)' markdown_field :description_html, null: true - field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :color, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :text_color, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :title, GraphQL::STRING_TYPE, null: false, + description: 'Content of the label' + field :color, GraphQL::STRING_TYPE, null: false, + description: 'Background color of the label' + field :text_color, GraphQL::STRING_TYPE, null: false, + description: 'Text color of the label' end end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 71a65dc6713..278a95fe3ca 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -12,70 +12,116 @@ module Types present_using MergeRequestPresenter - field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :iid, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :id, GraphQL::ID_TYPE, null: false, + description: 'ID of the merge request' + field :iid, GraphQL::STRING_TYPE, null: false, + description: 'Internal ID of the merge request' + field :title, GraphQL::STRING_TYPE, null: false, + description: 'Title of the merge request' markdown_field :title_html, null: true - field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :description, GraphQL::STRING_TYPE, null: true, + description: 'Description of the merge request (markdown rendered as HTML for caching)' markdown_field :description_html, null: true - field :state, MergeRequestStateEnum, null: false # rubocop:disable Graphql/Descriptions - field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions - field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions - field :source_project, Types::ProjectType, null: true # rubocop:disable Graphql/Descriptions - field :target_project, Types::ProjectType, null: false # rubocop:disable Graphql/Descriptions - field :diff_refs, Types::DiffRefsType, null: true # rubocop:disable Graphql/Descriptions - # Alias for target_project - field :project, Types::ProjectType, null: false # rubocop:disable Graphql/Descriptions - field :project_id, GraphQL::INT_TYPE, null: false, method: :target_project_id # rubocop:disable Graphql/Descriptions - field :source_project_id, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :target_project_id, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :source_branch, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :target_branch, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false # rubocop:disable Graphql/Descriptions - field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :diff_head_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :merge_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :user_notes_count, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true # rubocop:disable Graphql/Descriptions - field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true # rubocop:disable Graphql/Descriptions - field :merge_status, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :merge_error, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false # rubocop:disable Graphql/Descriptions - field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true # rubocop:disable Graphql/Descriptions - # rubocop:disable Graphql/Descriptions - field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage" - # rubocop:enable Graphql/Descriptions - field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false # rubocop:disable Graphql/Descriptions - field :source_branch_exists, GraphQL::BOOLEAN_TYPE, method: :source_branch_exists?, null: false # rubocop:disable Graphql/Descriptions - field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :upvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :downvotes, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions + 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 :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::INT_TYPE, null: false, method: :target_project_id, + description: 'ID of the merge request project' + field :source_project_id, GraphQL::INT_TYPE, null: true, + description: 'ID of the merge request source project' + field :target_project_id, GraphQL::INT_TYPE, null: false, + description: 'ID of the merge request target project' + field :source_branch, GraphQL::STRING_TYPE, null: false, + description: 'Source branch of the merge request' + field :target_branch, GraphQL::STRING_TYPE, null: false, + description: 'Target branch of the merge request' + field :work_in_progress, GraphQL::BOOLEAN_TYPE, method: :work_in_progress?, null: false, + description: 'Indicates if the merge request is a work in progress (WIP)' + field :merge_when_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)' + field :diff_head_sha, GraphQL::STRING_TYPE, null: true, + description: 'Diff head SHA of the merge request' + field :merge_commit_sha, GraphQL::STRING_TYPE, null: true, + description: 'SHA of the merge request commit (set once merged)' + field :user_notes_count, GraphQL::INT_TYPE, null: true, + description: 'User notes count of the merge request' + field :should_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :should_remove_source_branch?, null: true, + description: 'Indicates if the source branch of the merge request will be deleted after merge' + field :force_remove_source_branch, GraphQL::BOOLEAN_TYPE, method: :force_remove_source_branch?, null: true, + description: 'Indicates if the project settings will lead to source branch deletion after merge' + field :merge_status, GraphQL::STRING_TYPE, null: true, + description: 'Status of the merge request' + field :in_progress_merge_commit_sha, GraphQL::STRING_TYPE, null: true, + description: 'Commit SHA of the merge request if merge is in progress' + field :merge_error, GraphQL::STRING_TYPE, null: true, + description: 'Error message due to a merge error' + field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if members of the target project can push to the fork' + field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false, + description: 'Indicates if the merge request will be rebased' + field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true, + description: 'Rebase commit SHA of the merge request' + field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true, + description: 'Indicates if there is a rebase currently in progress for the merge request' + field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage", + description: 'Deprecated - renamed to defaultMergeCommitMessage' + field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true, + description: 'Default merge commit message of the merge request' + field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false, + description: 'Indicates if a merge is currently occurring' + field :source_branch_exists, GraphQL::BOOLEAN_TYPE, method: :source_branch_exists?, null: false, + description: 'Indicates if the source branch of the merge request exists' + field :mergeable_discussions_state, GraphQL::BOOLEAN_TYPE, 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::STRING_TYPE, null: true, + description: 'Web URL of the merge request' + field :upvotes, GraphQL::INT_TYPE, null: false, + description: 'Number of upvotes for the merge request' + field :downvotes, GraphQL::INT_TYPE, null: false, + description: 'Number of downvotes for the merge request' - field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline # rubocop:disable Graphql/Descriptions - field :pipelines, Types::Ci::PipelineType.connection_type, # rubocop:disable Graphql/Descriptions + field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline, + description: 'The pipeline running on the branch HEAD of the merge request' + field :pipelines, Types::Ci::PipelineType.connection_type, + description: 'Pipelines for the merge request', resolver: Resolvers::MergeRequestPipelinesResolver - field :milestone, Types::MilestoneType, description: 'The milestone this merge request is linked to', - null: true, + field :milestone, Types::MilestoneType, null: true, + description: 'The milestone of the merge request', resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find } - field :assignees, Types::UserType.connection_type, null: true, complexity: 5, description: 'The list of assignees for the merge request' - field :participants, Types::UserType.connection_type, null: true, complexity: 5, description: 'The list of participants on the merge request' + field :assignees, Types::UserType.connection_type, null: true, complexity: 5, + description: 'Assignees of the merge request' + field :participants, Types::UserType.connection_type, null: true, complexity: 5, + description: 'Participants in the merge request' field :subscribed, GraphQL::BOOLEAN_TYPE, method: :subscribed?, null: false, complexity: 5, - description: 'Boolean flag for whether the currently logged in user is subscribed to this MR' - field :labels, Types::LabelType.connection_type, null: true, complexity: 5, description: 'The list of labels on the merge request' - field :discussion_locked, GraphQL::BOOLEAN_TYPE, description: 'Boolean flag determining if comments on the merge request are locked to members only', + 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::BOOLEAN_TYPE, + description: 'Indicates if comments on the merge request are locked to members only', null: false, resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked } - field :time_estimate, GraphQL::INT_TYPE, null: false, description: 'The time estimate for the merge request' - field :total_time_spent, GraphQL::INT_TYPE, null: false, description: 'Total time reported as spent on the merge request' - field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference, description: 'Internal merge request reference. Returned in shortened format by default' do - argument :full, GraphQL::BOOLEAN_TYPE, required: false, default_value: false, description: 'Boolean option specifying whether the reference should be returned in full' + field :time_estimate, GraphQL::INT_TYPE, null: false, + description: 'Time estimate of the merge request' + field :total_time_spent, GraphQL::INT_TYPE, null: false, + description: 'Total time reported as spent on the merge request' + field :reference, GraphQL::STRING_TYPE, null: false, method: :to_reference, + description: 'Internal reference of the merge request. Returned in shortened format by default' do + argument :full, GraphQL::BOOLEAN_TYPE, 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 # rubocop:disable Graphql/Descriptions + field :task_completion_status, Types::TaskCompletionStatus, null: false, + description: Types::TaskCompletionStatus.description end end diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb index bfcb929f5ac..1998b036a53 100644 --- a/app/graphql/types/metadata_type.rb +++ b/app/graphql/types/metadata_type.rb @@ -6,7 +6,9 @@ module Types authorize :read_instance_metadata - field :version, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :revision, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :version, GraphQL::STRING_TYPE, null: false, + description: 'Version' + field :revision, GraphQL::STRING_TYPE, null: false, + description: 'Revision' end end diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb index 78d0a8220ec..9c3afb28674 100644 --- a/app/graphql/types/milestone_type.rb +++ b/app/graphql/types/milestone_type.rb @@ -6,14 +6,23 @@ module Types authorize :read_milestone - field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :title, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :state, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :id, GraphQL::ID_TYPE, null: false, + description: 'ID of the milestone' + field :description, GraphQL::STRING_TYPE, null: true, + description: 'Description of the milestone' + field :title, GraphQL::STRING_TYPE, null: false, + description: 'Title of the milestone' + field :state, GraphQL::STRING_TYPE, null: false, + description: 'State of the milestone' - field :due_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions - field :start_date, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions + field :due_date, Types::TimeType, null: true, + description: 'Timestamp of the milestone due date' + field :start_date, Types::TimeType, null: true, + description: 'Timestamp of the milestone start date' - field :created_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions - field :updated_at, Types::TimeType, null: false # rubocop:disable Graphql/Descriptions + field :created_at, Types::TimeType, null: false, + description: 'Timestamp of milestone creation' + field :updated_at, Types::TimeType, null: false, + description: 'Timestamp of last milestone update' end end diff --git a/app/graphql/types/mutation_operation_mode_enum.rb b/app/graphql/types/mutation_operation_mode_enum.rb new file mode 100644 index 00000000000..90a29d2b0e5 --- /dev/null +++ b/app/graphql/types/mutation_operation_mode_enum.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + class MutationOperationModeEnum < BaseEnum + graphql_name 'MutationOperationMode' + description 'Different toggles for changing mutator behavior.' + + # Suggested param name for the enum: `operation_mode` + + value 'REPLACE', 'Performs a replace operation' + value 'APPEND', 'Performs an append operation' + value 'REMOVE', 'Performs a removal operation' + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 17f922a5e54..b3c7c162bb3 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -9,12 +9,18 @@ module Types mount_mutation Mutations::AwardEmojis::Add mount_mutation Mutations::AwardEmojis::Remove mount_mutation Mutations::AwardEmojis::Toggle + mount_mutation Mutations::MergeRequests::SetLabels + mount_mutation Mutations::MergeRequests::SetLocked + mount_mutation Mutations::MergeRequests::SetMilestone + mount_mutation Mutations::MergeRequests::SetSubscription mount_mutation Mutations::MergeRequests::SetWip, calls_gitaly: true + mount_mutation Mutations::MergeRequests::SetAssignees mount_mutation Mutations::Notes::Create::Note, calls_gitaly: true mount_mutation Mutations::Notes::Create::DiffNote, calls_gitaly: true mount_mutation Mutations::Notes::Create::ImageDiffNote, calls_gitaly: true mount_mutation Mutations::Notes::Update mount_mutation Mutations::Notes::Destroy + mount_mutation Mutations::Todos::MarkDone end end diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index cc1d06b19e1..1714284a5cf 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -6,27 +6,35 @@ module Types authorize :read_namespace - field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :id, GraphQL::ID_TYPE, null: false, + description: 'ID of the namespace' - field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :full_name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :full_path, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :name, GraphQL::STRING_TYPE, null: false, + description: 'Name of the namespace' + field :path, GraphQL::STRING_TYPE, null: false, + description: 'Path of the namespace' + field :full_name, GraphQL::STRING_TYPE, null: false, + description: 'Full name of the namespace' + field :full_path, GraphQL::ID_TYPE, null: false, + description: 'Full path of the namespace' - field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :description, GraphQL::STRING_TYPE, null: true, + description: 'Description of the namespace' markdown_field :description_html, null: true - field :visibility, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled? # rubocop:disable Graphql/Descriptions - field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :visibility, GraphQL::STRING_TYPE, null: true, + description: 'Visibility of the namespace' + field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled?, + description: 'Indicates if Large File Storage (LFS) is enabled for namespace' + field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if users can request access to namespace' field :root_storage_statistics, Types::RootStorageStatisticsType, null: true, - description: 'The aggregated storage statistics. Only available for root namespaces', + description: 'Aggregated storage statistics of the namespace. Only available for root namespaces', resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(obj.id).find } - field :projects, # rubocop:disable Graphql/Descriptions - Types::ProjectType.connection_type, - null: false, + field :projects, Types::ProjectType.connection_type, null: false, + description: 'Projects within this namespace', resolver: ::Resolvers::NamespaceProjectsResolver end end diff --git a/app/graphql/types/project_statistics_type.rb b/app/graphql/types/project_statistics_type.rb index 5045471a75b..c46410df6c0 100644 --- a/app/graphql/types/project_statistics_type.rb +++ b/app/graphql/types/project_statistics_type.rb @@ -6,13 +6,20 @@ module Types authorize :read_statistics - field :commit_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :commit_count, GraphQL::INT_TYPE, null: false, + description: 'Commit count of the project' - field :storage_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :repository_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :lfs_objects_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :build_artifacts_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :packages_size, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :wiki_size, GraphQL::INT_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :storage_size, GraphQL::INT_TYPE, null: false, + description: 'Storage size of the project' + field :repository_size, GraphQL::INT_TYPE, null: false, + description: 'Repository size of the project' + field :lfs_objects_size, GraphQL::INT_TYPE, null: false, + description: 'Large File Storage (LFS) object size of the project' + field :build_artifacts_size, GraphQL::INT_TYPE, null: false, + description: 'Build artifacts size of the project' + field :packages_size, GraphQL::INT_TYPE, null: false, + description: 'Packages size of the project' + field :wiki_size, GraphQL::INT_TYPE, null: true, + description: 'Wiki size of the project' end end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 5663f833b7a..73255021119 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -8,97 +8,142 @@ module Types expose_permissions Types::PermissionTypes::Project - field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :id, GraphQL::ID_TYPE, null: false, + description: 'ID of the project' - field :full_path, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :full_path, GraphQL::ID_TYPE, null: false, + description: 'Full path of the project' + field :path, GraphQL::STRING_TYPE, null: false, + description: 'Path of the project' - field :name_with_namespace, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :name_with_namespace, GraphQL::STRING_TYPE, null: false, + description: 'Full name of the project with its namespace' + field :name, GraphQL::STRING_TYPE, null: false, + description: 'Name of the project (without namespace)' - field :description, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions + field :description, GraphQL::STRING_TYPE, null: true, + description: 'Short description of the project' markdown_field :description_html, null: true - field :tag_list, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :http_url_to_repo, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :web_url, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :star_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true # 4 times # rubocop:disable Graphql/Descriptions - - field :created_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions - field :last_activity_at, Types::TimeType, null: true # rubocop:disable Graphql/Descriptions - - field :archived, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :visibility, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions - project.avatar_url(only_path: false) - end + field :tag_list, GraphQL::STRING_TYPE, null: true, + description: 'List of project tags' + + field :ssh_url_to_repo, GraphQL::STRING_TYPE, null: true, + description: 'URL to connect to the project via SSH' + field :http_url_to_repo, GraphQL::STRING_TYPE, null: true, + description: 'URL to connect to the project via HTTPS' + field :web_url, GraphQL::STRING_TYPE, null: true, + description: 'Web URL of the project' + + field :star_count, GraphQL::INT_TYPE, null: false, + description: 'Number of times the project has been starred' + field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true, # 4 times + description: 'Number of times the project has been forked' + + field :created_at, Types::TimeType, null: true, + description: 'Timestamp of the project creation' + field :last_activity_at, Types::TimeType, null: true, + description: 'Timestamp of the project last activity' + + field :archived, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Archived status of the project' + + field :visibility, GraphQL::STRING_TYPE, null: true, + description: 'Visibility of the project' + + field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if the project stores Docker container images in a container registry' + field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if shared runners are enabled on the project' + field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if the project has Large File Storage (LFS) enabled' + field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, 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 :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, + description: 'URL to avatar image file of the project', + resolve: -> (project, args, ctx) do + project.avatar_url(only_path: false) + end %i[issues merge_requests wiki snippets].each do |feature| - field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions - project.feature_available?(feature, ctx[:current_user]) - end + field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true, + description: "(deprecated) Does this project have #{feature} enabled?. Use `#{feature}_access_level` instead", + resolve: -> (project, args, ctx) do + project.feature_available?(feature, ctx[:current_user]) + end end - field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions - project.feature_available?(:builds, ctx[:current_user]) - end - - field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true # rubocop:disable Graphql/Descriptions - - field :open_issues_count, GraphQL::INT_TYPE, null: true, resolve: -> (project, args, ctx) do # rubocop:disable Graphql/Descriptions - project.open_issues_count if project.feature_available?(:issues, ctx[:current_user]) - end - - field :import_status, GraphQL::STRING_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true # rubocop:disable Graphql/Descriptions - - field :namespace, Types::NamespaceType, null: true # rubocop:disable Graphql/Descriptions - field :group, Types::GroupType, null: true # rubocop:disable Graphql/Descriptions - - field :statistics, Types::ProjectStatisticsType, # rubocop:disable Graphql/Descriptions + field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: '(deprecated) Enable jobs for this project. Use `builds_access_level` instead', + resolve: -> (project, args, ctx) do + project.feature_available?(:builds, ctx[:current_user]) + end + + field :public_jobs, GraphQL::BOOLEAN_TYPE, method: :public_builds, null: true, + description: 'Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts' + + field :open_issues_count, GraphQL::INT_TYPE, null: true, + description: 'Number of open issues for the project', + resolve: -> (project, args, ctx) do + project.open_issues_count if project.feature_available?(:issues, ctx[:current_user]) + end + + field :import_status, GraphQL::STRING_TYPE, null: true, + description: 'Status of project import background job of the project' + + field :only_allow_merge_if_pipeline_succeeds, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if merge requests of the project can only be merged with successful jobs' + field :request_access_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if users can request member access to the project' + field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Indicates if merge requests of the project can only be merged when all the discussions are resolved' + field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, 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::BOOLEAN_TYPE, null: true, + description: 'Indicates if `Delete source branch` option should be enabled by default for all new merge requests 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, + description: 'Statistics of the project', resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find } - field :repository, Types::RepositoryType, null: true # rubocop:disable Graphql/Descriptions + field :repository, Types::RepositoryType, null: true, + description: 'Git repository of the project' - field :merge_requests, # rubocop:disable Graphql/Descriptions + field :merge_requests, Types::MergeRequestType.connection_type, null: true, + description: 'Merge requests of the project', resolver: Resolvers::MergeRequestsResolver - field :merge_request, # rubocop:disable Graphql/Descriptions + field :merge_request, Types::MergeRequestType, null: true, + description: 'A single merge request of the project', resolver: Resolvers::MergeRequestsResolver.single - field :issues, # rubocop:disable Graphql/Descriptions + field :issues, Types::IssueType.connection_type, null: true, + description: 'Issues of the project', resolver: Resolvers::IssuesResolver - field :issue, # rubocop:disable Graphql/Descriptions - Types::ExtendedIssueType, + field :issue, + Types::IssueType, null: true, + description: 'A single issue of the project', resolver: Resolvers::IssuesResolver.single - field :pipelines, # rubocop:disable Graphql/Descriptions + field :pipelines, Types::Ci::PipelineType.connection_type, null: true, + description: 'Build pipelines of the project', resolver: Resolvers::ProjectPipelinesResolver end end diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb index 9ecd336b41d..f0c25e13a26 100644 --- a/app/graphql/types/repository_type.rb +++ b/app/graphql/types/repository_type.rb @@ -6,9 +6,13 @@ module Types authorize :download_code - field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true # rubocop:disable Graphql/Descriptions - field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true # rubocop:disable Graphql/Descriptions - field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists? # rubocop:disable Graphql/Descriptions - field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true # rubocop:disable Graphql/Descriptions + field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, + description: 'Default branch of the repository' + field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true, + description: 'Indicates repository has no visible content' + field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists?, + 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' end end diff --git a/app/graphql/types/task_completion_status.rb b/app/graphql/types/task_completion_status.rb index 0aa8fc60a7c..73a8b4f3020 100644 --- a/app/graphql/types/task_completion_status.rb +++ b/app/graphql/types/task_completion_status.rb @@ -8,8 +8,10 @@ module Types graphql_name 'TaskCompletionStatus' description 'Completion status of tasks' - field :count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :completed_count, GraphQL::INT_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :count, GraphQL::INT_TYPE, null: false, + description: 'Number of total tasks' + field :completed_count, GraphQL::INT_TYPE, null: false, + description: 'Number of completed tasks' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/todo_target_enum.rb b/app/graphql/types/todo_target_enum.rb index 9a7391dcd99..8358a86b35c 100644 --- a/app/graphql/types/todo_target_enum.rb +++ b/app/graphql/types/todo_target_enum.rb @@ -2,8 +2,10 @@ module Types class TodoTargetEnum < BaseEnum - value 'Issue' - value 'MergeRequest' - value 'Epic' + value 'COMMIT', value: 'Commit', description: 'A Commit' + value 'ISSUE', value: 'Issue', description: 'An Issue' + value 'MERGEREQUEST', value: 'MergeRequest', description: 'A MergeRequest' end end + +Types::TodoTargetEnum.prepend_if_ee('::EE::Types::TodoTargetEnum') diff --git a/app/graphql/types/todo_type.rb b/app/graphql/types/todo_type.rb index d36daaf7dec..5ce5093c55e 100644 --- a/app/graphql/types/todo_type.rb +++ b/app/graphql/types/todo_type.rb @@ -40,7 +40,8 @@ module Types field :body, GraphQL::STRING_TYPE, description: 'Body of the todo', - null: false + null: false, + calls_gitaly: true # TODO This is only true when `target_type` is `Commit`. See https://gitlab.com/gitlab-org/gitlab/issues/34757#note_234752665 field :state, Types::TodoStateEnum, description: 'State of the todo', diff --git a/app/graphql/types/tree/entry_type.rb b/app/graphql/types/tree/entry_type.rb index 10c2ad8815e..87a3eced896 100644 --- a/app/graphql/types/tree/entry_type.rb +++ b/app/graphql/types/tree/entry_type.rb @@ -5,6 +5,7 @@ module Types include Types::BaseInterface field :id, GraphQL::ID_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :sha, GraphQL::STRING_TYPE, null: false, description: "Last commit sha for entry", method: :id field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions field :type, Tree::TypeEnum, null: false # rubocop:disable Graphql/Descriptions field :path, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 1ba37927b40..b45c7893e75 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -8,12 +8,16 @@ module Types present_using UserPresenter - field :name, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :username, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :avatar_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions - field :web_url, GraphQL::STRING_TYPE, null: false # rubocop:disable Graphql/Descriptions + field :name, GraphQL::STRING_TYPE, null: false, + description: 'Human-readable name of the user' + field :username, GraphQL::STRING_TYPE, null: false, + description: 'Username of the user. Unique within this instance of GitLab' + field :avatar_url, GraphQL::STRING_TYPE, null: false, + description: "URL of the user's avatar" + field :web_url, GraphQL::STRING_TYPE, null: false, + description: 'Web URL of the user' field :todos, Types::TodoType.connection_type, null: false, resolver: Resolvers::TodoResolver, - description: 'Todos of this user' + description: 'Todos of the user' end end |