diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /app/graphql/types | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'app/graphql/types')
52 files changed, 651 insertions, 190 deletions
diff --git a/app/graphql/types/alert_management/domain_filter_enum.rb b/app/graphql/types/alert_management/domain_filter_enum.rb new file mode 100644 index 00000000000..58dbc8bb2cf --- /dev/null +++ b/app/graphql/types/alert_management/domain_filter_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module AlertManagement + class DomainFilterEnum < BaseEnum + graphql_name 'AlertManagementDomainFilter' + description 'Filters the alerts based on given domain' + + value 'operations', description: 'Alerts for operations domain ' + value 'threat_monitoring', description: 'Alerts for threat monitoring domain' + end + end +end diff --git a/app/graphql/types/alert_management/prometheus_integration_type.rb b/app/graphql/types/alert_management/prometheus_integration_type.rb index f605e325b8b..79f265f2f1e 100644 --- a/app/graphql/types/alert_management/prometheus_integration_type.rb +++ b/app/graphql/types/alert_management/prometheus_integration_type.rb @@ -2,7 +2,7 @@ module Types module AlertManagement - class PrometheusIntegrationType < BaseObject + class PrometheusIntegrationType < ::Types::BaseObject include ::Gitlab::Routing graphql_name 'AlertManagementPrometheusIntegration' diff --git a/app/graphql/types/award_emojis/award_emoji_type.rb b/app/graphql/types/award_emojis/award_emoji_type.rb index fe7affa50cc..cd7a2f34ba6 100644 --- a/app/graphql/types/award_emojis/award_emoji_type.rb +++ b/app/graphql/types/award_emojis/award_emoji_type.rb @@ -38,10 +38,11 @@ module Types field :user, Types::UserType, null: false, - description: 'The user who awarded the emoji', - resolve: -> (award_emoji, _args, _context) { - Gitlab::Graphql::Loaders::BatchModelLoader.new(User, award_emoji.user_id).find - } + description: 'The user who awarded the emoji' + + def user + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.user_id).find + end end end end diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb index 5c8aabfe163..c4ce2cecd8b 100644 --- a/app/graphql/types/base_field.rb +++ b/app/graphql/types/base_field.rb @@ -12,6 +12,7 @@ module Types def initialize(*args, **kwargs, &block) @calls_gitaly = !!kwargs.delete(:calls_gitaly) @constant_complexity = !!kwargs[:complexity] + @requires_argument = !!kwargs.delete(:requires_argument) kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity]) @feature_flag = kwargs[:feature_flag] kwargs = check_feature_flag(kwargs) @@ -20,6 +21,10 @@ module Types super(*args, **kwargs, &block) end + def requires_argument? + @requires_argument || arguments.values.any? { |argument| argument.type.non_null? } + end + # Based on https://github.com/rmosolgo/graphql-ruby/blob/v1.11.4/lib/graphql/schema/field.rb#L538-L563 # Modified to fix https://github.com/rmosolgo/graphql-ruby/issues/3113 def resolve_field(obj, args, ctx) @@ -73,7 +78,7 @@ module Types attr_reader :feature_flag def feature_documentation_message(key, description) - "#{description}. Available only when feature flag `#{key}` is enabled" + "#{description} Available only when feature flag `#{key}` is enabled." end def check_feature_flag(args) diff --git a/app/graphql/types/base_interface.rb b/app/graphql/types/base_interface.rb index 3451a195c33..4b1f3193136 100644 --- a/app/graphql/types/base_interface.rb +++ b/app/graphql/types/base_interface.rb @@ -3,5 +3,7 @@ module Types module BaseInterface include GraphQL::Schema::Interface + + field_class ::Types::BaseField end end diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb index 6ee76b0d1f1..7999e77eb30 100644 --- a/app/graphql/types/board_list_type.rb +++ b/app/graphql/types/board_list_type.rb @@ -19,8 +19,7 @@ module Types field :label, Types::LabelType, null: true, description: 'Label of the list' field :collapsed, GraphQL::BOOLEAN_TYPE, null: true, - description: 'Indicates if list is collapsed for this user', - resolve: -> (list, _args, ctx) { list.collapsed?(ctx[:current_user]) } + description: 'Indicates if list is collapsed for this user' field :issues_count, GraphQL::INT_TYPE, null: true, description: 'Count of issues in the list' @@ -32,6 +31,10 @@ module Types metadata[:size] end + def collapsed + object.collapsed?(context[:current_user]) + end + def metadata strong_memoize(:metadata) do list = self.object diff --git a/app/graphql/types/board_type.rb b/app/graphql/types/board_type.rb index 2a7b318e283..f47c744d1bb 100644 --- a/app/graphql/types/board_type.rb +++ b/app/graphql/types/board_type.rb @@ -12,6 +12,12 @@ module Types field :name, type: GraphQL::STRING_TYPE, null: true, description: 'Name of the board' + field :hide_backlog_list, type: GraphQL::BOOLEAN_TYPE, null: true, + description: 'Whether or not backlog list is hidden' + + field :hide_closed_list, type: GraphQL::BOOLEAN_TYPE, null: true, + description: 'Whether or not closed list is hidden' + field :lists, Types::BoardListType.connection_type, null: true, diff --git a/app/graphql/types/ci/analytics_type.rb b/app/graphql/types/ci/analytics_type.rb new file mode 100644 index 00000000000..c8b12c6a9b8 --- /dev/null +++ b/app/graphql/types/ci/analytics_type.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + class AnalyticsType < BaseObject + graphql_name 'PipelineAnalytics' + + field :week_pipelines_totals, [GraphQL::INT_TYPE], null: true, + description: 'Total weekly pipeline count' + field :week_pipelines_successful, [GraphQL::INT_TYPE], null: true, + description: 'Total weekly successful pipeline count' + field :week_pipelines_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Labels for the weekly pipeline count' + field :month_pipelines_totals, [GraphQL::INT_TYPE], null: true, + description: 'Total monthly pipeline count' + field :month_pipelines_successful, [GraphQL::INT_TYPE], null: true, + description: 'Total monthly successful pipeline count' + field :month_pipelines_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Labels for the monthly pipeline count' + field :year_pipelines_totals, [GraphQL::INT_TYPE], null: true, + description: 'Total yearly pipeline count' + field :year_pipelines_successful, [GraphQL::INT_TYPE], null: true, + description: 'Total yearly successful pipeline count' + field :year_pipelines_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Labels for the yearly pipeline count' + field :pipeline_times_values, [GraphQL::INT_TYPE], null: true, + description: 'Pipeline times' + field :pipeline_times_labels, [GraphQL::STRING_TYPE], null: true, + description: 'Pipeline times labels' + end + end +end diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb new file mode 100644 index 00000000000..207c37f9538 --- /dev/null +++ b/app/graphql/types/ci/ci_cd_setting_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Types + module Ci + class CiCdSettingType < BaseObject + graphql_name 'ProjectCiCdSetting' + + authorize :admin_project + + field :merge_pipelines_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Whether merge pipelines are enabled.', + method: :merge_pipelines_enabled? + field :merge_trains_enabled, GraphQL::BOOLEAN_TYPE, null: true, + description: 'Whether merge trains are enabled.', + method: :merge_trains_enabled? + field :project, Types::ProjectType, null: true, + description: 'Project the CI/CD settings belong to.' + end + end +end diff --git a/app/graphql/types/ci/config/config_type.rb b/app/graphql/types/ci/config/config_type.rb new file mode 100644 index 00000000000..e54b345f3d3 --- /dev/null +++ b/app/graphql/types/ci/config/config_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + module Config + class ConfigType < BaseObject + graphql_name 'CiConfig' + + field :errors, [GraphQL::STRING_TYPE], null: true, + description: 'Linting errors' + field :merged_yaml, GraphQL::STRING_TYPE, null: true, + description: 'Merged CI config YAML' + field :stages, [Types::Ci::Config::StageType], null: true, + description: 'Stages of the pipeline' + field :status, Types::Ci::Config::StatusEnum, null: true, + description: 'Status of linting, can be either valid or invalid' + end + end + end +end diff --git a/app/graphql/types/ci/config/group_type.rb b/app/graphql/types/ci/config/group_type.rb new file mode 100644 index 00000000000..8b0db2934a4 --- /dev/null +++ b/app/graphql/types/ci/config/group_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + module Config + class GroupType < BaseObject + graphql_name 'CiConfigGroup' + + field :name, GraphQL::STRING_TYPE, null: true, + description: 'Name of the job group' + field :jobs, [Types::Ci::Config::JobType], null: true, + description: 'Jobs in group' + field :size, GraphQL::INT_TYPE, null: true, + description: 'Size of the job group' + end + end + end +end diff --git a/app/graphql/types/ci/config/job_type.rb b/app/graphql/types/ci/config/job_type.rb new file mode 100644 index 00000000000..59bcbd9ef49 --- /dev/null +++ b/app/graphql/types/ci/config/job_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + module Config + class JobType < BaseObject + graphql_name 'CiConfigJob' + + field :name, GraphQL::STRING_TYPE, null: true, + description: 'Name of the job' + field :group_name, GraphQL::STRING_TYPE, null: true, + description: 'Name of the job group' + field :stage, GraphQL::STRING_TYPE, null: true, + description: 'Name of the job stage' + field :needs, [Types::Ci::Config::NeedType], null: true, + description: 'Builds that must complete before the jobs run' + end + end + end +end diff --git a/app/graphql/types/ci/config/need_type.rb b/app/graphql/types/ci/config/need_type.rb new file mode 100644 index 00000000000..a442450b9ae --- /dev/null +++ b/app/graphql/types/ci/config/need_type.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + module Config + class NeedType < BaseObject + graphql_name 'CiConfigNeed' + + field :name, GraphQL::STRING_TYPE, null: true, + description: 'Name of the need' + end + end + end +end diff --git a/app/graphql/types/ci/config/stage_type.rb b/app/graphql/types/ci/config/stage_type.rb new file mode 100644 index 00000000000..20618bc41f8 --- /dev/null +++ b/app/graphql/types/ci/config/stage_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + module Config + class StageType < BaseObject + graphql_name 'CiConfigStage' + + field :name, GraphQL::STRING_TYPE, null: true, + description: 'Name of the stage' + field :groups, [Types::Ci::Config::GroupType], null: true, + description: 'Groups of jobs for the stage' + end + end + end +end diff --git a/app/graphql/types/ci/config/status_enum.rb b/app/graphql/types/ci/config/status_enum.rb new file mode 100644 index 00000000000..92b04c61679 --- /dev/null +++ b/app/graphql/types/ci/config/status_enum.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + module Ci + module Config + class StatusEnum < BaseEnum + graphql_name 'CiConfigStatus' + description 'Values for YAML processor result' + + value 'VALID', 'The configuration file is valid', value: :valid + value 'INVALID', 'The configuration file is not valid', value: :invalid + end + end + end +end diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb index 6d8af400ac4..80d73e9b174 100644 --- a/app/graphql/types/ci/detailed_status_type.rb +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -25,20 +25,22 @@ module Types description: 'Tooltip associated with the status', method: :status_tooltip field :action, Types::Ci::StatusActionType, null: true, - description: 'Action information for the status. This includes method, button title, icon, path, and title', - resolve: -> (obj, _args, _ctx) { - if obj.has_action? - { - button_title: obj.action_button_title, - icon: obj.action_icon, - method: obj.action_method, - path: obj.action_path, - title: obj.action_title - } - else - nil - end - } + calls_gitaly: true, + description: 'Action information for the status. This includes method, button title, icon, path, and title' + + def action + if object.has_action? + { + button_title: object.action_button_title, + icon: object.action_icon, + method: object.action_method, + path: object.action_path, + title: object.action_title + } + else + nil + end + end end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/ci/group_type.rb b/app/graphql/types/ci/group_type.rb index d930ae311b7..03fd50d5dbb 100644 --- a/app/graphql/types/ci/group_type.rb +++ b/app/graphql/types/ci/group_type.rb @@ -13,8 +13,11 @@ module Types field :jobs, Ci::JobType.connection_type, null: true, description: 'Jobs in group' field :detailed_status, Types::Ci::DetailedStatusType, null: true, - description: 'Detailed status of the group', - resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } + description: 'Detailed status of the group' + + def detailed_status + object.detailed_status(context[:current_user]) + end end end end diff --git a/app/graphql/types/ci/job_artifact_file_type_enum.rb b/app/graphql/types/ci/job_artifact_file_type_enum.rb new file mode 100644 index 00000000000..4b484dec590 --- /dev/null +++ b/app/graphql/types/ci/job_artifact_file_type_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module Ci + class JobArtifactFileTypeEnum < BaseEnum + graphql_name 'JobArtifactFileType' + + ::Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS.keys.each do |file_type| + value file_type.to_s.upcase, value: file_type.to_s + end + end + end +end diff --git a/app/graphql/types/ci/job_artifact_type.rb b/app/graphql/types/ci/job_artifact_type.rb new file mode 100644 index 00000000000..c34a12dcc61 --- /dev/null +++ b/app/graphql/types/ci/job_artifact_type.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + class JobArtifactType < BaseObject + graphql_name 'CiJobArtifact' + + field :download_path, GraphQL::STRING_TYPE, null: true, + description: "URL for downloading the artifact's file" + + field :file_type, ::Types::Ci::JobArtifactFileTypeEnum, null: true, + description: 'File type of the artifact' + + def download_path + ::Gitlab::Routing.url_helpers.download_project_job_artifacts_path( + object.project, + object.job, + file_type: object.file_type + ) + end + end + end +end diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index feaff4e81d8..5b6e8fe8567 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -6,18 +6,32 @@ module Types class JobType < BaseObject graphql_name 'CiJob' - field :pipeline, Types::Ci::PipelineType, null: false, - description: 'Pipeline the job belongs to', - resolve: -> (build, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, build.pipeline_id).find } + field :pipeline, Types::Ci::PipelineType, null: true, + description: 'Pipeline the job belongs to' field :name, GraphQL::STRING_TYPE, null: true, - description: 'Name of the job' + description: 'Name of the job' field :needs, JobType.connection_type, null: true, - description: 'Builds that must complete before the jobs run' + description: 'Builds that must complete before the jobs run' field :detailed_status, Types::Ci::DetailedStatusType, null: true, - description: 'Detailed status of the job', - resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } + description: 'Detailed status of the job' field :scheduled_at, Types::TimeType, null: true, - description: 'Schedule for the build' + description: 'Schedule for the build' + field :artifacts, Types::Ci::JobArtifactType.connection_type, null: true, + description: 'Artifacts generated by the job' + + def pipeline + Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, object.pipeline_id).find + end + + def detailed_status + object.detailed_status(context[:current_user]) + end + + def artifacts + if object.is_a?(::Ci::Build) + object.job_artifacts + end + end end end end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index c25db39f600..4709d5e8dd6 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -27,8 +27,7 @@ module Types description: "Status of the pipeline (#{::Ci::Pipeline.all_state_names.compact.join(', ').upcase})" field :detailed_status, Types::Ci::DetailedStatusType, null: false, - description: 'Detailed status of the pipeline', - resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } + description: 'Detailed status of the pipeline' field :config_source, PipelineConfigSourceEnum, null: true, description: "Config source of the pipeline (#{::Enums::Ci::Pipeline.config_sources.keys.join(', ').upcase})" @@ -60,8 +59,7 @@ module Types resolver: Resolvers::Ci::PipelineStagesResolver field :user, Types::UserType, null: true, - description: 'Pipeline user', - resolve: -> (pipeline, _args, _context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, pipeline.user_id).find } + description: 'Pipeline user' field :retryable, GraphQL::BOOLEAN_TYPE, description: 'Specifies if a pipeline can be retried', @@ -91,11 +89,25 @@ module Types method: :triggered_by_pipeline field :path, GraphQL::STRING_TYPE, null: true, - description: "Relative path to the pipeline's page", - resolve: -> (obj, _args, _ctx) { ::Gitlab::Routing.url_helpers.project_pipeline_path(obj.project, obj) } + description: "Relative path to the pipeline's page" field :project, Types::ProjectType, null: true, description: 'Project the pipeline belongs to' + + field :active, GraphQL::BOOLEAN_TYPE, null: false, method: :active?, + description: 'Indicates if the pipeline is active' + + def detailed_status + object.detailed_status(context[:current_user]) + end + + def user + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.user_id).find + end + + def path + ::Gitlab::Routing.url_helpers.project_pipeline_path(object.project, object) + end end end end diff --git a/app/graphql/types/ci/stage_type.rb b/app/graphql/types/ci/stage_type.rb index fc2c72d0d06..fd0bde90836 100644 --- a/app/graphql/types/ci/stage_type.rb +++ b/app/graphql/types/ci/stage_type.rb @@ -11,8 +11,11 @@ module Types field :groups, Ci::GroupType.connection_type, null: true, description: 'Group of jobs for the stage' field :detailed_status, Types::Ci::DetailedStatusType, null: true, - description: 'Detailed status of the stage', - resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } + description: 'Detailed status of the stage' + + def detailed_status + object.detailed_status(context[:current_user]) + end end end end diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index c24b47f08ef..37d19b4148b 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -12,6 +12,8 @@ module Types description: 'ID (global ID) of the commit' field :sha, type: GraphQL::STRING_TYPE, null: false, description: 'SHA1 ID of the commit' + field :short_id, type: GraphQL::STRING_TYPE, null: false, + description: 'Short SHA1 ID of the commit' field :title, type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true, description: 'Title of the commit message' markdown_field :title_html, null: true @@ -31,10 +33,7 @@ module Types field :author_name, type: GraphQL::STRING_TYPE, null: true, description: 'Commit authors name' field :author_gravatar, type: GraphQL::STRING_TYPE, null: true, - description: 'Commit authors gravatar', - resolve: -> (commit, args, context) do - GravatarService.new.execute(commit.author_email, 40) - end + description: 'Commit authors gravatar' # models/commit lazy loads the author by email field :author, type: Types::UserType, null: true, @@ -44,5 +43,9 @@ module Types null: true, description: 'Pipelines of the commit ordered latest first', resolver: Resolvers::CommitPipelinesResolver + + def author_gravatar + GravatarService.new.execute(object.author_email, 40) + end end end diff --git a/app/graphql/types/concerns/gitlab_style_deprecations.rb b/app/graphql/types/concerns/gitlab_style_deprecations.rb index 2c932f4214b..9f087f3812d 100644 --- a/app/graphql/types/concerns/gitlab_style_deprecations.rb +++ b/app/graphql/types/concerns/gitlab_style_deprecations.rb @@ -23,8 +23,8 @@ module GitlabStyleDeprecations raise ArgumentError, '`milestone` must be a `String`' unless milestone.is_a?(String) deprecated_in = "Deprecated in #{milestone}" - kwargs[:deprecation_reason] = "#{reason}. #{deprecated_in}" - kwargs[:description] += ". #{deprecated_in}: #{reason}" if kwargs[:description] + kwargs[:deprecation_reason] = "#{reason}. #{deprecated_in}." + kwargs[:description] += " #{deprecated_in}: #{reason}." if kwargs[:description] kwargs end diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb index 45d19fdbc50..8735f8a173d 100644 --- a/app/graphql/types/container_repository_type.rb +++ b/app/graphql/types/container_repository_type.rb @@ -19,9 +19,14 @@ module Types field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.' field :tags_count, GraphQL::INT_TYPE, null: false, description: 'Number of tags associated with this image.' field :can_delete, GraphQL::BOOLEAN_TYPE, null: false, description: 'Can the current user delete the container repository.' + field :project, Types::ProjectType, null: false, description: 'Project of the container registry' def can_delete Ability.allowed?(current_user, :update_container_image, object) end + + def project + Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find + end end end diff --git a/app/graphql/types/design_management/design_collection_type.rb b/app/graphql/types/design_management/design_collection_type.rb index 9af1f4db425..26fbac15b30 100644 --- a/app/graphql/types/design_management/design_collection_type.rb +++ b/app/graphql/types/design_management/design_collection_type.rb @@ -2,7 +2,7 @@ module Types module DesignManagement - class DesignCollectionType < BaseObject + class DesignCollectionType < ::Types::BaseObject graphql_name 'DesignCollection' description 'A collection of designs' diff --git a/app/graphql/types/error_tracking/sentry_error_collection_type.rb b/app/graphql/types/error_tracking/sentry_error_collection_type.rb index 798e0433d06..49d5d62c860 100644 --- a/app/graphql/types/error_tracking/sentry_error_collection_type.rb +++ b/app/graphql/types/error_tracking/sentry_error_collection_type.rb @@ -9,27 +9,12 @@ module Types authorize :read_sentry_issue field :errors, - Types::ErrorTracking::SentryErrorType.connection_type, - connection: false, - null: true, description: "Collection of Sentry Errors", - extensions: [Gitlab::Graphql::Extensions::ExternallyPaginatedArrayExtension], - resolver: Resolvers::ErrorTracking::SentryErrorsResolver do - argument :search_term, - String, - description: 'Search query for the Sentry error details', - required: false - argument :sort, - String, - description: 'Attribute to sort on. Options are frequency, first_seen, last_seen. last_seen is default', - required: false - end - field :detailed_error, Types::ErrorTracking::SentryDetailedErrorType, - null: true, + resolver: Resolvers::ErrorTracking::SentryErrorsResolver + field :detailed_error, description: 'Detailed version of a Sentry error on the project', resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver - field :error_stack_trace, Types::ErrorTracking::SentryErrorStackTraceType, - null: true, + field :error_stack_trace, description: 'Stack Trace of Sentry Error', resolver: Resolvers::ErrorTracking::SentryErrorStackTraceResolver field :external_url, diff --git a/app/graphql/types/group_invitation_type.rb b/app/graphql/types/group_invitation_type.rb index 0372ce178ff..efb0c8a41c8 100644 --- a/app/graphql/types/group_invitation_type.rb +++ b/app/graphql/types/group_invitation_type.rb @@ -11,7 +11,10 @@ module Types description 'Represents a Group Invitation' field :group, Types::GroupType, null: true, - description: 'Group that a User is invited to', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.source_id).find } + description: 'Group that a User is invited to' + + def group + Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, object.source_id).find + end end end diff --git a/app/graphql/types/group_member_relation_enum.rb b/app/graphql/types/group_member_relation_enum.rb new file mode 100644 index 00000000000..aa2e73d4944 --- /dev/null +++ b/app/graphql/types/group_member_relation_enum.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class GroupMemberRelationEnum < BaseEnum + graphql_name 'GroupMemberRelation' + description 'Group member relation' + + ::GroupMembersFinder::RELATIONS.each do |member_relation| + value member_relation.to_s.upcase, value: member_relation, description: "#{member_relation.to_s.titleize} members" + end + end +end diff --git a/app/graphql/types/group_member_type.rb b/app/graphql/types/group_member_type.rb index 6cca0a50647..204da5a302a 100644 --- a/app/graphql/types/group_member_type.rb +++ b/app/graphql/types/group_member_type.rb @@ -11,7 +11,10 @@ module Types description 'Represents a Group Membership' field :group, Types::GroupType, null: true, - description: 'Group that a User is a member of', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.source_id).find } + description: 'Group that a User is a member of' + + def group + Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, object.source_id).find + end end end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index fb028184488..0ee8a19c1a3 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -12,10 +12,7 @@ module Types description: 'Web URL of the group' 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 + description: 'Avatar URL of the group' field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, description: 'Custom emoji within this namespace', @@ -44,8 +41,7 @@ module Types description: 'Indicates if a group is disabled from getting mentioned' field :parent, GroupType, null: true, - description: 'Parent group', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, obj.parent_id).find } + description: 'Parent group' field :issues, Types::IssueType.connection_type, @@ -92,10 +88,13 @@ module Types field :container_repositories, Types::ContainerRepositoryType.connection_type, null: true, - description: 'Container repositories of the project', + description: 'Container repositories of the group', resolver: Resolvers::ContainerRepositoriesResolver, authorize: :read_container_image + field :container_repositories_count, GraphQL::INT_TYPE, null: false, + description: 'Number of container repositories in the group' + def label(title:) BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| LabelsFinder @@ -120,6 +119,18 @@ module Types .execute end + def avatar_url + object.avatar_url(only_path: false) + end + + def parent + Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, object.parent_id).find + end + + def container_repositories_count + group.container_repositories.size + end + private def group diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 49c84f75e1a..83b8a834801 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -61,9 +61,11 @@ module Types 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' + description: 'Number of user notes of the issue', + resolver: Resolvers::UserNotesCountResolver field :user_discussions_count, GraphQL::INT_TYPE, null: false, - description: 'Number of user discussions in the issue' + description: 'Number of user discussions in the issue', + resolver: Resolvers::UserDiscussionsCountResolver 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, @@ -119,26 +121,6 @@ module Types field :moved_to, Types::IssueType, null: true, description: 'Updated Issue after it got moved to another project' - def user_notes_count - BatchLoader::GraphQL.for(object.id).batch(key: :issue_user_notes_count) do |ids, loader, args| - counts = Note.count_for_collection(ids, 'Issue').index_by(&:noteable_id) - - ids.each do |id| - loader.call(id, counts[id]&.count || 0) - end - end - end - - def user_discussions_count - BatchLoader::GraphQL.for(object.id).batch(key: :issue_user_discussions_count) do |ids, loader, args| - counts = Note.count_for_collection(ids, 'Issue', 'COUNT(DISTINCT discussion_id) as count').index_by(&:noteable_id) - - ids.each do |id| - loader.call(id, counts[id]&.count || 0) - end - end - end - def author Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find end diff --git a/app/graphql/types/jira_import_type.rb b/app/graphql/types/jira_import_type.rb index cf58a53b40d..b3854487cec 100644 --- a/app/graphql/types/jira_import_type.rb +++ b/app/graphql/types/jira_import_type.rb @@ -2,8 +2,7 @@ module Types # rubocop: disable Graphql/AuthorizeTypes - # Authorization is at project level for owners or admins, - # so it is added directly to the Resolvers::JiraImportsResolver + # Authorization is at project level for owners or admins class JiraImportType < BaseObject graphql_name 'JiraImport' diff --git a/app/graphql/types/jira_users_mapping_input_type.rb b/app/graphql/types/jira_users_mapping_input_type.rb index 61cf1474493..d5b4b2f618a 100644 --- a/app/graphql/types/jira_users_mapping_input_type.rb +++ b/app/graphql/types/jira_users_mapping_input_type.rb @@ -8,7 +8,7 @@ module Types argument :jira_account_id, GraphQL::STRING_TYPE, required: true, - description: 'Jira account id of the user' + description: 'Jira account ID of the user' argument :gitlab_id, GraphQL::INT_TYPE, required: false, diff --git a/app/graphql/types/merge_request_connection_type.rb b/app/graphql/types/merge_request_connection_type.rb new file mode 100644 index 00000000000..da06bb86929 --- /dev/null +++ b/app/graphql/types/merge_request_connection_type.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + # rubocop: disable Graphql/AuthorizeTypes + class MergeRequestConnectionType < Types::CountableConnectionType + field :total_time_to_merge, GraphQL::FLOAT_TYPE, null: true, + description: 'Total sum of time to merge, in seconds, for the collection of merge requests' + + # rubocop: disable CodeReuse/ActiveRecord + def total_time_to_merge + object.items.reorder(nil).total_time_to_merge + end + # rubocop: enable CodeReuse/ActiveRecord + end +end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index e68d6706c43..816160e58f7 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -4,7 +4,7 @@ module Types class MergeRequestType < BaseObject graphql_name 'MergeRequest' - connection_type_class(Types::CountableConnectionType) + connection_type_class(Types::MergeRequestConnectionType) implements(Types::Notes::NoteableType) implements(Types::CurrentUserTodos) @@ -49,6 +49,8 @@ module Types description: 'ID of the merge request target project' field :source_branch, GraphQL::STRING_TYPE, null: false, description: 'Source branch of the merge request' + field :source_branch_protected, GraphQL::BOOLEAN_TYPE, null: false, calls_gitaly: true, + description: 'Indicates if the source branch is protected' 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, @@ -67,9 +69,11 @@ module Types 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' + description: 'User notes count of the merge request', + resolver: Resolvers::UserNotesCountResolver field :user_discussions_count, GraphQL::INT_TYPE, null: true, - description: 'Number of user discussions in the merge request' + description: 'Number of user discussions in the merge request', + resolver: Resolvers::UserDiscussionsCountResolver 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, @@ -90,6 +94,8 @@ module Types description: 'Indicates if there is a rebase currently in progress for the merge request' field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true, description: 'Default merge commit message of the merge request' + field :default_merge_commit_message_with_description, GraphQL::STRING_TYPE, null: true, + description: 'Default merge commit message of the merge request with description' 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, @@ -113,7 +119,7 @@ module Types description: 'The pipeline running on the branch HEAD of the merge request' field :pipelines, null: true, - description: 'Pipelines for the merge request', + description: 'Pipelines for the merge request. Note: for performance reasons, no more than the most recent 500 pipelines will be returned.', resolver: Resolvers::MergeRequestPipelinesResolver field :milestone, Types::MilestoneType, null: true, @@ -130,8 +136,7 @@ module Types 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 } + null: false field :time_estimate, GraphQL::INT_TYPE, null: false, description: 'Time estimate of the merge request' field :total_time_spent, GraphQL::INT_TYPE, null: false, @@ -152,6 +157,18 @@ module Types field :approved_by, Types::UserType.connection_type, null: true, description: 'Users who approved the merge request' + field :squash_on_merge, GraphQL::BOOLEAN_TYPE, null: false, method: :squash_on_merge?, + description: 'Indicates if squash on merge is enabled' + field :available_auto_merge_strategies, [GraphQL::STRING_TYPE], null: true, calls_gitaly: true, + description: 'Array of available auto merge strategies' + field :has_ci, GraphQL::BOOLEAN_TYPE, null: false, method: :has_ci?, + description: 'Indicates if the merge request has CI' + field :mergeable, GraphQL::BOOLEAN_TYPE, null: false, method: :mergeable?, calls_gitaly: true, + description: 'Indicates if the merge request is mergeable' + 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::BOOLEAN_TYPE, null: true, + description: 'Indicates if the merge request is created by @GitLab-Security-Bot.' def approved_by object.approved_by_users @@ -194,6 +211,31 @@ module Types def commit_count object&.metrics&.commits_count end + + def source_branch_protected + object.source_project.present? && ProtectedBranch.protected?(object.source_project, object.source_branch) + end + + def discussion_locked + !!object.discussion_locked + end + + def default_merge_commit_message_with_description + object.default_merge_commit_message(include_description: true) + end + + def available_auto_merge_strategies + AutoMergeService.new(object.project, current_user).available_strategies(object) + end + + def commits_without_merge_commits + object.recent_commits.without_merge_commits + end + + def security_auto_fix + object.author == User.security_bot + end end end + Types::MergeRequestType.prepend_if_ee('::EE::Types::MergeRequestType') diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 75ccac6d590..9eea81c9d3e 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -31,6 +31,7 @@ module Types mount_mutation Mutations::Commits::Create, calls_gitaly: true mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji mount_mutation Mutations::Discussions::ToggleResolve + mount_mutation Mutations::Environments::CanaryIngress::Update mount_mutation Mutations::Issues::Create mount_mutation Mutations::Issues::SetAssignees mount_mutation Mutations::Issues::SetConfidential @@ -65,6 +66,8 @@ module Types mount_mutation Mutations::Notes::RepositionImageDiffNote mount_mutation Mutations::Notes::Destroy mount_mutation Mutations::Releases::Create + mount_mutation Mutations::Releases::Update + mount_mutation Mutations::Releases::Delete mount_mutation Mutations::Terraform::State::Delete mount_mutation Mutations::Terraform::State::Lock mount_mutation Mutations::Terraform::State::Unlock @@ -84,6 +87,7 @@ module Types mount_mutation Mutations::DesignManagement::Move mount_mutation Mutations::ContainerExpirationPolicies::Update mount_mutation Mutations::ContainerRepositories::Destroy + mount_mutation Mutations::ContainerRepositories::DestroyTags mount_mutation Mutations::Ci::PipelineCancel mount_mutation Mutations::Ci::PipelineDestroy mount_mutation Mutations::Ci::PipelineRetry diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb index fbdf049b755..4dec6f4c5e6 100644 --- a/app/graphql/types/namespace_type.rb +++ b/app/graphql/types/namespace_type.rb @@ -21,6 +21,7 @@ module Types 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, description: 'Visibility of the namespace' field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true, method: :lfs_enabled?, @@ -30,12 +31,15 @@ module Types field :root_storage_statistics, Types::RootStorageStatisticsType, null: true, - description: 'Aggregated storage statistics of the namespace. Only available for root namespaces', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(obj.id).find } + description: 'Aggregated storage statistics of the namespace. Only available for root namespaces' field :projects, Types::ProjectType.connection_type, null: false, description: 'Projects within this namespace', resolver: ::Resolvers::NamespaceProjectsResolver + + def root_storage_statistics + Gitlab::Graphql::Loaders::BatchRootStorageStatisticsLoader.new(object.id).find + end end end diff --git a/app/graphql/types/notes/diff_position_type.rb b/app/graphql/types/notes/diff_position_type.rb index cc00feba2e6..13d9be49484 100644 --- a/app/graphql/types/notes/diff_position_type.rb +++ b/app/graphql/types/notes/diff_position_type.rb @@ -21,25 +21,43 @@ module Types # Fields for text positions field :old_line, GraphQL::INT_TYPE, null: true, - description: 'Line on start SHA that was changed', - resolve: -> (position, _args, _ctx) { position.old_line if position.on_text? } + description: 'Line on start SHA that was changed' field :new_line, GraphQL::INT_TYPE, null: true, - description: 'Line on HEAD SHA that was changed', - resolve: -> (position, _args, _ctx) { position.new_line if position.on_text? } + description: 'Line on HEAD SHA that was changed' # Fields for image positions field :x, GraphQL::INT_TYPE, null: true, - description: 'X position of the note', - resolve: -> (position, _args, _ctx) { position.x if position.on_image? } + description: 'X position of the note' field :y, GraphQL::INT_TYPE, null: true, - description: 'Y position of the note', - resolve: -> (position, _args, _ctx) { position.y if position.on_image? } + description: 'Y position of the note' field :width, GraphQL::INT_TYPE, null: true, - description: 'Total width of the image', - resolve: -> (position, _args, _ctx) { position.width if position.on_image? } + description: 'Total width of the image' field :height, GraphQL::INT_TYPE, null: true, - description: 'Total height of the image', - resolve: -> (position, _args, _ctx) { position.height if position.on_image? } + description: 'Total height of the image' + + def old_line + object.old_line if object.on_text? + end + + def new_line + object.new_line if object.on_text? + end + + def x + object.x if object.on_image? + end + + def y + object.y if object.on_image? + end + + def width + object.width if object.on_image? + end + + def height + object.height if object.on_image? + end end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index 5d41f0032bd..f4e05e19eca 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -16,13 +16,11 @@ module Types field :project, Types::ProjectType, null: true, - description: 'Project associated with the note', - resolve: -> (note, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, note.project_id).find } + description: 'Project associated with the note' field :author, Types::UserType, null: false, - description: 'User who wrote this note', - resolve: -> (note, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, note.author_id).find } + description: 'User who wrote this note' field :system, GraphQL::BOOLEAN_TYPE, null: false, @@ -52,6 +50,14 @@ module Types def system_note_icon_name SystemNoteHelper.system_note_icon_name(object) if object.system? end + + def project + Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find + end + + def author + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find + end end end end diff --git a/app/graphql/types/permission_types/merge_request.rb b/app/graphql/types/permission_types/merge_request.rb index e9c89b0c92e..52c11fe5588 100644 --- a/app/graphql/types/permission_types/merge_request.rb +++ b/app/graphql/types/permission_types/merge_request.rb @@ -19,7 +19,9 @@ module Types permission_field field_name, method: :"can_#{field_name}?", calls_gitaly: true end - permission_field :can_merge, calls_gitaly: true, resolve: -> (object, args, context) do + permission_field :can_merge, calls_gitaly: true + + def can_merge object.can_be_merged_by?(context[:current_user]) end end diff --git a/app/graphql/types/project_member_relation_enum.rb b/app/graphql/types/project_member_relation_enum.rb new file mode 100644 index 00000000000..fbad23b956f --- /dev/null +++ b/app/graphql/types/project_member_relation_enum.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class ProjectMemberRelationEnum < BaseEnum + graphql_name 'ProjectMemberRelation' + description 'Project member relation' + + ::MembersFinder::RELATIONS.each do |member_relation| + value member_relation.to_s.upcase, value: member_relation, description: "#{member_relation.to_s.titleize} members" + end + end +end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index 5a436886117..a7d9548610e 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -67,33 +67,25 @@ module Types description: 'E-mail address of the service desk.' 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 + description: 'URL to avatar image file of the project' %i[issues merge_requests wiki snippets].each do |feature| field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true, - description: "Indicates if #{feature.to_s.titleize.pluralize} are enabled for the current user", - resolve: -> (project, args, ctx) do - project.feature_available?(feature, ctx[:current_user]) - end + description: "Indicates if #{feature.to_s.titleize.pluralize} are enabled for the current user" + + define_method "#{feature}_enabled" do + object.feature_available?(feature, context[:current_user]) + end end field :jobs_enabled, GraphQL::BOOLEAN_TYPE, null: true, - description: 'Indicates if CI/CD pipeline jobs are enabled for the current user', - resolve: -> (project, args, ctx) do - project.feature_available?(:builds, ctx[:current_user]) - end + description: 'Indicates if CI/CD pipeline jobs are enabled for the current user' 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 + description: 'Number of open issues for the project' field :import_status, GraphQL::STRING_TYPE, null: true, description: 'Status of import background job of the project' @@ -115,6 +107,8 @@ module Types description: 'Indicates if issues referenced by merge requests and commits within the default branch are closed automatically' field :suggestion_commit_message, GraphQL::STRING_TYPE, null: true, description: 'The commit message used to apply merge request suggestions' + field :squash_read_only, GraphQL::BOOLEAN_TYPE, null: false, method: :squash_readonly?, + description: 'Indicates if squash readonly is enabled' field :namespace, Types::NamespaceType, null: true, description: 'Namespace of the project' @@ -123,8 +117,7 @@ module Types field :statistics, Types::ProjectStatisticsType, null: true, - description: 'Statistics of the project', - resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find } + description: 'Statistics of the project' field :repository, Types::RepositoryType, null: true, description: 'Git repository of the project' @@ -198,6 +191,11 @@ module Types description: 'Build pipeline of the project', resolver: Resolvers::ProjectPipelineResolver + field :ci_cd_settings, + Types::Ci::CiCdSettingType, + null: true, + description: 'CI/CD settings for the project' + field :sentry_detailed_error, Types::ErrorTracking::SentryDetailedErrorType, null: true, @@ -238,8 +236,7 @@ module Types field :jira_imports, Types::JiraImportType.connection_type, null: true, - description: 'Jira imports into the project', - resolver: Resolvers::Projects::JiraImportsResolver + description: 'Jira imports into the project' field :services, Types::Projects::ServiceType.connection_type, @@ -296,6 +293,9 @@ module Types description: 'Container repositories of the project', resolver: Resolvers::ContainerRepositoriesResolver + field :container_repositories_count, GraphQL::INT_TYPE, null: false, + description: 'Number of container repositories in the project' + field :label, Types::LabelType, null: true, @@ -311,6 +311,13 @@ module Types description: 'Terraform states associated with the project', resolver: Resolvers::Terraform::StatesResolver + field :pipeline_analytics, Types::Ci::AnalyticsType, null: true, + description: 'Pipeline analytics', + resolver: Resolvers::ProjectPipelineStatisticsResolver + + field :total_pipeline_duration, GraphQL::INT_TYPE, null: true, + description: 'Total pipeline duration for all of the pipelines in a project' + def label(title:) BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args| LabelsFinder @@ -335,6 +342,30 @@ module Types .execute end + def avatar_url + object.avatar_url(only_path: false) + end + + def jobs_enabled + object.feature_available?(:builds, context[:current_user]) + end + + def open_issues_count + object.open_issues_count if object.feature_available?(:issues, context[:current_user]) + end + + def statistics + Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(object.id).find + end + + def container_repositories_count + project.container_repositories.size + end + + def total_pipeline_duration + object.all_pipelines.total_duration + end + private def project diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index d194b0979b3..05bb371088c 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -24,7 +24,6 @@ module Types field :current_user, Types::UserType, null: true, - resolve: -> (_obj, _args, context) { context[:current_user] }, description: "Get information about current user" field :namespace, Types::NamespaceType, @@ -92,6 +91,11 @@ module Types description: 'Get runner setup instructions', resolver: Resolvers::Ci::RunnerSetupResolver + field :ci_config, Types::Ci::Config::ConfigType, null: true, + description: 'Get linted and processed contents of a CI config. Should not be requested more than once per request.', + resolver: Resolvers::Ci::ConfigResolver, + complexity: 126 # AUTHENTICATED_COMPLEXITY / 2 + 1 + def design_management DesignManagementObject.new(nil) end @@ -116,6 +120,10 @@ module Types id = ::Types::GlobalIDType[::ContainerRepository].coerce_isolated_input(id) GitlabSchema.find_by_gid(id) end + + def current_user + context[:current_user] + end end end diff --git a/app/graphql/types/snippets/blob_viewer_type.rb b/app/graphql/types/snippets/blob_viewer_type.rb index 50d0b0522d6..a2ffa144066 100644 --- a/app/graphql/types/snippets/blob_viewer_type.rb +++ b/app/graphql/types/snippets/blob_viewer_type.rb @@ -17,14 +17,12 @@ module Types field :collapsed, GraphQL::BOOLEAN_TYPE, description: 'Shows whether the blob should be displayed collapsed', method: :collapsed?, - null: false, - resolve: -> (viewer, _args, _ctx) { !!viewer&.collapsed? } + null: false field :too_large, GraphQL::BOOLEAN_TYPE, description: 'Shows whether the blob too large to be displayed', method: :too_large?, - null: false, - resolve: -> (viewer, _args, _ctx) { !!viewer&.too_large? } + null: false field :render_error, GraphQL::STRING_TYPE, description: 'Error rendering the blob content', @@ -38,6 +36,14 @@ module Types field :loading_partial_name, GraphQL::STRING_TYPE, description: 'Loading partial name', null: false + + def collapsed + !!object&.collapsed? + end + + def too_large + !!object&.too_large? + end end end end diff --git a/app/graphql/types/sort_enum.rb b/app/graphql/types/sort_enum.rb index d0a6eecb672..c3a76330fe9 100644 --- a/app/graphql/types/sort_enum.rb +++ b/app/graphql/types/sort_enum.rb @@ -7,10 +7,10 @@ module Types # Deprecated, as we prefer uppercase enums # https://gitlab.com/groups/gitlab-org/-/epics/1838 - value 'updated_desc', 'Updated at descending order', deprecated: { reason: 'Use UPDATED_DESC', milestone: '13.5' } - value 'updated_asc', 'Updated at ascending order', deprecated: { reason: 'Use UPDATED_ASC', milestone: '13.5' } - value 'created_desc', 'Created at descending order', deprecated: { reason: 'Use CREATED_DESC', milestone: '13.5' } - value 'created_asc', 'Created at ascending order', deprecated: { reason: 'Use CREATED_ASC', milestone: '13.5' } + value 'updated_desc', 'Updated at descending order', value: :updated_desc, deprecated: { reason: 'Use UPDATED_DESC', milestone: '13.5' } + value 'updated_asc', 'Updated at ascending order', value: :updated_asc, deprecated: { reason: 'Use UPDATED_ASC', milestone: '13.5' } + value 'created_desc', 'Created at descending order', value: :created_desc, deprecated: { reason: 'Use CREATED_DESC', milestone: '13.5' } + value 'created_asc', 'Created at ascending order', value: :created_asc, deprecated: { reason: 'Use CREATED_ASC', milestone: '13.5' } value 'UPDATED_DESC', 'Updated at descending order', value: :updated_desc value 'UPDATED_ASC', 'Updated at ascending order', value: :updated_asc diff --git a/app/graphql/types/terraform/state_type.rb b/app/graphql/types/terraform/state_type.rb index 05b6d130f19..d97e673bf31 100644 --- a/app/graphql/types/terraform/state_type.rb +++ b/app/graphql/types/terraform/state_type.rb @@ -19,9 +19,7 @@ module Types field :locked_by_user, Types::UserType, null: true, - authorize: :read_user, - description: 'The user currently holding a lock on the Terraform state', - resolve: -> (state, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, state.locked_by_user_id).find } + description: 'The user currently holding a lock on the Terraform state' field :locked_at, Types::TimeType, null: true, @@ -39,6 +37,10 @@ module Types field :updated_at, Types::TimeType, null: false, description: 'Timestamp the Terraform state was updated' + + def locked_by_user + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.locked_by_user_id).find + end end end end diff --git a/app/graphql/types/terraform/state_version_type.rb b/app/graphql/types/terraform/state_version_type.rb index b1fbe42ecaf..a3af5c876ca 100644 --- a/app/graphql/types/terraform/state_version_type.rb +++ b/app/graphql/types/terraform/state_version_type.rb @@ -3,6 +3,8 @@ module Types module Terraform class StateVersionType < BaseObject + include ::API::Helpers::RelatedResourcesHelpers + graphql_name 'TerraformStateVersion' authorize :read_terraform_state @@ -13,15 +15,20 @@ module Types field :created_by_user, Types::UserType, null: true, - authorize: :read_user, - description: 'The user that created this version', - resolve: -> (version, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, version.created_by_user_id).find } + description: 'The user that created this version' + + field :download_path, GraphQL::STRING_TYPE, + null: true, + description: "URL for downloading the version's JSON file" field :job, Types::Ci::JobType, null: true, - authorize: :read_build, - description: 'The job that created this version', - resolve: -> (version, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Build, version.ci_build_id).find } + description: 'The job that created this version' + + field :serial, GraphQL::INT_TYPE, + null: true, + description: 'Serial number of the version', + method: :version field :created_at, Types::TimeType, null: false, @@ -30,6 +37,22 @@ module Types field :updated_at, Types::TimeType, null: false, description: 'Timestamp the version was updated' + + def created_by_user + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.created_by_user_id).find + end + + def download_path + expose_path api_v4_projects_terraform_state_versions_path( + id: object.project_id, + name: object.terraform_state.name, + serial: object.version + ) + end + + def job + Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Build, object.ci_build_id).find + end end end end diff --git a/app/graphql/types/todo_type.rb b/app/graphql/types/todo_type.rb index 4f21da3d897..3694980ef93 100644 --- a/app/graphql/types/todo_type.rb +++ b/app/graphql/types/todo_type.rb @@ -16,19 +16,16 @@ module Types field :project, Types::ProjectType, description: 'The project this todo is associated with', null: true, - authorize: :read_project, - resolve: -> (todo, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, todo.project_id).find } + authorize: :read_project field :group, Types::GroupType, description: 'Group this todo is associated with', null: true, - authorize: :read_group, - resolve: -> (todo, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, todo.group_id).find } + authorize: :read_group field :author, Types::UserType, description: 'The author of this todo', - null: false, - resolve: -> (todo, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, todo.author_id).find } + null: false field :action, Types::TodoActionEnum, description: 'Action of the todo', @@ -50,5 +47,17 @@ module Types field :created_at, Types::TimeType, description: 'Timestamp this todo was created', null: false + + def project + Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find + end + + def group + Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, object.group_id).find + end + + def author + Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find + end end end diff --git a/app/graphql/types/tree/blob_type.rb b/app/graphql/types/tree/blob_type.rb index cc6bf7b4f00..a7b90d2533b 100644 --- a/app/graphql/types/tree/blob_type.rb +++ b/app/graphql/types/tree/blob_type.rb @@ -15,13 +15,14 @@ module Types field :web_path, GraphQL::STRING_TYPE, null: true, description: 'Web path of the blob' field :lfs_oid, GraphQL::STRING_TYPE, null: true, - description: 'LFS ID of the blob', - resolve: -> (blob, args, ctx) do - Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(blob.repository, blob.id).find - end + description: 'LFS ID of the blob' field :mode, GraphQL::STRING_TYPE, null: true, description: 'Blob mode in numeric format' - # rubocop: enable Graphql/AuthorizeTypes + + def lfs_oid + Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(object.repository, object.id).find + end end + # rubocop: enable Graphql/AuthorizeTypes end end diff --git a/app/graphql/types/tree/tree_type.rb b/app/graphql/types/tree/tree_type.rb index b9fb6b28e71..fecd6c0f309 100644 --- a/app/graphql/types/tree/tree_type.rb +++ b/app/graphql/types/tree/tree_type.rb @@ -8,27 +8,32 @@ module Types # Complexity 10 as it triggers a Gitaly call on each render field :last_commit, Types::CommitType, - null: true, complexity: 10, calls_gitaly: true, resolver: Resolvers::LastCommitResolver, - description: 'Last commit for the tree' + null: true, complexity: 10, calls_gitaly: true, resolver: Resolvers::LastCommitResolver, + description: 'Last commit for the tree' field :trees, Types::Tree::TreeEntryType.connection_type, null: false, - description: 'Trees of the tree', - resolve: -> (obj, args, ctx) do - Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository) - end + description: 'Trees of the tree' field :submodules, Types::Tree::SubmoduleType.connection_type, null: false, description: 'Sub-modules of the tree', - calls_gitaly: true, resolve: -> (obj, args, ctx) do - Gitlab::Graphql::Representation::SubmoduleTreeEntry.decorate(obj.submodules, obj) - end + calls_gitaly: true field :blobs, Types::Tree::BlobType.connection_type, null: false, description: 'Blobs of the tree', - calls_gitaly: true, resolve: -> (obj, args, ctx) do - Gitlab::Graphql::Representation::TreeEntry.decorate(obj.blobs, obj.repository) - end - # rubocop: enable Graphql/AuthorizeTypes + calls_gitaly: true + + def trees + Gitlab::Graphql::Representation::TreeEntry.decorate(object.trees, object.repository) + end + + def submodules + Gitlab::Graphql::Representation::SubmoduleTreeEntry.decorate(object.submodules, object) + end + + def blobs + Gitlab::Graphql::Representation::TreeEntry.decorate(object.blobs, object.repository) + end end + # rubocop: enable Graphql/AuthorizeTypes end end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index 783a0d8425a..93503268319 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -19,7 +19,10 @@ module Types field :state, Types::UserStateEnum, null: false, description: 'State of the user' field :email, GraphQL::STRING_TYPE, null: true, - description: 'User email', method: :public_email + description: 'User email', method: :public_email, + deprecated: { reason: 'Use public_email', milestone: '13.7' } + field :public_email, GraphQL::STRING_TYPE, null: true, + description: "User's public email" field :avatar_url, GraphQL::STRING_TYPE, null: true, description: "URL of the user's avatar" field :web_url, GraphQL::STRING_TYPE, null: false, @@ -37,19 +40,24 @@ module Types feature_flag: :user_group_counts field :status, Types::UserStatusType, null: true, description: 'User status' + field :location, ::GraphQL::STRING_TYPE, null: true, + description: 'The location of the user.' field :project_memberships, Types::ProjectMemberType.connection_type, null: true, description: 'Project memberships of the user' field :starred_projects, Types::ProjectType.connection_type, null: true, description: 'Projects starred by the user', resolver: Resolvers::UserStarredProjectsResolver - # Merge request field: MRs can be either authored or assigned: + # Merge request field: MRs can be authored, assigned, or assigned-for-review: field :authored_merge_requests, resolver: Resolvers::AuthoredMergeRequestsResolver, description: 'Merge Requests authored by the user' field :assigned_merge_requests, resolver: Resolvers::AssignedMergeRequestsResolver, description: 'Merge Requests assigned to the user' + field :review_requested_merge_requests, + resolver: Resolvers::ReviewRequestedMergeRequestsResolver, + description: 'Merge Requests assigned to the user for review' field :snippets, Types::SnippetType.connection_type, |