summaryrefslogtreecommitdiff
path: root/app/graphql
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-19 01:45:44 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-19 01:45:44 +0000
commit85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch)
tree9160f299afd8c80c038f08e1545be119f5e3f1e1 /app/graphql
parent15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff)
downloadgitlab-ce-85dc423f7090da0a52c73eb66faf22ddb20efff9.tar.gz
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'app/graphql')
-rw-r--r--app/graphql/gitlab_schema.rb4
-rw-r--r--app/graphql/mutations/alert_management/alerts/set_assignees.rb2
-rw-r--r--app/graphql/mutations/alert_management/alerts/todo/create.rb2
-rw-r--r--app/graphql/mutations/alert_management/base.rb1
-rw-r--r--app/graphql/mutations/alert_management/create_alert_issue.rb2
-rw-r--r--app/graphql/mutations/alert_management/update_alert_status.rb2
-rw-r--r--app/graphql/mutations/award_emojis/toggle.rb2
-rw-r--r--app/graphql/mutations/base_mutation.rb4
-rw-r--r--app/graphql/mutations/boards/destroy.rb37
-rw-r--r--app/graphql/mutations/boards/issues/issue_move_list.rb8
-rw-r--r--app/graphql/mutations/boards/lists/base.rb2
-rw-r--r--app/graphql/mutations/boards/lists/create.rb9
-rw-r--r--app/graphql/mutations/ci/base.rb17
-rw-r--r--app/graphql/mutations/ci/pipeline_cancel.rb22
-rw-r--r--app/graphql/mutations/ci/pipeline_destroy.rb22
-rw-r--r--app/graphql/mutations/ci/pipeline_retry.rb27
-rw-r--r--app/graphql/mutations/concerns/mutations/authorizes_project.rb17
-rw-r--r--app/graphql/mutations/design_management/move.rb4
-rw-r--r--app/graphql/mutations/issues/set_severity.rb25
-rw-r--r--app/graphql/mutations/merge_requests/set_wip.rb4
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/delete.rb2
-rw-r--r--app/graphql/mutations/snippets/create.rb13
-rw-r--r--app/graphql/mutations/snippets/update.rb13
-rw-r--r--app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb37
-rw-r--r--app/graphql/resolvers/board_list_issues_resolver.rb10
-rw-r--r--app/graphql/resolvers/concerns/board_issue_filterable.rb24
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb (renamed from app/graphql/resolvers/concerns/issue_resolver_fields.rb)6
-rw-r--r--app/graphql/resolvers/concerns/looks_ahead.rb2
-rw-r--r--app/graphql/resolvers/group_members_resolver.rb19
-rw-r--r--app/graphql/resolvers/issue_status_counts_resolver.rb19
-rw-r--r--app/graphql/resolvers/issues_resolver.rb14
-rw-r--r--app/graphql/resolvers/members_resolver.rb24
-rw-r--r--app/graphql/resolvers/merge_request_pipelines_resolver.rb2
-rw-r--r--app/graphql/resolvers/merge_requests_resolver.rb15
-rw-r--r--app/graphql/resolvers/metrics/dashboard_resolver.rb3
-rw-r--r--app/graphql/resolvers/namespace_projects_resolver.rb22
-rw-r--r--app/graphql/resolvers/project_members_resolver.rb16
-rw-r--r--app/graphql/resolvers/project_merge_requests_resolver.rb12
-rw-r--r--app/graphql/resolvers/projects_resolver.rb10
-rw-r--r--app/graphql/resolvers/user_starred_projects_resolver.rb17
-rw-r--r--app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb21
-rw-r--r--app/graphql/types/admin/analytics/instance_statistics/measurement_type.rb24
-rw-r--r--app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb2
-rw-r--r--app/graphql/types/alert_management/alert_type.rb2
-rw-r--r--app/graphql/types/award_emojis/award_emoji_type.rb2
-rw-r--r--app/graphql/types/base_enum.rb3
-rw-r--r--app/graphql/types/base_field.rb53
-rw-r--r--app/graphql/types/board_list_type.rb2
-rw-r--r--app/graphql/types/boards/board_issue_input_base_type.rb35
-rw-r--r--app/graphql/types/boards/board_issue_input_type.rb24
-rw-r--r--app/graphql/types/ci/pipeline_config_source_enum.rb2
-rw-r--r--app/graphql/types/ci/pipeline_type.rb10
-rw-r--r--app/graphql/types/concerns/gitlab_style_deprecations.rb31
-rw-r--r--app/graphql/types/current_user_todos.rb24
-rw-r--r--app/graphql/types/design_management/design_at_version_type.rb4
-rw-r--r--app/graphql/types/design_management/design_collection_type.rb2
-rw-r--r--app/graphql/types/design_management/design_type.rb1
-rw-r--r--app/graphql/types/error_tracking/sentry_detailed_error_type.rb2
-rw-r--r--app/graphql/types/error_tracking/sentry_error_collection_type.rb4
-rw-r--r--app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb2
-rw-r--r--app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb2
-rw-r--r--app/graphql/types/error_tracking/sentry_error_type.rb2
-rw-r--r--app/graphql/types/group_member_type.rb2
-rw-r--r--app/graphql/types/group_type.rb6
-rw-r--r--app/graphql/types/issuable_severity_enum.rb12
-rw-r--r--app/graphql/types/issue_status_counts_type.rb2
-rw-r--r--app/graphql/types/issue_type.rb15
-rw-r--r--app/graphql/types/jira_user_type.rb2
-rw-r--r--app/graphql/types/member_interface.rb19
-rw-r--r--app/graphql/types/merge_request_sort_enum.rb11
-rw-r--r--app/graphql/types/merge_request_type.rb8
-rw-r--r--app/graphql/types/metrics/dashboard_type.rb7
-rw-r--r--app/graphql/types/milestone_type.rb4
-rw-r--r--app/graphql/types/mutation_operation_mode_enum.rb2
-rw-r--r--app/graphql/types/mutation_type.rb5
-rw-r--r--app/graphql/types/permission_types/merge_request.rb4
-rw-r--r--app/graphql/types/project_member_type.rb9
-rw-r--r--app/graphql/types/project_type.rb8
-rw-r--r--app/graphql/types/projects/namespace_project_sort_enum.rb12
-rw-r--r--app/graphql/types/query_type.rb15
-rw-r--r--app/graphql/types/release_asset_link_type.rb12
-rw-r--r--app/graphql/types/release_type.rb4
-rw-r--r--app/graphql/types/todo_type.rb2
-rw-r--r--app/graphql/types/user_type.rb3
84 files changed, 778 insertions, 133 deletions
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb
index d8967da9f57..2f5043f9ffa 100644
--- a/app/graphql/gitlab_schema.rb
+++ b/app/graphql/gitlab_schema.rb
@@ -116,11 +116,11 @@ class GitlabSchema < GraphQL::Schema
expected_type = ctx[:expected_type]
gid = GlobalID.parse(global_id)
- raise Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid GitLab id." unless gid
+ raise Gitlab::Graphql::Errors::ArgumentError, "#{global_id} is not a valid GitLab ID." unless gid
if expected_type && !gid.model_class.ancestors.include?(expected_type)
vars = { global_id: global_id, expected_type: expected_type }
- msg = _('%{global_id} is not a valid id for %{expected_type}.') % vars
+ msg = _('%{global_id} is not a valid ID for %{expected_type}.') % vars
raise Gitlab::Graphql::Errors::ArgumentError, msg
end
diff --git a/app/graphql/mutations/alert_management/alerts/set_assignees.rb b/app/graphql/mutations/alert_management/alerts/set_assignees.rb
index 1e0c9fdeeaf..517c20a85d0 100644
--- a/app/graphql/mutations/alert_management/alerts/set_assignees.rb
+++ b/app/graphql/mutations/alert_management/alerts/set_assignees.rb
@@ -20,6 +20,8 @@ module Mutations
alert = authorized_find!(project_path: args[:project_path], iid: args[:iid])
result = set_assignees(alert, args[:assignee_usernames], args[:operation_mode])
+ track_usage_event(:incident_management_alert_assigned, current_user.id)
+
prepare_response(result)
end
diff --git a/app/graphql/mutations/alert_management/alerts/todo/create.rb b/app/graphql/mutations/alert_management/alerts/todo/create.rb
index 3dba96e43f1..2a1056e8f64 100644
--- a/app/graphql/mutations/alert_management/alerts/todo/create.rb
+++ b/app/graphql/mutations/alert_management/alerts/todo/create.rb
@@ -11,6 +11,8 @@ module Mutations
alert = authorized_find!(project_path: args[:project_path], iid: args[:iid])
result = ::AlertManagement::Alerts::Todo::CreateService.new(alert, current_user).execute
+ track_usage_event(:incident_management_alert_todo, current_user.id)
+
prepare_response(result)
end
diff --git a/app/graphql/mutations/alert_management/base.rb b/app/graphql/mutations/alert_management/base.rb
index 0de4b9409e4..0ccfcf34180 100644
--- a/app/graphql/mutations/alert_management/base.rb
+++ b/app/graphql/mutations/alert_management/base.rb
@@ -3,6 +3,7 @@
module Mutations
module AlertManagement
class Base < BaseMutation
+ include Gitlab::Utils::UsageData
include ResolvesProject
argument :project_path, GraphQL::ID_TYPE,
diff --git a/app/graphql/mutations/alert_management/create_alert_issue.rb b/app/graphql/mutations/alert_management/create_alert_issue.rb
index adb048a4479..2ddb94700c2 100644
--- a/app/graphql/mutations/alert_management/create_alert_issue.rb
+++ b/app/graphql/mutations/alert_management/create_alert_issue.rb
@@ -9,6 +9,8 @@ module Mutations
alert = authorized_find!(project_path: args[:project_path], iid: args[:iid])
result = create_alert_issue(alert, current_user)
+ track_usage_event(:incident_management_incident_created, current_user.id)
+
prepare_response(alert, result)
end
diff --git a/app/graphql/mutations/alert_management/update_alert_status.rb b/app/graphql/mutations/alert_management/update_alert_status.rb
index ed61555fbd6..1e14bae048a 100644
--- a/app/graphql/mutations/alert_management/update_alert_status.rb
+++ b/app/graphql/mutations/alert_management/update_alert_status.rb
@@ -13,6 +13,8 @@ module Mutations
alert = authorized_find!(project_path: args[:project_path], iid: args[:iid])
result = update_status(alert, args[:status])
+ track_usage_event(:incident_management_alert_status_changed, current_user.id)
+
prepare_response(result)
end
diff --git a/app/graphql/mutations/award_emojis/toggle.rb b/app/graphql/mutations/award_emojis/toggle.rb
index a7714e695d2..679ec7a14ff 100644
--- a/app/graphql/mutations/award_emojis/toggle.rb
+++ b/app/graphql/mutations/award_emojis/toggle.rb
@@ -5,7 +5,7 @@ module Mutations
class Toggle < Base
graphql_name 'AwardEmojiToggle'
- field :toggledOn, GraphQL::BOOLEAN_TYPE, null: false,
+ field :toggled_on, GraphQL::BOOLEAN_TYPE, null: false,
description: 'Indicates the status of the emoji. ' \
'True if the toggle awarded the emoji, and false if the toggle removed the emoji.'
diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb
index 68e7853a9b1..577f10545b3 100644
--- a/app/graphql/mutations/base_mutation.rb
+++ b/app/graphql/mutations/base_mutation.rb
@@ -17,6 +17,10 @@ module Mutations
context[:current_user]
end
+ def api_user?
+ context[:is_sessionless_user]
+ end
+
# Returns Array of errors on an ActiveRecord object
def errors_on_object(record)
record.errors.full_messages
diff --git a/app/graphql/mutations/boards/destroy.rb b/app/graphql/mutations/boards/destroy.rb
new file mode 100644
index 00000000000..7c381113d38
--- /dev/null
+++ b/app/graphql/mutations/boards/destroy.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Boards
+ class Destroy < ::Mutations::BaseMutation
+ graphql_name 'DestroyBoard'
+
+ field :board,
+ Types::BoardType,
+ null: true,
+ description: 'The board after mutation'
+ argument :id,
+ ::Types::GlobalIDType[::Board],
+ required: true,
+ description: 'The global ID of the board to destroy'
+
+ authorize :admin_board
+
+ def resolve(id:)
+ board = authorized_find!(id: id)
+
+ response = ::Boards::DestroyService.new(board.resource_parent, current_user).execute(board)
+
+ {
+ board: response.success? ? nil : board,
+ errors: response.errors
+ }
+ end
+
+ private
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::Board)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/boards/issues/issue_move_list.rb b/app/graphql/mutations/boards/issues/issue_move_list.rb
index d4bf47af4cf..813b6d3cb2a 100644
--- a/app/graphql/mutations/boards/issues/issue_move_list.rb
+++ b/app/graphql/mutations/boards/issues/issue_move_list.rb
@@ -29,11 +29,11 @@ module Mutations
argument :move_before_id, GraphQL::ID_TYPE,
required: false,
- description: 'ID of issue before which the current issue will be positioned at'
+ description: 'ID of issue that should be placed before the current issue'
argument :move_after_id, GraphQL::ID_TYPE,
required: false,
- description: 'ID of issue after which the current issue will be positioned at'
+ description: 'ID of issue that should be placed after the current issue'
def ready?(**args)
if move_arguments(args).blank?
@@ -50,6 +50,8 @@ module Mutations
end
def resolve(board:, **args)
+ Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/247861')
+
raise_resource_not_available_error! unless board
authorize_board!(board)
@@ -89,3 +91,5 @@ module Mutations
end
end
end
+
+Mutations::Boards::Issues::IssueMoveList.prepend_if_ee('EE::Mutations::Boards::Issues::IssueMoveList')
diff --git a/app/graphql/mutations/boards/lists/base.rb b/app/graphql/mutations/boards/lists/base.rb
index 34b271ba3b8..d244d6bf8dd 100644
--- a/app/graphql/mutations/boards/lists/base.rb
+++ b/app/graphql/mutations/boards/lists/base.rb
@@ -8,7 +8,7 @@ module Mutations
argument :board_id, ::Types::GlobalIDType[::Board],
required: true,
- description: 'The Global ID of the issue board to mutate'
+ description: 'Global ID of the issue board to mutate'
field :list,
Types::BoardListType,
diff --git a/app/graphql/mutations/boards/lists/create.rb b/app/graphql/mutations/boards/lists/create.rb
index 4f545709ee9..3fe1052315f 100644
--- a/app/graphql/mutations/boards/lists/create.rb
+++ b/app/graphql/mutations/boards/lists/create.rb
@@ -12,7 +12,7 @@ module Mutations
argument :label_id, ::Types::GlobalIDType[::Label],
required: false,
- description: 'ID of an existing label'
+ description: 'Global ID of an existing label'
def ready?(**args)
if args.slice(*mutually_exclusive_args).size != 1
@@ -39,6 +39,7 @@ module Mutations
private
+ # Overridden in EE
def authorize_list_type_resource!(board, params)
return unless params[:label_id]
@@ -57,13 +58,15 @@ module Mutations
create_list_service.execute(board)
end
+ # Overridden in EE
def create_list_params(args)
params = args.slice(*mutually_exclusive_args).with_indifferent_access
- params[:label_id] = GitlabSchema.parse_gid(params[:label_id]).model_id if params[:label_id]
+ params[:label_id] &&= ::GitlabSchema.parse_gid(params[:label_id], expected_type: ::Label).model_id
params
end
+ # Overridden in EE
def mutually_exclusive_args
[:backlog, :label_id]
end
@@ -71,3 +74,5 @@ module Mutations
end
end
end
+
+Mutations::Boards::Lists::Create.prepend_if_ee('::EE::Mutations::Boards::Lists::Create')
diff --git a/app/graphql/mutations/ci/base.rb b/app/graphql/mutations/ci/base.rb
new file mode 100644
index 00000000000..09df4487a50
--- /dev/null
+++ b/app/graphql/mutations/ci/base.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ class Base < BaseMutation
+ argument :id, ::Types::GlobalIDType[::Ci::Pipeline],
+ required: true,
+ description: 'The id of the pipeline to mutate'
+
+ private
+
+ def find_object(id:)
+ GlobalID::Locator.locate(id)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/pipeline_cancel.rb b/app/graphql/mutations/ci/pipeline_cancel.rb
new file mode 100644
index 00000000000..bc881e2ac02
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_cancel.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ class PipelineCancel < Base
+ graphql_name 'PipelineCancel'
+
+ authorize :update_pipeline
+
+ def resolve(id:)
+ pipeline = authorized_find!(id: id)
+
+ if pipeline.cancelable?
+ pipeline.cancel_running
+ { success: true, errors: [] }
+ else
+ { success: false, errors: ['Pipeline is not cancelable'] }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/pipeline_destroy.rb b/app/graphql/mutations/ci/pipeline_destroy.rb
new file mode 100644
index 00000000000..bb24d416583
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_destroy.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ class PipelineDestroy < Base
+ graphql_name 'PipelineDestroy'
+
+ authorize :destroy_pipeline
+
+ def resolve(id:)
+ pipeline = authorized_find!(id: id)
+ project = pipeline.project
+
+ result = ::Ci::DestroyPipelineService.new(project, current_user).execute(pipeline)
+ {
+ success: result.success?,
+ errors: result.errors
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/pipeline_retry.rb b/app/graphql/mutations/ci/pipeline_retry.rb
new file mode 100644
index 00000000000..0669bfc449c
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_retry.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ class PipelineRetry < Base
+ graphql_name 'PipelineRetry'
+
+ field :pipeline,
+ Types::Ci::PipelineType,
+ null: true,
+ description: 'The pipeline after mutation'
+
+ authorize :update_pipeline
+
+ def resolve(id:)
+ pipeline = authorized_find!(id: id)
+ project = pipeline.project
+
+ ::Ci::RetryPipelineService.new(project, current_user).execute(pipeline)
+ {
+ pipeline: pipeline,
+ errors: errors_on_object(pipeline)
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/concerns/mutations/authorizes_project.rb b/app/graphql/mutations/concerns/mutations/authorizes_project.rb
new file mode 100644
index 00000000000..87341525d6c
--- /dev/null
+++ b/app/graphql/mutations/concerns/mutations/authorizes_project.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AuthorizesProject
+ include ResolvesProject
+
+ def authorized_find_project!(full_path:)
+ authorized_find!(full_path: full_path)
+ end
+
+ private
+
+ def find_object(full_path:)
+ resolve_project(full_path: full_path)
+ end
+ end
+end
diff --git a/app/graphql/mutations/design_management/move.rb b/app/graphql/mutations/design_management/move.rb
index 0b654447844..6126af8b68b 100644
--- a/app/graphql/mutations/design_management/move.rb
+++ b/app/graphql/mutations/design_management/move.rb
@@ -20,10 +20,6 @@ module Mutations
null: true,
description: "The current state of the collection"
- def ready(*)
- raise ::Gitlab::Graphql::Errors::ResourceNotAvailable unless ::Feature.enabled?(:reorder_designs, default_enabled: true)
- end
-
def resolve(**args)
service = ::DesignManagement::MoveDesignsService.new(current_user, parameters(args))
diff --git a/app/graphql/mutations/issues/set_severity.rb b/app/graphql/mutations/issues/set_severity.rb
new file mode 100644
index 00000000000..bc386e07178
--- /dev/null
+++ b/app/graphql/mutations/issues/set_severity.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Issues
+ class SetSeverity < Base
+ graphql_name 'IssueSetSeverity'
+
+ argument :severity, Types::IssuableSeverityEnum, required: true,
+ description: 'Set the incident severity level.'
+
+ def resolve(project_path:, iid:, severity:)
+ issue = authorized_find!(project_path: project_path, iid: iid)
+ project = issue.project
+
+ ::Issues::UpdateService.new(project, current_user, severity: severity)
+ .execute(issue)
+
+ {
+ issue: issue,
+ errors: errors_on_object(issue)
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/merge_requests/set_wip.rb b/app/graphql/mutations/merge_requests/set_wip.rb
index 5d2077c12f2..0b5c20de377 100644
--- a/app/graphql/mutations/merge_requests/set_wip.rb
+++ b/app/graphql/mutations/merge_requests/set_wip.rb
@@ -9,8 +9,8 @@ module Mutations
GraphQL::BOOLEAN_TYPE,
required: true,
description: <<~DESC
- Whether or not to set the merge request as a WIP.
- DESC
+ Whether or not to set the merge request as a WIP.
+ DESC
def resolve(project_path:, iid:, wip: nil)
merge_request = authorized_find!(project_path: project_path, iid: iid)
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
index fb828ba0e2f..6e183e78d9b 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/delete.rb
@@ -12,7 +12,7 @@ module Mutations
argument :id,
GraphQL::ID_TYPE,
required: true,
- description: 'The global id of the annotation to delete'
+ description: 'The global ID of the annotation to delete'
def resolve(id:)
annotation = authorized_find!(id: id)
diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb
index a068fd806f5..a8aeb15afcd 100644
--- a/app/graphql/mutations/snippets/create.rb
+++ b/app/graphql/mutations/snippets/create.rb
@@ -16,14 +16,6 @@ module Mutations
required: true,
description: 'Title of the snippet'
- argument :file_name, GraphQL::STRING_TYPE,
- required: false,
- description: 'File name of the snippet'
-
- argument :content, GraphQL::STRING_TYPE,
- required: false,
- description: 'Content of the snippet'
-
argument :description, GraphQL::STRING_TYPE,
required: false,
description: 'Description of the snippet'
@@ -59,6 +51,11 @@ module Mutations
snippet = service_response.payload[:snippet]
+ # Only when the user is not an api user and the operation was successful
+ if !api_user? && service_response.success?
+ ::Gitlab::UsageDataCounters::EditorUniqueCounter.track_snippet_editor_edit_action(author: current_user)
+ end
+
{
snippet: service_response.success? ? snippet : nil,
errors: errors_on_object(snippet)
diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb
index 6ff632ec008..d0db5fa2eb9 100644
--- a/app/graphql/mutations/snippets/update.rb
+++ b/app/graphql/mutations/snippets/update.rb
@@ -14,14 +14,6 @@ module Mutations
required: false,
description: 'Title of the snippet'
- argument :file_name, GraphQL::STRING_TYPE,
- required: false,
- description: 'File name of the snippet'
-
- argument :content, GraphQL::STRING_TYPE,
- required: false,
- description: 'Content of the snippet'
-
argument :description, GraphQL::STRING_TYPE,
required: false,
description: 'Description of the snippet'
@@ -42,6 +34,11 @@ module Mutations
update_params(args)).execute(snippet)
snippet = result.payload[:snippet]
+ # Only when the user is not an api user and the operation was successful
+ if !api_user? && result.success?
+ ::Gitlab::UsageDataCounters::EditorUniqueCounter.track_snippet_editor_edit_action(author: current_user)
+ end
+
{
snippet: result.success? ? snippet : snippet.reset,
errors: errors_on_object(snippet)
diff --git a/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb b/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb
new file mode 100644
index 00000000000..aea3afa8ec5
--- /dev/null
+++ b/app/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Admin
+ module Analytics
+ module InstanceStatistics
+ class MeasurementsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::Admin::Analytics::InstanceStatistics::MeasurementType, null: true
+
+ argument :identifier, Types::Admin::Analytics::InstanceStatistics::MeasurementIdentifierEnum,
+ required: true,
+ description: 'The type of measurement/statistics to retrieve'
+
+ def resolve(identifier:)
+ authorize!
+
+ ::Analytics::InstanceStatistics::Measurement
+ .with_identifier(identifier)
+ .order_by_latest
+ end
+
+ private
+
+ def authorize!
+ admin? || raise_resource_not_available_error!
+ end
+
+ def admin?
+ context[:current_user].present? && context[:current_user].admin?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/board_list_issues_resolver.rb b/app/graphql/resolvers/board_list_issues_resolver.rb
index a7cc367379d..dba9f99edeb 100644
--- a/app/graphql/resolvers/board_list_issues_resolver.rb
+++ b/app/graphql/resolvers/board_list_issues_resolver.rb
@@ -2,12 +2,20 @@
module Resolvers
class BoardListIssuesResolver < BaseResolver
+ include BoardIssueFilterable
+
+ argument :filters, Types::Boards::BoardIssueInputType,
+ required: false,
+ description: 'Filters applied when selecting issues in the board list'
+
type Types::IssueType, null: true
alias_method :list, :object
def resolve(**args)
- service = Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], { board_id: list.board.id, id: list.id })
+ filter_params = issue_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)
+
Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection.new(service.execute)
end
diff --git a/app/graphql/resolvers/concerns/board_issue_filterable.rb b/app/graphql/resolvers/concerns/board_issue_filterable.rb
new file mode 100644
index 00000000000..1541738f46c
--- /dev/null
+++ b/app/graphql/resolvers/concerns/board_issue_filterable.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module BoardIssueFilterable
+ extend ActiveSupport::Concern
+
+ private
+
+ def issue_filters(args)
+ filters = args.to_h
+ set_filter_values(filters)
+
+ if filters[:not]
+ filters[:not] = filters[:not].to_h
+ set_filter_values(filters[:not])
+ end
+
+ filters
+ end
+
+ def set_filter_values(filters)
+ end
+end
+
+::BoardIssueFilterable.prepend_if_ee('::EE::Resolvers::BoardIssueFilterable')
diff --git a/app/graphql/resolvers/concerns/issue_resolver_fields.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index bf2f510dd89..2b14d8275d1 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_fields.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -1,9 +1,11 @@
# frozen_string_literal: true
-module IssueResolverFields
+module IssueResolverArguments
extend ActiveSupport::Concern
prepended do
+ include LooksAhead
+
argument :iid, GraphQL::STRING_TYPE,
required: false,
description: 'IID of the issue. For example, "1"'
@@ -49,7 +51,7 @@ module IssueResolverFields
required: false
end
- def resolve(**args)
+ def resolve_with_lookahead(**args)
# The project could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` of the project to query for issues, so
# make sure it's loaded and not `nil` before continuing.
diff --git a/app/graphql/resolvers/concerns/looks_ahead.rb b/app/graphql/resolvers/concerns/looks_ahead.rb
index becc6debd33..e7230287e13 100644
--- a/app/graphql/resolvers/concerns/looks_ahead.rb
+++ b/app/graphql/resolvers/concerns/looks_ahead.rb
@@ -46,7 +46,7 @@ module LooksAhead
if lookahead.selects?(:nodes)
lookahead.selection(:nodes)
elsif lookahead.selects?(:edges)
- lookahead.selection(:edges).selection(:nodes)
+ lookahead.selection(:edges).selection(:node)
end
end
end
diff --git a/app/graphql/resolvers/group_members_resolver.rb b/app/graphql/resolvers/group_members_resolver.rb
new file mode 100644
index 00000000000..f34c873a8a9
--- /dev/null
+++ b/app/graphql/resolvers/group_members_resolver.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class GroupMembersResolver < MembersResolver
+ authorize :read_group_member
+
+ private
+
+ def preloads
+ {
+ user: [:user, :source]
+ }
+ end
+
+ def finder_class
+ GroupMembersFinder
+ end
+ end
+end
diff --git a/app/graphql/resolvers/issue_status_counts_resolver.rb b/app/graphql/resolvers/issue_status_counts_resolver.rb
index 0b26b9def54..5d0d5693244 100644
--- a/app/graphql/resolvers/issue_status_counts_resolver.rb
+++ b/app/graphql/resolvers/issue_status_counts_resolver.rb
@@ -2,26 +2,13 @@
module Resolvers
class IssueStatusCountsResolver < BaseResolver
- prepend IssueResolverFields
+ prepend IssueResolverArguments
type Types::IssueStatusCountsType, null: true
def continue_issue_resolve(parent, finder, **args)
- finder.params[parent_param(parent)] = parent if parent
- Gitlab::IssuablesCountForState.new(finder, parent)
- end
-
- private
-
- def parent_param(parent)
- case parent
- when Project
- :project_id
- when Group
- :group_id
- else
- raise "Unexpected type of parent: #{parent.class}. Must be Project or Group"
- end
+ finder.parent_param = parent
+ apply_lookahead(Gitlab::IssuablesCountForState.new(finder, parent))
end
end
end
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index e2874f6643c..396ae02ae13 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -2,7 +2,7 @@
module Resolvers
class IssuesResolver < BaseResolver
- prepend IssueResolverFields
+ prepend IssueResolverArguments
argument :state, Types::IssuableStateEnum,
required: false,
@@ -19,7 +19,7 @@ module Resolvers
milestone_due_asc milestone_due_desc].freeze
def continue_issue_resolve(parent, finder, **args)
- issues = Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all
+ issues = apply_lookahead(Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all)
if non_stable_cursor_sort?(args[:sort])
# Certain complex sorts are not supported by the stable cursor pagination yet.
@@ -30,6 +30,16 @@ module Resolvers
end
end
+ private
+
+ def preloads
+ {
+ alert_management_alert: [:alert_management_alert],
+ labels: [:labels],
+ assignees: [:assignees]
+ }
+ end
+
def non_stable_cursor_sort?(sort)
NON_STABLE_CURSOR_SORTS.include?(sort)
end
diff --git a/app/graphql/resolvers/members_resolver.rb b/app/graphql/resolvers/members_resolver.rb
new file mode 100644
index 00000000000..88a1ab71c45
--- /dev/null
+++ b/app/graphql/resolvers/members_resolver.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class MembersResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include LooksAhead
+
+ argument :search, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Search query'
+
+ def resolve_with_lookahead(**args)
+ authorize!(object)
+
+ apply_lookahead(finder_class.new(object, current_user, params: args).execute)
+ end
+
+ private
+
+ def finder_class
+ # override in subclass
+ end
+ end
+end
diff --git a/app/graphql/resolvers/merge_request_pipelines_resolver.rb b/app/graphql/resolvers/merge_request_pipelines_resolver.rb
index b371f1335f8..b95e46d9cff 100644
--- a/app/graphql/resolvers/merge_request_pipelines_resolver.rb
+++ b/app/graphql/resolvers/merge_request_pipelines_resolver.rb
@@ -7,6 +7,8 @@ module Resolvers
alias_method :merge_request, :object
def resolve(**args)
+ return unless project
+
resolve_pipelines(project, args)
.merge(merge_request.all_pipelines)
end
diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb
index d15a1ede6fe..677f84e5795 100644
--- a/app/graphql/resolvers/merge_requests_resolver.rb
+++ b/app/graphql/resolvers/merge_requests_resolver.rb
@@ -29,11 +29,18 @@ module Resolvers
as: :label_name,
description: 'Array of label names. All resolved merge requests will have all of these labels.'
argument :merged_after, Types::TimeType,
- required: false,
- description: 'Merge requests merged after this date'
+ required: false,
+ description: 'Merge requests merged after this date'
argument :merged_before, Types::TimeType,
- required: false,
- description: 'Merge requests merged before this date'
+ required: false,
+ description: 'Merge requests merged before this date'
+ argument :milestone_title, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Title of the milestone'
+ argument :sort, Types::MergeRequestSortEnum,
+ description: 'Sort merge requests by this criteria',
+ required: false,
+ default_value: 'created_desc'
def self.single
::Resolvers::MergeRequestResolver
diff --git a/app/graphql/resolvers/metrics/dashboard_resolver.rb b/app/graphql/resolvers/metrics/dashboard_resolver.rb
index 05d82ca0f46..18a654c7dc5 100644
--- a/app/graphql/resolvers/metrics/dashboard_resolver.rb
+++ b/app/graphql/resolvers/metrics/dashboard_resolver.rb
@@ -14,7 +14,8 @@ module Resolvers
def resolve(**args)
return unless environment
- ::PerformanceMonitoring::PrometheusDashboard.find_for(project: environment.project, user: context[:current_user], path: args[:path], options: { environment: environment })
+ ::PerformanceMonitoring::PrometheusDashboard
+ .find_for(project: environment.project, user: context[:current_user], path: args[:path], options: { environment: environment })
end
end
end
diff --git a/app/graphql/resolvers/namespace_projects_resolver.rb b/app/graphql/resolvers/namespace_projects_resolver.rb
index e841132eea7..c221cb9aed6 100644
--- a/app/graphql/resolvers/namespace_projects_resolver.rb
+++ b/app/graphql/resolvers/namespace_projects_resolver.rb
@@ -7,19 +7,33 @@ module Resolvers
default_value: false,
description: 'Include also subgroup projects'
+ argument :search, GraphQL::STRING_TYPE,
+ required: false,
+ default_value: nil,
+ description: 'Search project with most similar names or paths'
+
+ argument :sort, Types::Projects::NamespaceProjectSortEnum,
+ required: false,
+ default_value: nil,
+ description: 'Sort projects by this criteria'
+
type Types::ProjectType, null: true
- def resolve(include_subgroups:)
+ def resolve(include_subgroups:, sort:, search:)
# The namespace could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` or the `full_path` of the namespace
# to query for projects, so make sure it's loaded and not `nil` before continuing.
namespace = object.respond_to?(:sync) ? object.sync : object
return Project.none if namespace.nil?
- if include_subgroups
- namespace.all_projects.with_route
+ query = include_subgroups ? namespace.all_projects.with_route : namespace.projects.with_route
+
+ return query unless search.present?
+
+ if sort == :similarity
+ query.sorted_by_similarity_desc(search, include_in_select: true).merge(Project.search(search))
else
- namespace.projects.with_route
+ query.merge(Project.search(search))
end
end
diff --git a/app/graphql/resolvers/project_members_resolver.rb b/app/graphql/resolvers/project_members_resolver.rb
index 3846531762e..1ca4e81f397 100644
--- a/app/graphql/resolvers/project_members_resolver.rb
+++ b/app/graphql/resolvers/project_members_resolver.rb
@@ -1,21 +1,15 @@
# frozen_string_literal: true
module Resolvers
- class ProjectMembersResolver < BaseResolver
- argument :search, GraphQL::STRING_TYPE,
- required: false,
- description: 'Search query'
+ class ProjectMembersResolver < MembersResolver
+ type Types::MemberInterface, null: true
- type Types::ProjectMemberType, null: true
+ authorize :read_project_member
- alias_method :project, :object
-
- def resolve(**args)
- return Member.none unless project.present?
+ private
+ def finder_class
MembersFinder
- .new(project, context[:current_user], params: args)
- .execute
end
end
end
diff --git a/app/graphql/resolvers/project_merge_requests_resolver.rb b/app/graphql/resolvers/project_merge_requests_resolver.rb
new file mode 100644
index 00000000000..0526ccd315f
--- /dev/null
+++ b/app/graphql/resolvers/project_merge_requests_resolver.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class ProjectMergeRequestsResolver < MergeRequestsResolver
+ argument :assignee_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of the assignee'
+ argument :author_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of the author'
+ end
+end
diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb
index f75f591b381..3bbadf87a71 100644
--- a/app/graphql/resolvers/projects_resolver.rb
+++ b/app/graphql/resolvers/projects_resolver.rb
@@ -12,9 +12,13 @@ module Resolvers
required: false,
description: 'Search query for project name, path, or description'
+ argument :ids, [GraphQL::ID_TYPE],
+ required: false,
+ description: 'Filter projects by IDs'
+
def resolve(**args)
ProjectsFinder
- .new(current_user: current_user, params: project_finder_params(args))
+ .new(current_user: current_user, params: project_finder_params(args), project_ids_relation: parse_gids(args[:ids]))
.execute
end
@@ -27,5 +31,9 @@ module Resolvers
search: params[:search]
}.compact
end
+
+ def parse_gids(gids)
+ gids&.map { |gid| GitlabSchema.parse_gid(gid, expected_type: ::Project).model_id }
+ end
end
end
diff --git a/app/graphql/resolvers/user_starred_projects_resolver.rb b/app/graphql/resolvers/user_starred_projects_resolver.rb
new file mode 100644
index 00000000000..cc3bb90decf
--- /dev/null
+++ b/app/graphql/resolvers/user_starred_projects_resolver.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class UserStarredProjectsResolver < BaseResolver
+ type Types::ProjectType, null: true
+
+ argument :search, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Search query'
+
+ alias_method :user, :object
+
+ def resolve(**args)
+ StarredProjectsFinder.new(user, params: args, current_user: current_user).execute
+ end
+ end
+end
diff --git a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb
new file mode 100644
index 00000000000..13c67442c2e
--- /dev/null
+++ b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Types
+ module Admin
+ module Analytics
+ module InstanceStatistics
+ class MeasurementIdentifierEnum < BaseEnum
+ graphql_name 'MeasurementIdentifier'
+ description 'Possible identifier types for a measurement'
+
+ value 'PROJECTS', 'Project count', value: :projects
+ value 'USERS', 'User count', value: :users
+ value 'ISSUES', 'Issue count', value: :issues
+ value 'MERGE_REQUESTS', 'Merge request count', value: :merge_requests
+ value 'GROUPS', 'Group count', value: :groups
+ value 'PIPELINES', 'Pipeline count', value: :pipelines
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/admin/analytics/instance_statistics/measurement_type.rb b/app/graphql/types/admin/analytics/instance_statistics/measurement_type.rb
new file mode 100644
index 00000000000..d45341077a4
--- /dev/null
+++ b/app/graphql/types/admin/analytics/instance_statistics/measurement_type.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+# rubocop:disable Graphql/AuthorizeTypes
+
+module Types
+ module Admin
+ module Analytics
+ module InstanceStatistics
+ class MeasurementType < BaseObject
+ graphql_name 'InstanceStatisticsMeasurement'
+ description 'Represents a recorded measurement (object count) for the Admins'
+
+ field :recorded_at, Types::TimeType, null: true,
+ description: 'The time the measurement was recorded'
+
+ field :count, GraphQL::INT_TYPE, null: false,
+ description: 'Object count'
+
+ field :identifier, Types::Admin::Analytics::InstanceStatistics::MeasurementIdentifierEnum, null: false,
+ description: 'The type of objects being measured'
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb b/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb
index 69af9d463bb..93dd49b3c38 100644
--- a/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb
+++ b/app/graphql/types/admin/sidekiq_queues/delete_jobs_response_type.rb
@@ -7,7 +7,7 @@ module Types
# a plain hash.
class DeleteJobsResponseType < BaseObject # rubocop:disable Graphql/AuthorizeTypes
graphql_name 'DeleteJobsResponse'
- description 'The response from the AdminSidekiqQueuesDeleteJobs mutation.'
+ description 'The response from the AdminSidekiqQueuesDeleteJobs mutation'
field :completed,
GraphQL::BOOLEAN_TYPE,
diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb
index 1a0b0685ffe..2da97030b88 100644
--- a/app/graphql/types/alert_management/alert_type.rb
+++ b/app/graphql/types/alert_management/alert_type.rb
@@ -6,6 +6,8 @@ module Types
graphql_name 'AlertManagementAlert'
description "Describes an alert from the project's Alert Management"
+ present_using ::AlertManagement::AlertPresenter
+
implements(Types::Notes::NoteableType)
authorize :read_alert_management_alert
diff --git a/app/graphql/types/award_emojis/award_emoji_type.rb b/app/graphql/types/award_emojis/award_emoji_type.rb
index 0247ec767c8..fe7affa50cc 100644
--- a/app/graphql/types/award_emojis/award_emoji_type.rb
+++ b/app/graphql/types/award_emojis/award_emoji_type.rb
@@ -4,7 +4,7 @@ module Types
module AwardEmojis
class AwardEmojiType < BaseObject
graphql_name 'AwardEmoji'
- description 'An emoji awarded by a user.'
+ description 'An emoji awarded by a user'
authorize :read_emoji
diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb
index 94f6c47e876..159443641bc 100644
--- a/app/graphql/types/base_enum.rb
+++ b/app/graphql/types/base_enum.rb
@@ -2,9 +2,12 @@
module Types
class BaseEnum < GraphQL::Schema::Enum
+ extend GitlabStyleDeprecations
+
class << self
def value(*args, **kwargs, &block)
enum[args[0].downcase] = kwargs[:value] || args[0]
+ kwargs = gitlab_deprecation(kwargs)
super(*args, **kwargs, &block)
end
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index c8ec4b3f897..1e72a4cddf5 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -3,6 +3,7 @@
module Types
class BaseField < GraphQL::Schema::Field
prepend Gitlab::Graphql::Authorize
+ include GitlabStyleDeprecations
DEFAULT_COMPLEXITY = 1
@@ -12,11 +13,39 @@ module Types
kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity])
@feature_flag = kwargs[:feature_flag]
kwargs = check_feature_flag(kwargs)
- kwargs = handle_deprecated(kwargs)
+ kwargs = gitlab_deprecation(kwargs)
super(*args, **kwargs, &block)
end
+ # Based on https://github.com/rmosolgo/graphql-ruby/blob/v1.11.4/lib/graphql/schema/field.rb#L538-L563
+ # Modified to fix https://github.com/rmosolgo/graphql-ruby/issues/3113
+ def resolve_field(obj, args, ctx)
+ ctx.schema.after_lazy(obj) do |after_obj|
+ query_ctx = ctx.query.context
+ inner_obj = after_obj && after_obj.object
+
+ ctx.schema.after_lazy(to_ruby_args(after_obj, args, ctx)) do |ruby_args|
+ if authorized?(inner_obj, ruby_args, query_ctx)
+ if @resolve_proc
+ # We pass `after_obj` here instead of `inner_obj` because extensions expect a GraphQL::Schema::Object
+ with_extensions(after_obj, ruby_args, query_ctx) do |extended_obj, extended_args|
+ # Since `extended_obj` is now a GraphQL::Schema::Object, we need to get the inner object and pass that to `@resolve_proc`
+ extended_obj = extended_obj.object if extended_obj.is_a?(GraphQL::Schema::Object)
+
+ @resolve_proc.call(extended_obj, args, ctx)
+ end
+ else
+ public_send_field(after_obj, ruby_args, query_ctx)
+ end
+ else
+ err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
+ query_ctx.schema.unauthorized_field(err)
+ end
+ end
+ end
+ end
+
def base_complexity
complexity = DEFAULT_COMPLEXITY
complexity += 1 if calls_gitaly?
@@ -52,28 +81,6 @@ module Types
args
end
- def handle_deprecated(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-fields'
- end
-
- deprecation = kwargs.delete(:deprecated)
- return kwargs unless deprecation
-
- milestone, reason = deprecation.values_at(:milestone, :reason).map(&:presence)
-
- raise ArgumentError, 'Please provide a `milestone` within `deprecated`' unless milestone
- raise ArgumentError, 'Please provide a `reason` within `deprecated`' unless reason
- raise ArgumentError, '`milestone` must be a `String`' unless milestone.is_a?(String)
-
- deprecated_in = "Deprecated in #{milestone}"
- kwargs[:deprecation_reason] = "#{reason}. #{deprecated_in}"
- kwargs[:description] += ". #{deprecated_in}: #{reason}" if kwargs[:description]
-
- kwargs
- end
-
def field_complexity(resolver_class, current)
return current if current.present? && current > 0
diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb
index 70c0794fc90..24faf1fe8bc 100644
--- a/app/graphql/types/board_list_type.rb
+++ b/app/graphql/types/board_list_type.rb
@@ -41,7 +41,7 @@ module Types
list = self.object
user = context[:current_user]
- Boards::Issues::ListService
+ ::Boards::Issues::ListService
.new(list.board.resource_parent, user, board_id: list.board_id, id: list.id)
.metadata
end
diff --git a/app/graphql/types/boards/board_issue_input_base_type.rb b/app/graphql/types/boards/board_issue_input_base_type.rb
new file mode 100644
index 00000000000..1187b3352cd
--- /dev/null
+++ b/app/graphql/types/boards/board_issue_input_base_type.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Types
+ module Boards
+ # rubocop: disable Graphql/AuthorizeTypes
+ class BoardIssueInputBaseType < BaseInputObject
+ argument :label_name, GraphQL::STRING_TYPE.to_list_type,
+ required: false,
+ description: 'Filter by label name'
+
+ argument :milestone_title, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Filter by milestone title'
+
+ argument :assignee_username, GraphQL::STRING_TYPE.to_list_type,
+ required: false,
+ description: 'Filter by assignee username'
+
+ argument :author_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Filter by author username'
+
+ argument :release_tag, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Filter by release tag'
+
+ argument :my_reaction_emoji, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Filter by reaction emoji'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
+
+Types::Boards::BoardIssueInputBaseType.prepend_if_ee('::EE::Types::Boards::BoardIssueInputBaseType')
diff --git a/app/graphql/types/boards/board_issue_input_type.rb b/app/graphql/types/boards/board_issue_input_type.rb
new file mode 100644
index 00000000000..40d065d8ea9
--- /dev/null
+++ b/app/graphql/types/boards/board_issue_input_type.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Types
+ module Boards
+ # rubocop: disable Graphql/AuthorizeTypes
+ class NegatedBoardIssueInputType < BoardIssueInputBaseType
+ end
+
+ class BoardIssueInputType < BoardIssueInputBaseType
+ graphql_name 'BoardIssueInput'
+
+ argument :not, NegatedBoardIssueInputType,
+ required: false,
+ description: 'List of negated params. Warning: this argument is experimental and a subject to change in future'
+
+ argument :search, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Search query for issue title or description'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
+
+Types::Boards::BoardIssueInputType.prepend_if_ee('::EE::Types::Boards::BoardIssueInputType')
diff --git a/app/graphql/types/ci/pipeline_config_source_enum.rb b/app/graphql/types/ci/pipeline_config_source_enum.rb
index 48f88c133b4..e1575cb2f99 100644
--- a/app/graphql/types/ci/pipeline_config_source_enum.rb
+++ b/app/graphql/types/ci/pipeline_config_source_enum.rb
@@ -3,7 +3,7 @@
module Types
module Ci
class PipelineConfigSourceEnum < BaseEnum
- ::Ci::PipelineEnums.config_sources.keys.each do |state_symbol|
+ ::Enums::Ci::Pipeline.config_sources.keys.each do |state_symbol|
value state_symbol.to_s.upcase, value: state_symbol.to_s
end
end
diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb
index 82a9f8495ce..c508b746317 100644
--- a/app/graphql/types/ci/pipeline_type.rb
+++ b/app/graphql/types/ci/pipeline_type.rb
@@ -26,7 +26,7 @@ module Types
description: 'Detailed status of the pipeline',
resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) }
field :config_source, PipelineConfigSourceEnum, null: true,
- description: "Config source of the pipeline (#{::Ci::PipelineEnums.config_sources.keys.join(', ').upcase})"
+ description: "Config source of the pipeline (#{::Enums::Ci::Pipeline.config_sources.keys.join(', ').upcase})"
field :duration, GraphQL::INT_TYPE, null: true,
description: 'Duration of the pipeline in seconds'
field :coverage, GraphQL::FLOAT_TYPE, null: true,
@@ -48,6 +48,14 @@ module Types
field :user, Types::UserType, null: true,
description: 'Pipeline user',
resolve: -> (pipeline, _args, _context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, pipeline.user_id).find }
+ field :retryable, GraphQL::BOOLEAN_TYPE,
+ description: 'Specifies if a pipeline can be retried',
+ method: :retryable?,
+ null: false
+ field :cancelable, GraphQL::BOOLEAN_TYPE,
+ description: 'Specifies if a pipeline can be canceled',
+ method: :cancelable?,
+ null: false
end
end
end
diff --git a/app/graphql/types/concerns/gitlab_style_deprecations.rb b/app/graphql/types/concerns/gitlab_style_deprecations.rb
new file mode 100644
index 00000000000..2c932f4214b
--- /dev/null
+++ b/app/graphql/types/concerns/gitlab_style_deprecations.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+# Concern for handling deprecation arguments.
+# https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-fields-and-enum-values
+module GitlabStyleDeprecations
+ extend ActiveSupport::Concern
+
+ private
+
+ def 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-fields-and-enum-values'
+ end
+
+ deprecation = kwargs.delete(:deprecated)
+ return kwargs unless deprecation
+
+ milestone, reason = deprecation.values_at(:milestone, :reason).map(&:presence)
+
+ raise ArgumentError, 'Please provide a `milestone` within `deprecated`' unless milestone
+ raise ArgumentError, 'Please provide a `reason` within `deprecated`' unless reason
+ raise ArgumentError, '`milestone` must be a `String`' unless milestone.is_a?(String)
+
+ deprecated_in = "Deprecated in #{milestone}"
+ kwargs[:deprecation_reason] = "#{reason}. #{deprecated_in}"
+ kwargs[:description] += ". #{deprecated_in}: #{reason}" if kwargs[:description]
+
+ kwargs
+ end
+end
diff --git a/app/graphql/types/current_user_todos.rb b/app/graphql/types/current_user_todos.rb
new file mode 100644
index 00000000000..e610286c1a9
--- /dev/null
+++ b/app/graphql/types/current_user_todos.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+# Interface to expose todos for the current_user on the `object`
+module Types
+ module CurrentUserTodos
+ include BaseInterface
+
+ field_class Types::BaseField
+
+ field :current_user_todos, Types::TodoType.connection_type,
+ description: 'Todos for the current user',
+ null: false do
+ argument :state, Types::TodoStateEnum,
+ description: 'State of the todos',
+ required: false
+ end
+
+ def current_user_todos(state: nil)
+ state ||= %i(done pending) # TodosFinder treats a `nil` state param as `pending`
+
+ TodosFinder.new(current_user, state: state, type: object.class.name, target_id: object.id).execute
+ end
+ end
+end
diff --git a/app/graphql/types/design_management/design_at_version_type.rb b/app/graphql/types/design_management/design_at_version_type.rb
index 343d4cf4ff4..e10a0de1715 100644
--- a/app/graphql/types/design_management/design_at_version_type.rb
+++ b/app/graphql/types/design_management/design_at_version_type.rb
@@ -6,7 +6,7 @@ module Types
graphql_name 'DesignAtVersion'
description 'A design pinned to a specific version. ' \
- 'The image field reflects the design as of the associated version.'
+ 'The image field reflects the design as of the associated version'
authorize :read_design
@@ -23,7 +23,7 @@ module Types
field :design,
Types::DesignManagement::DesignType,
null: false,
- description: 'The underlying design.'
+ description: 'The underlying design'
def cached_stateful_version(_parent)
version
diff --git a/app/graphql/types/design_management/design_collection_type.rb b/app/graphql/types/design_management/design_collection_type.rb
index 194910831c6..904fb270e11 100644
--- a/app/graphql/types/design_management/design_collection_type.rb
+++ b/app/graphql/types/design_management/design_collection_type.rb
@@ -4,7 +4,7 @@ module Types
module DesignManagement
class DesignCollectionType < BaseObject
graphql_name 'DesignCollection'
- description 'A collection of designs.'
+ description 'A collection of designs'
authorize :read_design
diff --git a/app/graphql/types/design_management/design_type.rb b/app/graphql/types/design_management/design_type.rb
index 3c84dc151bd..4e11a7aaf09 100644
--- a/app/graphql/types/design_management/design_type.rb
+++ b/app/graphql/types/design_management/design_type.rb
@@ -12,6 +12,7 @@ module Types
implements(Types::Notes::NoteableType)
implements(Types::DesignManagement::DesignFields)
+ implements(Types::CurrentUserTodos)
field :versions,
Types::DesignManagement::VersionType.connection_type,
diff --git a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb
index 8bdd8afcbff..cfde9fa0d6a 100644
--- a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb
+++ b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb
@@ -4,7 +4,7 @@ module Types
module ErrorTracking
class SentryDetailedErrorType < ::Types::BaseObject
graphql_name 'SentryDetailedError'
- description 'A Sentry error.'
+ description 'A Sentry error'
present_using SentryErrorPresenter
diff --git a/app/graphql/types/error_tracking/sentry_error_collection_type.rb b/app/graphql/types/error_tracking/sentry_error_collection_type.rb
index f423fcb1b9f..798e0433d06 100644
--- a/app/graphql/types/error_tracking/sentry_error_collection_type.rb
+++ b/app/graphql/types/error_tracking/sentry_error_collection_type.rb
@@ -4,7 +4,7 @@ module Types
module ErrorTracking
class SentryErrorCollectionType < ::Types::BaseObject
graphql_name 'SentryErrorCollection'
- description 'An object containing a collection of Sentry errors, and a detailed error.'
+ description 'An object containing a collection of Sentry errors, and a detailed error'
authorize :read_sentry_issue
@@ -21,7 +21,7 @@ module Types
required: false
argument :sort,
String,
- description: 'Attribute to sort on. Options are frequency, first_seen, last_seen. last_seen is default.',
+ description: 'Attribute to sort on. Options are frequency, first_seen, last_seen. last_seen is default',
required: false
end
field :detailed_error, Types::ErrorTracking::SentryDetailedErrorType,
diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb
index 0747e41e9fb..2e6c40b233b 100644
--- a/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb
+++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_entry_type.rb
@@ -5,7 +5,7 @@ module Types
# rubocop: disable Graphql/AuthorizeTypes
class SentryErrorStackTraceEntryType < ::Types::BaseObject
graphql_name 'SentryErrorStackTraceEntry'
- description 'An object containing a stack trace entry for a Sentry error.'
+ description 'An object containing a stack trace entry for a Sentry error'
field :function, GraphQL::STRING_TYPE,
null: true,
diff --git a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
index 0e6105d1ff2..1bbe7e0c77b 100644
--- a/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
+++ b/app/graphql/types/error_tracking/sentry_error_stack_trace_type.rb
@@ -4,7 +4,7 @@ module Types
module ErrorTracking
class SentryErrorStackTraceType < ::Types::BaseObject
graphql_name 'SentryErrorStackTrace'
- description 'An object containing a stack trace entry for a Sentry error.'
+ description 'An object containing a stack trace entry for a Sentry error'
authorize :read_sentry_issue
diff --git a/app/graphql/types/error_tracking/sentry_error_type.rb b/app/graphql/types/error_tracking/sentry_error_type.rb
index 7a842025e45..693ab0c4f8f 100644
--- a/app/graphql/types/error_tracking/sentry_error_type.rb
+++ b/app/graphql/types/error_tracking/sentry_error_type.rb
@@ -5,7 +5,7 @@ module Types
# rubocop: disable Graphql/AuthorizeTypes
class SentryErrorType < ::Types::BaseObject
graphql_name 'SentryError'
- description 'A Sentry error. A simplified version of SentryDetailedError.'
+ description 'A Sentry error. A simplified version of SentryDetailedError'
present_using SentryErrorPresenter
diff --git a/app/graphql/types/group_member_type.rb b/app/graphql/types/group_member_type.rb
index ffffa3247db..6cca0a50647 100644
--- a/app/graphql/types/group_member_type.rb
+++ b/app/graphql/types/group_member_type.rb
@@ -8,7 +8,7 @@ module Types
implements MemberInterface
graphql_name 'GroupMember'
- description 'Represents a Group Member'
+ description 'Represents a Group Membership'
field :group, Types::GroupType, null: true,
description: 'Group that a User is a member of',
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index cc8cd7c01f9..60b2e3c7b6e 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -75,6 +75,12 @@ module Types
description: 'Title of the label'
end
+ field :group_members,
+ Types::GroupMemberType.connection_type,
+ description: 'A membership of a user within this group',
+ extras: [:lookahead],
+ resolver: Resolvers::GroupMembersResolver
+
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|
LabelsFinder
diff --git a/app/graphql/types/issuable_severity_enum.rb b/app/graphql/types/issuable_severity_enum.rb
new file mode 100644
index 00000000000..563965d991e
--- /dev/null
+++ b/app/graphql/types/issuable_severity_enum.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Types
+ class IssuableSeverityEnum < BaseEnum
+ graphql_name 'IssuableSeverity'
+ description 'Incident severity'
+
+ ::IssuableSeverity.severities.keys.each do |severity|
+ value severity.upcase, value: severity, description: "#{severity.titleize} severity"
+ end
+ end
+end
diff --git a/app/graphql/types/issue_status_counts_type.rb b/app/graphql/types/issue_status_counts_type.rb
index f2b1ba8e655..77429f9ea12 100644
--- a/app/graphql/types/issue_status_counts_type.rb
+++ b/app/graphql/types/issue_status_counts_type.rb
@@ -3,7 +3,7 @@
module Types
class IssueStatusCountsType < BaseObject
graphql_name 'IssueStatusCountsType'
- description "Represents total number of issues for the represented statuses."
+ description 'Represents total number of issues for the represented statuses'
authorize :read_issue
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index 0a73ce95424..d6253f74ce5 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -7,6 +7,7 @@ module Types
connection_type_class(Types::CountableConnectionType)
implements(Types::Notes::NoteableType)
+ implements(Types::CurrentUserTodos)
authorize :read_issue
@@ -38,12 +39,10 @@ module Types
description: 'User that created the issue',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find }
- # Remove complexity when BatchLoader is used
- field :assignees, Types::UserType.connection_type, null: true, complexity: 5,
+ field :assignees, Types::UserType.connection_type, null: true,
description: 'Assignees of the issue'
- # Remove complexity when BatchLoader is used
- field :labels, Types::LabelType.connection_type, null: true, complexity: 5,
+ field :labels, Types::LabelType.connection_type, null: true,
description: 'Labels of the issue'
field :milestone, Types::MilestoneType, null: true,
description: 'Milestone of the issue',
@@ -101,6 +100,14 @@ module Types
field :type, Types::IssueTypeEnum, null: true,
method: :issue_type,
description: 'Type of the issue'
+
+ field :alert_management_alert,
+ Types::AlertManagement::AlertType,
+ null: true,
+ description: 'Alert associated to this issue'
+
+ field :severity, Types::IssuableSeverityEnum, null: true,
+ description: 'Severity level of the incident'
end
end
diff --git a/app/graphql/types/jira_user_type.rb b/app/graphql/types/jira_user_type.rb
index 999526a920e..394820d23be 100644
--- a/app/graphql/types/jira_user_type.rb
+++ b/app/graphql/types/jira_user_type.rb
@@ -7,7 +7,7 @@ module Types
graphql_name 'JiraUser'
field :jira_account_id, GraphQL::STRING_TYPE, null: false,
- description: 'Account id of the Jira user'
+ description: 'Account ID of the Jira user'
field :jira_display_name, GraphQL::STRING_TYPE, null: false,
description: 'Display name of the Jira user'
field :jira_email, GraphQL::STRING_TYPE, null: true,
diff --git a/app/graphql/types/member_interface.rb b/app/graphql/types/member_interface.rb
index 976836221bc..615a45413cb 100644
--- a/app/graphql/types/member_interface.rb
+++ b/app/graphql/types/member_interface.rb
@@ -4,6 +4,9 @@ module Types
module MemberInterface
include BaseInterface
+ field :id, GraphQL::ID_TYPE, null: false,
+ description: 'ID of the member'
+
field :access_level, Types::AccessLevelType, null: true,
description: 'GitLab::Access level'
@@ -18,5 +21,21 @@ module Types
field :expires_at, Types::TimeType, null: true,
description: 'Date and time the membership expires'
+
+ field :user, Types::UserType, null: false,
+ description: 'User that is associated with the member object'
+
+ definition_methods do
+ def resolve_type(object, context)
+ case object
+ when GroupMember
+ Types::GroupMemberType
+ when ProjectMember
+ Types::ProjectMemberType
+ else
+ raise ::Gitlab::Graphql::Errors::BaseError, "Unknown member type #{object.class.name}"
+ end
+ end
+ end
end
end
diff --git a/app/graphql/types/merge_request_sort_enum.rb b/app/graphql/types/merge_request_sort_enum.rb
new file mode 100644
index 00000000000..c64ae367a76
--- /dev/null
+++ b/app/graphql/types/merge_request_sort_enum.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+ class MergeRequestSortEnum < IssuableSortEnum
+ graphql_name 'MergeRequestSort'
+ description 'Values for sorting merge requests'
+
+ value 'MERGED_AT_ASC', 'Merge time by ascending order', value: :merged_at_asc
+ value 'MERGED_AT_DESC', 'Merge time by descending order', value: :merged_at_desc
+ end
+end
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 01b02b7976f..56c88491684 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -7,6 +7,7 @@ module Types
connection_type_class(Types::CountableConnectionType)
implements(Types::Notes::NoteableType)
+ implements(Types::CurrentUserTodos)
authorize :read_merge_request
@@ -79,7 +80,7 @@ module Types
description: 'Error message due to a merge error'
field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if members of the target project can push to the fork'
- field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false,
+ field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false, calls_gitaly: true,
description: 'Indicates if the merge request will be rebased'
field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true,
description: 'Rebase commit SHA of the merge request'
@@ -112,6 +113,7 @@ module Types
field :head_pipeline, Types::Ci::PipelineType, null: true, method: :actual_head_pipeline,
description: 'The pipeline running on the branch HEAD of the merge request'
field :pipelines, Types::Ci::PipelineType.connection_type,
+ null: true,
description: 'Pipelines for the merge request',
resolver: Resolvers::MergeRequestPipelinesResolver
@@ -145,6 +147,10 @@ module Types
description: Types::TaskCompletionStatus.description
field :commit_count, GraphQL::INT_TYPE, null: true,
description: 'Number of commits in the merge request'
+ field :conflicts, GraphQL::BOOLEAN_TYPE, null: false, method: :cannot_be_merged?,
+ description: 'Indicates if the merge request has conflicts'
+ field :auto_merge_enabled, GraphQL::BOOLEAN_TYPE, null: false,
+ description: 'Indicates if auto merge is enabled for the merge request'
def diff_stats(path: nil)
stats = Array.wrap(object.diff_stats&.to_a)
diff --git a/app/graphql/types/metrics/dashboard_type.rb b/app/graphql/types/metrics/dashboard_type.rb
index bbcce2d9596..47502356773 100644
--- a/app/graphql/types/metrics/dashboard_type.rb
+++ b/app/graphql/types/metrics/dashboard_type.rb
@@ -16,6 +16,13 @@ module Types
field :annotations, Types::Metrics::Dashboards::AnnotationType.connection_type, null: true,
description: 'Annotations added to the dashboard',
resolver: Resolvers::Metrics::Dashboards::AnnotationResolver
+
+ # In order to maintain backward compatibility we need to return NULL when there are no warnings
+ # and dashboard validation returns an empty array when there are no issues.
+ def schema_validation_warnings
+ warnings = object.schema_validation_warnings
+ warnings unless warnings.empty?
+ end
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb
index ca606c9da44..8603043804e 100644
--- a/app/graphql/types/milestone_type.rb
+++ b/app/graphql/types/milestone_type.rb
@@ -3,7 +3,7 @@
module Types
class MilestoneType < BaseObject
graphql_name 'Milestone'
- description 'Represents a milestone.'
+ description 'Represents a milestone'
present_using MilestonePresenter
@@ -60,3 +60,5 @@ module Types
end
end
end
+
+Types::MilestoneType.prepend_if_ee('::EE::Types::MilestoneType')
diff --git a/app/graphql/types/mutation_operation_mode_enum.rb b/app/graphql/types/mutation_operation_mode_enum.rb
index 90a29d2b0e5..37e83e7a2e1 100644
--- a/app/graphql/types/mutation_operation_mode_enum.rb
+++ b/app/graphql/types/mutation_operation_mode_enum.rb
@@ -3,7 +3,7 @@
module Types
class MutationOperationModeEnum < BaseEnum
graphql_name 'MutationOperationMode'
- description 'Different toggles for changing mutator behavior.'
+ description 'Different toggles for changing mutator behavior'
# Suggested param name for the enum: `operation_mode`
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index e143d14676e..b2732d83aac 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -14,6 +14,7 @@ module Types
mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove
mount_mutation Mutations::AwardEmojis::Toggle
+ mount_mutation Mutations::Boards::Destroy
mount_mutation Mutations::Boards::Issues::IssueMoveList
mount_mutation Mutations::Boards::Lists::Create
mount_mutation Mutations::Boards::Lists::Update
@@ -24,6 +25,7 @@ module Types
mount_mutation Mutations::Issues::SetConfidential
mount_mutation Mutations::Issues::SetLocked
mount_mutation Mutations::Issues::SetDueDate
+ mount_mutation Mutations::Issues::SetSeverity
mount_mutation Mutations::Issues::SetSubscription
mount_mutation Mutations::Issues::Update
mount_mutation Mutations::MergeRequests::Create
@@ -62,6 +64,9 @@ module Types
mount_mutation Mutations::DesignManagement::Delete, calls_gitaly: true
mount_mutation Mutations::DesignManagement::Move
mount_mutation Mutations::ContainerExpirationPolicies::Update
+ mount_mutation Mutations::Ci::PipelineCancel
+ mount_mutation Mutations::Ci::PipelineDestroy
+ mount_mutation Mutations::Ci::PipelineRetry
end
end
diff --git a/app/graphql/types/permission_types/merge_request.rb b/app/graphql/types/permission_types/merge_request.rb
index 28b7ebd2af6..e9c89b0c92e 100644
--- a/app/graphql/types/permission_types/merge_request.rb
+++ b/app/graphql/types/permission_types/merge_request.rb
@@ -18,6 +18,10 @@ module Types
PERMISSION_FIELDS.each do |field_name|
permission_field field_name, method: :"can_#{field_name}?", calls_gitaly: true
end
+
+ permission_field :can_merge, calls_gitaly: true, resolve: -> (object, args, context) do
+ object.can_be_merged_by?(context[:current_user])
+ end
end
end
end
diff --git a/app/graphql/types/project_member_type.rb b/app/graphql/types/project_member_type.rb
index e9ccb51886b..f08781238d0 100644
--- a/app/graphql/types/project_member_type.rb
+++ b/app/graphql/types/project_member_type.rb
@@ -3,7 +3,7 @@
module Types
class ProjectMemberType < BaseObject
graphql_name 'ProjectMember'
- description 'Represents a Project Member'
+ description 'Represents a Project Membership'
expose_permissions Types::PermissionTypes::Project
@@ -11,13 +11,6 @@ module Types
authorize :read_project
- field :id, GraphQL::ID_TYPE, null: false,
- description: 'ID of the member'
-
- field :user, Types::UserType, null: false,
- description: 'User that is associated with the member object',
- resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.user_id).find }
-
field :project, Types::ProjectType, null: true,
description: 'Project that User is a member of',
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, obj.source_id).find }
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 5562db69de6..0fd54af1538 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -54,7 +54,7 @@ module Types
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'
+ description: 'Indicates if shared runners are enabled for the project'
field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if the project has Large File Storage (LFS) enabled'
field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true,
@@ -134,7 +134,7 @@ module Types
null: true,
description: 'Merge requests of the project',
extras: [:lookahead],
- resolver: Resolvers::MergeRequestsResolver
+ resolver: Resolvers::ProjectMergeRequestsResolver
field :merge_request,
Types::MergeRequestType,
@@ -146,12 +146,14 @@ module Types
Types::IssueType.connection_type,
null: true,
description: 'Issues of the project',
+ extras: [:lookahead],
resolver: Resolvers::IssuesResolver
field :issue_status_counts,
Types::IssueStatusCountsType,
null: true,
description: 'Counts of issues by status for the project',
+ extras: [:lookahead],
resolver: Resolvers::IssueStatusCountsResolver
field :milestones, Types::MilestoneType.connection_type, null: true,
@@ -159,7 +161,7 @@ module Types
resolver: Resolvers::ProjectMilestonesResolver
field :project_members,
- Types::ProjectMemberType.connection_type,
+ Types::MemberInterface.connection_type,
description: 'Members of the project',
resolver: Resolvers::ProjectMembersResolver
diff --git a/app/graphql/types/projects/namespace_project_sort_enum.rb b/app/graphql/types/projects/namespace_project_sort_enum.rb
new file mode 100644
index 00000000000..1e13deb6508
--- /dev/null
+++ b/app/graphql/types/projects/namespace_project_sort_enum.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ class NamespaceProjectSortEnum < BaseEnum
+ graphql_name 'NamespaceProjectSort'
+ description 'Values for sorting projects'
+
+ value 'SIMILARITY', 'Most similar to the search query', value: :similarity
+ end
+ end
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index c04f4da70cf..447ac63a294 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -70,9 +70,24 @@ module Types
description: 'Text to echo back',
resolver: Resolvers::EchoResolver
+ field :issue, Types::IssueType,
+ null: true,
+ description: 'Find an issue' do
+ argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'The global ID of the Issue'
+ end
+
+ field :instance_statistics_measurements, Types::Admin::Analytics::InstanceStatistics::MeasurementType.connection_type,
+ null: true,
+ description: 'Get statistics on the instance',
+ resolver: Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsResolver
+
def design_management
DesignManagementObject.new(nil)
end
+
+ def issue(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::Issue)
+ end
end
end
diff --git a/app/graphql/types/release_asset_link_type.rb b/app/graphql/types/release_asset_link_type.rb
index 21f1bd50cff..0e519ece791 100644
--- a/app/graphql/types/release_asset_link_type.rb
+++ b/app/graphql/types/release_asset_link_type.rb
@@ -17,5 +17,17 @@ module Types
description: 'Type of the link: `other`, `runbook`, `image`, `package`; defaults to `other`'
field :external, GraphQL::BOOLEAN_TYPE, null: true, method: :external?,
description: 'Indicates the link points to an external resource'
+
+ field :direct_asset_url, GraphQL::STRING_TYPE, null: true,
+ description: 'Direct asset URL of the link'
+
+ def direct_asset_url
+ return object.url unless object.filepath
+
+ release = object.release
+ project = release.project
+
+ Gitlab::Routing.url_helpers.project_release_url(project, release) << object.filepath
+ end
end
end
diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb
index a0703b96a36..b715b981483 100644
--- a/app/graphql/types/release_type.rb
+++ b/app/graphql/types/release_type.rb
@@ -5,6 +5,8 @@ module Types
graphql_name 'Release'
description 'Represents a release'
+ connection_type_class(Types::CountableConnectionType)
+
authorize :read_release
alias_method :release, :object
@@ -26,6 +28,8 @@ module Types
description: 'Timestamp of when the release was created'
field :released_at, Types::TimeType, null: true,
description: 'Timestamp of when the release was released'
+ field :upcoming_release, GraphQL::BOOLEAN_TYPE, null: true, method: :upcoming_release?,
+ description: 'Indicates the release is an upcoming release'
field :assets, Types::ReleaseAssetsType, null: true, method: :itself,
description: 'Assets of the release'
field :links, Types::ReleaseLinksType, null: true, method: :itself,
diff --git a/app/graphql/types/todo_type.rb b/app/graphql/types/todo_type.rb
index 08e7fabeb74..4f21da3d897 100644
--- a/app/graphql/types/todo_type.rb
+++ b/app/graphql/types/todo_type.rb
@@ -26,7 +26,7 @@ module Types
resolve: -> (todo, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Group, todo.group_id).find }
field :author, Types::UserType,
- description: 'The owner of this todo',
+ description: 'The author of this todo',
null: false,
resolve: -> (todo, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, todo.author_id).find }
diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb
index cb3575b41d1..8047708776d 100644
--- a/app/graphql/types/user_type.rb
+++ b/app/graphql/types/user_type.rb
@@ -37,6 +37,9 @@ module Types
field :project_memberships, Types::ProjectMemberType.connection_type, null: true,
description: 'Project memberships of the user',
method: :project_members
+ field :starred_projects, Types::ProjectType.connection_type, null: true,
+ description: 'Projects starred by the user',
+ resolver: Resolvers::UserStarredProjectsResolver
# Merge request field: MRs can be either authored or assigned:
field :authored_merge_requests, Types::MergeRequestType.connection_type, null: true,