diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 09:16:11 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 09:16:11 +0000 |
commit | edaa33dee2ff2f7ea3fac488d41558eb5f86d68c (patch) | |
tree | 11f143effbfeba52329fb7afbd05e6e2a3790241 /app/graphql | |
parent | d8a5691316400a0f7ec4f83832698f1988eb27c1 (diff) | |
download | gitlab-ce-edaa33dee2ff2f7ea3fac488d41558eb5f86d68c.tar.gz |
Add latest changes from gitlab-org/gitlab@14-7-stable-eev14.7.0-rc42
Diffstat (limited to 'app/graphql')
39 files changed, 508 insertions, 56 deletions
diff --git a/app/graphql/mutations/clusters/agent_tokens/revoke.rb b/app/graphql/mutations/clusters/agent_tokens/revoke.rb new file mode 100644 index 00000000000..ca570792296 --- /dev/null +++ b/app/graphql/mutations/clusters/agent_tokens/revoke.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Mutations + module Clusters + module AgentTokens + class Revoke < BaseMutation + graphql_name 'ClusterAgentTokenRevoke' + + authorize :admin_cluster + + TokenID = ::Types::GlobalIDType[::Clusters::AgentToken] + + argument :id, TokenID, + required: true, + description: 'Global ID of the agent token that will be revoked.' + + def resolve(id:) + token = authorized_find!(id: id) + token.update(status: token.class.statuses[:revoked]) + + { errors: errors_on_object(token) } + 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 = TokenID.coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end + end +end diff --git a/app/graphql/mutations/issues/set_crm_contacts.rb b/app/graphql/mutations/issues/set_crm_contacts.rb index 4e49a45d52a..62990fc67f1 100644 --- a/app/graphql/mutations/issues/set_crm_contacts.rb +++ b/app/graphql/mutations/issues/set_crm_contacts.rb @@ -18,7 +18,8 @@ module Mutations def resolve(project_path:, iid:, contact_ids:, operation_mode: Types::MutationOperationModeEnum.enum[:replace]) issue = authorized_find!(project_path: project_path, iid: iid) project = issue.project - raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless Feature.enabled?(:customer_relations, project.group, default_enabled: :yaml) + + raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless feature_enabled?(project) contact_ids = contact_ids.compact.map do |contact_id| raise Gitlab::Graphql::Errors::ArgumentError, "Contact #{contact_id} is invalid." unless contact_id.respond_to?(:model_id) @@ -43,6 +44,12 @@ module Mutations errors: response.errors } end + + private + + def feature_enabled?(project) + Feature.enabled?(:customer_relations, project.group, default_enabled: :yaml) && project.group&.crm_enabled? + end end end end diff --git a/app/graphql/mutations/issues/set_escalation_status.rb b/app/graphql/mutations/issues/set_escalation_status.rb new file mode 100644 index 00000000000..6073b73277b --- /dev/null +++ b/app/graphql/mutations/issues/set_escalation_status.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Mutations + module Issues + class SetEscalationStatus < Base + graphql_name 'IssueSetEscalationStatus' + + argument :status, Types::IncidentManagement::EscalationStatusEnum, + required: true, + description: 'Set the escalation status.' + + def resolve(project_path:, iid:, status:) + issue = authorized_find!(project_path: project_path, iid: iid) + project = issue.project + + authorize_escalation_status!(project) + check_feature_availability!(project, issue) + + ::Issues::UpdateService.new( + project: project, + current_user: current_user, + params: { escalation_status: { status: status } } + ).execute(issue) + + { + issue: issue, + errors: errors_on_object(issue) + } + end + + private + + def authorize_escalation_status!(project) + return if Ability.allowed?(current_user, :update_escalation_status, project) + + raise_resource_not_available_error! + end + + def check_feature_availability!(project, issue) + return if Feature.enabled?(:incident_escalations, project) && issue.supports_escalation? + + raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature unavailable for provided issue' + end + end + end +end diff --git a/app/graphql/mutations/work_items/create.rb b/app/graphql/mutations/work_items/create.rb new file mode 100644 index 00000000000..88b8cefd8d2 --- /dev/null +++ b/app/graphql/mutations/work_items/create.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module Mutations + module WorkItems + class Create < BaseMutation + include Mutations::SpamProtection + include FindsProject + + graphql_name 'WorkItemCreate' + + authorize :create_work_item + + argument :description, GraphQL::Types::String, + required: false, + description: copy_field_description(Types::WorkItemType, :description) + argument :project_path, GraphQL::Types::ID, + required: true, + description: 'Full path of the project the work item is associated with.' + argument :title, GraphQL::Types::String, + required: true, + description: copy_field_description(Types::WorkItemType, :title) + argument :work_item_type_id, ::Types::GlobalIDType[::WorkItems::Type], + required: true, + description: 'Global ID of a work item type.' + + field :work_item, Types::WorkItemType, + null: true, + description: 'Created work item.' + + def resolve(project_path:, **attributes) + project = authorized_find!(project_path) + params = global_id_compatibility_params(attributes).merge(author_id: current_user.id) + + spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) + work_item = ::WorkItems::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute + + check_spam_action_response!(work_item) + + { + work_item: work_item.valid? ? work_item : nil, + errors: errors_on_object(work_item) + } + end + + private + + def global_id_compatibility_params(params) + # TODO: remove this line when the compatibility layer is removed + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + params[:work_item_type_id] = ::Types::GlobalIDType[::WorkItems::Type].coerce_isolated_input(params[:work_item_type_id]) if params[:work_item_type_id] + params[:work_item_type_id] = params[:work_item_type_id]&.model_id + + params + end + end + end +end diff --git a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql index dd5c9e07488..5dece2f81cc 100644 --- a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql +++ b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql @@ -1,3 +1,18 @@ +fragment CiNeeds on JobNeedUnion { + ...CiBuildNeedFields + ...CiJobNeedFields +} + +fragment CiBuildNeedFields on CiBuildNeed { + id + name +} + +fragment CiJobNeedFields on CiJob { + id + name +} + fragment LinkedPipelineData on Pipeline { __typename id @@ -91,6 +106,12 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) { name } } + previousStageJobsOrNeeds { + __typename + nodes { + ...CiNeeds + } + } status: detailedStatus { __typename id diff --git a/app/graphql/resolvers/base_issues_resolver.rb b/app/graphql/resolvers/base_issues_resolver.rb index 3983a3697cb..3e7509b4068 100644 --- a/app/graphql/resolvers/base_issues_resolver.rb +++ b/app/graphql/resolvers/base_issues_resolver.rb @@ -48,7 +48,8 @@ module Resolvers labels: [:labels], assignees: [:assignees], timelogs: [:timelogs], - customer_relations_contacts: { customer_relations_contacts: [:group] } + customer_relations_contacts: { customer_relations_contacts: [:group] }, + escalation_status: [:incident_management_issuable_escalation_status] } end diff --git a/app/graphql/resolvers/ci/config_resolver.rb b/app/graphql/resolvers/ci/config_resolver.rb index 2d74392a84c..387185b5171 100644 --- a/app/graphql/resolvers/ci/config_resolver.rb +++ b/app/graphql/resolvers/ci/config_resolver.rb @@ -47,11 +47,13 @@ module Resolvers { status: :valid, errors: [], + warnings: result.warnings, stages: make_stages(result.jobs) } else { status: :invalid, + warnings: result.warnings, errors: result.errors } end diff --git a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb index 5ae19700fd5..8208fa56485 100644 --- a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb +++ b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb @@ -9,10 +9,17 @@ module Resolvers delegate :project, to: :agent + argument :status, Types::Clusters::AgentTokenStatusEnum, + required: false, + description: 'Status of the token.' + def resolve(**args) return ::Clusters::AgentToken.none unless can_read_agent_tokens? - agent.last_used_agent_tokens + tokens = agent.last_used_agent_tokens + tokens = tokens.with_status(args[:status]) if args[:status].present? + + tokens end private diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb index 1c01e5e0250..42c4c22a938 100644 --- a/app/graphql/resolvers/concerns/resolves_pipelines.rb +++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb @@ -24,7 +24,7 @@ module ResolvesPipelines argument :source, GraphQL::Types::String, required: false, - description: "Filter pipelines by their source. Will be ignored if `dast_view_scans` feature flag is disabled." + description: "Filter pipelines by their source." end class_methods do @@ -38,8 +38,6 @@ module ResolvesPipelines end def resolve_pipelines(project, params = {}) - params.delete(:source) unless Feature.enabled?(:dast_view_scans, project, default_enabled: :yaml) - Ci::PipelinesFinder.new(project, context[:current_user], params).execute end end diff --git a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb index 254f1efa0a5..97cc7554ba8 100644 --- a/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb +++ b/app/graphql/resolvers/design_management/version/designs_at_version_resolver.rb @@ -13,13 +13,13 @@ module Resolvers DesignID = ::Types::GlobalIDType[::DesignManagement::Design] - argument :ids, [DesignID], - required: false, - description: 'Filters designs by their ID.' argument :filenames, [GraphQL::Types::String], required: false, description: 'Filters designs by their filename.' + argument :ids, [DesignID], + required: false, + description: 'Filters designs by their ID.' def self.single ::Resolvers::DesignManagement::Version::DesignAtVersionResolver diff --git a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb index 80db15755d3..2682ce6b3b1 100644 --- a/app/graphql/resolvers/design_management/version_in_collection_resolver.rb +++ b/app/graphql/resolvers/design_management/version_in_collection_resolver.rb @@ -15,13 +15,13 @@ module Resolvers VersionID = ::Types::GlobalIDType[::DesignManagement::Version] - argument :sha, GraphQL::Types::String, - required: false, - description: "SHA256 of a specific version." argument :id, VersionID, as: :version_id, required: false, description: 'Global ID of the version.' + argument :sha, GraphQL::Types::String, + required: false, + description: "SHA256 of a specific version." def resolve(version_id: nil, sha: nil) # TODO: remove this line when the compatibility layer is removed diff --git a/app/graphql/resolvers/group_milestones_resolver.rb b/app/graphql/resolvers/group_milestones_resolver.rb index 44192b6f4bf..319ff9f68c4 100644 --- a/app/graphql/resolvers/group_milestones_resolver.rb +++ b/app/graphql/resolvers/group_milestones_resolver.rb @@ -2,12 +2,12 @@ module Resolvers class GroupMilestonesResolver < MilestonesResolver - argument :include_descendants, GraphQL::Types::Boolean, - required: false, - description: 'Include milestones from all subgroups and subprojects.' argument :include_ancestors, GraphQL::Types::Boolean, required: false, description: 'Include milestones from all parent groups.' + argument :include_descendants, GraphQL::Types::Boolean, + required: false, + description: 'Include milestones from all subgroups and subprojects.' type Types::MilestoneType.connection_type, null: true diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb index bd7f1f0774e..6dbcbe0e04d 100644 --- a/app/graphql/resolvers/merge_requests_resolver.rb +++ b/app/graphql/resolvers/merge_requests_resolver.rb @@ -51,6 +51,10 @@ module Resolvers required: false, description: 'Merge request state. If provided, all resolved merge requests will have this state.' + argument :draft, GraphQL::Types::Boolean, + required: false, + description: 'Limit result to draft merge requests.' + argument :labels, [GraphQL::Types::String], required: false, as: :label_name, diff --git a/app/graphql/resolvers/users/groups_resolver.rb b/app/graphql/resolvers/users/groups_resolver.rb index eafb56d8f4c..d8492a8fcf9 100644 --- a/app/graphql/resolvers/users/groups_resolver.rb +++ b/app/graphql/resolvers/users/groups_resolver.rb @@ -23,10 +23,6 @@ module Resolvers Preloaders::GroupPolicyPreloader.new(nodes, current_user).execute end - def ready?(**args) - Feature.enabled?(:paginatable_namespace_drop_down_for_project_creation, current_user, default_enabled: :yaml) - end - private def resolve_groups(**args) diff --git a/app/graphql/resolvers/work_items/types_resolver.rb b/app/graphql/resolvers/work_items/types_resolver.rb new file mode 100644 index 00000000000..b7a32e13423 --- /dev/null +++ b/app/graphql/resolvers/work_items/types_resolver.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Resolvers + module WorkItems + class TypesResolver < BaseResolver + type Types::WorkItems::TypeType.connection_type, null: true + + def resolve + # 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 + end + end + end +end diff --git a/app/graphql/types/ci/config/config_type.rb b/app/graphql/types/ci/config/config_type.rb index 6ac21968bd4..de355c8eacf 100644 --- a/app/graphql/types/ci/config/config_type.rb +++ b/app/graphql/types/ci/config/config_type.rb @@ -15,6 +15,8 @@ module Types description: 'Stages of the pipeline.' field :status, Types::Ci::Config::StatusEnum, null: true, description: 'Status of linting, can be either valid or invalid.' + field :warnings, [GraphQL::Types::String], null: true, + description: 'Linting warnings.' end end end diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index 928ca2f597d..1320b96907e 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -50,6 +50,8 @@ 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, @@ -89,6 +91,10 @@ module Types Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, object.pipeline_id).find end + def downstream_pipeline + object.downstream_pipeline if object.respond_to?(:downstream_pipeline) + end + def tags object.tags.map(&:name) if object.is_a?(::Ci::Build) end diff --git a/app/graphql/types/ci/pipeline_message_type.rb b/app/graphql/types/ci/pipeline_message_type.rb new file mode 100644 index 00000000000..7edea1901a1 --- /dev/null +++ b/app/graphql/types/ci/pipeline_message_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + class PipelineMessageType < BaseObject + graphql_name 'PipelineMessage' + + field :id, GraphQL::Types::ID, null: false, + description: 'ID of the pipeline message.' + + field :content, GraphQL::Types::String, null: false, + description: 'Content of the pipeline message.' + end + end +end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index c8ac31bce4d..537b8e42ad1 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -18,8 +18,14 @@ module Types field :iid, GraphQL::Types::String, null: false, description: 'Internal ID of the pipeline.' - field :sha, GraphQL::Types::String, null: false, - description: "SHA of the pipeline's commit." + field :sha, GraphQL::Types::String, null: true, + method: :sha, + description: "SHA of the pipeline's commit." do + argument :format, + type: Types::ShaFormatEnum, + required: false, + description: 'Format of the SHA.' + end field :before_sha, GraphQL::Types::String, null: true, description: 'Base SHA of the source branch.' @@ -162,6 +168,13 @@ module Types field :ref, GraphQL::Types::String, null: true, description: 'Reference to the branch from which the pipeline was triggered.' + field :ref_path, GraphQL::Types::String, null: true, + description: 'Reference path to the branch from which the pipeline was triggered.', + method: :source_ref_path + + field :warning_messages, [Types::Ci::PipelineMessageType], null: true, + description: 'Pipeline warning messages.' + def detailed_status object.detailed_status(current_user) end @@ -189,6 +202,12 @@ module Types end.take # rubocop: disable CodeReuse/ActiveRecord end + def sha(format: Types::ShaFormatEnum.enum[:long]) + return pipeline.short_sha if format == Types::ShaFormatEnum.enum[:short] + + pipeline.sha + end + alias_method :pipeline, :object end end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index d37cca0927f..4fe65734911 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -4,6 +4,7 @@ module Types module Ci class RunnerType < BaseObject edge_type_class(RunnerWebUrlEdge) + connection_type_class(Types::CountableConnectionType) graphql_name 'CiRunner' authorize :read_runner present_using ::Ci::RunnerPresenter @@ -18,8 +19,10 @@ module Types 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: 'Last contact from the runner.', + description: 'Timestamp of last contact from this runner.', method: :contacted_at field :maximum_timeout, GraphQL::Types::Int, null: true, description: 'Maximum timeout (in seconds) for jobs processed by the runner.' @@ -54,6 +57,12 @@ module Types 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 :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, + description: 'Executor last advertised by the runner.', + method: :executor_name, + feature_flag: :graphql_ci_runner_executor def job_count # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT @@ -64,6 +73,10 @@ module Types Gitlab::Routing.url_helpers.admin_runner_url(runner) if can_admin_runners? end + def edit_admin_url + Gitlab::Routing.url_helpers.edit_admin_runner_url(runner) if can_admin_runners? + end + # rubocop: disable CodeReuse/ActiveRecord def project_count BatchLoader::GraphQL.for(runner.id).batch(key: :runner_project_count) do |ids, loader, args| diff --git a/app/graphql/types/clusters/agent_token_status_enum.rb b/app/graphql/types/clusters/agent_token_status_enum.rb new file mode 100644 index 00000000000..c00a64d21c1 --- /dev/null +++ b/app/graphql/types/clusters/agent_token_status_enum.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + module Clusters + class AgentTokenStatusEnum < BaseEnum + graphql_name 'AgentTokenStatus' + description 'Agent token statuses' + + ::Clusters::AgentToken.statuses.keys.each do |status| + value status.upcase, value: status, description: "#{status.titleize} agent token." + end + end + end +end diff --git a/app/graphql/types/clusters/agent_token_type.rb b/app/graphql/types/clusters/agent_token_type.rb index 94c5fc46a5d..96fdb5f05c8 100644 --- a/app/graphql/types/clusters/agent_token_type.rb +++ b/app/graphql/types/clusters/agent_token_type.rb @@ -44,6 +44,11 @@ module Types null: true, description: 'Name given to the token.' + field :status, + Types::Clusters::AgentTokenStatusEnum, + null: true, + description: 'Current status of the token.' + def cluster_agent Gitlab::Graphql::Loaders::BatchModelLoader.new(::Clusters::Agent, object.agent_id).find end diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index 7d141bd6daa..2584e15ff0b 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -39,6 +39,8 @@ module Types 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.' diff --git a/app/graphql/types/deprecated_mutations.rb b/app/graphql/types/deprecated_mutations.rb index 49bad56b6f9..70d5fc31cd1 100644 --- a/app/graphql/types/deprecated_mutations.rb +++ b/app/graphql/types/deprecated_mutations.rb @@ -5,7 +5,8 @@ module Types extend ActiveSupport::Concern prepended do - # placeholder for any FOSS mutations to be deprecated + mount_mutation Mutations::Clusters::AgentTokens::Delete, + deprecated: { reason: 'Tokens must be revoked with ClusterAgentTokenRevoke', milestone: '14.7' } end end end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 4a20d84f2ab..e02650fd285 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -210,6 +210,11 @@ module Types null: true, description: "Find contacts of this group." + 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 + def avatar_url object.avatar_url(only_path: false) end diff --git a/app/graphql/types/incident_management/escalation_status_enum.rb b/app/graphql/types/incident_management/escalation_status_enum.rb new file mode 100644 index 00000000000..bc462f03148 --- /dev/null +++ b/app/graphql/types/incident_management/escalation_status_enum.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Types + module IncidentManagement + class EscalationStatusEnum < BaseEnum + graphql_name 'IssueEscalationStatus' + description 'Issue escalation status values' + + ::IncidentManagement::IssuableEscalationStatus.status_names.each do |status| + value status.to_s.upcase, value: status, description: "#{::IncidentManagement::IssuableEscalationStatus::STATUS_DESCRIPTIONS[status]}." + end + end + end +end diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 498569f11ca..46fe91feae4 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -140,6 +140,9 @@ module Types field :customer_relations_contacts, Types::CustomerRelations::ContactType.connection_type, null: true, description: 'Customer relations contacts of the issue.' + field :escalation_status, Types::IncidentManagement::EscalationStatusEnum, null: true, + description: 'Escalation status of the issue.' + def author Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find end @@ -167,6 +170,12 @@ module Types def hidden? object.hidden? if Feature.enabled?(:ban_user_feature_flag) end + + def escalation_status + return unless Feature.enabled?(:incident_escalations, object.project) && object.supports_escalation? + + object.escalation_status&.status_name + end end end diff --git a/app/graphql/types/issue_type_enum.rb b/app/graphql/types/issue_type_enum.rb index 0cfba6bbbd0..b18c8b90e96 100644 --- a/app/graphql/types/issue_type_enum.rb +++ b/app/graphql/types/issue_type_enum.rb @@ -5,7 +5,7 @@ module Types graphql_name 'IssueType' description 'Issue type' - ::WorkItem::Type.allowed_types_for_issues.each do |issue_type| + ::WorkItems::Type.allowed_types_for_issues.each do |issue_type| value issue_type.upcase, value: issue_type, description: "#{issue_type.titleize} issue type" end end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index 0672ec6f0f8..ea05671c79c 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -189,6 +189,8 @@ module Types 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 :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, @@ -196,7 +198,7 @@ module Types field :auto_merge_strategy, GraphQL::Types::String, null: true, description: 'Selected auto merge strategy.' field :merge_user, Types::UserType, null: true, - description: 'User who merged this merge request.' + description: 'User who merged this merge request or set it to merge when pipeline succeeds.' field :timelogs, Types::TimelogType.connection_type, null: false, description: 'Timelogs on the merge request.' @@ -249,16 +251,28 @@ module Types !!object.discussion_locked end + def default_merge_commit_message + object.default_merge_commit_message(include_description: false, user: current_user) + end + def default_merge_commit_message_with_description object.default_merge_commit_message(include_description: true) end + def default_squash_commit_message + object.default_squash_commit_message(user: current_user) + end + def available_auto_merge_strategies AutoMergeService.new(object.project, current_user).available_strategies(object) end + def commits + object.commits.commits + end + def commits_without_merge_commits - object.recent_commits.without_merge_commits + object.commits.without_merge_commits end def security_auto_fix @@ -268,6 +282,10 @@ module Types def reviewers object.reviewers end + + def merge_user + object.metrics&.merged_by || object.merge_user + end end end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index e8a952e9c61..c350f4dd922 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -35,7 +35,7 @@ module Types mount_mutation Mutations::Clusters::Agents::Create mount_mutation Mutations::Clusters::Agents::Delete mount_mutation Mutations::Clusters::AgentTokens::Create - mount_mutation Mutations::Clusters::AgentTokens::Delete + mount_mutation Mutations::Clusters::AgentTokens::Revoke mount_mutation Mutations::Commits::Create, calls_gitaly: true mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji mount_mutation Mutations::CustomEmoji::Destroy, feature_flag: :custom_emoji @@ -55,6 +55,7 @@ module Types mount_mutation Mutations::Issues::SetDueDate mount_mutation Mutations::Issues::SetSeverity mount_mutation Mutations::Issues::SetSubscription + mount_mutation Mutations::Issues::SetEscalationStatus mount_mutation Mutations::Issues::Update mount_mutation Mutations::Issues::Move mount_mutation Mutations::Labels::Create @@ -123,6 +124,7 @@ module Types mount_mutation Mutations::Packages::Destroy mount_mutation Mutations::Packages::DestroyFile mount_mutation Mutations::Echo + mount_mutation Mutations::WorkItems::Create, feature_flag: :work_items end end diff --git a/app/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb index 5ac80860fe2..1d2cf9649d8 100644 --- a/app/graphql/types/packages/package_details_type.rb +++ b/app/graphql/types/packages/package_details_type.rb @@ -3,6 +3,8 @@ module Types module Packages class PackageDetailsType < PackageType + include ::PackagesHelper + graphql_name 'PackageDetailsType' description 'Represents a package details in the Package Registry. Note that this type is in beta and susceptible to changes' authorize :read_package @@ -21,9 +23,58 @@ module Types description: 'Pipelines that built the package.', deprecated: { reason: 'Due to scalability concerns, this field is going to be removed', milestone: '14.6' } + field :composer_config_repository_url, GraphQL::Types::String, null: true, description: 'Url of the Composer setup endpoint.' + field :composer_url, GraphQL::Types::String, null: true, description: 'Url of the Composer endpoint.' + field :conan_url, GraphQL::Types::String, null: true, description: 'Url of the Conan project endpoint.' + field :maven_url, GraphQL::Types::String, null: true, description: 'Url of the Maven project endpoint.' + field :npm_url, GraphQL::Types::String, null: true, description: 'Url of the NPM project endpoint.' + field :nuget_url, GraphQL::Types::String, null: true, description: 'Url of the Nuget project endpoint.' + field :pypi_setup_url, GraphQL::Types::String, null: true, description: 'Url of the PyPi project setup endpoint.' + field :pypi_url, GraphQL::Types::String, null: true, description: 'Url of the PyPi project endpoint.' + def versions object.versions end + + def package_files + if Feature.enabled?(:packages_installable_package_files, default_enabled: :yaml) + object.installable_package_files + else + object.package_files + end + end + + def composer_config_repository_url + composer_config_repository_name(object.project.group&.id) + end + + def composer_url + composer_registry_url(object.project.group&.id) + end + + def conan_url + package_registry_project_url(object.project.id, :conan) + end + + def maven_url + package_registry_project_url(object.project.id, :maven) + end + + def npm_url + package_registry_project_url(object.project.id, :npm) + end + + def nuget_url + nuget_package_registry_url(object.project.id) + end + + def pypi_setup_url + package_registry_project_url(object.project.id, :pypi) + end + + def pypi_url + pypi_registry_url(object.project.id) + end end end end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 3d2ee47a499..f4067552f55 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -27,7 +27,6 @@ module Types field :description, GraphQL::Types::String, null: true, description: 'Short description of the project.' - markdown_field :description_html, null: true field :tag_list, GraphQL::Types::String, null: true, deprecated: { reason: 'Use `topics`', milestone: '13.12' }, @@ -75,21 +74,6 @@ module Types field :avatar_url, GraphQL::Types::String, null: true, calls_gitaly: true, description: 'URL to avatar image file of the project.' - { - issues: "Issues are", - merge_requests: "Merge Requests are", - wiki: 'Wikis are', - snippets: 'Snippets are', - container_registry: 'Container Registry is' - }.each do |feature, name_string| - field "#{feature}_enabled", GraphQL::Types::Boolean, null: true, - description: "Indicates if #{name_string} enabled for the current user" - - define_method "#{feature}_enabled" do - object.feature_available?(feature, context[:current_user]) - end - end - field :jobs_enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates if CI/CD pipeline jobs are enabled for the current user.' @@ -391,6 +375,17 @@ module Types null: true, description: 'Template used to create squash commit message in merge requests.' + field :labels, + Types::LabelType.connection_type, + null: true, + description: 'Labels available on this project.', + resolver: Resolvers::LabelsResolver + + 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 + def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| LabelsFinder @@ -400,11 +395,22 @@ module Types end end - field :labels, - Types::LabelType.connection_type, - null: true, - description: 'Labels available on this project.', - resolver: Resolvers::LabelsResolver + { + issues: "Issues are", + merge_requests: "Merge Requests are", + wiki: 'Wikis are', + snippets: 'Snippets are', + container_registry: 'Container Registry is' + }.each do |feature, name_string| + field "#{feature}_enabled", GraphQL::Types::Boolean, null: true, + description: "Indicates if #{name_string} enabled for the current user" + + define_method "#{feature}_enabled" do + object.feature_available?(feature, context[:current_user]) + end + end + + markdown_field :description_html, null: true def avatar_url object.avatar_url(only_path: false) diff --git a/app/graphql/types/projects/topic_type.rb b/app/graphql/types/projects/topic_type.rb index 79ab69e794b..c579f2f2b9d 100644 --- a/app/graphql/types/projects/topic_type.rb +++ b/app/graphql/types/projects/topic_type.rb @@ -14,11 +14,12 @@ module Types field :description, GraphQL::Types::String, null: true, description: 'Description of the topic.' - markdown_field :description_html, null: true field :avatar_url, GraphQL::Types::String, null: true, description: 'URL to avatar image file of the topic.' + markdown_field :description_html, null: true + def avatar_url object.avatar_url(only_path: false) end diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb index fcc9ec49252..fbc3779ea9b 100644 --- a/app/graphql/types/release_type.rb +++ b/app/graphql/types/release_type.rb @@ -20,7 +20,6 @@ module Types authorize: :download_code field :description, GraphQL::Types::String, null: true, description: 'Description (also known as "release notes") of the release.' - markdown_field :description_html, null: true field :name, GraphQL::Types::String, null: true, description: 'Name of the release.' field :created_at, Types::TimeType, null: true, @@ -42,14 +41,16 @@ module Types field :author, Types::UserType, null: true, description: 'User that created the release.' - def author - Gitlab::Graphql::Loaders::BatchModelLoader.new(User, release.author_id).find - end - field :commit, Types::CommitType, null: true, complexity: 10, calls_gitaly: true, description: 'Commit associated with the release.' + markdown_field :description_html, null: true + + def author + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, release.author_id).find + end + def commit return if release.sha.nil? diff --git a/app/graphql/types/repository/blob_type.rb b/app/graphql/types/repository/blob_type.rb index 3265c14bdca..28339093172 100644 --- a/app/graphql/types/repository/blob_type.rb +++ b/app/graphql/types/repository/blob_type.rb @@ -56,6 +56,9 @@ module Types field :stored_externally, GraphQL::Types::Boolean, null: true, method: :stored_externally?, description: "Whether the blob's content is stored externally (for instance, in LFS)." + field :external_storage, GraphQL::Types::String, null: true, method: :external_storage, + description: "External storage being used, if enabled (for instance, 'LFS')." + field :edit_blob_path, GraphQL::Types::String, null: true, description: 'Web path to edit the blob in the old-style editor.' @@ -71,6 +74,19 @@ module Types field :pipeline_editor_path, GraphQL::Types::String, null: true, description: 'Web path to edit .gitlab-ci.yml file.' + field :find_file_path, GraphQL::Types::String, null: true, + description: 'Web path to find file.' + + field :blame_path, GraphQL::Types::String, null: true, + description: 'Web path to blob blame page.' + + field :history_path, GraphQL::Types::String, null: true, + description: 'Web path to blob history page.' + + field :permalink_path, GraphQL::Types::String, null: true, + description: 'Web path to blob permalink.', + calls_gitaly: true + field :code_owners, [Types::UserType], null: true, description: 'List of code owners for the blob.', calls_gitaly: true @@ -98,6 +114,9 @@ module Types field :can_current_user_push_to_branch, GraphQL::Types::Boolean, null: true, method: :can_current_user_push_to_branch?, description: 'Whether the current user can push to the branch.' + field :archived, GraphQL::Types::Boolean, null: true, method: :archived?, + description: 'Whether the current project is archived.' + def raw_text_blob object.data unless object.binary? end diff --git a/app/graphql/types/sha_format_enum.rb b/app/graphql/types/sha_format_enum.rb new file mode 100644 index 00000000000..2e0e5bb85f3 --- /dev/null +++ b/app/graphql/types/sha_format_enum.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + class ShaFormatEnum < BaseEnum + graphql_name 'ShaFormat' + description 'How to format SHA strings.' + + FORMATS_DESCRIPTION = { + short: 'Abbreviated format. Short SHAs are typically eight characters long.', + long: 'Unabbreviated format.' + }.freeze + + FORMATS_DESCRIPTION.each do |format, description| + value format.to_s.upcase, + description: description, + value: format.to_s + end + end +end diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index 7cc201b6df4..6bb4cb29cdd 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -64,8 +64,7 @@ module Types description: 'Group memberships of the user.' field :groups, resolver: Resolvers::Users::GroupsResolver, - description: 'Groups where the user has access. Will always return `null` if ' \ - '`paginatable_namespace_drop_down_for_project_creation` feature flag is disabled.' + description: 'Groups where the user has access.' field :group_count, resolver: Resolvers::Users::GroupCountResolver, description: 'Group count for the user.' diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb new file mode 100644 index 00000000000..486c1e52987 --- /dev/null +++ b/app/graphql/types/work_item_type.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Types + class WorkItemType < BaseObject + graphql_name 'WorkItem' + + authorize :read_issue + + field :description, GraphQL::Types::String, null: true, + description: 'Description of the work item.' + field :id, Types::GlobalIDType[::WorkItem], null: false, + description: 'Global ID of the work item.' + field :iid, GraphQL::Types::ID, null: false, + description: 'Internal ID of the work item.' + field :title, GraphQL::Types::String, null: false, + description: 'Title of the work item.' + field :work_item_type, Types::WorkItems::TypeType, null: false, + description: 'Type assigned to the work item.' + + markdown_field :title_html, null: true + markdown_field :description_html, null: true + end +end diff --git a/app/graphql/types/work_items/type_type.rb b/app/graphql/types/work_items/type_type.rb new file mode 100644 index 00000000000..f31bd7ee9ba --- /dev/null +++ b/app/graphql/types/work_items/type_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Types + module WorkItems + class TypeType < BaseObject + graphql_name 'WorkItemType' + + authorize :read_work_item_type + + field :icon_name, GraphQL::Types::String, null: true, + description: 'Icon name of the work item type.' + field :id, Types::GlobalIDType[::WorkItems::Type], null: false, + description: 'Global ID of the work item type.' + field :name, GraphQL::Types::String, null: false, + description: 'Name of the work item type.' + end + end +end |