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:
Diffstat (limited to 'app/graphql')
-rw-r--r--app/graphql/mutations/ci/runner/delete.rb2
-rw-r--r--app/graphql/mutations/clusters/agent_tokens/create.rb69
-rw-r--r--app/graphql/mutations/clusters/agent_tokens/delete.rb35
-rw-r--r--app/graphql/mutations/clusters/agents/create.rb38
-rw-r--r--app/graphql/mutations/clusters/agents/delete.rb39
-rw-r--r--app/graphql/mutations/customer_relations/contacts/create.rb69
-rw-r--r--app/graphql/mutations/customer_relations/contacts/update.rb61
-rw-r--r--app/graphql/mutations/customer_relations/organizations/create.rb2
-rw-r--r--app/graphql/mutations/customer_relations/organizations/update.rb2
-rw-r--r--app/graphql/mutations/dependency_proxy/group_settings/update.rb49
-rw-r--r--app/graphql/mutations/issues/create.rb5
-rw-r--r--app/graphql/resolvers/board_list_issues_resolver.rb5
-rw-r--r--app/graphql/resolvers/board_list_resolver.rb35
-rw-r--r--app/graphql/resolvers/clusters/agent_tokens_resolver.rb25
-rw-r--r--app/graphql/resolvers/clusters/agents_resolver.rb35
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb9
-rw-r--r--app/graphql/resolvers/concerns/search_arguments.rb18
-rw-r--r--app/graphql/resolvers/issues_resolver.rb3
-rw-r--r--app/graphql/resolvers/kas/agent_configurations_resolver.rb32
-rw-r--r--app/graphql/resolvers/kas/agent_connections_resolver.rb41
-rw-r--r--app/graphql/resolvers/project_pipeline_resolver.rb17
-rw-r--r--app/graphql/resolvers/project_pipelines_resolver.rb2
-rw-r--r--app/graphql/types/base_field.rb4
-rw-r--r--app/graphql/types/board_list_type.rb15
-rw-r--r--app/graphql/types/ci/runner_status_enum.rb15
-rw-r--r--app/graphql/types/ci/runner_type.rb15
-rw-r--r--app/graphql/types/ci/runner_web_url_edge.rb31
-rw-r--r--app/graphql/types/clusters/agent_token_type.rb52
-rw-r--r--app/graphql/types/clusters/agent_type.rb67
-rw-r--r--app/graphql/types/concerns/find_closest.rb14
-rw-r--r--app/graphql/types/container_expiration_policy_older_than_enum.rb1
-rw-r--r--app/graphql/types/container_repository_details_type.rb6
-rw-r--r--app/graphql/types/container_repository_type.rb6
-rw-r--r--app/graphql/types/customer_relations/contact_type.rb2
-rw-r--r--app/graphql/types/customer_relations/organization_type.rb2
-rw-r--r--app/graphql/types/error_tracking/sentry_detailed_error_type.rb3
-rw-r--r--app/graphql/types/group_type.rb4
-rw-r--r--app/graphql/types/issue_type.rb3
-rw-r--r--app/graphql/types/issues/negated_issue_filter_input_type.rb4
-rw-r--r--app/graphql/types/kas/agent_configuration_type.rb17
-rw-r--r--app/graphql/types/kas/agent_connection_type.rb32
-rw-r--r--app/graphql/types/kas/agent_metadata_type.rb33
-rw-r--r--app/graphql/types/merge_requests/interacts_with_merge_request.rb2
-rw-r--r--app/graphql/types/milestone_wildcard_id_enum.rb2
-rw-r--r--app/graphql/types/mutation_type.rb7
-rw-r--r--app/graphql/types/packages/nuget/metadatum_type.rb6
-rw-r--r--app/graphql/types/packages/package_type.rb7
-rw-r--r--app/graphql/types/permission_types/ci/runner.rb13
-rw-r--r--app/graphql/types/project_type.rb20
-rw-r--r--app/graphql/types/query_type.rb4
50 files changed, 946 insertions, 34 deletions
diff --git a/app/graphql/mutations/ci/runner/delete.rb b/app/graphql/mutations/ci/runner/delete.rb
index 8d9a5f15505..88dc426398b 100644
--- a/app/graphql/mutations/ci/runner/delete.rb
+++ b/app/graphql/mutations/ci/runner/delete.rb
@@ -28,7 +28,7 @@ module Mutations
def authenticate_delete_runner!(runner)
return if current_user.can_admin_all_resources?
- "Runner #{runner.to_global_id} associated with more than one project" if runner.projects.count > 1
+ "Runner #{runner.to_global_id} associated with more than one project" if runner.runner_projects.count > 1
end
def find_object(id)
diff --git a/app/graphql/mutations/clusters/agent_tokens/create.rb b/app/graphql/mutations/clusters/agent_tokens/create.rb
new file mode 100644
index 00000000000..07bf2536065
--- /dev/null
+++ b/app/graphql/mutations/clusters/agent_tokens/create.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Clusters
+ module AgentTokens
+ class Create < BaseMutation
+ graphql_name 'ClusterAgentTokenCreate'
+
+ authorize :create_cluster
+
+ ClusterAgentID = ::Types::GlobalIDType[::Clusters::Agent]
+
+ argument :cluster_agent_id,
+ ClusterAgentID,
+ required: true,
+ description: 'Global ID of the cluster agent that will be associated with the new token.'
+
+ argument :description,
+ GraphQL::Types::String,
+ required: false,
+ description: 'Description of the token.'
+
+ argument :name,
+ GraphQL::Types::String,
+ required: true,
+ description: 'Name of the token.'
+
+ field :secret,
+ GraphQL::Types::String,
+ null: true,
+ description: "Token secret value. Make sure you save it - you won't be able to access it again."
+
+ field :token,
+ Types::Clusters::AgentTokenType,
+ null: true,
+ description: 'Token created after mutation.'
+
+ def resolve(args)
+ cluster_agent = authorized_find!(id: args[:cluster_agent_id])
+
+ result = ::Clusters::AgentTokens::CreateService
+ .new(
+ container: cluster_agent.project,
+ current_user: current_user,
+ params: args.merge(agent_id: cluster_agent.id)
+ )
+ .execute
+
+ payload = result.payload
+
+ {
+ secret: payload[:secret],
+ token: payload[:token],
+ errors: Array.wrap(result.message)
+ }
+ 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 = ClusterAgentID.coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/clusters/agent_tokens/delete.rb b/app/graphql/mutations/clusters/agent_tokens/delete.rb
new file mode 100644
index 00000000000..603b6b30910
--- /dev/null
+++ b/app/graphql/mutations/clusters/agent_tokens/delete.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Clusters
+ module AgentTokens
+ class Delete < BaseMutation
+ graphql_name 'ClusterAgentTokenDelete'
+
+ authorize :admin_cluster
+
+ TokenID = ::Types::GlobalIDType[::Clusters::AgentToken]
+
+ argument :id, TokenID,
+ required: true,
+ description: 'Global ID of the cluster agent token that will be deleted.'
+
+ def resolve(id:)
+ token = authorized_find!(id: id)
+ token.destroy
+
+ { errors: errors_on_object(token) }
+ end
+
+ private
+
+ def find_object(id:)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = TokenID.coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/clusters/agents/create.rb b/app/graphql/mutations/clusters/agents/create.rb
new file mode 100644
index 00000000000..0896cc7b203
--- /dev/null
+++ b/app/graphql/mutations/clusters/agents/create.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Clusters
+ module Agents
+ class Create < BaseMutation
+ include FindsProject
+
+ authorize :create_cluster
+
+ graphql_name 'CreateClusterAgent'
+
+ argument :project_path, GraphQL::Types::ID,
+ required: true,
+ description: 'Full path of the associated project for this cluster agent.'
+
+ argument :name, GraphQL::Types::String,
+ required: true,
+ description: 'Name of the cluster agent.'
+
+ field :cluster_agent,
+ Types::Clusters::AgentType,
+ null: true,
+ description: 'Cluster agent created after mutation.'
+
+ def resolve(project_path:, name:)
+ project = authorized_find!(project_path)
+ result = ::Clusters::Agents::CreateService.new(project, current_user).execute(name: name)
+
+ {
+ cluster_agent: result[:cluster_agent],
+ errors: Array.wrap(result[:message])
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/clusters/agents/delete.rb b/app/graphql/mutations/clusters/agents/delete.rb
new file mode 100644
index 00000000000..9ada1f31f60
--- /dev/null
+++ b/app/graphql/mutations/clusters/agents/delete.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Clusters
+ module Agents
+ class Delete < BaseMutation
+ graphql_name 'ClusterAgentDelete'
+
+ authorize :admin_cluster
+
+ AgentID = ::Types::GlobalIDType[::Clusters::Agent]
+
+ argument :id, AgentID,
+ required: true,
+ description: 'Global ID of the cluster agent that will be deleted.'
+
+ def resolve(id:)
+ cluster_agent = authorized_find!(id: id)
+ result = ::Clusters::Agents::DeleteService
+ .new(container: cluster_agent.project, current_user: current_user)
+ .execute(cluster_agent)
+
+ {
+ errors: Array.wrap(result.message)
+ }
+ 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 = AgentID.coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/customer_relations/contacts/create.rb b/app/graphql/mutations/customer_relations/contacts/create.rb
new file mode 100644
index 00000000000..77b4864468b
--- /dev/null
+++ b/app/graphql/mutations/customer_relations/contacts/create.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Mutations
+ module CustomerRelations
+ module Contacts
+ class Create < BaseMutation
+ include ResolvesIds
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ graphql_name 'CustomerRelationsContactCreate'
+
+ field :contact,
+ Types::CustomerRelations::ContactType,
+ null: true,
+ description: 'Contact after the mutation.'
+
+ argument :group_id, ::Types::GlobalIDType[::Group],
+ required: true,
+ description: 'Group for the contact.'
+
+ argument :organization_id, ::Types::GlobalIDType[::CustomerRelations::Organization],
+ required: false,
+ description: 'Organization for the contact.'
+
+ argument :first_name, GraphQL::Types::String,
+ required: true,
+ description: 'First name of the contact.'
+
+ argument :last_name, GraphQL::Types::String,
+ required: true,
+ description: 'Last name of the contact.'
+
+ argument :phone, GraphQL::Types::String,
+ required: false,
+ description: 'Phone number of the contact.'
+
+ argument :email, GraphQL::Types::String,
+ required: false,
+ description: 'Email address of the contact.'
+
+ argument :description, GraphQL::Types::String,
+ required: false,
+ description: 'Description of or notes for the contact.'
+
+ authorize :admin_contact
+
+ def resolve(args)
+ group = authorized_find!(id: args[:group_id])
+
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless Feature.enabled?(:customer_relations, group, default_enabled: :yaml)
+
+ set_organization!(args)
+ result = ::CustomerRelations::Contacts::CreateService.new(group: group, current_user: current_user, params: args).execute
+ { contact: result.payload, errors: result.errors }
+ end
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::Group)
+ end
+
+ def set_organization!(args)
+ return unless args[:organization_id]
+
+ args[:organization_id] = resolve_ids(args[:organization_id], ::Types::GlobalIDType[::CustomerRelations::Organization])[0]
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/customer_relations/contacts/update.rb b/app/graphql/mutations/customer_relations/contacts/update.rb
new file mode 100644
index 00000000000..e9e7c9b6abd
--- /dev/null
+++ b/app/graphql/mutations/customer_relations/contacts/update.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Mutations
+ module CustomerRelations
+ module Contacts
+ class Update < Mutations::BaseMutation
+ include ResolvesIds
+
+ graphql_name 'CustomerRelationsContactUpdate'
+
+ authorize :admin_contact
+
+ field :contact,
+ Types::CustomerRelations::ContactType,
+ null: true,
+ description: 'Contact after the mutation.'
+
+ argument :id, ::Types::GlobalIDType[::CustomerRelations::Contact],
+ required: true,
+ description: 'Global ID of the contact.'
+
+ argument :organization_id, ::Types::GlobalIDType[::CustomerRelations::Organization],
+ required: false,
+ description: 'Organization of the contact.'
+
+ argument :first_name, GraphQL::Types::String,
+ required: false,
+ description: 'First name of the contact.'
+
+ argument :last_name, GraphQL::Types::String,
+ required: false,
+ description: 'Last name of the contact.'
+
+ argument :phone, GraphQL::Types::String,
+ required: false,
+ description: 'Phone number of the contact.'
+
+ argument :email, GraphQL::Types::String,
+ required: false,
+ description: 'Email address of the contact.'
+
+ argument :description, GraphQL::Types::String,
+ required: false,
+ description: 'Description of or notes for the contact.'
+
+ def resolve(args)
+ contact = ::Gitlab::Graphql::Lazy.force(GitlabSchema.object_from_id(args.delete(:id), expected_type: ::CustomerRelations::Contact))
+ raise_resource_not_available_error! unless contact
+
+ group = contact.group
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable, 'Feature disabled' unless Feature.enabled?(:customer_relations, group, default_enabled: :yaml)
+
+ authorize!(group)
+
+ result = ::CustomerRelations::Contacts::UpdateService.new(group: group, current_user: current_user, params: args).execute(contact)
+ { contact: result.payload, errors: result.errors }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/customer_relations/organizations/create.rb b/app/graphql/mutations/customer_relations/organizations/create.rb
index 3fa7b0327ca..bb02e1f7346 100644
--- a/app/graphql/mutations/customer_relations/organizations/create.rb
+++ b/app/graphql/mutations/customer_relations/organizations/create.rb
@@ -31,7 +31,7 @@ module Mutations
argument :description,
GraphQL::Types::String,
required: false,
- description: 'Description or notes for the organization.'
+ description: 'Description of or notes for the organization.'
authorize :admin_organization
diff --git a/app/graphql/mutations/customer_relations/organizations/update.rb b/app/graphql/mutations/customer_relations/organizations/update.rb
index c6ae62193f9..d8eb55d77e9 100644
--- a/app/graphql/mutations/customer_relations/organizations/update.rb
+++ b/app/graphql/mutations/customer_relations/organizations/update.rb
@@ -32,7 +32,7 @@ module Mutations
argument :description,
GraphQL::Types::String,
required: false,
- description: 'Description or notes for the organization.'
+ description: 'Description of or notes for the organization.'
def resolve(args)
organization = ::Gitlab::Graphql::Lazy.force(GitlabSchema.object_from_id(args.delete(:id), expected_type: ::CustomerRelations::Organization))
diff --git a/app/graphql/mutations/dependency_proxy/group_settings/update.rb b/app/graphql/mutations/dependency_proxy/group_settings/update.rb
new file mode 100644
index 00000000000..d10e43cde29
--- /dev/null
+++ b/app/graphql/mutations/dependency_proxy/group_settings/update.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Mutations
+ module DependencyProxy
+ module GroupSettings
+ class Update < Mutations::BaseMutation
+ include Mutations::ResolvesGroup
+
+ graphql_name 'UpdateDependencyProxySettings'
+
+ authorize :admin_dependency_proxy
+
+ argument :group_path,
+ GraphQL::Types::ID,
+ required: true,
+ description: 'Group path for the group dependency proxy.'
+
+ argument :enabled,
+ GraphQL::Types::Boolean,
+ required: false,
+ description: copy_field_description(Types::DependencyProxy::ImageTtlGroupPolicyType, :enabled)
+
+ field :dependency_proxy_setting,
+ Types::DependencyProxy::GroupSettingType,
+ null: true,
+ description: 'Group dependency proxy settings after mutation.'
+
+ def resolve(group_path:, **args)
+ group = authorized_find!(group_path: group_path)
+
+ result = ::DependencyProxy::GroupSettings::UpdateService
+ .new(container: group, current_user: current_user, params: args)
+ .execute
+
+ {
+ dependency_proxy_setting: result.payload[:dependency_proxy_setting],
+ errors: result.errors
+ }
+ end
+
+ private
+
+ def find_object(group_path:)
+ resolve_group(full_path: group_path)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb
index 32f96f1bfe6..70a8f539ccf 100644
--- a/app/graphql/mutations/issues/create.rb
+++ b/app/graphql/mutations/issues/create.rb
@@ -71,7 +71,7 @@ module Mutations
def resolve(project_path:, **attributes)
project = authorized_find!(project_path)
- params = build_create_issue_params(attributes.merge(author_id: current_user.id))
+ params = build_create_issue_params(attributes.merge(author_id: current_user.id), project)
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
@@ -88,7 +88,8 @@ module Mutations
private
- def build_create_issue_params(params)
+ # _project argument is unused here, but it is necessary on the EE version of the method
+ def build_create_issue_params(params, _project)
params[:milestone_id] &&= params[:milestone_id]&.model_id
params[:assignee_ids] &&= params[:assignee_ids].map { |assignee_id| assignee_id&.model_id }
params[:label_ids] &&= params[:label_ids].map { |label_id| label_id&.model_id }
diff --git a/app/graphql/resolvers/board_list_issues_resolver.rb b/app/graphql/resolvers/board_list_issues_resolver.rb
index 7c85dd8fb9b..d70acdf7ca0 100644
--- a/app/graphql/resolvers/board_list_issues_resolver.rb
+++ b/app/graphql/resolvers/board_list_issues_resolver.rb
@@ -18,11 +18,8 @@ module Resolvers
filter_params = filters.merge(board_id: list.board.id, id: list.id)
service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params)
- pagination_connections = Gitlab::Graphql::Pagination::Keyset::Connection.new(service.execute)
- ::Boards::Issues::ListService.initialize_relative_positions(list.board, current_user, pagination_connections.items)
-
- pagination_connections
+ service.execute
end
# https://gitlab.com/gitlab-org/gitlab/-/issues/235681
diff --git a/app/graphql/resolvers/board_list_resolver.rb b/app/graphql/resolvers/board_list_resolver.rb
new file mode 100644
index 00000000000..d853846b674
--- /dev/null
+++ b/app/graphql/resolvers/board_list_resolver.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class BoardListResolver < BaseResolver.single
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include BoardItemFilterable
+
+ type Types::BoardListType, null: true
+ description 'Find an issue board list.'
+
+ authorize :read_issue_board_list
+
+ argument :id, Types::GlobalIDType[List],
+ required: true,
+ description: 'Global ID of the list.'
+
+ argument :issue_filters, Types::Boards::BoardIssueInputType,
+ required: false,
+ description: 'Filters applied when getting issue metadata in the board list.'
+
+ def resolve(id: nil, issue_filters: {})
+ context.scoped_set!(:issue_filters, item_filters(issue_filters))
+
+ Gitlab::Graphql::Lazy.with_value(find_list(id: id)) do |list|
+ list if authorized_resource?(list)
+ end
+ end
+
+ private
+
+ def find_list(id:)
+ GitlabSchema.object_from_id(id, expected_type: ::List)
+ end
+ end
+end
diff --git a/app/graphql/resolvers/clusters/agent_tokens_resolver.rb b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb
new file mode 100644
index 00000000000..5ae19700fd5
--- /dev/null
+++ b/app/graphql/resolvers/clusters/agent_tokens_resolver.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Clusters
+ class AgentTokensResolver < BaseResolver
+ type Types::Clusters::AgentTokenType, null: true
+
+ alias_method :agent, :object
+
+ delegate :project, to: :agent
+
+ def resolve(**args)
+ return ::Clusters::AgentToken.none unless can_read_agent_tokens?
+
+ agent.last_used_agent_tokens
+ end
+
+ private
+
+ def can_read_agent_tokens?
+ current_user.can?(:admin_cluster, project)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/clusters/agents_resolver.rb b/app/graphql/resolvers/clusters/agents_resolver.rb
new file mode 100644
index 00000000000..9b8cea52e3b
--- /dev/null
+++ b/app/graphql/resolvers/clusters/agents_resolver.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Clusters
+ class AgentsResolver < BaseResolver
+ include LooksAhead
+
+ type Types::Clusters::AgentType.connection_type, null: true
+
+ extras [:lookahead]
+
+ when_single do
+ argument :name, GraphQL::Types::String,
+ required: true,
+ description: 'Name of the cluster agent.'
+ end
+
+ alias_method :project, :object
+
+ def resolve_with_lookahead(**args)
+ apply_lookahead(
+ ::Clusters::AgentsFinder
+ .new(project, current_user, params: args)
+ .execute
+ )
+ end
+
+ private
+
+ def preloads
+ { tokens: :last_used_agent_tokens }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index 9de36b5b7d1..855877110e5 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -4,6 +4,7 @@ module IssueResolverArguments
extend ActiveSupport::Concern
prepended do
+ include SearchArguments
include LooksAhead
argument :iid, GraphQL::Types::String,
@@ -49,9 +50,6 @@ module IssueResolverArguments
argument :closed_after, Types::TimeType,
required: false,
description: 'Issues closed after this date.'
- argument :search, GraphQL::Types::String,
- required: false,
- description: 'Search query for issue title or description.'
argument :types, [Types::IssueTypeEnum],
as: :issue_types,
description: 'Filter issues by the given issue types.',
@@ -62,6 +60,10 @@ module IssueResolverArguments
argument :my_reaction_emoji, GraphQL::Types::String,
required: false,
description: 'Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported.'
+ argument :confidential,
+ GraphQL::Types::Boolean,
+ required: false,
+ description: 'Filter for confidential issues. If "false", excludes confidential issues. If "true", returns only confidential issues.'
argument :not, Types::Issues::NegatedIssueFilterInputType,
description: 'Negated arguments.',
prepare: ->(negated_args, ctx) { negated_args.to_h },
@@ -91,6 +93,7 @@ module IssueResolverArguments
params_not_mutually_exclusive(args, mutually_exclusive_assignee_username_args)
params_not_mutually_exclusive(args, mutually_exclusive_milestone_args)
params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args)
+ validate_anonymous_search_access! if args[:search].present?
super
end
diff --git a/app/graphql/resolvers/concerns/search_arguments.rb b/app/graphql/resolvers/concerns/search_arguments.rb
new file mode 100644
index 00000000000..7f480f9d0b6
--- /dev/null
+++ b/app/graphql/resolvers/concerns/search_arguments.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module SearchArguments
+ extend ActiveSupport::Concern
+
+ included do
+ argument :search, GraphQL::Types::String,
+ required: false,
+ description: 'Search query for title or description.'
+ end
+
+ def validate_anonymous_search_access!
+ return if current_user.present? || Feature.disabled?(:disable_anonymous_search, type: :ops)
+
+ raise ::Gitlab::Graphql::Errors::ArgumentError,
+ "User must be authenticated to include the `search` argument."
+ end
+end
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index 47e4e3c0b32..b556964ae0c 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -47,7 +47,8 @@ module Resolvers
alert_management_alert: [:alert_management_alert],
labels: [:labels],
assignees: [:assignees],
- timelogs: [:timelogs]
+ timelogs: [:timelogs],
+ customer_relations_contacts: { customer_relations_contacts: [:group] }
}
end
diff --git a/app/graphql/resolvers/kas/agent_configurations_resolver.rb b/app/graphql/resolvers/kas/agent_configurations_resolver.rb
new file mode 100644
index 00000000000..238dae0bf12
--- /dev/null
+++ b/app/graphql/resolvers/kas/agent_configurations_resolver.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Kas
+ class AgentConfigurationsResolver < BaseResolver
+ type Types::Kas::AgentConfigurationType, null: true
+
+ # Calls Gitaly via KAS
+ calls_gitaly!
+
+ alias_method :project, :object
+
+ def resolve
+ return [] unless can_read_agent_configuration?
+
+ kas_client.list_agent_config_files(project: project)
+ rescue GRPC::BadStatus => e
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable, e.class.name
+ end
+
+ private
+
+ def can_read_agent_configuration?
+ current_user.can?(:admin_cluster, project)
+ end
+
+ def kas_client
+ @kas_client ||= Gitlab::Kas::Client.new
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/kas/agent_connections_resolver.rb b/app/graphql/resolvers/kas/agent_connections_resolver.rb
new file mode 100644
index 00000000000..8b7c4003598
--- /dev/null
+++ b/app/graphql/resolvers/kas/agent_connections_resolver.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Kas
+ class AgentConnectionsResolver < BaseResolver
+ type Types::Kas::AgentConnectionType, null: true
+
+ alias_method :agent, :object
+
+ delegate :project, to: :agent
+
+ def resolve
+ return [] unless can_read_connected_agents?
+
+ BatchLoader::GraphQL.for(agent.id).batch(key: project, default_value: []) do |agent_ids, loader|
+ agents = get_connected_agents.group_by(&:agent_id).slice(*agent_ids)
+
+ agents.each do |agent_id, connections|
+ loader.call(agent_id, connections)
+ end
+ end
+ end
+
+ private
+
+ def can_read_connected_agents?
+ current_user.can?(:admin_cluster, project)
+ end
+
+ def get_connected_agents
+ kas_client.get_connected_agents(project: project)
+ rescue GRPC::BadStatus => e
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable, e.class.name
+ end
+
+ def kas_client
+ @kas_client ||= Gitlab::Kas::Client.new
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/project_pipeline_resolver.rb b/app/graphql/resolvers/project_pipeline_resolver.rb
index ce4b6ac6b0c..5acd7f95606 100644
--- a/app/graphql/resolvers/project_pipeline_resolver.rb
+++ b/app/graphql/resolvers/project_pipeline_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class ProjectPipelineResolver < BaseResolver
+ include LooksAhead
+
type ::Types::Ci::PipelineType, null: true
alias_method :project, :object
@@ -14,7 +16,7 @@ module Resolvers
required: false,
description: 'SHA of the Pipeline. For example, "dyd0f15ay83993f5ab66k927w28673882x99100b".'
- def ready?(iid: nil, sha: nil)
+ def ready?(iid: nil, sha: nil, **args)
unless iid.present? ^ sha.present?
raise Gitlab::Graphql::Errors::ArgumentError, 'Provide one of an IID or SHA'
end
@@ -22,18 +24,21 @@ module Resolvers
super
end
- def resolve(iid: nil, sha: nil)
+ # the preloads are defined on ee/app/graphql/ee/resolvers/project_pipeline_resolver.rb
+ def resolve(iid: nil, sha: nil, **args)
+ self.lookahead = args.delete(:lookahead)
+
if iid
- BatchLoader::GraphQL.for(iid).batch(key: project) do |iids, loader, args|
+ BatchLoader::GraphQL.for(iid).batch(key: project) do |iids, loader|
finder = ::Ci::PipelinesFinder.new(project, current_user, iids: iids)
- finder.execute.each { |pipeline| loader.call(pipeline.iid.to_s, pipeline) }
+ apply_lookahead(finder.execute).each { |pipeline| loader.call(pipeline.iid.to_s, pipeline) }
end
else
- BatchLoader::GraphQL.for(sha).batch(key: project) do |shas, loader, args|
+ BatchLoader::GraphQL.for(sha).batch(key: project) do |shas, loader|
finder = ::Ci::PipelinesFinder.new(project, current_user, sha: shas)
- finder.execute.each { |pipeline| loader.call(pipeline.sha.to_s, pipeline) }
+ apply_lookahead(finder.execute).each { |pipeline| loader.call(pipeline.sha.to_s, pipeline) }
end
end
end
diff --git a/app/graphql/resolvers/project_pipelines_resolver.rb b/app/graphql/resolvers/project_pipelines_resolver.rb
index 0171473a77f..5a1e92efc96 100644
--- a/app/graphql/resolvers/project_pipelines_resolver.rb
+++ b/app/graphql/resolvers/project_pipelines_resolver.rb
@@ -26,3 +26,5 @@ module Resolvers
end
end
# rubocop: enable Graphql/ResolverType
+
+Resolvers::ProjectPipelinesResolver.prepend_mod
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index 9c27f0f8138..93e17ea6dfc 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -9,7 +9,6 @@ module Types
DEFAULT_COMPLEXITY = 1
attr_reader :deprecation, :doc_reference
- attr_writer :max_page_size # Can be removed with :performance_roadmap feature flag: https://gitlab.com/gitlab-org/gitlab/-/issues/337198
def initialize(**kwargs, &block)
@calls_gitaly = !!kwargs.delete(:calls_gitaly)
@@ -21,6 +20,7 @@ module Types
@feature_flag = kwargs[:feature_flag]
kwargs = check_feature_flag(kwargs)
@deprecation = gitlab_deprecation(kwargs)
+ after_connection_extensions = kwargs.delete(:late_extensions) || []
super(**kwargs, &block)
@@ -28,6 +28,8 @@ module Types
extension ::Gitlab::Graphql::CallsGitaly::FieldExtension if Gitlab.dev_or_test_env?
extension ::Gitlab::Graphql::Present::FieldExtension
extension ::Gitlab::Graphql::Authorize::ConnectionFilterExtension
+
+ after_connection_extensions.each { extension _1 } if after_connection_extensions.any?
end
def may_call_gitaly?
diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb
index 762e03973d9..8c67803e39e 100644
--- a/app/graphql/types/board_list_type.rb
+++ b/app/graphql/types/board_list_type.rb
@@ -10,8 +10,10 @@ module Types
alias_method :list, :object
- field :id, GraphQL::Types::ID, null: false,
+ field :id, GraphQL::Types::ID,
+ null: false,
description: 'ID (global ID) of the list.'
+
field :title, GraphQL::Types::String, null: false,
description: 'Title of the list.'
field :list_type, GraphQL::Types::String, null: false,
@@ -27,6 +29,7 @@ module Types
field :issues, ::Types::IssueType.connection_type, null: true,
description: 'Board issues.',
+ late_extensions: [Gitlab::Graphql::Board::IssuesConnectionExtension],
resolver: ::Resolvers::BoardListIssuesResolver
def issues_count
@@ -46,6 +49,16 @@ module Types
.metadata
end
end
+
+ # board lists have a data dependency on label - so we batch load them here
+ def title
+ BatchLoader::GraphQL.for(object).batch do |lists, callback|
+ ActiveRecord::Associations::Preloader.new.preload(lists, :label) # rubocop: disable CodeReuse/ActiveRecord
+
+ # all list titles are preloaded at this point
+ lists.each { |list| callback.call(list, list.title) }
+ end
+ end
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/ci/runner_status_enum.rb b/app/graphql/types/ci/runner_status_enum.rb
index ad69175e44a..8501ce20204 100644
--- a/app/graphql/types/ci/runner_status_enum.rb
+++ b/app/graphql/types/ci/runner_status_enum.rb
@@ -6,8 +6,21 @@ module Types
graphql_name 'CiRunnerStatus'
::Ci::Runner::AVAILABLE_STATUSES.each do |status|
+ description = case status
+ when 'active'
+ "A runner that is not paused."
+ when 'online'
+ "A runner that contacted this instance within the last #{::Ci::Runner::ONLINE_CONTACT_TIMEOUT.inspect}."
+ when 'offline'
+ "A runner that has not contacted this instance within the last #{::Ci::Runner::ONLINE_CONTACT_TIMEOUT.inspect}."
+ when 'not_connected'
+ "A runner that has never contacted this instance."
+ else
+ "A runner that is #{status.to_s.tr('_', ' ')}."
+ end
+
value status.to_s.upcase,
- description: "A runner that is #{status.to_s.tr('_', ' ')}.",
+ description: description,
value: status.to_sym
end
end
diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb
index e2c8070af0c..9bf98aa7e86 100644
--- a/app/graphql/types/ci/runner_type.rb
+++ b/app/graphql/types/ci/runner_type.rb
@@ -3,10 +3,13 @@
module Types
module Ci
class RunnerType < BaseObject
+ edge_type_class(RunnerWebUrlEdge)
graphql_name 'CiRunner'
authorize :read_runner
present_using ::Ci::RunnerPresenter
+ expose_permissions Types::PermissionTypes::Ci::Runner
+
JOB_COUNT_LIMIT = 1000
alias_method :runner, :object
@@ -46,12 +49,18 @@ module Types
description: 'Number of projects that the runner is associated with.'
field :job_count, GraphQL::Types::Int, null: true,
description: "Number of jobs processed by the runner (limited to #{JOB_COUNT_LIMIT}, plus one to indicate that more items exist)."
+ field :admin_url, GraphQL::Types::String, null: true,
+ description: 'Admin URL of the runner. Only available for adminstrators.'
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
+ def admin_url
+ Gitlab::Routing.url_helpers.admin_runner_url(runner) if can_admin_runners?
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def project_count
BatchLoader::GraphQL.for(runner.id).batch(key: :runner_project_count) do |ids, loader, args|
@@ -68,6 +77,12 @@ module Types
end
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ private
+
+ def can_admin_runners?
+ context[:current_user]&.can_admin_all_resources?
+ end
end
end
end
diff --git a/app/graphql/types/ci/runner_web_url_edge.rb b/app/graphql/types/ci/runner_web_url_edge.rb
new file mode 100644
index 00000000000..3b9fdfd1571
--- /dev/null
+++ b/app/graphql/types/ci/runner_web_url_edge.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ # rubocop: disable Graphql/AuthorizeTypes
+ class RunnerWebUrlEdge < GraphQL::Types::Relay::BaseEdge
+ include FindClosest
+
+ field :web_url, GraphQL::Types::String, null: true,
+ description: 'Web URL of the runner. The value depends on where you put this field in the query. You can use it for projects or groups.',
+ extras: [:parent]
+
+ def initialize(node, connection)
+ super
+
+ @runner = node.node
+ end
+
+ def web_url(parent:)
+ owner = closest_parent([::Types::ProjectType, ::Types::GroupType], parent)
+
+ case owner
+ when ::Group
+ Gitlab::Routing.url_helpers.group_runner_url(owner, @runner)
+ when ::Project
+ Gitlab::Routing.url_helpers.project_runner_url(owner, @runner)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/clusters/agent_token_type.rb b/app/graphql/types/clusters/agent_token_type.rb
new file mode 100644
index 00000000000..94c5fc46a5d
--- /dev/null
+++ b/app/graphql/types/clusters/agent_token_type.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Types
+ module Clusters
+ class AgentTokenType < BaseObject
+ graphql_name 'ClusterAgentToken'
+
+ authorize :admin_cluster
+
+ connection_type_class(Types::CountableConnectionType)
+
+ field :cluster_agent,
+ Types::Clusters::AgentType,
+ description: 'Cluster agent this token is associated with.',
+ null: true
+
+ field :created_at,
+ Types::TimeType,
+ null: true,
+ description: 'Timestamp the token was created.'
+
+ field :created_by_user,
+ Types::UserType,
+ null: true,
+ description: 'User who created the token.'
+
+ field :description,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Description of the token.'
+
+ field :last_used_at,
+ Types::TimeType,
+ null: true,
+ description: 'Timestamp the token was last used.'
+
+ field :id,
+ ::Types::GlobalIDType[::Clusters::AgentToken],
+ null: false,
+ description: 'Global ID of the token.'
+
+ field :name,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Name given to the token.'
+
+ def cluster_agent
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(::Clusters::Agent, object.agent_id).find
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/clusters/agent_type.rb b/app/graphql/types/clusters/agent_type.rb
new file mode 100644
index 00000000000..ce748f6e8ae
--- /dev/null
+++ b/app/graphql/types/clusters/agent_type.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Types
+ module Clusters
+ class AgentType < BaseObject
+ graphql_name 'ClusterAgent'
+
+ authorize :admin_cluster
+
+ connection_type_class(Types::CountableConnectionType)
+
+ field :created_at,
+ Types::TimeType,
+ null: true,
+ description: 'Timestamp the cluster agent was created.'
+
+ field :created_by_user,
+ Types::UserType,
+ null: true,
+ description: 'User object, containing information about the person who created the agent.'
+
+ field :id, GraphQL::Types::ID,
+ null: false,
+ description: 'ID of the cluster agent.'
+
+ field :name,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Name of the cluster agent.'
+
+ field :project, Types::ProjectType,
+ description: 'Project this cluster agent is associated with.',
+ null: true,
+ authorize: :read_project
+
+ field :tokens, Types::Clusters::AgentTokenType.connection_type,
+ description: 'Tokens associated with the cluster agent.',
+ null: true,
+ resolver: ::Resolvers::Clusters::AgentTokensResolver
+
+ field :updated_at,
+ Types::TimeType,
+ null: true,
+ description: 'Timestamp the cluster agent was updated.'
+
+ field :web_path,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Web path of the cluster agent.'
+
+ field :connections,
+ Types::Kas::AgentConnectionType.connection_type,
+ null: true,
+ description: 'Active connections for the cluster agent',
+ complexity: 5,
+ resolver: ::Resolvers::Kas::AgentConnectionsResolver
+
+ def project
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
+ end
+
+ def web_path
+ ::Gitlab::Routing.url_helpers.project_cluster_agent_path(object.project, object.name)
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/concerns/find_closest.rb b/app/graphql/types/concerns/find_closest.rb
index 1d76e872364..3064db19ea0 100644
--- a/app/graphql/types/concerns/find_closest.rb
+++ b/app/graphql/types/concerns/find_closest.rb
@@ -1,11 +1,15 @@
# frozen_string_literal: true
module FindClosest
- # Find the closest node of a given type above this node, and return the domain object
- def closest_parent(type, parent)
- parent = parent.try(:parent) while parent && parent.object.class != type
- return unless parent
+ # Find the closest node which has any of the given types above this node, and return the domain object
+ def closest_parent(types, parent)
+ while parent
- parent.object.object
+ if types.any? {|type| parent.object.instance_of? type}
+ return parent.object.object
+ else
+ parent = parent.try(:parent)
+ end
+ end
end
end
diff --git a/app/graphql/types/container_expiration_policy_older_than_enum.rb b/app/graphql/types/container_expiration_policy_older_than_enum.rb
index 7364910f8cd..9c32d767caf 100644
--- a/app/graphql/types/container_expiration_policy_older_than_enum.rb
+++ b/app/graphql/types/container_expiration_policy_older_than_enum.rb
@@ -6,6 +6,7 @@ module Types
'7d': 'SEVEN_DAYS',
'14d': 'FOURTEEN_DAYS',
'30d': 'THIRTY_DAYS',
+ '60d': 'SIXTY_DAYS',
'90d': 'NINETY_DAYS'
}.freeze
diff --git a/app/graphql/types/container_repository_details_type.rb b/app/graphql/types/container_repository_details_type.rb
index 1a9f57e701f..8190cc9bc25 100644
--- a/app/graphql/types/container_repository_details_type.rb
+++ b/app/graphql/types/container_repository_details_type.rb
@@ -17,5 +17,11 @@ module Types
def can_delete
Ability.allowed?(current_user, :destroy_container_image, object)
end
+
+ def tags
+ object.tags
+ rescue Faraday::Error
+ raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'We are having trouble connecting to the Container Registry. If this error persists, please review the troubleshooting documentation.'
+ end
end
end
diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb
index 67093f57862..1fe5cf112f0 100644
--- a/app/graphql/types/container_repository_type.rb
+++ b/app/graphql/types/container_repository_type.rb
@@ -28,5 +28,11 @@ module Types
def project
Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
end
+
+ def tags_count
+ object.tags_count
+ rescue Faraday::Error
+ raise ::Gitlab::Graphql::Errors::ResourceNotAvailable, 'We are having trouble connecting to the Container Registry. If this error persists, please review the troubleshooting documentation.'
+ end
end
end
diff --git a/app/graphql/types/customer_relations/contact_type.rb b/app/graphql/types/customer_relations/contact_type.rb
index 35b5bf45698..b5224a3e239 100644
--- a/app/graphql/types/customer_relations/contact_type.rb
+++ b/app/graphql/types/customer_relations/contact_type.rb
@@ -39,7 +39,7 @@ module Types
field :description,
GraphQL::Types::String,
null: true,
- description: 'Description or notes for the contact.'
+ description: 'Description of or notes for the contact.'
field :created_at,
Types::TimeType,
diff --git a/app/graphql/types/customer_relations/organization_type.rb b/app/graphql/types/customer_relations/organization_type.rb
index 0e091d4a9a3..9b22fa35b11 100644
--- a/app/graphql/types/customer_relations/organization_type.rb
+++ b/app/graphql/types/customer_relations/organization_type.rb
@@ -25,7 +25,7 @@ module Types
field :description,
GraphQL::Types::String,
null: true,
- description: 'Description or notes for the organization.'
+ description: 'Description of or notes for the organization.'
field :created_at,
Types::TimeType,
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 79e789d3f8b..826ae61a1a3 100644
--- a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb
+++ b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb
@@ -13,6 +13,9 @@ module Types
field :id, GraphQL::Types::ID,
null: false,
description: 'ID (global ID) of the error.'
+ field :integrated, GraphQL::Types::Boolean,
+ null: true,
+ description: 'Error tracking backend.'
field :sentry_id, GraphQL::Types::String,
method: :id,
null: false,
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 8fe4ba557ea..b1bbabcdaed 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -234,6 +234,10 @@ module Types
)
end
+ def dependency_proxy_setting
+ group.dependency_proxy_setting || group.create_dependency_proxy_setting
+ end
+
private
def group
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index c8db2b84ff2..3b0f93d8dc1 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -136,6 +136,9 @@ module Types
field :project_id, GraphQL::Types::Int, null: false, method: :project_id,
description: 'ID of the issue project.'
+ field :customer_relations_contacts, Types::CustomerRelations::ContactType.connection_type, null: true,
+ description: 'Customer relations contacts of the issue.'
+
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 4f620a5b3d9..c8b7cdaa68e 100644
--- a/app/graphql/types/issues/negated_issue_filter_input_type.rb
+++ b/app/graphql/types/issues/negated_issue_filter_input_type.rb
@@ -29,6 +29,10 @@ module Types
argument :my_reaction_emoji, GraphQL::Types::String,
required: false,
description: 'Filter by reaction emoji applied by the current user.'
+ argument :types, [Types::IssueTypeEnum],
+ as: :issue_types,
+ description: 'Filters out issues by the given issue types.',
+ required: false
end
end
end
diff --git a/app/graphql/types/kas/agent_configuration_type.rb b/app/graphql/types/kas/agent_configuration_type.rb
new file mode 100644
index 00000000000..397a5739671
--- /dev/null
+++ b/app/graphql/types/kas/agent_configuration_type.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Types
+ module Kas
+ # rubocop: disable Graphql/AuthorizeTypes
+ class AgentConfigurationType < BaseObject
+ graphql_name 'AgentConfiguration'
+ description 'Configuration details for an Agent'
+
+ field :agent_name,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Name of the agent.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/kas/agent_connection_type.rb b/app/graphql/types/kas/agent_connection_type.rb
new file mode 100644
index 00000000000..9c6321bece9
--- /dev/null
+++ b/app/graphql/types/kas/agent_connection_type.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Types
+ module Kas
+ # rubocop: disable Graphql/AuthorizeTypes
+ class AgentConnectionType < BaseObject
+ graphql_name 'ConnectedAgent'
+ description 'Connection details for an Agent'
+
+ field :connected_at,
+ Types::TimeType,
+ null: true,
+ description: 'When the connection was established.'
+
+ field :connection_id,
+ GraphQL::Types::BigInt,
+ null: true,
+ description: 'ID of the connection.'
+
+ field :metadata,
+ Types::Kas::AgentMetadataType,
+ method: :agent_meta,
+ null: true,
+ description: 'Information about the Agent.'
+
+ def connected_at
+ Time.at(object.connected_at.seconds)
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/kas/agent_metadata_type.rb b/app/graphql/types/kas/agent_metadata_type.rb
new file mode 100644
index 00000000000..4a3bb09b9e1
--- /dev/null
+++ b/app/graphql/types/kas/agent_metadata_type.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Types
+ module Kas
+ # rubocop: disable Graphql/AuthorizeTypes
+ class AgentMetadataType < BaseObject
+ graphql_name 'AgentMetadata'
+ description 'Information about a connected Agent'
+
+ field :version,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Agent version tag.'
+
+ field :commit,
+ GraphQL::Types::String,
+ method: :commit_id,
+ null: true,
+ description: 'Agent version commit.'
+
+ field :pod_namespace,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Namespace of the pod running the Agent.'
+
+ field :pod_name,
+ GraphQL::Types::String,
+ null: true,
+ description: 'Name of the pod running the Agent.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/merge_requests/interacts_with_merge_request.rb b/app/graphql/types/merge_requests/interacts_with_merge_request.rb
index d685ac4d3c9..d4a1f2faa8d 100644
--- a/app/graphql/types/merge_requests/interacts_with_merge_request.rb
+++ b/app/graphql/types/merge_requests/interacts_with_merge_request.rb
@@ -14,7 +14,7 @@ module Types
end
def merge_request_interaction(parent:)
- merge_request = closest_parent(::Types::MergeRequestType, parent)
+ merge_request = closest_parent([::Types::MergeRequestType], parent)
return unless merge_request
Users::MergeRequestInteraction.new(user: object, merge_request: merge_request)
diff --git a/app/graphql/types/milestone_wildcard_id_enum.rb b/app/graphql/types/milestone_wildcard_id_enum.rb
index 12e8e07fb05..ad9651a26dc 100644
--- a/app/graphql/types/milestone_wildcard_id_enum.rb
+++ b/app/graphql/types/milestone_wildcard_id_enum.rb
@@ -8,6 +8,6 @@ module Types
value 'NONE', 'No milestone is assigned.'
value 'ANY', 'Milestone is assigned.'
value 'STARTED', 'Milestone assigned is open and started (start date <= today).'
- value 'UPCOMING', 'Milestone assigned is due closest in the future (due date > today).'
+ value 'UPCOMING', 'Milestone assigned is due in the future (due date > today).'
end
end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index ea50af1c554..cd4c45d2942 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -31,13 +31,20 @@ module Types
mount_mutation Mutations::Boards::Lists::Update
mount_mutation Mutations::Boards::Lists::Destroy
mount_mutation Mutations::Branches::Create, calls_gitaly: true
+ mount_mutation Mutations::Clusters::Agents::Create
+ mount_mutation Mutations::Clusters::Agents::Delete
+ mount_mutation Mutations::Clusters::AgentTokens::Create
+ mount_mutation Mutations::Clusters::AgentTokens::Delete
mount_mutation Mutations::Commits::Create, calls_gitaly: true
mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji
mount_mutation Mutations::CustomEmoji::Destroy, feature_flag: :custom_emoji
+ mount_mutation Mutations::CustomerRelations::Contacts::Create
+ mount_mutation Mutations::CustomerRelations::Contacts::Update
mount_mutation Mutations::CustomerRelations::Organizations::Create
mount_mutation Mutations::CustomerRelations::Organizations::Update
mount_mutation Mutations::Discussions::ToggleResolve
mount_mutation Mutations::DependencyProxy::ImageTtlGroupPolicy::Update
+ mount_mutation Mutations::DependencyProxy::GroupSettings::Update
mount_mutation Mutations::Environments::CanaryIngress::Update
mount_mutation Mutations::Issues::Create
mount_mutation Mutations::Issues::SetAssignees
diff --git a/app/graphql/types/packages/nuget/metadatum_type.rb b/app/graphql/types/packages/nuget/metadatum_type.rb
index ed9d97724af..b58fd954a74 100644
--- a/app/graphql/types/packages/nuget/metadatum_type.rb
+++ b/app/graphql/types/packages/nuget/metadatum_type.rb
@@ -10,9 +10,9 @@ module Types
authorize :read_package
field :id, ::Types::GlobalIDType[::Packages::Nuget::Metadatum], null: false, description: 'ID of the metadatum.'
- field :license_url, GraphQL::Types::String, null: false, description: 'License URL of the Nuget package.'
- field :project_url, GraphQL::Types::String, null: false, description: 'Project URL of the Nuget package.'
- field :icon_url, GraphQL::Types::String, null: false, description: 'Icon URL of the Nuget package.'
+ field :license_url, GraphQL::Types::String, null: true, description: 'License URL of the Nuget package.'
+ field :project_url, GraphQL::Types::String, null: true, description: 'Project URL of the Nuget package.'
+ field :icon_url, GraphQL::Types::String, null: true, description: 'Icon URL of the Nuget package.'
end
end
end
diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb
index f3fa79cc08c..9851c6aec7e 100644
--- a/app/graphql/types/packages/package_type.rb
+++ b/app/graphql/types/packages/package_type.rb
@@ -6,6 +6,8 @@ module Types
graphql_name 'Package'
description 'Represents a package in the Package Registry. Note that this type is in beta and susceptible to changes'
+ connection_type_class(Types::CountableConnectionType)
+
authorize :read_package
field :id, ::Types::GlobalIDType[::Packages::Package], null: false,
@@ -26,6 +28,7 @@ module Types
description: 'Other versions of the package.',
deprecated: { reason: 'This field is now only returned in the PackageDetailsType', milestone: '13.11' }
field :status, Types::Packages::PackageStatusEnum, null: false, description: 'Package status.'
+ field :can_destroy, GraphQL::Types::Boolean, null: false, description: 'Whether the user can destroy the package.'
def project
Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
@@ -35,6 +38,10 @@ module Types
[]
end
+ def can_destroy
+ Ability.allowed?(current_user, :destroy_package, object)
+ end
+
# NOTE: This method must be kept in sync with the union
# type: `Types::Packages::MetadataType`.
#
diff --git a/app/graphql/types/permission_types/ci/runner.rb b/app/graphql/types/permission_types/ci/runner.rb
new file mode 100644
index 00000000000..2e92a4011e9
--- /dev/null
+++ b/app/graphql/types/permission_types/ci/runner.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Types
+ module PermissionTypes
+ module Ci
+ class Runner < BasePermissionType
+ graphql_name 'RunnerPermissions'
+
+ abilities :read_runner, :update_runner, :delete_runner
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index aef46a05a2f..791875242df 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -208,6 +208,7 @@ module Types
Types::Ci::PipelineType,
null: true,
description: 'Build pipeline of the project.',
+ extras: [:lookahead],
resolver: Resolvers::ProjectPipelineResolver
field :ci_cd_settings,
@@ -361,6 +362,25 @@ module Types
complexity: 5,
resolver: ::Resolvers::TimelogResolver
+ field :agent_configurations,
+ ::Types::Kas::AgentConfigurationType.connection_type,
+ null: true,
+ description: 'Agent configurations defined by the project',
+ resolver: ::Resolvers::Kas::AgentConfigurationsResolver
+
+ field :cluster_agent,
+ ::Types::Clusters::AgentType,
+ null: true,
+ description: 'Find a single cluster agent by name.',
+ resolver: ::Resolvers::Clusters::AgentsResolver.single
+
+ field :cluster_agents,
+ ::Types::Clusters::AgentType.connection_type,
+ extras: [:lookahead],
+ null: true,
+ description: 'Cluster agents associated with the project.',
+ resolver: ::Resolvers::Clusters::AgentsResolver
+
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args|
LabelsFinder
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index e02191fbf3e..ed4ddbb982b 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -136,6 +136,10 @@ module Types
complexity: 5,
resolver: ::Resolvers::TimelogResolver
+ field :board_list, ::Types::BoardListType,
+ null: true,
+ resolver: Resolvers::BoardListResolver
+
def design_management
DesignManagementObject.new(nil)
end