Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 12:55:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 12:55:51 +0300
commite8d2c2579383897a1dd7f9debd359abe8ae8373d (patch)
treec42be41678c2586d49a75cabce89322082698334 /app/graphql
parentfc845b37ec3a90aaa719975f607740c22ba6a113 (diff)
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'app/graphql')
-rw-r--r--app/graphql/mutations/alert_management/prometheus_integration/create.rb4
-rw-r--r--app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb2
-rw-r--r--app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb2
-rw-r--r--app/graphql/mutations/alert_management/prometheus_integration/update.rb2
-rw-r--r--app/graphql/mutations/boards/issues/issue_move_list.rb2
-rw-r--r--app/graphql/mutations/ci/job_token_scope/add_project.rb49
-rw-r--r--app/graphql/mutations/ci/job_token_scope/remove_project.rb49
-rw-r--r--app/graphql/mutations/ci/runner/update.rb2
-rw-r--r--app/graphql/mutations/concerns/mutations/package_eventable.rb2
-rw-r--r--app/graphql/mutations/concerns/mutations/spam_protection.rb19
-rw-r--r--app/graphql/mutations/issues/create.rb3
-rw-r--r--app/graphql/mutations/issues/set_confidential.rb8
-rw-r--r--app/graphql/mutations/issues/update.rb3
-rw-r--r--app/graphql/mutations/packages/destroy.rb37
-rw-r--r--app/graphql/mutations/release_asset_links/create.rb4
-rw-r--r--app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb44
-rw-r--r--app/graphql/mutations/security/ci_configuration/configure_sast.rb33
-rw-r--r--app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb33
-rw-r--r--app/graphql/mutations/snippets/create.rb10
-rw-r--r--app/graphql/mutations/snippets/update.rb10
-rw-r--r--app/graphql/queries/container_registry/get_container_repositories.query.graphql2
-rw-r--r--app/graphql/queries/epic/epic_children.query.graphql1
-rw-r--r--app/graphql/queries/pipelines/get_pipeline_details.query.graphql3
-rw-r--r--app/graphql/queries/releases/all_releases.query.graphql105
-rw-r--r--app/graphql/resolvers/alert_management/alert_resolver.rb2
-rw-r--r--app/graphql/resolvers/alert_management/integrations_resolver.rb4
-rw-r--r--app/graphql/resolvers/board_list_issues_resolver.rb2
-rw-r--r--app/graphql/resolvers/ci/config_resolver.rb8
-rw-r--r--app/graphql/resolvers/ci/job_token_scope_resolver.rb21
-rw-r--r--app/graphql/resolvers/ci/runners_resolver.rb16
-rw-r--r--app/graphql/resolvers/ci/template_resolver.rb2
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb2
-rw-r--r--app/graphql/resolvers/issues_resolver.rb1
-rw-r--r--app/graphql/resolvers/milestones_resolver.rb20
-rw-r--r--app/graphql/resolvers/projects/jira_projects_resolver.rb6
-rw-r--r--app/graphql/types/alert_management/alert_sort_enum.rb4
-rw-r--r--app/graphql/types/alert_management/alert_type.rb2
-rw-r--r--app/graphql/types/alert_management/integration_type.rb2
-rw-r--r--app/graphql/types/alert_management/prometheus_integration_type.rb10
-rw-r--r--app/graphql/types/base_field.rb12
-rw-r--r--app/graphql/types/boards/board_issue_input_base_type.rb2
-rw-r--r--app/graphql/types/ci/build_need_type.rb2
-rw-r--r--app/graphql/types/ci/detailed_status_type.rb7
-rw-r--r--app/graphql/types/ci/group_type.rb8
-rw-r--r--app/graphql/types/ci/job_token_scope_type.rb16
-rw-r--r--app/graphql/types/ci/job_type.rb2
-rw-r--r--app/graphql/types/ci/pipeline_type.rb3
-rw-r--r--app/graphql/types/ci/runner_type.rb36
-rw-r--r--app/graphql/types/ci/stage_type.rb20
-rw-r--r--app/graphql/types/ci/status_action_type.rb7
-rw-r--r--app/graphql/types/deployment_tier_enum.rb14
-rw-r--r--app/graphql/types/design_management/design_type.rb2
-rw-r--r--app/graphql/types/issuable_searchable_field_enum.rb12
-rw-r--r--app/graphql/types/issue_sort_enum.rb2
-rw-r--r--app/graphql/types/issue_type.rb5
-rw-r--r--app/graphql/types/issues/negated_issue_filter_input_type.rb2
-rw-r--r--app/graphql/types/merge_request_type.rb2
-rw-r--r--app/graphql/types/milestone_sort_enum.rb13
-rw-r--r--app/graphql/types/milestone_type.rb3
-rw-r--r--app/graphql/types/mutation_type.rb3
-rw-r--r--app/graphql/types/noteable_type.rb23
-rw-r--r--app/graphql/types/notes/discussion_type.rb10
-rw-r--r--app/graphql/types/notes/noteable_interface.rb (renamed from app/graphql/types/notes/noteable_type.rb)4
-rw-r--r--app/graphql/types/project_type.rb16
-rw-r--r--app/graphql/types/projects/service_type_enum.rb2
-rw-r--r--app/graphql/types/query_complexity_type.rb30
-rw-r--r--app/graphql/types/query_type.rb8
-rw-r--r--app/graphql/types/release_asset_link_type.rb2
-rw-r--r--app/graphql/types/snippet_type.rb2
-rw-r--r--app/graphql/types/snippets/blob_type.rb4
-rw-r--r--app/graphql/types/user_callout_type.rb2
71 files changed, 644 insertions, 163 deletions
diff --git a/app/graphql/mutations/alert_management/prometheus_integration/create.rb b/app/graphql/mutations/alert_management/prometheus_integration/create.rb
index c6dc85dc07c..4d0a5a5cb13 100644
--- a/app/graphql/mutations/alert_management/prometheus_integration/create.rb
+++ b/app/graphql/mutations/alert_management/prometheus_integration/create.rb
@@ -23,7 +23,7 @@ module Mutations
def resolve(args)
project = authorized_find!(args[:project_path])
- return integration_exists if project.prometheus_service
+ return integration_exists if project.prometheus_integration
result = ::Projects::Operations::UpdateService.new(
project,
@@ -32,7 +32,7 @@ module Mutations
**token_attributes
).execute
- response(project.prometheus_service, result)
+ response(project.prometheus_integration, result)
end
private
diff --git a/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb b/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb
index cb243f49b33..d8678ea4d61 100644
--- a/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb
+++ b/app/graphql/mutations/alert_management/prometheus_integration/prometheus_integration_base.rb
@@ -14,7 +14,7 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id, expected_class: ::PrometheusService)
+ GitlabSchema.object_from_id(id, expected_class: ::Integrations::Prometheus)
end
def response(integration, result)
diff --git a/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb b/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb
index 428be091436..33a12405583 100644
--- a/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb
+++ b/app/graphql/mutations/alert_management/prometheus_integration/reset_token.rb
@@ -6,7 +6,7 @@ module Mutations
class ResetToken < PrometheusIntegrationBase
graphql_name 'PrometheusIntegrationResetToken'
- argument :id, Types::GlobalIDType[::PrometheusService],
+ argument :id, Types::GlobalIDType[::Integrations::Prometheus],
required: true,
description: "The ID of the integration to mutate."
diff --git a/app/graphql/mutations/alert_management/prometheus_integration/update.rb b/app/graphql/mutations/alert_management/prometheus_integration/update.rb
index 7594766176f..ddab1af908c 100644
--- a/app/graphql/mutations/alert_management/prometheus_integration/update.rb
+++ b/app/graphql/mutations/alert_management/prometheus_integration/update.rb
@@ -6,7 +6,7 @@ module Mutations
class Update < PrometheusIntegrationBase
graphql_name 'PrometheusIntegrationUpdate'
- argument :id, Types::GlobalIDType[::PrometheusService],
+ argument :id, Types::GlobalIDType[::Integrations::Prometheus],
required: true,
description: "The ID of the integration to mutate."
diff --git a/app/graphql/mutations/boards/issues/issue_move_list.rb b/app/graphql/mutations/boards/issues/issue_move_list.rb
index 4c9752c6343..b73657ea0c8 100644
--- a/app/graphql/mutations/boards/issues/issue_move_list.rb
+++ b/app/graphql/mutations/boards/issues/issue_move_list.rb
@@ -53,8 +53,6 @@ module Mutations
end
def resolve(board:, project_path:, iid:, **args)
- Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/247861')
-
issue = authorized_find!(project_path: project_path, iid: iid)
move_params = { id: issue.id, board_id: board.id }.merge(move_arguments(args))
diff --git a/app/graphql/mutations/ci/job_token_scope/add_project.rb b/app/graphql/mutations/ci/job_token_scope/add_project.rb
new file mode 100644
index 00000000000..30f98a537b5
--- /dev/null
+++ b/app/graphql/mutations/ci/job_token_scope/add_project.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module JobTokenScope
+ class AddProject < BaseMutation
+ include FindsProject
+
+ graphql_name 'CiJobTokenScopeAddProject'
+
+ authorize :admin_project
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project that the CI job token scope belongs to.'
+
+ argument :target_project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project to be added to the CI job token scope.'
+
+ field :ci_job_token_scope,
+ Types::Ci::JobTokenScopeType,
+ null: true,
+ description: "The CI job token's scope of access."
+
+ def resolve(project_path:, target_project_path:)
+ project = authorized_find!(project_path)
+ target_project = Project.find_by_full_path(target_project_path)
+
+ result = ::Ci::JobTokenScope::AddProjectService
+ .new(project, current_user)
+ .execute(target_project)
+
+ if result.success?
+ {
+ ci_job_token_scope: ::Ci::JobToken::Scope.new(project),
+ errors: []
+ }
+ else
+ {
+ ci_job_token_scope: nil,
+ errors: [result.message]
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/job_token_scope/remove_project.rb b/app/graphql/mutations/ci/job_token_scope/remove_project.rb
new file mode 100644
index 00000000000..71c9083bef8
--- /dev/null
+++ b/app/graphql/mutations/ci/job_token_scope/remove_project.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module JobTokenScope
+ class RemoveProject < BaseMutation
+ include FindsProject
+
+ graphql_name 'CiJobTokenScopeRemoveProject'
+
+ authorize :admin_project
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project that the CI job token scope belongs to.'
+
+ argument :target_project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project to be removed from the CI job token scope.'
+
+ field :ci_job_token_scope,
+ Types::Ci::JobTokenScopeType,
+ null: true,
+ description: "The CI job token's scope of access."
+
+ def resolve(project_path:, target_project_path:)
+ project = authorized_find!(project_path)
+ target_project = Project.find_by_full_path(target_project_path)
+
+ result = ::Ci::JobTokenScope::RemoveProjectService
+ .new(project, current_user)
+ .execute(target_project)
+
+ if result.success?
+ {
+ ci_job_token_scope: ::Ci::JobToken::Scope.new(project),
+ errors: []
+ }
+ else
+ {
+ ci_job_token_scope: nil,
+ errors: [result.message]
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb
index 5b61b2ffc0d..4cdfa1fb1bd 100644
--- a/app/graphql/mutations/ci/runner/update.rb
+++ b/app/graphql/mutations/ci/runner/update.rb
@@ -66,3 +66,5 @@ module Mutations
end
end
end
+
+Mutations::Ci::Runner::Update.prepend_mod_with('Mutations::Ci::Runner::Update')
diff --git a/app/graphql/mutations/concerns/mutations/package_eventable.rb b/app/graphql/mutations/concerns/mutations/package_eventable.rb
index 86fd7b9a88a..134e3659125 100644
--- a/app/graphql/mutations/concerns/mutations/package_eventable.rb
+++ b/app/graphql/mutations/concerns/mutations/package_eventable.rb
@@ -8,7 +8,7 @@ module Mutations
def track_event(event, scope)
::Packages::CreateEventService.new(nil, current_user, event_name: event, scope: scope).execute
- ::Gitlab::Tracking.event(event.to_s, scope.to_s)
+ ::Gitlab::Tracking.event(event.to_s, scope.to_s, user: current_user)
end
end
end
diff --git a/app/graphql/mutations/concerns/mutations/spam_protection.rb b/app/graphql/mutations/concerns/mutations/spam_protection.rb
index d765da23a4b..341067710b2 100644
--- a/app/graphql/mutations/concerns/mutations/spam_protection.rb
+++ b/app/graphql/mutations/concerns/mutations/spam_protection.rb
@@ -16,25 +16,6 @@ module Mutations
private
- # additional_spam_params -> hash
- #
- # Used from a spammable mutation's #resolve method to generate
- # the required additional spam/CAPTCHA params which must be merged into the params
- # passed to the constructor of a service, where they can then be used in the service
- # to perform spam checking via SpamActionService.
- #
- # Also accesses the #context of the mutation's Resolver superclass to obtain the request.
- #
- # Example:
- #
- # existing_args.merge!(additional_spam_params)
- def additional_spam_params
- {
- api: true,
- request: context[:request]
- }
- end
-
def spam_action_response(object)
fields = spam_action_response_fields(object)
diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb
index 3a57e2434a5..7c4a851f8aa 100644
--- a/app/graphql/mutations/issues/create.rb
+++ b/app/graphql/mutations/issues/create.rb
@@ -73,7 +73,8 @@ module Mutations
project = authorized_find!(project_path)
params = build_create_issue_params(attributes.merge(author_id: current_user.id))
- issue = ::Issues::CreateService.new(project: project, current_user: current_user, params: params).execute
+ spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
+ issue = ::Issues::CreateService.new(project: project, current_user: current_user, params: params, spam_params: spam_params).execute
if issue.spam?
issue.errors.add(:base, 'Spam detected.')
diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb
index 8e88b31d9ed..cfee2420ee0 100644
--- a/app/graphql/mutations/issues/set_confidential.rb
+++ b/app/graphql/mutations/issues/set_confidential.rb
@@ -3,6 +3,8 @@
module Mutations
module Issues
class SetConfidential < Base
+ include Mutations::SpamProtection
+
graphql_name 'IssueSetConfidential'
argument :confidential,
@@ -13,9 +15,13 @@ module Mutations
def resolve(project_path:, iid:, confidential:)
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
+ # Changing confidentiality affects spam checking rules, therefore we need to provide
+ # spam_params so a check can be performed.
+ spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: { confidential: confidential })
+ ::Issues::UpdateService.new(project: project, current_user: current_user, params: { confidential: confidential }, spam_params: spam_params)
.execute(issue)
+ check_spam_action_response!(issue)
{
issue: issue,
diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb
index eb16b7b38d0..1ceed868a6c 100644
--- a/app/graphql/mutations/issues/update.rb
+++ b/app/graphql/mutations/issues/update.rb
@@ -31,7 +31,8 @@ module Mutations
issue = authorized_find!(project_path: project_path, iid: iid)
project = issue.project
- ::Issues::UpdateService.new(project: project, current_user: current_user, params: args).execute(issue)
+ spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
+ ::Issues::UpdateService.new(project: project, current_user: current_user, params: args, spam_params: spam_params).execute(issue)
{
issue: issue,
diff --git a/app/graphql/mutations/packages/destroy.rb b/app/graphql/mutations/packages/destroy.rb
new file mode 100644
index 00000000000..979a54da6bd
--- /dev/null
+++ b/app/graphql/mutations/packages/destroy.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Packages
+ class Destroy < ::Mutations::BaseMutation
+ graphql_name 'DestroyPackage'
+
+ authorize :destroy_package
+
+ argument :id,
+ ::Types::GlobalIDType[::Packages::Package],
+ required: true,
+ description: 'ID of the Package.'
+
+ def resolve(id:)
+ package = authorized_find!(id: id)
+
+ result = ::Packages::DestroyPackageService.new(container: package, current_user: current_user).execute
+
+ errors = result.error? ? Array.wrap(result[:message]) : []
+
+ {
+ errors: errors
+ }
+ end
+
+ private
+
+ def find_object(id:)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Packages::Package].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/release_asset_links/create.rb b/app/graphql/mutations/release_asset_links/create.rb
index 02704efb47c..ff9d98d2c0f 100644
--- a/app/graphql/mutations/release_asset_links/create.rb
+++ b/app/graphql/mutations/release_asset_links/create.rb
@@ -33,6 +33,10 @@ module Mutations
return { link: nil, errors: [message] }
end
+ unless Ability.allowed?(current_user, :update_release, release)
+ raise_resource_not_available_error!
+ end
+
new_link = release.links.create(link_attrs)
unless new_link.persisted?
diff --git a/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb
new file mode 100644
index 00000000000..090a9a4e0ef
--- /dev/null
+++ b/app/graphql/mutations/security/ci_configuration/base_security_analyzer.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Security
+ module CiConfiguration
+ class BaseSecurityAnalyzer < BaseMutation
+ include FindsProject
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'Full path of the project.'
+
+ field :success_path, GraphQL::STRING_TYPE, null: true,
+ description: 'Redirect path to use when the response is successful.'
+
+ field :branch, GraphQL::STRING_TYPE, null: true,
+ description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
+
+ authorize :push_code
+
+ def resolve(project_path:, **args)
+ project = authorized_find!(project_path)
+
+ result = configure_analyzer(project, **args)
+ prepare_response(result)
+ end
+
+ private
+
+ def configure_analyzer(project, **args)
+ raise NotImplementedError
+ end
+
+ def prepare_response(result)
+ {
+ branch: result.payload[:branch],
+ success_path: result.payload[:success_path],
+ errors: result.errors
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/security/ci_configuration/configure_sast.rb b/app/graphql/mutations/security/ci_configuration/configure_sast.rb
index 237aff1f052..7ce0bf83a4b 100644
--- a/app/graphql/mutations/security/ci_configuration/configure_sast.rb
+++ b/app/graphql/mutations/security/ci_configuration/configure_sast.rb
@@ -3,9 +3,7 @@
module Mutations
module Security
module CiConfiguration
- class ConfigureSast < BaseMutation
- include FindsProject
-
+ class ConfigureSast < BaseSecurityAnalyzer
graphql_name 'ConfigureSast'
description <<~DESC
Configure SAST for a project by enabling SAST in a new or modified
@@ -13,37 +11,12 @@ module Mutations
create a Merge Request are a part of the response.
DESC
- argument :project_path, GraphQL::ID_TYPE,
- required: true,
- description: 'Full path of the project.'
-
argument :configuration, ::Types::CiConfiguration::Sast::InputType,
required: true,
description: 'SAST CI configuration for the project.'
- field :success_path, GraphQL::STRING_TYPE, null: true,
- description: 'Redirect path to use when the response is successful.'
-
- field :branch, GraphQL::STRING_TYPE, null: true,
- description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
-
- authorize :push_code
-
- def resolve(project_path:, configuration:)
- project = authorized_find!(project_path)
-
- result = ::Security::CiConfiguration::SastCreateService.new(project, current_user, configuration).execute
- prepare_response(result)
- end
-
- private
-
- def prepare_response(result)
- {
- branch: result.payload[:branch],
- success_path: result.payload[:success_path],
- errors: result.errors
- }
+ def configure_analyzer(project, **args)
+ ::Security::CiConfiguration::SastCreateService.new(project, current_user, args[:configuration]).execute
end
end
end
diff --git a/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb b/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb
index 32ad670edaa..54322babb26 100644
--- a/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb
+++ b/app/graphql/mutations/security/ci_configuration/configure_secret_detection.rb
@@ -3,9 +3,7 @@
module Mutations
module Security
module CiConfiguration
- class ConfigureSecretDetection < BaseMutation
- include FindsProject
-
+ class ConfigureSecretDetection < BaseSecurityAnalyzer
graphql_name 'ConfigureSecretDetection'
description <<~DESC
Configure Secret Detection for a project by enabling Secret Detection
@@ -14,33 +12,8 @@ module Mutations
response.
DESC
- argument :project_path, GraphQL::ID_TYPE,
- required: true,
- description: 'Full path of the project.'
-
- field :success_path, GraphQL::STRING_TYPE, null: true,
- description: 'Redirect path to use when the response is successful.'
-
- field :branch, GraphQL::STRING_TYPE, null: true,
- description: 'Branch that has the new/modified `.gitlab-ci.yml` file.'
-
- authorize :push_code
-
- def resolve(project_path:)
- project = authorized_find!(project_path)
-
- result = ::Security::CiConfiguration::SecretDetectionCreateService.new(project, current_user).execute
- prepare_response(result)
- end
-
- private
-
- def prepare_response(result)
- {
- branch: result.payload[:branch],
- success_path: result.payload[:success_path],
- errors: result.errors
- }
+ def configure_analyzer(project, **_args)
+ ::Security::CiConfiguration::SecretDetectionCreateService.new(project, current_user).execute
end
end
end
diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb
index d1ad0697acd..765163e73a1 100644
--- a/app/graphql/mutations/snippets/create.rb
+++ b/app/graphql/mutations/snippets/create.rb
@@ -49,7 +49,9 @@ module Mutations
process_args_for_params!(args)
- service_response = ::Snippets::CreateService.new(project: project, current_user: current_user, params: args).execute
+ spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
+ service = ::Snippets::CreateService.new(project: project, current_user: current_user, params: args, spam_params: spam_params)
+ service_response = service.execute
# Only when the user is not an api user and the operation was successful
if !api_user? && service_response.success?
@@ -81,12 +83,6 @@ module Mutations
# it's the expected key param
args[:files] = args.delete(:uploaded_files)
- if Feature.enabled?(:snippet_spam)
- args.merge!(additional_spam_params)
- else
- args[:disable_spam_action_service] = true
- end
-
# Return nil to make it explicit that this method is mutating the args parameter, and that
# the return value is not relevant and is not to be used.
nil
diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb
index 2e1382e1cb1..792c631e5ca 100644
--- a/app/graphql/mutations/snippets/update.rb
+++ b/app/graphql/mutations/snippets/update.rb
@@ -34,7 +34,9 @@ module Mutations
process_args_for_params!(args)
- service_response = ::Snippets::UpdateService.new(project: snippet.project, current_user: current_user, params: args).execute(snippet)
+ spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
+ service = ::Snippets::UpdateService.new(project: snippet.project, current_user: current_user, params: args, spam_params: spam_params)
+ service_response = service.execute(snippet)
# TODO: DRY this up - From here down, this is all duplicated with Mutations::Snippets::Create#resolve, except for
# `snippet.reset`, which is required in order to return the object in its non-dirty, unmodified, database state
@@ -62,12 +64,6 @@ module Mutations
def process_args_for_params!(args)
convert_blob_actions_to_snippet_actions!(args)
- if Feature.enabled?(:snippet_spam)
- args.merge!(additional_spam_params)
- else
- args[:disable_spam_action_service] = true
- end
-
# Return nil to make it explicit that this method is mutating the args parameter, and that
# the return value is not relevant and is not to be used.
nil
diff --git a/app/graphql/queries/container_registry/get_container_repositories.query.graphql b/app/graphql/queries/container_registry/get_container_repositories.query.graphql
index 4683ef9dfdb..df0b590acac 100644
--- a/app/graphql/queries/container_registry/get_container_repositories.query.graphql
+++ b/app/graphql/queries/container_registry/get_container_repositories.query.graphql
@@ -29,6 +29,7 @@ query getProjectContainerRepositories(
canDelete
createdAt
expirationPolicyStartedAt
+ expirationPolicyCleanupStatus
__typename
}
pageInfo {
@@ -61,6 +62,7 @@ query getProjectContainerRepositories(
canDelete
createdAt
expirationPolicyStartedAt
+ expirationPolicyCleanupStatus
__typename
}
pageInfo {
diff --git a/app/graphql/queries/epic/epic_children.query.graphql b/app/graphql/queries/epic/epic_children.query.graphql
index 5ee27052f95..b0e55811b7d 100644
--- a/app/graphql/queries/epic/epic_children.query.graphql
+++ b/app/graphql/queries/epic/epic_children.query.graphql
@@ -42,6 +42,7 @@ fragment EpicNode on Epic {
relationPath
createdAt
closedAt
+ confidential
hasChildren
hasIssues
group {
diff --git a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql
index 873ecc81466..4e4caa1e27c 100644
--- a/app/graphql/queries/pipelines/get_pipeline_details.query.graphql
+++ b/app/graphql/queries/pipelines/get_pipeline_details.query.graphql
@@ -29,6 +29,9 @@ query getPipelineDetails($projectPath: ID!, $iid: ID!) {
iid
complete
usesNeeds
+ userPermissions {
+ updatePipeline
+ }
downstream {
__typename
nodes {
diff --git a/app/graphql/queries/releases/all_releases.query.graphql b/app/graphql/queries/releases/all_releases.query.graphql
new file mode 100644
index 00000000000..ab8cbcb8aa3
--- /dev/null
+++ b/app/graphql/queries/releases/all_releases.query.graphql
@@ -0,0 +1,105 @@
+# This query is identical to
+# `app/assets/javascripts/releases/graphql/queries/all_releases.query.graphql`.
+# These two queries should be kept in sync.
+query allReleases(
+ $fullPath: ID!
+ $first: Int
+ $last: Int
+ $before: String
+ $after: String
+ $sort: ReleaseSort
+) {
+ project(fullPath: $fullPath) {
+ __typename
+ releases(first: $first, last: $last, before: $before, after: $after, sort: $sort) {
+ __typename
+ nodes {
+ __typename
+ name
+ tagName
+ tagPath
+ descriptionHtml
+ releasedAt
+ createdAt
+ upcomingRelease
+ assets {
+ __typename
+ count
+ sources {
+ __typename
+ nodes {
+ __typename
+ format
+ url
+ }
+ }
+ links {
+ __typename
+ nodes {
+ __typename
+ id
+ name
+ url
+ directAssetUrl
+ linkType
+ external
+ }
+ }
+ }
+ evidences {
+ __typename
+ nodes {
+ __typename
+ filepath
+ collectedAt
+ sha
+ }
+ }
+ links {
+ __typename
+ editUrl
+ selfUrl
+ openedIssuesUrl
+ closedIssuesUrl
+ openedMergeRequestsUrl
+ mergedMergeRequestsUrl
+ closedMergeRequestsUrl
+ }
+ commit {
+ __typename
+ sha
+ webUrl
+ title
+ }
+ author {
+ __typename
+ webUrl
+ avatarUrl
+ username
+ }
+ milestones {
+ __typename
+ nodes {
+ __typename
+ id
+ title
+ description
+ webPath
+ stats {
+ __typename
+ totalIssuesCount
+ closedIssuesCount
+ }
+ }
+ }
+ }
+ pageInfo {
+ __typename
+ startCursor
+ hasPreviousPage
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+}
diff --git a/app/graphql/resolvers/alert_management/alert_resolver.rb b/app/graphql/resolvers/alert_management/alert_resolver.rb
index 008641ed88a..62744e719da 100644
--- a/app/graphql/resolvers/alert_management/alert_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_resolver.rb
@@ -12,7 +12,7 @@ module Resolvers
argument :statuses, [Types::AlertManagement::StatusEnum],
as: :status,
required: false,
- description: 'Alerts with the specified statues. For example, [TRIGGERED].'
+ description: 'Alerts with the specified statues. For example, `[TRIGGERED]`.'
argument :sort, Types::AlertManagement::AlertSortEnum,
description: 'Sort alerts by this criteria.',
diff --git a/app/graphql/resolvers/alert_management/integrations_resolver.rb b/app/graphql/resolvers/alert_management/integrations_resolver.rb
index cb7e73c2d1a..a97650e95d9 100644
--- a/app/graphql/resolvers/alert_management/integrations_resolver.rb
+++ b/app/graphql/resolvers/alert_management/integrations_resolver.rb
@@ -34,7 +34,7 @@ module Resolvers
def prometheus_integrations
return [] unless prometheus_integrations_allowed?
- Array(project.prometheus_service)
+ Array(project.prometheus_integration)
end
def http_integrations
@@ -54,7 +54,7 @@ module Resolvers
def expected_integration_types
[].tap do |types|
types << ::AlertManagement::HttpIntegration if http_integrations_allowed?
- types << ::PrometheusService if prometheus_integrations_allowed?
+ types << ::Integrations::Prometheus if prometheus_integrations_allowed?
end
end
end
diff --git a/app/graphql/resolvers/board_list_issues_resolver.rb b/app/graphql/resolvers/board_list_issues_resolver.rb
index dac93b91469..25fb35ec74b 100644
--- a/app/graphql/resolvers/board_list_issues_resolver.rb
+++ b/app/graphql/resolvers/board_list_issues_resolver.rb
@@ -16,7 +16,7 @@ module Resolvers
filter_params = item_filters(args[:filters]).merge(board_id: list.board.id, id: list.id)
service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params)
- offset_pagination(service.execute)
+ service.execute
end
# https://gitlab.com/gitlab-org/gitlab/-/issues/235681
diff --git a/app/graphql/resolvers/ci/config_resolver.rb b/app/graphql/resolvers/ci/config_resolver.rb
index 252c9d3acf0..f2e33251b9c 100644
--- a/app/graphql/resolvers/ci/config_resolver.rb
+++ b/app/graphql/resolvers/ci/config_resolver.rb
@@ -18,6 +18,10 @@ module Resolvers
required: true,
description: 'The project of the CI config.'
+ argument :sha, GraphQL::STRING_TYPE,
+ required: false,
+ description: "Sha for the pipeline."
+
argument :content, GraphQL::STRING_TYPE,
required: true,
description: "Contents of `.gitlab-ci.yml`."
@@ -26,11 +30,11 @@ module Resolvers
required: false,
description: 'Run pipeline creation simulation, or only do static check.'
- def resolve(project_path:, content:, dry_run: false)
+ def resolve(project_path:, content:, sha: nil, dry_run: false)
project = authorized_find!(project_path: project_path)
result = ::Gitlab::Ci::Lint
- .new(project: project, current_user: context[:current_user])
+ .new(project: project, current_user: context[:current_user], sha: sha)
.validate(content, dry_run: dry_run)
response(result).merge(merged_yaml: result.merged_yaml)
diff --git a/app/graphql/resolvers/ci/job_token_scope_resolver.rb b/app/graphql/resolvers/ci/job_token_scope_resolver.rb
new file mode 100644
index 00000000000..ca76a7b94fc
--- /dev/null
+++ b/app/graphql/resolvers/ci/job_token_scope_resolver.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Ci
+ class JobTokenScopeResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorize :admin_project
+ description 'Container for resources that can be accessed by a CI job token from the current project. Null if job token scope setting is disabled.'
+ type ::Types::Ci::JobTokenScopeType, null: true
+
+ def resolve
+ authorize!(object)
+
+ return unless object.ci_job_token_scope_enabled?
+
+ ::Ci::JobToken::Scope.new(object)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb
index 3ad1e2780dd..5074a248e18 100644
--- a/app/graphql/resolvers/ci/runners_resolver.rb
+++ b/app/graphql/resolvers/ci/runners_resolver.rb
@@ -3,6 +3,8 @@
module Resolvers
module Ci
class RunnersResolver < BaseResolver
+ include LooksAhead
+
type Types::Ci::RunnerType.connection_type, null: true
argument :status, ::Types::Ci::RunnerStatusEnum,
@@ -25,10 +27,11 @@ module Resolvers
required: false,
description: 'Sort order of results.'
- def resolve(**args)
- ::Ci::RunnersFinder
- .new(current_user: current_user, params: runners_finder_params(args))
- .execute
+ def resolve_with_lookahead(**args)
+ apply_lookahead(
+ ::Ci::RunnersFinder
+ .new(current_user: current_user, params: runners_finder_params(args))
+ .execute)
end
private
@@ -39,7 +42,10 @@ module Resolvers
type_type: params[:type],
tag_name: params[:tag_list],
search: params[:search],
- sort: params[:sort]&.to_s
+ sort: params[:sort]&.to_s,
+ preload: {
+ tag_name: node_selection&.selects?(:tag_list)
+ }
}.compact
end
end
diff --git a/app/graphql/resolvers/ci/template_resolver.rb b/app/graphql/resolvers/ci/template_resolver.rb
index dd910116544..7f5a1a486d7 100644
--- a/app/graphql/resolvers/ci/template_resolver.rb
+++ b/app/graphql/resolvers/ci/template_resolver.rb
@@ -6,7 +6,7 @@ module Resolvers
type Types::Ci::TemplateType, null: true
argument :name, GraphQL::STRING_TYPE, required: true,
- description: 'Name of the CI/CD template to search for.'
+ description: 'Name of the CI/CD template to search for. Template must be formatted as `Name.gitlab-ci.yml`.'
alias_method :project, :object
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index aa08d62c6a5..c24f4dedc0e 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -11,7 +11,7 @@ module IssueResolverArguments
description: 'IID of the issue. For example, "1".'
argument :iids, [GraphQL::STRING_TYPE],
required: false,
- description: 'List of IIDs of issues. For example, ["1", "2"].'
+ description: 'List of IIDs of issues. For example, `["1", "2"]`.'
argument :label_name, [GraphQL::STRING_TYPE, null: true],
required: false,
description: 'Labels applied to this issue.'
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index 93e679b2d0c..2017eb7decd 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -15,6 +15,7 @@ module Resolvers
type Types::IssueType.connection_type, null: true
NON_STABLE_CURSOR_SORTS = %i[priority_asc priority_desc
+ popularity_asc popularity_desc
label_priority_asc label_priority_desc
milestone_due_asc milestone_due_desc].freeze
diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb
index 1241b41501d..4fa4c939a23 100644
--- a/app/graphql/resolvers/milestones_resolver.rb
+++ b/app/graphql/resolvers/milestones_resolver.rb
@@ -25,14 +25,27 @@ module Resolvers
required: false,
description: 'A date that the milestone contains.'
+ argument :sort, Types::MilestoneSortEnum,
+ description: 'Sort milestones by this criteria.',
+ required: false,
+ default_value: :due_date_asc
+
type Types::MilestoneType.connection_type, null: true
+ NON_STABLE_CURSOR_SORTS = %i[expired_last_due_date_asc expired_last_due_date_desc].freeze
+
def resolve(**args)
validate_timeframe_params!(args)
authorize!
- MilestonesFinder.new(milestones_finder_params(args)).execute
+ milestones = MilestonesFinder.new(milestones_finder_params(args)).execute
+
+ if non_stable_cursor_sort?(args[:sort])
+ offset_pagination(milestones)
+ else
+ milestones
+ end
end
private
@@ -43,6 +56,7 @@ module Resolvers
state: args[:state] || 'all',
title: args[:title],
search_title: args[:search_title],
+ sort: args[:sort],
containing_date: args[:containing_date]
}.merge!(transform_timeframe_parameters(args)).merge!(parent_id_parameters(args))
end
@@ -64,5 +78,9 @@ module Resolvers
def parse_gids(gids)
gids&.map { |gid| GitlabSchema.parse_gid(gid, expected_type: Milestone).model_id }
end
+
+ def non_stable_cursor_sort?(sort)
+ NON_STABLE_CURSOR_SORTS.include?(sort)
+ end
end
end
diff --git a/app/graphql/resolvers/projects/jira_projects_resolver.rb b/app/graphql/resolvers/projects/jira_projects_resolver.rb
index de85e8c42e6..864acb6d759 100644
--- a/app/graphql/resolvers/projects/jira_projects_resolver.rb
+++ b/app/graphql/resolvers/projects/jira_projects_resolver.rb
@@ -34,16 +34,16 @@ module Resolvers
private
- alias_method :jira_service, :object
+ alias_method :jira_integration, :object
def project
- jira_service&.project
+ jira_integration&.project
end
def jira_projects(name:)
args = { query: name }.compact
- Jira::Requests::Projects::ListService.new(project.jira_service, args).execute
+ Jira::Requests::Projects::ListService.new(project.jira_integration, args).execute
end
end
end
diff --git a/app/graphql/types/alert_management/alert_sort_enum.rb b/app/graphql/types/alert_management/alert_sort_enum.rb
index 11a5cb95722..b4d09734e30 100644
--- a/app/graphql/types/alert_management/alert_sort_enum.rb
+++ b/app/graphql/types/alert_management/alert_sort_enum.rb
@@ -18,8 +18,8 @@ module Types
value 'EVENT_COUNT_DESC', 'Events count by descending order.', value: :event_count_desc
value 'SEVERITY_ASC', 'Severity from less critical to more critical.', value: :severity_asc
value 'SEVERITY_DESC', 'Severity from more critical to less critical.', value: :severity_desc
- value 'STATUS_ASC', 'Status by order: Ignored > Resolved > Acknowledged > Triggered.', value: :status_asc
- value 'STATUS_DESC', 'Status by order: Triggered > Acknowledged > Resolved > Ignored.', value: :status_desc
+ value 'STATUS_ASC', 'Status by order: `Ignored > Resolved > Acknowledged > Triggered`.', value: :status_asc
+ value 'STATUS_DESC', 'Status by order: `Triggered > Acknowledged > Resolved > Ignored`.', value: :status_desc
end
end
end
diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb
index 5a2a5c68c8d..0ff0775ca86 100644
--- a/app/graphql/types/alert_management/alert_type.rb
+++ b/app/graphql/types/alert_management/alert_type.rb
@@ -8,7 +8,7 @@ module Types
present_using ::AlertManagement::AlertPresenter
- implements(Types::Notes::NoteableType)
+ implements(Types::Notes::NoteableInterface)
authorize :read_alert_management_alert
diff --git a/app/graphql/types/alert_management/integration_type.rb b/app/graphql/types/alert_management/integration_type.rb
index d26d7348765..6cbc17cdbfb 100644
--- a/app/graphql/types/alert_management/integration_type.rb
+++ b/app/graphql/types/alert_management/integration_type.rb
@@ -43,7 +43,7 @@ module Types
definition_methods do
def resolve_type(object, context)
- if object.is_a?(::PrometheusService)
+ if object.is_a?(::Integrations::Prometheus)
Types::AlertManagement::PrometheusIntegrationType
else
Types::AlertManagement::HttpIntegrationType
diff --git a/app/graphql/types/alert_management/prometheus_integration_type.rb b/app/graphql/types/alert_management/prometheus_integration_type.rb
index 79f265f2f1e..27e4832d8f6 100644
--- a/app/graphql/types/alert_management/prometheus_integration_type.rb
+++ b/app/graphql/types/alert_management/prometheus_integration_type.rb
@@ -12,10 +12,10 @@ module Types
authorize :admin_project
- alias_method :prometheus_service, :object
+ alias_method :prometheus_integration, :object
def name
- prometheus_service.title
+ prometheus_integration.title
end
def type
@@ -23,15 +23,15 @@ module Types
end
def token
- prometheus_service.project&.alerting_setting&.token
+ prometheus_integration.project&.alerting_setting&.token
end
def url
- prometheus_service.project && notify_project_prometheus_alerts_url(prometheus_service.project, format: :json)
+ prometheus_integration.project && notify_project_prometheus_alerts_url(prometheus_integration.project, format: :json)
end
def active
- prometheus_service.manual_configuration?
+ prometheus_integration.manual_configuration?
end
end
end
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index 47caf83eb1c..75fdb41ceb6 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -65,7 +65,7 @@ module Types
end
def visible?(context)
- return false if feature_flag.present? && !Feature.enabled?(feature_flag)
+ return false if feature_flag.present? && !Feature.enabled?(feature_flag, default_enabled: :yaml)
super
end
@@ -95,7 +95,15 @@ module Types
end
def feature_documentation_message(key, description)
- "#{description} Available only when feature flag `#{key}` is enabled."
+ message_parts = ["#{description} Available only when feature flag `#{key}` is enabled."]
+
+ message_parts << if Feature::Definition.has_definition?(key) && Feature::Definition.default_enabled?(key)
+ "This flag is enabled by default."
+ else
+ "This flag is disabled by default, because the feature is experimental and is subject to change without notice."
+ end
+
+ message_parts.join(' ')
end
def check_feature_flag(args)
diff --git a/app/graphql/types/boards/board_issue_input_base_type.rb b/app/graphql/types/boards/board_issue_input_base_type.rb
index 633221e61d1..30f4efcd403 100644
--- a/app/graphql/types/boards/board_issue_input_base_type.rb
+++ b/app/graphql/types/boards/board_issue_input_base_type.rb
@@ -6,7 +6,7 @@ module Types
class BoardIssueInputBaseType < BoardIssuableInputBaseType
argument :iids, [GraphQL::STRING_TYPE],
required: false,
- description: 'List of IIDs of issues. For example ["1", "2"].'
+ description: 'List of IIDs of issues. For example `["1", "2"]`.'
argument :milestone_title, GraphQL::STRING_TYPE,
required: false,
diff --git a/app/graphql/types/ci/build_need_type.rb b/app/graphql/types/ci/build_need_type.rb
index 3bd81f8fa8f..19ff758ad1d 100644
--- a/app/graphql/types/ci/build_need_type.rb
+++ b/app/graphql/types/ci/build_need_type.rb
@@ -7,6 +7,8 @@ module Types
class BuildNeedType < BaseObject
graphql_name 'CiBuildNeed'
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the job we need to complete.'
field :name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the job we need to complete.'
end
diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb
index 0b643a6b676..6310a62a103 100644
--- a/app/graphql/types/ci/detailed_status_type.rb
+++ b/app/graphql/types/ci/detailed_status_type.rb
@@ -6,6 +6,9 @@ module Types
class DetailedStatusType < BaseObject
graphql_name 'DetailedStatus'
+ field :id, GraphQL::STRING_TYPE, null: false,
+ description: 'ID for a detailed status.',
+ extras: [:parent]
field :group, GraphQL::STRING_TYPE, null: true,
description: 'Group of the status.'
field :icon, GraphQL::STRING_TYPE, null: true,
@@ -29,6 +32,10 @@ module Types
calls_gitaly: true,
description: 'Action information for the status. This includes method, button title, icon, path, and title.'
+ def id(parent:)
+ "#{object.id}-#{parent.object.object.id}"
+ end
+
def action
if object.has_action?
{
diff --git a/app/graphql/types/ci/group_type.rb b/app/graphql/types/ci/group_type.rb
index d6d4252e8d7..3da183cb842 100644
--- a/app/graphql/types/ci/group_type.rb
+++ b/app/graphql/types/ci/group_type.rb
@@ -6,12 +6,14 @@ module Types
class GroupType < BaseObject
graphql_name 'CiGroup'
+ field :id, GraphQL::STRING_TYPE, null: false,
+ description: 'ID for a group.'
field :name, GraphQL::STRING_TYPE, null: true,
- description: 'Name of the job group.'
+ description: 'Name of the job group.'
field :size, GraphQL::INT_TYPE, null: true,
- description: 'Size of the group.'
+ description: 'Size of the group.'
field :jobs, Ci::JobType.connection_type, null: true,
- description: 'Jobs in group.'
+ description: 'Jobs in group.'
field :detailed_status, Types::Ci::DetailedStatusType, null: true,
description: 'Detailed status of the group.'
diff --git a/app/graphql/types/ci/job_token_scope_type.rb b/app/graphql/types/ci/job_token_scope_type.rb
new file mode 100644
index 00000000000..9f48298e1d3
--- /dev/null
+++ b/app/graphql/types/ci/job_token_scope_type.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ # Authorization is in the resolver based on the parent project
+ module Ci
+ class JobTokenScopeType < BaseObject
+ graphql_name 'CiJobTokenScopeType'
+
+ field :projects, 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
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+end
diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb
index 5ed4d823aee..360ea3ba7a9 100644
--- a/app/graphql/types/ci/job_type.rb
+++ b/app/graphql/types/ci/job_type.rb
@@ -56,7 +56,7 @@ module Types
field :short_sha, type: GraphQL::STRING_TYPE, null: false,
description: 'Short SHA1 ID of the commit.'
field :scheduling_type, GraphQL::STRING_TYPE, null: true,
- description: 'Type of pipeline scheduling. Value is `dag` if the pipeline uses the `needs` keyword, and `stage` otherwise.'
+ description: 'Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise.'
field :commit_path, GraphQL::STRING_TYPE, null: true,
description: 'Path to the commit that triggered the job.'
field :ref_name, GraphQL::STRING_TYPE, null: true,
diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb
index 2eeddaca6ba..f4a6c18f73e 100644
--- a/app/graphql/types/ci/pipeline_type.rb
+++ b/app/graphql/types/ci/pipeline_type.rb
@@ -150,6 +150,9 @@ module Types
description: 'A specific test suite in a pipeline test report.',
resolver: Resolvers::Ci::TestSuiteResolver
+ field :ref, GraphQL::STRING_TYPE, null: true,
+ description: 'Reference to the branch from which the pipeline was triggered.'
+
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 837d91ef765..9c5041b0860 100644
--- a/app/graphql/types/ci/runner_type.rb
+++ b/app/graphql/types/ci/runner_type.rb
@@ -6,6 +6,10 @@ module Types
graphql_name 'CiRunner'
authorize :read_runner
+ JOB_COUNT_LIMIT = 1000
+
+ alias_method :runner, :object
+
field :id, ::Types::GlobalIDType[::Ci::Runner], null: false,
description: 'ID of the runner.'
field :description, GraphQL::STRING_TYPE, null: true,
@@ -21,22 +25,48 @@ module Types
description: 'Indicates the runner is allowed to receive jobs.'
field :status, ::Types::Ci::RunnerStatusEnum, null: false,
description: 'Status of the runner.'
- field :version, GraphQL::STRING_TYPE, null: false,
+ field :version, GraphQL::STRING_TYPE, null: true,
description: 'Version of the runner.'
field :short_sha, GraphQL::STRING_TYPE, null: true,
description: %q(First eight characters of the runner's token used to authenticate new job requests. Used as the runner's unique ID.)
- field :revision, GraphQL::STRING_TYPE, null: false,
+ field :revision, GraphQL::STRING_TYPE, null: true,
description: 'Revision of the runner.'
field :locked, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates the runner is locked.'
field :run_untagged, GraphQL::BOOLEAN_TYPE, null: false,
description: 'Indicates the runner is able to run untagged jobs.'
- field :ip_address, GraphQL::STRING_TYPE, null: false,
+ field :ip_address, GraphQL::STRING_TYPE, null: true,
description: 'IP address of the runner.'
field :runner_type, ::Types::Ci::RunnerTypeEnum, null: false,
description: 'Type of the runner.'
field :tag_list, [GraphQL::STRING_TYPE], null: true,
description: 'Tags associated with the runner.'
+ field :project_count, GraphQL::INT_TYPE, null: true,
+ description: 'Number of projects that the runner is associated with.'
+ field :job_count, GraphQL::INT_TYPE, null: true,
+ description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)."
+
+ def job_count
+ # We limit to 1 above the JOB_COUNT_LIMIT to indicate that more items exist after JOB_COUNT_LIMIT
+ runner.builds.limit(JOB_COUNT_LIMIT + 1).count
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def project_count
+ BatchLoader::GraphQL.for(runner.id).batch(key: :runner_project_count) do |ids, loader, args|
+ counts = ::Ci::Runner.project_type
+ .select(:id, 'COUNT(ci_runner_projects.id) as count')
+ .left_outer_joins(:runner_projects)
+ .where(id: ids)
+ .group(:id)
+ .index_by(&:id)
+
+ ids.each do |id|
+ loader.call(id, counts[id]&.count)
+ end
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/app/graphql/types/ci/stage_type.rb b/app/graphql/types/ci/stage_type.rb
index 1be9e3192a9..ce3edb6c54f 100644
--- a/app/graphql/types/ci/stage_type.rb
+++ b/app/graphql/types/ci/stage_type.rb
@@ -6,22 +6,21 @@ module Types
graphql_name 'CiStage'
authorize :read_commit_status
- field :name,
- type: GraphQL::STRING_TYPE,
- null: true,
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the stage.'
+ field :name, type: GraphQL::STRING_TYPE, null: true,
description: 'Name of the stage.'
- field :groups,
- type: Ci::GroupType.connection_type,
- null: true,
+ field :groups, type: Ci::GroupType.connection_type, null: true,
extras: [:lookahead],
description: 'Group of jobs for the stage.'
- field :detailed_status, Types::Ci::DetailedStatusType,
- null: true,
+ field :detailed_status, Types::Ci::DetailedStatusType, null: true,
description: 'Detailed status of the stage.'
- field :jobs, Ci::JobType.connection_type,
- null: true,
+ field :jobs, Ci::JobType.connection_type, null: true,
description: 'Jobs for the stage.',
method: 'latest_statuses'
+ field :status, GraphQL::STRING_TYPE,
+ null: true,
+ description: 'Status of the pipeline stage.'
def detailed_status
object.detailed_status(current_user)
@@ -54,6 +53,7 @@ module Types
# rubocop: disable CodeReuse/ActiveRecord
def jobs_for_pipeline(pipeline, stage_ids, include_needs)
results = pipeline.latest_statuses.where(stage_id: stage_ids)
+ results = results.preload(:project)
results = results.preload(:needs) if include_needs
results.group_by(&:stage_id)
diff --git a/app/graphql/types/ci/status_action_type.rb b/app/graphql/types/ci/status_action_type.rb
index 9f7299c0270..a06b09735b3 100644
--- a/app/graphql/types/ci/status_action_type.rb
+++ b/app/graphql/types/ci/status_action_type.rb
@@ -5,6 +5,9 @@ module Types
class StatusActionType < BaseObject
graphql_name 'StatusAction'
+ field :id, GraphQL::STRING_TYPE, null: false,
+ description: 'ID for a status action.',
+ extras: [:parent]
field :button_title, GraphQL::STRING_TYPE, null: true,
description: 'Title for the button, for example: Retry this job.'
field :icon, GraphQL::STRING_TYPE, null: true,
@@ -17,6 +20,10 @@ module Types
field :title, GraphQL::STRING_TYPE, null: true,
description: 'Title for the action, for example: Retry.'
+ def id(parent:)
+ "#{parent.parent.object.object.class.name}-#{parent.object.object.id}"
+ end
+
def action_method
object[:method]
end
diff --git a/app/graphql/types/deployment_tier_enum.rb b/app/graphql/types/deployment_tier_enum.rb
new file mode 100644
index 00000000000..7079b98c512
--- /dev/null
+++ b/app/graphql/types/deployment_tier_enum.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Types
+ class DeploymentTierEnum < BaseEnum
+ graphql_name 'DeploymentTier'
+ description 'All environment deployment tiers.'
+
+ value 'PRODUCTION', description: 'Production.', value: :production
+ value 'STAGING', description: 'Staging.', value: :staging
+ value 'TESTING', description: 'Testing.', value: :testing
+ value 'DEVELOPMENT', description: 'Development.', value: :development
+ value 'OTHER', description: 'Other.', value: :other
+ end
+end
diff --git a/app/graphql/types/design_management/design_type.rb b/app/graphql/types/design_management/design_type.rb
index 44e87905f92..2f40bf5ebfd 100644
--- a/app/graphql/types/design_management/design_type.rb
+++ b/app/graphql/types/design_management/design_type.rb
@@ -10,7 +10,7 @@ module Types
alias_method :design, :object
- implements(Types::Notes::NoteableType)
+ implements(Types::Notes::NoteableInterface)
implements(Types::DesignManagement::DesignFields)
implements(Types::CurrentUserTodos)
diff --git a/app/graphql/types/issuable_searchable_field_enum.rb b/app/graphql/types/issuable_searchable_field_enum.rb
new file mode 100644
index 00000000000..88a49504f28
--- /dev/null
+++ b/app/graphql/types/issuable_searchable_field_enum.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Types
+ class IssuableSearchableFieldEnum < BaseEnum
+ graphql_name 'IssuableSearchableField'
+ description 'Fields to perform the search in'
+
+ Issuable::SEARCHABLE_FIELDS.each do |field|
+ value field.upcase, value: field, description: "Search in #{field} field."
+ end
+ end
+end
diff --git a/app/graphql/types/issue_sort_enum.rb b/app/graphql/types/issue_sort_enum.rb
index e730a51b60e..a2390ff01fe 100644
--- a/app/graphql/types/issue_sort_enum.rb
+++ b/app/graphql/types/issue_sort_enum.rb
@@ -10,6 +10,8 @@ module Types
value 'RELATIVE_POSITION_ASC', 'Relative position by ascending order.', value: :relative_position_asc
value 'SEVERITY_ASC', 'Severity from less critical to more critical.', value: :severity_asc
value 'SEVERITY_DESC', 'Severity from more critical to less critical.', value: :severity_desc
+ value 'POPULARITY_ASC', 'Number of upvotes (awarded "thumbs up" emoji) by ascending order.', value: :popularity_asc
+ value 'POPULARITY_DESC', 'Number of upvotes (awarded "thumbs up" emoji) by descending order.', value: :popularity_desc
end
end
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index 0ccd1e2cebd..6ff38273c03 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -6,7 +6,7 @@ module Types
connection_type_class(Types::IssueConnectionType)
- implements(Types::Notes::NoteableType)
+ implements(Types::Notes::NoteableInterface)
implements(Types::CurrentUserTodos)
authorize :read_issue
@@ -127,6 +127,9 @@ module Types
field :timelogs, Types::TimelogType.connection_type, null: false,
description: 'Timelogs on the issue.'
+ field :project_id, GraphQL::INT_TYPE, null: false, method: :project_id,
+ description: 'ID of the issue project.'
+
def author
Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find
end
diff --git a/app/graphql/types/issues/negated_issue_filter_input_type.rb b/app/graphql/types/issues/negated_issue_filter_input_type.rb
index 8a2e75ed9ba..88faf7e7074 100644
--- a/app/graphql/types/issues/negated_issue_filter_input_type.rb
+++ b/app/graphql/types/issues/negated_issue_filter_input_type.rb
@@ -7,7 +7,7 @@ module Types
argument :iids, [GraphQL::STRING_TYPE],
required: false,
- description: 'List of IIDs of issues to exclude. For example, [1, 2].'
+ description: 'List of IIDs of issues to exclude. For example, `[1, 2]`.'
argument :label_name, [GraphQL::STRING_TYPE],
required: false,
description: 'Labels not applied to this issue.'
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 338b70bb0c6..0e9df926cdd 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -6,7 +6,7 @@ module Types
connection_type_class(Types::MergeRequestConnectionType)
- implements(Types::Notes::NoteableType)
+ implements(Types::Notes::NoteableInterface)
implements(Types::CurrentUserTodos)
authorize :read_merge_request
diff --git a/app/graphql/types/milestone_sort_enum.rb b/app/graphql/types/milestone_sort_enum.rb
new file mode 100644
index 00000000000..9f7dedb4c4c
--- /dev/null
+++ b/app/graphql/types/milestone_sort_enum.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ class MilestoneSortEnum < SortEnum
+ graphql_name 'MilestoneSort'
+ description 'Values for sorting milestones'
+
+ value 'DUE_DATE_ASC', 'Milestone due date by ascending order.', value: :due_date_asc
+ value 'DUE_DATE_DESC', 'Milestone due date by descending order.', value: :due_date_desc
+ value 'EXPIRED_LAST_DUE_DATE_ASC', 'Group milestones in this order: non-expired milestones with due dates, non-expired milestones without due dates and expired milestones then sort by due date in ascending order.', value: :expired_last_due_date_asc
+ value 'EXPIRED_LAST_DUE_DATE_DESC', 'Group milestones in this order: non-expired milestones with due dates, non-expired milestones without due dates and expired milestones then sort by due date in descending order.', value: :expired_last_due_date_desc
+ end
+end
diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb
index eafede26c9e..27bc77b4da1 100644
--- a/app/graphql/types/milestone_type.rb
+++ b/app/graphql/types/milestone_type.rb
@@ -26,6 +26,9 @@ module Types
field :state, Types::MilestoneStateEnum, null: false,
description: 'State of the milestone.'
+ field :expired, GraphQL::BOOLEAN_TYPE, null: false,
+ description: 'Expired state of the milestone (a milestone is expired when the due date is past the current date). Defaults to `false` when due date has not been set.'
+
field :web_path, GraphQL::STRING_TYPE, null: false, method: :milestone_path,
description: 'Web path of the milestone.'
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 6d3327f9735..df693fafbb9 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -99,11 +99,14 @@ module Types
mount_mutation Mutations::Ci::CiCdSettingsUpdate
mount_mutation Mutations::Ci::Job::Play
mount_mutation Mutations::Ci::Job::Retry
+ mount_mutation Mutations::Ci::JobTokenScope::AddProject
+ mount_mutation Mutations::Ci::JobTokenScope::RemoveProject
mount_mutation Mutations::Ci::Runner::Update, feature_flag: :runner_graphql_query
mount_mutation Mutations::Ci::Runner::Delete, feature_flag: :runner_graphql_query
mount_mutation Mutations::Ci::RunnersRegistrationToken::Reset, feature_flag: :runner_graphql_query
mount_mutation Mutations::Namespace::PackageSettings::Update
mount_mutation Mutations::UserCallouts::Create
+ mount_mutation Mutations::Packages::Destroy
mount_mutation Mutations::Echo
end
end
diff --git a/app/graphql/types/noteable_type.rb b/app/graphql/types/noteable_type.rb
new file mode 100644
index 00000000000..859de86d6b8
--- /dev/null
+++ b/app/graphql/types/noteable_type.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Types
+ class NoteableType < BaseUnion
+ graphql_name 'NoteableType'
+ description 'Represents an object that supports notes.'
+
+ possible_types Types::IssueType, Types::DesignManagement::DesignType, Types::MergeRequestType
+
+ def self.resolve_type(object, context)
+ case object
+ when Issue
+ Types::IssueType
+ when ::DesignManagement::Design
+ Types::DesignManagement::DesignType
+ when MergeRequest
+ Types::MergeRequestType
+ else
+ raise 'Unsupported issuable type'
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/notes/discussion_type.rb b/app/graphql/types/notes/discussion_type.rb
index 17cb4debd63..56579c357a7 100644
--- a/app/graphql/types/notes/discussion_type.rb
+++ b/app/graphql/types/notes/discussion_type.rb
@@ -19,6 +19,8 @@ module Types
description: "Timestamp of the discussion's creation."
field :notes, Types::Notes::NoteType.connection_type, null: false,
description: 'All notes in the discussion.'
+ field :noteable, Types::NoteableType, null: true,
+ description: 'Object which the discussion belongs to.'
# DiscussionID.coerce_result is suitable here, but will always mark this
# as being a 'Discussion'. Using `GlobalId.build` guarantees that we get
@@ -26,6 +28,14 @@ module Types
def reply_id
::Gitlab::GlobalId.build(object, id: object.reply_id)
end
+
+ def noteable
+ noteable = object.noteable
+
+ return unless Ability.allowed?(context[:current_user], :"read_#{noteable.to_ability_name}", noteable)
+
+ noteable
+ end
end
end
end
diff --git a/app/graphql/types/notes/noteable_type.rb b/app/graphql/types/notes/noteable_interface.rb
index a82a76f9c87..bd22f12d6f0 100644
--- a/app/graphql/types/notes/noteable_type.rb
+++ b/app/graphql/types/notes/noteable_interface.rb
@@ -2,7 +2,7 @@
module Types
module Notes
- module NoteableType
+ module NoteableInterface
include Types::BaseInterface
field :notes, Types::Notes::NoteType.connection_type, null: false, description: "All notes on this noteable."
@@ -28,4 +28,4 @@ module Types
end
end
-Types::Notes::NoteableType.prepend_mod_with('Types::Notes::NoteableType')
+Types::Notes::NoteableInterface.prepend_mod_with('Types::Notes::NoteableInterface')
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 55dc73d898d..968635f9e6e 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -59,8 +59,6 @@ module Types
field :visibility, GraphQL::STRING_TYPE, null: true,
description: 'Visibility of the project.'
- field :container_registry_enabled, GraphQL::BOOLEAN_TYPE, null: true,
- description: 'Indicates if the project stores Docker container images in a container registry.'
field :shared_runners_enabled, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if shared runners are enabled for the project.'
field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true,
@@ -77,9 +75,15 @@ module Types
field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true,
description: 'URL to avatar image file of the project.'
- %i[issues merge_requests wiki snippets].each do |feature|
+ {
+ issues: "Issues are",
+ merge_requests: "Merge Requests are",
+ wiki: 'Wikis are',
+ snippets: 'Snippets are',
+ container_registry: 'Container Registry is'
+ }.each do |feature, name_string|
field "#{feature}_enabled", GraphQL::BOOLEAN_TYPE, null: true,
- description: "Indicates if #{feature.to_s.titleize.pluralize} are enabled for the current user"
+ description: "Indicates if #{name_string} enabled for the current user"
define_method "#{feature}_enabled" do
object.feature_available?(feature, context[:current_user])
@@ -346,6 +350,10 @@ module Types
description: 'Find a single CI/CD template by name.',
resolver: Resolvers::Ci::TemplateResolver
+ field :ci_job_token_scope, Types::Ci::JobTokenScopeType, null: true,
+ description: 'The CI Job Tokens scope of access.',
+ resolver: Resolvers::Ci::JobTokenScopeResolver
+
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args|
LabelsFinder
diff --git a/app/graphql/types/projects/service_type_enum.rb b/app/graphql/types/projects/service_type_enum.rb
index 9948fa8bb69..027026dc16c 100644
--- a/app/graphql/types/projects/service_type_enum.rb
+++ b/app/graphql/types/projects/service_type_enum.rb
@@ -5,7 +5,7 @@ module Types
class ServiceTypeEnum < BaseEnum
graphql_name 'ServiceType'
- ::Integration.available_services_types(include_dev: false).each do |type|
+ ::Integration.available_integration_types(include_dev: false).each do |type|
value type.underscore.upcase, value: type, description: "#{type} type"
end
end
diff --git a/app/graphql/types/query_complexity_type.rb b/app/graphql/types/query_complexity_type.rb
new file mode 100644
index 00000000000..82809fac22f
--- /dev/null
+++ b/app/graphql/types/query_complexity_type.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ class QueryComplexityType < ::Types::BaseObject
+ ANALYZER = GraphQL::Analysis::QueryComplexity.new { |_query, complexity| complexity }
+
+ graphql_name 'QueryComplexity'
+
+ alias_method :query, :object
+
+ field :limit, GraphQL::INT_TYPE,
+ null: true,
+ method: :max_complexity,
+ see: {
+ 'GitLab documentation on this limit' =>
+ 'https://docs.gitlab.com/ee/api/graphql/index.html#max-query-complexity'
+ },
+ description: 'GraphQL query complexity limit.'
+
+ field :score, GraphQL::INT_TYPE,
+ null: true,
+ description: 'GraphQL query complexity score.'
+
+ def score
+ ::GraphQL::Analysis.analyze_query(query, [ANALYZER]).first
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 8b7b9f0107b..d2c67aea95c 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -36,6 +36,10 @@ module Types
resolver: Resolvers::MetadataResolver,
description: 'Metadata about GitLab.'
+ field :query_complexity, Types::QueryComplexityType,
+ null: true,
+ description: 'Information about the complexity of the GraphQL query.'
+
field :snippets,
Types::SnippetType.connection_type,
null: true,
@@ -170,6 +174,10 @@ module Types
def application_settings
Gitlab::CurrentSettings.current_application_settings
end
+
+ def query_complexity
+ context.query
+ end
end
end
diff --git a/app/graphql/types/release_asset_link_type.rb b/app/graphql/types/release_asset_link_type.rb
index c27e1cf19b3..829e7e246db 100644
--- a/app/graphql/types/release_asset_link_type.rb
+++ b/app/graphql/types/release_asset_link_type.rb
@@ -20,6 +20,8 @@ module Types
field :direct_asset_url, GraphQL::STRING_TYPE, null: true,
description: 'Direct asset URL of the link.'
+ field :direct_asset_path, GraphQL::STRING_TYPE, null: true, method: :filepath,
+ description: 'Relative path for the direct asset link.'
def direct_asset_url
return object.url unless object.filepath
diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb
index 34357ead048..7606bdbc46d 100644
--- a/app/graphql/types/snippet_type.rb
+++ b/app/graphql/types/snippet_type.rb
@@ -5,7 +5,7 @@ module Types
graphql_name 'Snippet'
description 'Represents a snippet entry'
- implements(Types::Notes::NoteableType)
+ implements(Types::Notes::NoteableInterface)
present_using SnippetPresenter
diff --git a/app/graphql/types/snippets/blob_type.rb b/app/graphql/types/snippets/blob_type.rb
index fb9ee380705..1335838935e 100644
--- a/app/graphql/types/snippets/blob_type.rb
+++ b/app/graphql/types/snippets/blob_type.rb
@@ -16,6 +16,10 @@ module Types
description: 'Blob plain highlighted data.',
null: true
+ field :raw_plain_data, GraphQL::STRING_TYPE,
+ description: 'The raw content of the blob, if the blob is text data.',
+ null: true
+
field :raw_path, GraphQL::STRING_TYPE,
description: 'Blob raw content endpoint path.',
null: false
diff --git a/app/graphql/types/user_callout_type.rb b/app/graphql/types/user_callout_type.rb
index 12f4fdea878..0ff32d68400 100644
--- a/app/graphql/types/user_callout_type.rb
+++ b/app/graphql/types/user_callout_type.rb
@@ -4,7 +4,7 @@ module Types
class UserCalloutType < BaseObject # rubocop:disable Graphql/AuthorizeTypes
graphql_name 'UserCallout'
- field :feature_name, UserCalloutFeatureNameEnum, null: false,
+ field :feature_name, UserCalloutFeatureNameEnum, null: true,
description: 'Name of the feature that the callout is for.'
field :dismissed_at, Types::TimeType, null: true,
description: 'Date when the callout was dismissed.'