diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 16:49:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 16:49:51 +0300 |
commit | 71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch) | |
tree | 6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /app/graphql/types | |
parent | a7253423e3403b8c08f8a161e5937e1488f5f407 (diff) |
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'app/graphql/types')
44 files changed, 429 insertions, 109 deletions
diff --git a/app/graphql/types/achievements/achievement_type.rb b/app/graphql/types/achievements/achievement_type.rb index e2b9495c83d..67cc9778797 100644 --- a/app/graphql/types/achievements/achievement_type.rb +++ b/app/graphql/types/achievements/achievement_type.rb @@ -32,11 +32,6 @@ module Types null: true, description: 'Description or notes for the achievement.' - field :revokeable, - GraphQL::Types::Boolean, - null: false, - description: 'Revokeability of the achievement.' - field :created_at, Types::TimeType, null: false, diff --git a/app/graphql/types/base_argument.rb b/app/graphql/types/base_argument.rb index 4086015dad6..d2bc1d55408 100644 --- a/app/graphql/types/base_argument.rb +++ b/app/graphql/types/base_argument.rb @@ -2,7 +2,7 @@ module Types class BaseArgument < GraphQL::Schema::Argument - include GitlabStyleDeprecations + include Gitlab::Graphql::Deprecations attr_reader :doc_reference diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb index 11877b79e59..45e78b330fb 100644 --- a/app/graphql/types/base_enum.rb +++ b/app/graphql/types/base_enum.rb @@ -4,7 +4,7 @@ module Types class BaseEnum < GraphQL::Schema::Enum class CustomValue < GraphQL::Schema::EnumValue - include ::GitlabStyleDeprecations + include Gitlab::Graphql::Deprecations def initialize(name, desc = nil, **kwargs) init_gitlab_deprecation(kwargs) diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb index 615c143a0b9..caeb81c95cb 100644 --- a/app/graphql/types/base_field.rb +++ b/app/graphql/types/base_field.rb @@ -2,7 +2,7 @@ module Types class BaseField < GraphQL::Schema::Field - include GitlabStyleDeprecations + include Gitlab::Graphql::Deprecations argument_class ::Types::BaseArgument diff --git a/app/graphql/types/ci/ci_cd_setting_type.rb b/app/graphql/types/ci/ci_cd_setting_type.rb index 574791b79e6..dd6647b749d 100644 --- a/app/graphql/types/ci/ci_cd_setting_type.rb +++ b/app/graphql/types/ci/ci_cd_setting_type.rb @@ -30,6 +30,11 @@ module Types field :merge_trains_enabled, GraphQL::Types::Boolean, null: true, description: 'Whether merge trains are enabled.', method: :merge_trains_enabled? + field :opt_in_jwt, + GraphQL::Types::Boolean, + null: true, + description: 'When disabled, the JSON Web Token is always available in all jobs in the pipeline.', + method: :opt_in_jwt? field :project, Types::ProjectType, null: true, description: 'Project the CI/CD settings belong to.' end diff --git a/app/graphql/types/ci/code_quality_report_summary_type.rb b/app/graphql/types/ci/code_quality_report_summary_type.rb new file mode 100644 index 00000000000..0d560d9e9e8 --- /dev/null +++ b/app/graphql/types/ci/code_quality_report_summary_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Types + module Ci + # rubocop: disable Graphql/AuthorizeTypes + # This is presented through `PipelineType` that has its own authorization + class CodeQualityReportSummaryType < BaseObject + graphql_name 'CodeQualityReportSummary' + description 'Code Quality report for a pipeline' + + field :count, GraphQL::Types::Int, null: true, + description: 'Total number of Code Quality reports.' + ::Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.each_key do |status| + field status, GraphQL::Types::Int, null: true, + description: "Total number of #{status} status." + end + end + # rubocop: enable Graphql/AuthorizeTypes + end +end diff --git a/app/graphql/types/ci/job_token_scope/direction_enum.rb b/app/graphql/types/ci/job_token_scope/direction_enum.rb new file mode 100644 index 00000000000..f52cf891af8 --- /dev/null +++ b/app/graphql/types/ci/job_token_scope/direction_enum.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Types + module Ci + module JobTokenScope + class DirectionEnum < BaseEnum + graphql_name 'CiJobTokenScopeDirection' + description 'Direction of access.' + + value 'OUTBOUND', + value: :outbound, + description: 'Job token scope project can access target project in the outbound allowlist.' + + value 'INBOUND', + value: :inbound, + description: 'Target projects in the inbound allowlist can access the scope project ' \ + 'through their job tokens.' + end + end + end +end diff --git a/app/graphql/types/ci/job_token_scope_type.rb b/app/graphql/types/ci/job_token_scope_type.rb index 37c0af944a7..639bbaa22af 100644 --- a/app/graphql/types/ci/job_token_scope_type.rb +++ b/app/graphql/types/ci/job_token_scope_type.rb @@ -11,7 +11,23 @@ module Types Types::ProjectType.connection_type, null: false, description: 'Allow list of projects that can be accessed by CI Job tokens created by this project.', - method: :all_projects + method: :outbound_projects, + deprecated: { + reason: 'The `projects` attribute is being deprecated. Use `outbound_allowlist`', + milestone: '15.9' + } + + field :outbound_allowlist, + Types::ProjectType.connection_type, + null: false, + description: "Allow list of projects that are accessible using the current project's CI Job tokens.", + method: :outbound_projects + + field :inbound_allowlist, + Types::ProjectType.connection_type, + null: false, + description: "Allow list of projects that can access the current project through its CI Job tokens.", + method: :inbound_projects end end # rubocop: enable Graphql/AuthorizeTypes diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index 4447a10a74e..a97e9cee4b1 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -37,6 +37,8 @@ module Types # Life-cycle timestamps: field :created_at, Types::TimeType, null: false, description: "When the job was created." + field :erased_at, Types::TimeType, null: true, + description: "When the job was erased." field :finished_at, Types::TimeType, null: true, description: 'When a job has finished running.' field :queued_at, Types::TimeType, null: true, @@ -97,6 +99,8 @@ module Types field :web_path, GraphQL::Types::String, null: true, description: 'Web path of the job.' + field :project, Types::ProjectType, null: true, description: 'Project that the job belongs to.' + def kind return ::Ci::Build unless [::Ci::Build, ::Ci::Bridge].include?(object.class) diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index cb561f48b3b..19d261853a7 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -178,6 +178,10 @@ module Types field :merge_request_event_type, Types::Ci::PipelineMergeRequestEventTypeEnum, null: true, description: "Event type of the pipeline associated with a merge request." + def commit + BatchLoader::GraphQL.wrap(object.commit) + end + def detailed_status object.detailed_status(current_user) end diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index 35339624e37..10d18f9ad2a 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -14,6 +14,9 @@ module Types JOB_COUNT_LIMIT = 1000 + # Only allow ephemeral_authentication_token to be visible for a short while + RUNNER_EPHEMERAL_TOKEN_AVAILABILITY_TIME = 3.hours + alias_method :runner, :object field :access_level, ::Types::Ci::RunnerAccessLevelEnum, null: false, @@ -35,6 +38,10 @@ module Types description: 'Description of the runner.' field :edit_admin_url, GraphQL::Types::String, null: true, description: 'Admin form URL of the runner. Only available for administrators.' + field :ephemeral_authentication_token, GraphQL::Types::String, null: true, + description: 'Ephemeral authentication token used for runner machine registration.', + authorize: :read_ephemeral_token, + alpha: { milestone: '15.9' } field :executor_name, GraphQL::Types::String, null: true, description: 'Executor last advertised by the runner.', method: :executor_name @@ -134,6 +141,14 @@ module Types Gitlab::Routing.url_helpers.edit_admin_runner_url(runner) if can_admin_runners? end + def ephemeral_authentication_token + return unless runner.authenticated_user_registration_type? + return unless runner.created_at > RUNNER_EPHEMERAL_TOKEN_AVAILABILITY_TIME.ago + return if runner.runner_machines.any? + + runner.token + end + def project_count BatchLoader::GraphQL.for(runner.id).batch(key: :runner_project_count) do |ids, loader, args| counts = ::Ci::Runner.project_type diff --git a/app/graphql/types/ci/runner_upgrade_status_enum.rb b/app/graphql/types/ci/runner_upgrade_status_enum.rb index 34a931c8f79..668970aaff2 100644 --- a/app/graphql/types/ci/runner_upgrade_status_enum.rb +++ b/app/graphql/types/ci/runner_upgrade_status_enum.rb @@ -5,13 +5,13 @@ module Types class RunnerUpgradeStatusEnum < BaseEnum graphql_name 'CiRunnerUpgradeStatus' + MODEL_STATUS_TO_GRAPHQL_TRANSLATIONS = { + invalid_version: :invalid, + unavailable: :not_available + }.freeze + ::Ci::RunnerVersion::STATUS_DESCRIPTIONS.each do |status, description| - status_name_src = - if status == :invalid_version - :invalid - else - status - end + status_name_src = MODEL_STATUS_TO_GRAPHQL_TRANSLATIONS.fetch(status, status) value status_name_src.to_s.upcase, description: description, value: status end diff --git a/app/graphql/types/ci/variable_sort_enum.rb b/app/graphql/types/ci/variable_sort_enum.rb new file mode 100644 index 00000000000..3a60899ab5d --- /dev/null +++ b/app/graphql/types/ci/variable_sort_enum.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module Ci + class VariableSortEnum < BaseEnum + graphql_name 'CiVariableSort' + description 'Values for sorting variables' + + value 'KEY_ASC', 'Sorted by key in ascending order.', value: :key_asc + value 'KEY_DESC', 'Sorted by key in descending order.', value: :key_desc + end + end +end diff --git a/app/graphql/types/concerns/gitlab_style_deprecations.rb b/app/graphql/types/concerns/gitlab_style_deprecations.rb deleted file mode 100644 index 859a27cac4c..00000000000 --- a/app/graphql/types/concerns/gitlab_style_deprecations.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -# Concern for handling GraphQL deprecations. -# https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-schema-items -module GitlabStyleDeprecations - extend ActiveSupport::Concern - - included do - attr_accessor :deprecation - end - - def visible?(ctx) - super && ctx[:remove_deprecated] == true ? deprecation.nil? : true - end - - private - - # Set deprecation, mutate the arguments - def init_gitlab_deprecation(kwargs) - if kwargs[:deprecation_reason].present? - raise ArgumentError, 'Use `deprecated` property instead of `deprecation_reason`. ' \ - 'See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-schema-items' - end - - # GitLab allows items to be marked as "alpha", which leverages GraphQL deprecations. - deprecation_args = kwargs.extract!(:alpha, :deprecated) - - self.deprecation = ::Gitlab::Graphql::Deprecation.parse(**deprecation_args) - return unless deprecation - - raise ArgumentError, "Bad deprecation. #{deprecation.errors.full_messages.to_sentence}" unless deprecation.valid? - - kwargs[:deprecation_reason] = deprecation.deprecation_reason - kwargs[:description] = deprecation.edit_description(kwargs[:description]) - end -end diff --git a/app/graphql/types/data_transfer/base_type.rb b/app/graphql/types/data_transfer/base_type.rb new file mode 100644 index 00000000000..e077612bfd5 --- /dev/null +++ b/app/graphql/types/data_transfer/base_type.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Types + module DataTransfer + class BaseType < BaseObject + authorize + + field :egress_nodes, type: Types::DataTransfer::EgressNodeType.connection_type, + description: 'Data nodes.', + null: true # disallow null once data_transfer_monitoring feature flag is rolled-out! + end + end +end diff --git a/app/graphql/types/data_transfer/egress_node_type.rb b/app/graphql/types/data_transfer/egress_node_type.rb new file mode 100644 index 00000000000..a050540999f --- /dev/null +++ b/app/graphql/types/data_transfer/egress_node_type.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Types + module DataTransfer + class EgressNodeType < BaseObject + authorize + + field :date, GraphQL::Types::String, + description: 'First day of the node range. There is one node per month.', + null: false + + field :total_egress, GraphQL::Types::BigInt, + description: 'Total egress for that project in that period of time.', + null: false + + field :repository_egress, GraphQL::Types::BigInt, + description: 'Repository egress for that project in that period of time.', + null: false + + field :artifacts_egress, GraphQL::Types::BigInt, + description: 'Artifacts egress for that project in that period of time.', + null: false + + field :packages_egress, GraphQL::Types::BigInt, + description: 'Packages egress for that project in that period of time.', + null: false + + field :registry_egress, GraphQL::Types::BigInt, + description: 'Registery egress for that project in that period of time.', + null: false + + def total_egress + object.values.select { |x| x.is_a?(Integer) }.sum + end + end + end +end diff --git a/app/graphql/types/data_transfer/group_data_transfer_type.rb b/app/graphql/types/data_transfer/group_data_transfer_type.rb new file mode 100644 index 00000000000..a9a353e10e8 --- /dev/null +++ b/app/graphql/types/data_transfer/group_data_transfer_type.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Types + module DataTransfer + class GroupDataTransferType < BaseType + graphql_name 'GroupDataTransfer' + authorize + end + end +end diff --git a/app/graphql/types/data_transfer/project_data_transfer_type.rb b/app/graphql/types/data_transfer/project_data_transfer_type.rb new file mode 100644 index 00000000000..f385aa20a7e --- /dev/null +++ b/app/graphql/types/data_transfer/project_data_transfer_type.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Types + module DataTransfer + class ProjectDataTransferType < BaseType + graphql_name 'ProjectDataTransfer' + authorize + + field :total_egress, GraphQL::Types::BigInt, + description: 'Total egress for that project in that period of time.', + null: true # disallow null once data_transfer_monitoring feature flag is rolled-out! + + def total_egress(**_) + return unless Feature.enabled?(:data_transfer_monitoring) + + 40_000_000 + end + end + end +end diff --git a/app/graphql/types/deployment_type.rb b/app/graphql/types/deployment_type.rb index 1c23fd44ea1..6d895cc81cf 100644 --- a/app/graphql/types/deployment_type.rb +++ b/app/graphql/types/deployment_type.rb @@ -65,9 +65,9 @@ module Types field :tags, [Types::DeploymentTagType], description: 'Git tags that contain this deployment. ' \ - 'This field can only be resolved for one deployment in any single request.', + 'This field can only be resolved for two deployments in any single request.', calls_gitaly: true do - extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 2 end end end diff --git a/app/graphql/types/group_release_sort_enum.rb b/app/graphql/types/group_release_sort_enum.rb new file mode 100644 index 00000000000..7420e7a31ad --- /dev/null +++ b/app/graphql/types/group_release_sort_enum.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Types + # Not inheriting from Types::SortEnum since we only want + # to implement a subset of the sort values it defines. + class GroupReleaseSortEnum < BaseEnum + graphql_name 'GroupReleaseSort' + description 'Values for sorting releases belonging to a group' + + # Borrowed from Types::ReleaseSortEnum and Types::SortEnum + # These values/descriptions should stay in-sync as much as possible. + value 'RELEASED_AT_DESC', 'Released at by descending order.', value: :released_at_desc + value 'RELEASED_AT_ASC', 'Released at by ascending order.', value: :released_at_asc + end +end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index 4e5ddbac8a2..3543ac29c17 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -193,14 +193,14 @@ module Types null: true, description: 'List of descendant groups of this group.', complexity: 5, - resolver: Resolvers::GroupsResolver + resolver: Resolvers::NestedGroupsResolver field :ci_variables, Types::Ci::GroupVariableType.connection_type, null: true, description: "List of the group's CI/CD variables.", authorize: :admin_group, - method: :variables + resolver: Resolvers::Ci::VariablesResolver field :runners, Types::Ci::RunnerType.connection_type, null: true, @@ -233,6 +233,17 @@ module Types resolver: Resolvers::WorkItems::TypesResolver, description: 'Work item types available to the group.' + field :releases, + Types::ReleaseType.connection_type, + null: true, + description: 'Releases belonging to projects in the group.', + resolver: Resolvers::GroupReleasesResolver + + field :data_transfer, Types::DataTransfer::GroupDataTransferType, + null: true, + resolver: Resolvers::DataTransferResolver.group, + description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.' + def label(title:) BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args| LabelsFinder diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb index 4948063610a..1e5833a5cf0 100644 --- a/app/graphql/types/issue_type.rb +++ b/app/graphql/types/issue_type.rb @@ -54,19 +54,24 @@ module Types description: 'Indicates the issue is confidential.' field :discussion_locked, GraphQL::Types::Boolean, null: false, description: 'Indicates discussion is locked on the issue.' - field :due_date, Types::TimeType, null: true, - description: 'Due date of the issue.' - field :hidden, GraphQL::Types::Boolean, null: true, resolver_method: :hidden?, - description: 'Indicates the issue is hidden because the author has been banned. ' \ - 'Will always return `null` if `ban_user_feature_flag` feature flag is disabled.' - field :downvotes, GraphQL::Types::Int, null: false, description: 'Number of downvotes the issue has received.', resolver: Resolvers::DownVotesCountResolver + field :due_date, Types::TimeType, null: true, + description: 'Due date of the issue.' + field :hidden, GraphQL::Types::Boolean, null: true, + description: 'Indicates the issue is hidden because the author has been banned.', method: :hidden? field :merge_requests_count, GraphQL::Types::Int, null: false, description: 'Number of merge requests that close the issue on merge.', resolver: Resolvers::MergeRequestsCountResolver + + field :related_merge_requests, Types::MergeRequestType.connection_type, + null: true, + description: 'Merge requests related to the issue. This field can only be resolved for one issue in any single request.' do + extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1 + end + field :relative_position, GraphQL::Types::Int, null: true, description: 'Relative position of the issue (used for positioning in epic tree and issue boards).' field :upvotes, GraphQL::Types::Int, @@ -182,6 +187,17 @@ module Types Gitlab::Graphql::Loaders::BatchModelLoader.new(Issue, object.duplicated_to_id).find end + def related_merge_requests + # rubocop: disable CodeReuse/ActiveRecord + MergeRequest.where( + id: ::Issues::ReferencedMergeRequestsService.new(container: object.project, current_user: current_user) + .execute(object) + .first + .map(&:id) + ) + # rubocop: enable CodeReuse/ActiveRecord + end + def discussion_locked !!object.discussion_locked end @@ -190,10 +206,6 @@ module Types object.creatable_note_email_address(context[:current_user]) end - def hidden? - object.hidden? if Feature.enabled?(:ban_user_feature_flag) - end - def escalation_status object.supports_escalation? ? object.escalation_status&.status_name : nil end diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index abf7b3ad530..3c288c1d496 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -213,9 +213,9 @@ module Types field :security_auto_fix, GraphQL::Types::Boolean, null: true, description: 'Indicates if the merge request is created by @GitLab-Security-Bot.' field :squash, GraphQL::Types::Boolean, null: false, - description: 'Indicates if squash on merge is enabled.' + description: 'Indicates if the merge request is set to be squashed when merged. [Project settings](https://docs.gitlab.com/ee/user/project/merge_requests/squash_and_merge.html#configure-squash-options-for-a-project) may override this value. Use `squash_on_merge` instead to take project squash options into account.' field :squash_on_merge, GraphQL::Types::Boolean, null: false, method: :squash_on_merge?, - description: 'Indicates if squash on merge is enabled.' + description: 'Indicates if the merge request will be squashed when merged.' field :timelogs, Types::TimelogType.connection_type, null: false, description: 'Timelogs on the merge request.' diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 5a92ba754aa..e48e9deae96 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -66,6 +66,7 @@ module Types mount_mutation Mutations::Issues::Move mount_mutation Mutations::Issues::LinkAlerts mount_mutation Mutations::Issues::UnlinkAlert + mount_mutation Mutations::Issues::BulkUpdate, alpha: { milestone: '15.9' } mount_mutation Mutations::Labels::Create mount_mutation Mutations::Members::Groups::BulkUpdate mount_mutation Mutations::MergeRequests::Accept @@ -123,6 +124,7 @@ module Types mount_mutation Mutations::Ci::PipelineSchedule::TakeOwnership mount_mutation Mutations::Ci::PipelineSchedule::Play mount_mutation Mutations::Ci::PipelineSchedule::Create + mount_mutation Mutations::Ci::PipelineSchedule::Update mount_mutation Mutations::Ci::CiCdSettingsUpdate, deprecated: { reason: :renamed, replacement: 'ProjectCiCdSettingsUpdate', diff --git a/app/graphql/types/notes/deleted_note_type.rb b/app/graphql/types/notes/deleted_note_type.rb new file mode 100644 index 00000000000..f799fc01f6e --- /dev/null +++ b/app/graphql/types/notes/deleted_note_type.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Types + module Notes + # rubocop: disable Graphql/AuthorizeTypes + class DeletedNoteType < BaseObject + graphql_name 'DeletedNote' + + field :id, ::Types::GlobalIDType[::Note], + null: false, + description: 'ID of the deleted note.' + + field :discussion_id, ::Types::GlobalIDType[::Discussion], + null: true, + description: 'ID of the discussion for the deleted note.' + + field :last_discussion_note, GraphQL::Types::Boolean, + null: true, + description: 'Whether deleted note is the last note in the discussion.' + end + # rubocop: enable Graphql/AuthorizeTypes + end +end diff --git a/app/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb index 6c0d955ed77..f63b41b3c92 100644 --- a/app/graphql/types/packages/package_details_type.rb +++ b/app/graphql/types/packages/package_details_type.rb @@ -28,6 +28,8 @@ module Types field :last_downloaded_at, Types::TimeType, null: true, description: 'Last time that a file of this package was downloaded.' + field :public_package, GraphQL::Types::Boolean, null: true, description: 'Indicates if there is public access to the package.' + def versions object.versions end @@ -63,6 +65,10 @@ module Types def pypi_url pypi_registry_url(object.project.id) end + + def public_package + object.project.public? || object.project.project_feature.package_registry_access_level == ProjectFeature::PUBLIC + end end end end diff --git a/app/graphql/types/permission_types/base_permission_type.rb b/app/graphql/types/permission_types/base_permission_type.rb index 0192af25d0f..d45c61f489b 100644 --- a/app/graphql/types/permission_types/base_permission_type.rb +++ b/app/graphql/types/permission_types/base_permission_type.rb @@ -28,7 +28,7 @@ module Types end def self.define_field_resolver_method(ability) - unless self.respond_to?(ability) + unless respond_to?(ability) define_method ability.to_sym do |*args| Ability.allowed?(context[:current_user], ability, object, args.to_h) end diff --git a/app/graphql/types/permission_types/merge_request.rb b/app/graphql/types/permission_types/merge_request.rb index 73a2f820f79..88d8c38361a 100644 --- a/app/graphql/types/permission_types/merge_request.rb +++ b/app/graphql/types/permission_types/merge_request.rb @@ -21,10 +21,15 @@ module Types end permission_field :can_merge, calls_gitaly: true + permission_field :can_approve def can_merge object.can_be_merged_by?(context[:current_user]) end + + def can_approve + object.eligible_for_approval_by?(context[:current_user]) + end end end end diff --git a/app/graphql/types/permission_types/work_item.rb b/app/graphql/types/permission_types/work_item.rb index bae1dae4834..f35f42001e0 100644 --- a/app/graphql/types/permission_types/work_item.rb +++ b/app/graphql/types/permission_types/work_item.rb @@ -6,7 +6,7 @@ module Types graphql_name 'WorkItemPermissions' description 'Check permissions for the current user on a work item' - abilities :read_work_item, :update_work_item, :delete_work_item + abilities :read_work_item, :update_work_item, :delete_work_item, :admin_work_item end end end diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb index fe13ee7ef3c..c105ab9814c 100644 --- a/app/graphql/types/project_type.rb +++ b/app/graphql/types/project_type.rb @@ -345,7 +345,7 @@ module Types null: true, description: "List of the project's CI/CD variables.", authorize: :admin_build, - method: :variables + resolver: Resolvers::Ci::VariablesResolver field :ci_cd_settings, Types::Ci::CiCdSettingType, null: true, @@ -393,6 +393,10 @@ module Types field :services, Types::Projects::ServiceType.connection_type, null: true, + deprecated: { + reason: 'This will be renamed to `Project.integrations`', + milestone: '15.9' + }, description: 'Project services.', resolver: Resolvers::Projects::ServicesResolver @@ -562,6 +566,21 @@ module Types resolver: ::Resolvers::Ci::ProjectRunnersResolver, description: "Find runners visible to the current user." + field :data_transfer, Types::DataTransfer::ProjectDataTransferType, + null: true, # disallow null once data_transfer_monitoring feature flag is rolled-out! + resolver: Resolvers::DataTransferResolver.project, + description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.' + + field :visible_forks, Types::ProjectType.connection_type, + null: true, + alpha: { milestone: '15.10' }, + description: "Visible forks of the project." do + argument :minimum_access_level, + type: ::Types::AccessLevelEnum, + required: false, + description: 'Minimum access level.' + end + def timelog_categories object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories) end @@ -601,7 +620,11 @@ module Types end def open_issues_count - object.open_issues_count if object.feature_available?(:issues, context[:current_user]) + BatchLoader::GraphQL.wrap(object.open_issues_count) if object.feature_available?(:issues, context[:current_user]) + end + + def forks_count + BatchLoader::GraphQL.wrap(object.forks_count) end def statistics @@ -612,6 +635,8 @@ module Types project.container_repositories.size end + # Even if the parameter name is `sha`, it is actually a ref name. We always send `ref` to the endpoint. + # See: https://gitlab.com/gitlab-org/gitlab/-/issues/389065 def ci_config_variables(sha:) result = ::Ci::ListConfigVariablesService.new(object, context[:current_user]).execute(sha) @@ -630,6 +655,11 @@ module Types def sast_ci_configuration return unless Ability.allowed?(current_user, :read_code, object) + if project.repository.empty? + raise Gitlab::Graphql::Errors::MutationError, + _(format('You must %s before using Security features.', add_file_docs_link.html_safe)).html_safe + end + ::Security::CiConfiguration::SastParserService.new(object).configuration end @@ -643,11 +673,28 @@ module Types ::Projects::RepositoryLanguagesService.new(project, current_user).execute end + def visible_forks(minimum_access_level: nil) + if minimum_access_level.nil? + object.forks.public_or_visible_to_user(current_user) + else + object.forks.visible_to_user_and_access_level(current_user, minimum_access_level) + end + end + private def project @project ||= object.respond_to?(:sync) ? object.sync : object end + + def add_file_docs_link + ActionController::Base.helpers.link_to _('add at least one file to the repository'), + Rails.application.routes.url_helpers.help_page_url( + 'user/project/repository/index.md', + anchor: 'add-files-to-a-repository'), + target: '_blank', + rel: 'noopener noreferrer' + end end end diff --git a/app/graphql/types/projects/namespace_project_sort_enum.rb b/app/graphql/types/projects/namespace_project_sort_enum.rb index bd7058196dd..7c7b54226d3 100644 --- a/app/graphql/types/projects/namespace_project_sort_enum.rb +++ b/app/graphql/types/projects/namespace_project_sort_enum.rb @@ -8,6 +8,7 @@ module Types value 'SIMILARITY', 'Most similar to the search query.', value: :similarity value 'STORAGE', 'Sort by storage size.', value: :storage + value 'ACTIVITY_DESC', 'Sort by latest activity, in descending order.', value: :latest_activity_desc end end end diff --git a/app/graphql/types/projects/service_type.rb b/app/graphql/types/projects/service_type.rb index 1416d93d3b4..ec58e3254ae 100644 --- a/app/graphql/types/projects/service_type.rb +++ b/app/graphql/types/projects/service_type.rb @@ -2,6 +2,7 @@ module Types module Projects + # TODO: Remove in 17.0, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108418 module ServiceType include Types::BaseInterface graphql_name 'Service' diff --git a/app/graphql/types/projects/service_type_enum.rb b/app/graphql/types/projects/service_type_enum.rb index d0cecbfea49..fd88fa957e7 100644 --- a/app/graphql/types/projects/service_type_enum.rb +++ b/app/graphql/types/projects/service_type_enum.rb @@ -2,6 +2,7 @@ module Types module Projects + # TODO: Remove in 17.0, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108418 class ServiceTypeEnum < BaseEnum graphql_name 'ServiceType' diff --git a/app/graphql/types/projects/services/base_service_type.rb b/app/graphql/types/projects/services/base_service_type.rb index 5341ae2a864..9a48aafa5a8 100644 --- a/app/graphql/types/projects/services/base_service_type.rb +++ b/app/graphql/types/projects/services/base_service_type.rb @@ -3,6 +3,7 @@ module Types module Projects module Services + # TODO: Remove in 17.0, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108418 class BaseServiceType < BaseObject graphql_name 'BaseService' diff --git a/app/graphql/types/projects/services/jira_project_type.rb b/app/graphql/types/projects/services/jira_project_type.rb index 1c5b97802e3..eb721d02b36 100644 --- a/app/graphql/types/projects/services/jira_project_type.rb +++ b/app/graphql/types/projects/services/jira_project_type.rb @@ -4,6 +4,7 @@ module Types module Projects module Services # rubocop:disable Graphql/AuthorizeTypes + # TODO: Remove in 17.0, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108418 class JiraProjectType < BaseObject graphql_name 'JiraProject' diff --git a/app/graphql/types/projects/services/jira_service_type.rb b/app/graphql/types/projects/services/jira_service_type.rb index 425a283c674..ac274d7f890 100644 --- a/app/graphql/types/projects/services/jira_service_type.rb +++ b/app/graphql/types/projects/services/jira_service_type.rb @@ -3,6 +3,7 @@ module Types module Projects module Services + # TODO: Remove in 17.0, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108418 class JiraServiceType < BaseObject graphql_name 'JiraService' diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 990ba1fb7fc..fb906759ba4 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -17,7 +17,8 @@ module Types field :ci_variables, Types::Ci::InstanceVariableType.connection_type, null: true, - description: "List of the instance's CI/CD variables." + description: "List of the instance's CI/CD variables.", + resolver: Resolvers::Ci::VariablesResolver field :container_repository, Types::ContainerRepositoryDetailsType, null: true, description: 'Find a container repository.' do @@ -40,6 +41,10 @@ module Types null: true, resolver: Resolvers::GroupResolver, description: "Find a group." + field :groups, Types::GroupType.connection_type, + null: true, + resolver: Resolvers::GroupsResolver, + description: "Find groups." field :issue, Types::IssueType, null: true, description: 'Find an issue.' do @@ -50,8 +55,7 @@ module Types alpha: { milestone: '15.6' }, resolver: Resolvers::IssuesResolver, description: 'Find issues visible to the current user.' \ - ' At least one filter must be provided.' \ - ' Returns `null` if the `root_level_issues_query` feature flag is disabled.' + ' At least one filter must be provided.' field :jobs, ::Types::Ci::JobType.connection_type, null: true, @@ -76,6 +80,15 @@ module Types null: true, resolver: Resolvers::NamespaceResolver, description: "Find a namespace." + field :note, + ::Types::Notes::NoteType, + null: true, + description: 'Find a note.', + alpha: { milestone: '15.9' } do + argument :id, ::Types::GlobalIDType[::Note], + required: true, + description: 'Global ID of the note.' + end field :package, description: 'Find a package. This field can only be resolved for one query in any single request. Returns `null` if a package has no `default` status.', resolver: Resolvers::PackageDetailsResolver @@ -95,8 +108,10 @@ module Types resolver: Resolvers::Ci::RunnerResolver, extras: [:lookahead], description: "Find a runner." - field :runner_platforms, resolver: Resolvers::Ci::RunnerPlatformsResolver - field :runner_setup, resolver: Resolvers::Ci::RunnerSetupResolver + field :runner_platforms, resolver: Resolvers::Ci::RunnerPlatformsResolver, + deprecated: { reason: 'No longer used, use gitlab-runner documentation to learn about supported platforms', milestone: '15.9' } + field :runner_setup, resolver: Resolvers::Ci::RunnerSetupResolver, + deprecated: { reason: 'No longer used, use gitlab-runner documentation to learn about runner registration commands', milestone: '15.9' } field :runners, Types::Ci::RunnerType.connection_type, null: true, resolver: Resolvers::Ci::RunnersResolver, @@ -106,6 +121,12 @@ module Types null: true, resolver: Resolvers::SnippetsResolver, description: 'Find Snippets visible to the current user.' + field :synthetic_note, + Types::Notes::NoteType, + null: true, + description: 'Find a synthetic note', + resolver: ::Resolvers::Notes::SyntheticNoteResolver, + alpha: { milestone: '15.9' } field :timelogs, Types::TimelogType.connection_type, null: true, description: 'Find timelogs visible to the current user.', @@ -145,6 +166,10 @@ module Types GitlabSchema.find_by_gid(id) end + def note(id:) + GitlabSchema.find_by_gid(id) + end + def merge_request(id:) GitlabSchema.find_by_gid(id) end @@ -166,12 +191,6 @@ module Types application_settings end - def ci_variables - return unless current_user&.can_admin_all_resources? - - ::Ci::InstanceVariable.all - end - def application_settings Gitlab::CurrentSettings.current_application_settings end diff --git a/app/graphql/types/release_asset_link_type.rb b/app/graphql/types/release_asset_link_type.rb index e171c683e7d..b2bc52c7745 100644 --- a/app/graphql/types/release_asset_link_type.rb +++ b/app/graphql/types/release_asset_link_type.rb @@ -9,8 +9,12 @@ module Types present_using Releases::LinkPresenter - field :external, GraphQL::Types::Boolean, null: true, method: :external?, - description: 'Indicates the link points to an external resource.' + field :external, GraphQL::Types::Boolean, + null: true, + method: :external?, + description: 'Indicates the link points to an external resource.', + deprecated: { reason: 'No longer used', milestone: '15.9' } + field :id, GraphQL::Types::ID, null: false, description: 'ID of the link.' field :link_type, diff --git a/app/graphql/types/saved_reply_type.rb b/app/graphql/types/saved_reply_type.rb index 329f431b10e..8c9f3d19810 100644 --- a/app/graphql/types/saved_reply_type.rb +++ b/app/graphql/types/saved_reply_type.rb @@ -4,6 +4,8 @@ module Types class SavedReplyType < BaseObject graphql_name 'SavedReply' + connection_type_class(Types::CountableConnectionType) + authorize :read_saved_replies field :id, Types::GlobalIDType[::Users::SavedReply], diff --git a/app/graphql/types/subscription_type.rb b/app/graphql/types/subscription_type.rb index f7f26ba4c5a..33fc0cbe20e 100644 --- a/app/graphql/types/subscription_type.rb +++ b/app/graphql/types/subscription_type.rb @@ -4,41 +4,60 @@ module Types class SubscriptionType < ::Types::BaseObject graphql_name 'Subscription' - field :issuable_assignees_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the assignees of an issuable are updated.' + field :issuable_assignees_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the assignees of an issuable are updated.' - field :issue_crm_contacts_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the crm contacts of an issuable are updated.' + field :issue_crm_contacts_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the crm contacts of an issuable are updated.' - field :issuable_title_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the title of an issuable is updated.' + field :issuable_title_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the title of an issuable is updated.' - field :issuable_description_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the description of an issuable is updated.' + field :issuable_description_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the description of an issuable is updated.' - field :issuable_labels_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the labels of an issuable are updated.' + field :issuable_labels_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the labels of an issuable are updated.' - field :issuable_dates_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the due date or start date of an issuable is updated.' + field :issuable_dates_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the due date or start date of an issuable is updated.' - field :issuable_milestone_updated, subscription: Subscriptions::IssuableUpdated, null: true, - description: 'Triggered when the milestone of an issuable is updated.' + field :issuable_milestone_updated, + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the milestone of an issuable is updated.' + + field :work_item_note_created, + subscription: ::Subscriptions::Notes::Created, null: true, + description: 'Triggered when a note is created.', + alpha: { milestone: '15.9' } + + field :work_item_note_deleted, + subscription: ::Subscriptions::Notes::Deleted, null: true, + description: 'Triggered when a note is deleted.', + alpha: { milestone: '15.9' } + + field :work_item_note_updated, + subscription: ::Subscriptions::Notes::Updated, null: true, + description: 'Triggered when a note is updated.', + alpha: { milestone: '15.9' } field :merge_request_reviewers_updated, - subscription: Subscriptions::IssuableUpdated, - null: true, - description: 'Triggered when the reviewers of a merge request are updated.' + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the reviewers of a merge request are updated.' field :merge_request_merge_status_updated, - subscription: Subscriptions::IssuableUpdated, - null: true, - description: 'Triggered when the merge status of a merge request is updated.' + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when the merge status of a merge request is updated.' field :merge_request_approval_state_updated, - subscription: Subscriptions::IssuableUpdated, - null: true, - description: 'Triggered when approval state of a merge request is updated.' + subscription: Subscriptions::IssuableUpdated, null: true, + description: 'Triggered when approval state of a merge request is updated.' end end diff --git a/app/graphql/types/user_interface.rb b/app/graphql/types/user_interface.rb index a5bed3b9e19..9115b5a4760 100644 --- a/app/graphql/types/user_interface.rb +++ b/app/graphql/types/user_interface.rb @@ -137,6 +137,11 @@ module Types description: 'Saved replies authored by the user. ' \ 'Will not return saved replies if `saved_replies` feature flag is disabled.' + field :saved_reply, + resolver: Resolvers::SavedReplyResolver, + description: 'Saved reply authored by the user. ' \ + 'Will not return saved reply if `saved_replies` feature flag is disabled.' + field :gitpod_enabled, GraphQL::Types::Boolean, null: true, description: 'Whether Gitpod is enabled at the user level.' diff --git a/app/graphql/types/work_item_id_type.rb b/app/graphql/types/work_item_id_type.rb index bb01f865414..777edfad529 100644 --- a/app/graphql/types/work_item_id_type.rb +++ b/app/graphql/types/work_item_id_type.rb @@ -37,7 +37,11 @@ module Types def suitable?(gid) return false if gid&.model_name&.safe_constantize.blank? + # Using === operation doesn't work for model classes. + # See https://github.com/rails/rails/blob/v6.1.6.1/activerecord/lib/active_record/core.rb#L452 + # rubocop:disable Performance/RedundantEqualityComparisonBlock [::WorkItem, ::Issue].any? { |model_class| gid.model_class == model_class } + # rubocop:enable Performance/RedundantEqualityComparisonBlock end private diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb index 6a1a4f158be..b46362f66b8 100644 --- a/app/graphql/types/work_item_type.rb +++ b/app/graphql/types/work_item_type.rb @@ -8,6 +8,9 @@ module Types authorize :read_work_item + field :author, Types::UserType, null: true, + description: 'User that created the work item.', + alpha: { milestone: '15.9' } field :closed_at, Types::TimeType, null: true, description: 'Timestamp of when the work item was closed.' field :confidential, GraphQL::Types::Boolean, null: false, diff --git a/app/graphql/types/work_items/widget_type_enum.rb b/app/graphql/types/work_items/widget_type_enum.rb index 4e5933bff86..2ad951d421b 100644 --- a/app/graphql/types/work_items/widget_type_enum.rb +++ b/app/graphql/types/work_items/widget_type_enum.rb @@ -6,8 +6,8 @@ module Types graphql_name 'WorkItemWidgetType' description 'Type of a work item widget' - ::WorkItems::Type.available_widgets.each do |widget| - value widget.type.to_s.upcase, value: widget.type, description: "#{widget.type.to_s.titleize} widget." + ::WorkItems::WidgetDefinition.widget_classes.each do |cls| + value cls.type.to_s.upcase, value: cls.type, description: "#{cls.type.to_s.titleize} widget." end end end |