diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index b056b50d16d9dd0f4c5d2e1209822bc235958a95..774de53928981a3d126448dcf1c4798ed5b76d3c 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -25481,6 +25481,10 @@ four standard [pagination arguments](#pagination-arguments):
Cluster agents in the namespace with remote development capabilities.
+DETAILS:
+**Deprecated** in GitLab 17.8.
+Use `workspacesClusterAgents`.
+
Returns [`ClusterAgentConnection`](#clusteragentconnection).
This field returns a [connection](#connections). It accepts the
@@ -25966,6 +25970,26 @@ four standard [pagination arguments](#pagination-arguments):
| `subscribed` **{warning-solid}** | [`SubscriptionStatus`](#subscriptionstatus) | **Introduced** in GitLab 17.5. **Status**: Experiment. Work items the current user is subscribed to. Is ignored if `filter_subscriptions` feature flag is disabled. |
| `types` | [`[IssueType!]`](#issuetype) | Filter work items by the given work item types. |
+##### `Group.workspacesClusterAgents`
+
+Cluster agents in the namespace with workspaces capabilities.
+
+DETAILS:
+**Introduced** in GitLab 17.8.
+**Status**: Experiment.
+
+Returns [`ClusterAgentConnection`](#clusteragentconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#pagination-arguments):
+`before: String`, `after: String`, `first: Int`, and `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `filter` | [`NamespaceClusterAgentFilter!`](#namespaceclusteragentfilter) | Filter the types of cluster agents to return. |
+
### `GroupAuditEventNamespaceFilter`
Represents a subgroup or project filter that belongs to a group level external audit event streaming destination.
@@ -29634,6 +29658,10 @@ four standard [pagination arguments](#pagination-arguments):
Cluster agents in the namespace with remote development capabilities.
+DETAILS:
+**Deprecated** in GitLab 17.8.
+Use `workspacesClusterAgents`.
+
Returns [`ClusterAgentConnection`](#clusteragentconnection).
This field returns a [connection](#connections). It accepts the
@@ -29763,6 +29791,26 @@ four standard [pagination arguments](#pagination-arguments):
| ---- | ---- | ----------- |
| `name` | [`IssueType`](#issuetype) | Filter work item types by the given name. |
+##### `Namespace.workspacesClusterAgents`
+
+Cluster agents in the namespace with workspaces capabilities.
+
+DETAILS:
+**Introduced** in GitLab 17.8.
+**Status**: Experiment.
+
+Returns [`ClusterAgentConnection`](#clusteragentconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#pagination-arguments):
+`before: String`, `after: String`, `first: Int`, and `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| `filter` | [`NamespaceClusterAgentFilter!`](#namespaceclusteragentfilter) | Filter the types of cluster agents to return. |
+
### `NamespaceBan`
#### Fields
diff --git a/ee/app/finders/remote_development/cluster_agents_finder.rb b/ee/app/finders/remote_development/cluster_agents_finder.rb
index 7eedf70acce6c4f419a8ae82e3182a292f066bc3..892ad043265d3d771cef6e272c5a94cdcb7eec70 100644
--- a/ee/app/finders/remote_development/cluster_agents_finder.rb
+++ b/ee/app/finders/remote_development/cluster_agents_finder.rb
@@ -11,7 +11,7 @@ def self.execute(namespace:, filter:, user:)
def self.fetch_agents(filter, namespace, user)
case filter
when :unmapped
- validate_user_can_read_namespace_agent_mappings!(user: user, namespace: namespace)
+ return Clusters::Agent.none unless user_can_read_namespace_agent_mappings?(user: user, namespace: namespace)
# noinspection RailsParamDefResolve -- A symbol is a valid argument for 'select'
existing_mapped_agents =
@@ -26,7 +26,7 @@ def self.fetch_agents(filter, namespace, user)
namespace.cluster_agents.id_not_in(existing_mapped_agents)
when :directly_mapped
- validate_user_can_read_namespace_agent_mappings!(user: user, namespace: namespace)
+ return Clusters::Agent.none unless user_can_read_namespace_agent_mappings?(user: user, namespace: namespace)
relevant_mappings = RemoteDevelopmentNamespaceClusterAgentMapping.for_namespaces([namespace.id])
relevant_mappings =
@@ -48,11 +48,8 @@ def self.fetch_agents(filter, namespace, user)
end
end
- def self.validate_user_can_read_namespace_agent_mappings!(user:, namespace:)
- raise Gitlab::Access::AccessDeniedError unless user.can?(
- :read_remote_development_cluster_agent_mapping,
- namespace
- )
+ def self.user_can_read_namespace_agent_mappings?(user:, namespace:)
+ user.can?(:read_remote_development_cluster_agent_mapping, namespace)
end
end
end
diff --git a/ee/app/graphql/ee/types/clusters/agent_type.rb b/ee/app/graphql/ee/types/clusters/agent_type.rb
index 7037ba7b7eef047eb5a2f1655661cc9d6a85673a..ea5a9f524e8c4e1a982b96e7a2f5b15adb439930 100644
--- a/ee/app/graphql/ee/types/clusters/agent_type.rb
+++ b/ee/app/graphql/ee/types/clusters/agent_type.rb
@@ -26,7 +26,7 @@ module AgentType
field :workspaces,
::Types::RemoteDevelopment::WorkspaceType.connection_type,
null: true,
- resolver: ::Resolvers::RemoteDevelopment::WorkspacesForAgentResolver,
+ resolver: ::Resolvers::RemoteDevelopment::ClusterAgent::WorkspacesResolver,
description: 'Workspaces associated with the agent.'
field :remote_development_agent_config,
@@ -34,7 +34,7 @@ module AgentType
extras: [:lookahead],
null: true,
description: 'Remote development agent config for the cluster agent.',
- resolver: ::Resolvers::RemoteDevelopment::RemoteDevelopmentAgentConfigForAgentResolver,
+ resolver: ::Resolvers::RemoteDevelopment::ClusterAgent::RemoteDevelopmentAgentConfigResolver,
experiment: { milestone: '17.4' }
field :workspaces_agent_config,
@@ -42,7 +42,7 @@ module AgentType
extras: [:lookahead],
null: true,
description: 'Workspaces agent config for the cluster agent.',
- resolver: ::Resolvers::RemoteDevelopment::WorkspacesAgentConfigForAgentResolver,
+ resolver: ::Resolvers::RemoteDevelopment::ClusterAgent::WorkspacesAgentConfigResolver,
experiment: { milestone: '17.4' }
def url_configurations
diff --git a/ee/app/graphql/ee/types/current_user_type.rb b/ee/app/graphql/ee/types/current_user_type.rb
index 71c5e0d0f36d81a76d5d10ee3a0e249a52d8bc29..f16a35e5342bb88ad5a5651cf7ac3b879c07ad51 100644
--- a/ee/app/graphql/ee/types/current_user_type.rb
+++ b/ee/app/graphql/ee/types/current_user_type.rb
@@ -9,7 +9,7 @@ module CurrentUserType
prepended do
field :workspaces,
description: 'Workspaces owned by the current user.',
- resolver: ::Resolvers::RemoteDevelopment::WorkspacesForCurrentUserResolver
+ resolver: ::Resolvers::RemoteDevelopment::WorkspacesResolver
field :duo_chat_available, ::GraphQL::Types::Boolean,
resolver: ::Resolvers::Ai::UserChatAccessResolver,
diff --git a/ee/app/graphql/ee/types/namespace_type.rb b/ee/app/graphql/ee/types/namespace_type.rb
index 8a888ad6d33d81602da224c0ed51a77a4d92617d..4d2184909a456eb091c502812f40be20c053d4c2 100644
--- a/ee/app/graphql/ee/types/namespace_type.rb
+++ b/ee/app/graphql/ee/types/namespace_type.rb
@@ -136,10 +136,11 @@ module NamespaceType
field :remote_development_cluster_agents,
::Types::Clusters::AgentType.connection_type,
+ deprecated: { reason: 'Use `workspacesClusterAgents`', milestone: '17.8' },
extras: [:lookahead],
null: true,
description: 'Cluster agents in the namespace with remote development capabilities',
- resolver: ::Resolvers::RemoteDevelopment::AgentsForNamespaceResolver
+ resolver: ::Resolvers::RemoteDevelopment::Namespace::ClusterAgentsResolver
field :subscription_history,
::Types::GitlabSubscriptions::SubscriptionHistoryType.connection_type,
@@ -147,6 +148,15 @@ module NamespaceType
description: 'Find subscription history records.',
experiment: { milestone: '17.3' },
method: :gitlab_subscription_histories
+
+ field :workspaces_cluster_agents,
+ ::Types::Clusters::AgentType.connection_type,
+ extras: [:lookahead],
+ null: true,
+ description: 'Cluster agents in the namespace with workspaces capabilities',
+ experiment: { milestone: '17.8' },
+ resolver: ::Resolvers::RemoteDevelopment::Namespace::ClusterAgentsResolver
+
def product_analytics_stored_events_limit
object.root_ancestor.product_analytics_stored_events_limit
end
diff --git a/ee/app/graphql/ee/types/query_type.rb b/ee/app/graphql/ee/types/query_type.rb
index a59094139f785dd5bda8039d4e45ff5065051bdf..4b9aa30bd8b638eef86cf748c20a9f81ee6d9a17 100644
--- a/ee/app/graphql/ee/types/query_type.rb
+++ b/ee/app/graphql/ee/types/query_type.rb
@@ -98,7 +98,7 @@ module QueryType
field :workspaces,
::Types::RemoteDevelopment::WorkspaceType.connection_type,
null: true,
- resolver: ::Resolvers::RemoteDevelopment::WorkspacesForQueryRootResolver,
+ resolver: ::Resolvers::RemoteDevelopment::AdminWorkspacesResolver,
description: 'Find workspaces across the entire instance. This field is only available to instance admins, ' \
'it will return an empty result for all non-admins.'
field :instance_external_audit_event_destinations,
diff --git a/ee/app/graphql/ee/types/user_type.rb b/ee/app/graphql/ee/types/user_type.rb
index b2d035b5437397aa142653e2c30910c7bd424a53..e9b815c09d08363df51e51350563eb2694e63371 100644
--- a/ee/app/graphql/ee/types/user_type.rb
+++ b/ee/app/graphql/ee/types/user_type.rb
@@ -9,7 +9,7 @@ module UserType
prepended do
field :workspaces,
description: 'Workspaces owned by the current user.',
- resolver: ::Resolvers::RemoteDevelopment::WorkspacesForCurrentUserResolver
+ resolver: ::Resolvers::RemoteDevelopment::WorkspacesResolver
end
end
end
diff --git a/ee/app/graphql/resolvers/remote_development/workspaces_for_query_root_resolver.rb b/ee/app/graphql/resolvers/remote_development/admin_workspaces_resolver.rb
similarity index 98%
rename from ee/app/graphql/resolvers/remote_development/workspaces_for_query_root_resolver.rb
rename to ee/app/graphql/resolvers/remote_development/admin_workspaces_resolver.rb
index 6009e607f052d9e3899cb43ab99575cfea660dfc..ff856113f963775ea48e486418e0b85e06f95931 100644
--- a/ee/app/graphql/resolvers/remote_development/workspaces_for_query_root_resolver.rb
+++ b/ee/app/graphql/resolvers/remote_development/admin_workspaces_resolver.rb
@@ -2,7 +2,7 @@
module Resolvers
module RemoteDevelopment
- class WorkspacesForQueryRootResolver < ::Resolvers::BaseResolver
+ class AdminWorkspacesResolver < ::Resolvers::BaseResolver
include ResolvesIds
# NOTE: We are intentionally not including Gitlab::Graphql::Authorize::AuthorizeResource, because this resolver
diff --git a/ee/app/graphql/resolvers/remote_development/agents_for_namespace_resolver.rb b/ee/app/graphql/resolvers/remote_development/agents_for_namespace_resolver.rb
deleted file mode 100644
index d67df22afa414524cee822a3c693d3887c6f58f1..0000000000000000000000000000000000000000
--- a/ee/app/graphql/resolvers/remote_development/agents_for_namespace_resolver.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
- module RemoteDevelopment
- class AgentsForNamespaceResolver < ::Resolvers::BaseResolver
- include Gitlab::Graphql::Authorize::AuthorizeResource
-
- type Types::Clusters::AgentType.connection_type, null: true
-
- argument :filter, Types::RemoteDevelopment::NamespaceClusterAgentFilterEnum,
- required: true,
- description: 'Filter the types of cluster agents to return.'
-
- def resolve(**args)
- unless License.feature_available?(:remote_development)
- raise_resource_not_available_error! "'remote_development' licensed feature is not available"
- end
-
- raise_resource_not_available_error! unless @object.group_namespace?
-
- ::RemoteDevelopment::ClusterAgentsFinder.execute(
- namespace: @object,
- filter: args[:filter].downcase.to_sym,
- user: current_user
- )
- rescue Gitlab::Access::AccessDeniedError
- raise_resource_not_available_error!
- end
- end
- end
-end
diff --git a/ee/app/graphql/resolvers/remote_development/cluster_agent/remote_development_agent_config_resolver.rb b/ee/app/graphql/resolvers/remote_development/cluster_agent/remote_development_agent_config_resolver.rb
new file mode 100644
index 0000000000000000000000000000000000000000..46a91d17d4ce33f7d3377b0b1f094f94219991dd
--- /dev/null
+++ b/ee/app/graphql/resolvers/remote_development/cluster_agent/remote_development_agent_config_resolver.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+# TODO: clusterAgent.remoteDevelopmentAgentConfig GraphQL is deprecated - remove in 17.10 - https://gitlab.com/gitlab-org/gitlab/-/issues/480769
+module Resolvers
+ module RemoteDevelopment
+ module ClusterAgent
+ class RemoteDevelopmentAgentConfigResolver < ::Resolvers::BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include LooksAhead
+
+ type Types::RemoteDevelopment::RemoteDevelopmentAgentConfigType, null: true
+
+ alias_method :agent, :object
+
+ # @param [Hash] _args Not used
+ # @return [RemoteDevelopmentAgentConfig]
+ def resolve_with_lookahead(**_args)
+ unless License.feature_available?(:remote_development)
+ raise_resource_not_available_error! "'remote_development' licensed feature is not available"
+ end
+
+ raise Gitlab::Access::AccessDeniedError unless can_read_remote_development_agent_config?
+
+ BatchLoader::GraphQL.for(agent.id).batch do |agent_ids, loader|
+ agent_configs = ::RemoteDevelopment::RemoteDevelopmentAgentConfigsFinder.execute(
+ current_user: current_user,
+ cluster_agent_ids: agent_ids
+ )
+ apply_lookahead(agent_configs).each do |agent_config|
+ # noinspection RubyResolve -- https://handbook.gitlab.com/handbook/tools-and-tips/editors-and-ides/jetbrains-ides/tracked-jetbrains-issues/#ruby-32301
+ loader.call(agent_config.cluster_agent_id, agent_config)
+ end
+ end
+ end
+
+ private
+
+ # @return [TrueClass, FalseClass]
+ def can_read_remote_development_agent_config?
+ # noinspection RubyNilAnalysis - This is because the superclass #current_user uses #[], which can return nil
+ current_user.can?(:read_cluster_agent, agent)
+ end
+ end
+ end
+ end
+end
diff --git a/ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_agent_config_resolver.rb b/ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_agent_config_resolver.rb
new file mode 100644
index 0000000000000000000000000000000000000000..908f9dc7a5d70652ae5c27f0b83b567cf5ef6edf
--- /dev/null
+++ b/ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_agent_config_resolver.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module RemoteDevelopment
+ module ClusterAgent
+ class WorkspacesAgentConfigResolver < ::Resolvers::BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+ include LooksAhead
+
+ type Types::RemoteDevelopment::WorkspacesAgentConfigType, null: true
+
+ alias_method :agent, :object
+
+ # @param [Hash] _args Not used
+ # @return [WorkspacesAgentConfig]
+ def resolve_with_lookahead(**_args)
+ unless License.feature_available?(:remote_development)
+ raise_resource_not_available_error! "'remote_development' licensed feature is not available"
+ end
+
+ raise Gitlab::Access::AccessDeniedError unless can_read_workspaces_agent_config?
+
+ BatchLoader::GraphQL.for(agent.id).batch do |agent_ids, loader|
+ agent_configs = ::RemoteDevelopment::AgentConfigsFinder.execute(
+ current_user: current_user,
+ cluster_agent_ids: agent_ids
+ )
+ apply_lookahead(agent_configs).each do |agent_config|
+ # noinspection RubyResolve -- https://handbook.gitlab.com/handbook/tools-and-tips/editors-and-ides/jetbrains-ides/tracked-jetbrains-issues/#ruby-32301
+ loader.call(agent_config.cluster_agent_id, agent_config)
+ end
+ end
+ end
+
+ private
+
+ # @return [TrueClass, FalseClass]
+ def can_read_workspaces_agent_config?
+ # noinspection RubyNilAnalysis - This is because the superclass #current_user uses #[], which can return nil
+ current_user.can?(:read_cluster_agent, agent)
+ end
+ end
+ end
+ end
+end
diff --git a/ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_resolver.rb b/ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_resolver.rb
new file mode 100644
index 0000000000000000000000000000000000000000..68c04db7e4506d429e7f0c9782f0cec655d430d8
--- /dev/null
+++ b/ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_resolver.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module RemoteDevelopment
+ module ClusterAgent
+ class WorkspacesResolver < ::Resolvers::BaseResolver
+ include ResolvesIds
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::RemoteDevelopment::WorkspaceType.connection_type, null: true
+ authorize :admin_cluster
+ authorizes_object!
+
+ argument :ids, [::Types::GlobalIDType[::RemoteDevelopment::Workspace]],
+ required: false,
+ description:
+ 'Filter workspaces by workspace GlobalIDs. For example, `["gid://gitlab/RemoteDevelopment::Workspace/1"]`.'
+
+ argument :project_ids, [::Types::GlobalIDType[Project]],
+ required: false,
+ description: 'Filter workspaces by project GlobalID.'
+
+ argument :actual_states, [GraphQL::Types::String],
+ required: false,
+ description: 'Filter workspaces by actual states.'
+
+ alias_method :agent, :object
+
+ def resolve(**args)
+ unless License.feature_available?(:remote_development)
+ raise_resource_not_available_error! "'remote_development' licensed feature is not available"
+ end
+
+ ::RemoteDevelopment::WorkspacesFinder.execute(
+ current_user: current_user,
+ agent_ids: [agent.id],
+ ids: resolve_ids(args[:ids]).map(&:to_i),
+ project_ids: resolve_ids(args[:project_ids]).map(&:to_i),
+ actual_states: args[:actual_states] || []
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver.rb b/ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1ee5baad49f90526709eb7b3ca323f42c6541d84
--- /dev/null
+++ b/ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module RemoteDevelopment
+ module Namespace
+ class ClusterAgentsResolver < ::Resolvers::BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ type Types::Clusters::AgentType.connection_type, null: true
+
+ argument :filter, Types::RemoteDevelopment::NamespaceClusterAgentFilterEnum,
+ required: true,
+ description: 'Filter the types of cluster agents to return.'
+
+ def resolve(**args)
+ unless License.feature_available?(:remote_development)
+ raise_resource_not_available_error! "'remote_development' licensed feature is not available"
+ end
+
+ raise_resource_not_available_error! unless @object.group_namespace?
+
+ ::RemoteDevelopment::ClusterAgentsFinder.execute(
+ namespace: @object,
+ filter: args[:filter].downcase.to_sym,
+ user: current_user
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/ee/app/graphql/resolvers/remote_development/remote_development_agent_config_for_agent_resolver.rb b/ee/app/graphql/resolvers/remote_development/remote_development_agent_config_for_agent_resolver.rb
deleted file mode 100644
index 771f6fa669e8e44c60f96dc0f3c58de0d4d5a4e0..0000000000000000000000000000000000000000
--- a/ee/app/graphql/resolvers/remote_development/remote_development_agent_config_for_agent_resolver.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-# TODO: clusterAgent.remoteDevelopmentAgentConfig GraphQL is deprecated - remove in 17.10 - https://gitlab.com/gitlab-org/gitlab/-/issues/480769
-module Resolvers
- module RemoteDevelopment
- class RemoteDevelopmentAgentConfigForAgentResolver < ::Resolvers::BaseResolver
- include Gitlab::Graphql::Authorize::AuthorizeResource
- include LooksAhead
-
- type Types::RemoteDevelopment::RemoteDevelopmentAgentConfigType, null: true
-
- alias_method :agent, :object
-
- #
- # Resolve the remote development agent config for the given agent.
- #
- # @param [Hash] **_args The arguments passed to the resolver, and do not in use here
- #
- # @return [RemoteDevelopmentAgentConfig] The remote development agent config for the given agent
- #
- def resolve_with_lookahead(**_args)
- unless License.feature_available?(:remote_development)
- raise_resource_not_available_error! "'remote_development' licensed feature is not available"
- end
-
- raise Gitlab::Access::AccessDeniedError unless can_read_remote_development_agent_config?
-
- BatchLoader::GraphQL.for(agent.id).batch do |agent_ids, loader|
- agent_configs = ::RemoteDevelopment::RemoteDevelopmentAgentConfigsFinder.execute(
- current_user: current_user,
- cluster_agent_ids: agent_ids
- )
- apply_lookahead(agent_configs).each do |agent_config|
- # noinspection RubyResolve -- https://handbook.gitlab.com/handbook/tools-and-tips/editors-and-ides/jetbrains-ides/tracked-jetbrains-issues/#ruby-32301
- loader.call(agent_config.cluster_agent_id, agent_config)
- end
- end
- end
-
- private
-
- def can_read_remote_development_agent_config?
- # noinspection RubyNilAnalysis - This is because the superclass #current_user uses #[], which can return nil
- current_user.can?(:read_cluster_agent, agent)
- end
- end
- end
-end
diff --git a/ee/app/graphql/resolvers/remote_development/workspaces_agent_config_for_agent_resolver.rb b/ee/app/graphql/resolvers/remote_development/workspaces_agent_config_for_agent_resolver.rb
deleted file mode 100644
index 5ff7a6388851dc4c377a2a4ac7655d205f72c2d5..0000000000000000000000000000000000000000
--- a/ee/app/graphql/resolvers/remote_development/workspaces_agent_config_for_agent_resolver.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
- module RemoteDevelopment
- class WorkspacesAgentConfigForAgentResolver < ::Resolvers::BaseResolver
- include Gitlab::Graphql::Authorize::AuthorizeResource
- include LooksAhead
-
- type Types::RemoteDevelopment::WorkspacesAgentConfigType, null: true
-
- alias_method :agent, :object
-
- #
- # Resolve the workspaces agent config for the given agent.
- #
- # @param [Hash] **_args The arguments passed to the resolver, and do not in use here
- #
- # @return [WorkspacesAgentConfig] The workspaces agent config for the given agent
- #
- def resolve_with_lookahead(**_args)
- unless License.feature_available?(:remote_development)
- raise_resource_not_available_error! "'remote_development' licensed feature is not available"
- end
-
- raise Gitlab::Access::AccessDeniedError unless can_read_workspaces_agent_config?
-
- BatchLoader::GraphQL.for(agent.id).batch do |agent_ids, loader|
- agent_configs = ::RemoteDevelopment::AgentConfigsFinder.execute(
- current_user: current_user,
- cluster_agent_ids: agent_ids
- )
- apply_lookahead(agent_configs).each do |agent_config|
- # noinspection RubyResolve -- https://handbook.gitlab.com/handbook/tools-and-tips/editors-and-ides/jetbrains-ides/tracked-jetbrains-issues/#ruby-32301
- loader.call(agent_config.cluster_agent_id, agent_config)
- end
- end
- end
-
- private
-
- def can_read_workspaces_agent_config?
- # noinspection RubyNilAnalysis - This is because the superclass #current_user uses #[], which can return nil
- current_user.can?(:read_cluster_agent, agent)
- end
- end
- end
-end
diff --git a/ee/app/graphql/resolvers/remote_development/workspaces_for_agent_resolver.rb b/ee/app/graphql/resolvers/remote_development/workspaces_for_agent_resolver.rb
deleted file mode 100644
index 880535807c02d9d399ba1806b2600b57a32f886e..0000000000000000000000000000000000000000
--- a/ee/app/graphql/resolvers/remote_development/workspaces_for_agent_resolver.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
- module RemoteDevelopment
- class WorkspacesForAgentResolver < ::Resolvers::BaseResolver
- include ResolvesIds
- include Gitlab::Graphql::Authorize::AuthorizeResource
-
- type Types::RemoteDevelopment::WorkspaceType.connection_type, null: true
- authorize :admin_cluster
- authorizes_object!
-
- argument :ids, [::Types::GlobalIDType[::RemoteDevelopment::Workspace]],
- required: false,
- description:
- 'Filter workspaces by workspace GlobalIDs. For example, `["gid://gitlab/RemoteDevelopment::Workspace/1"]`.'
-
- argument :project_ids, [::Types::GlobalIDType[Project]],
- required: false,
- description: 'Filter workspaces by project GlobalID.'
-
- argument :actual_states, [GraphQL::Types::String],
- required: false,
- description: 'Filter workspaces by actual states.'
-
- alias_method :agent, :object
-
- def resolve(**args)
- unless License.feature_available?(:remote_development)
- raise_resource_not_available_error! "'remote_development' licensed feature is not available"
- end
-
- ::RemoteDevelopment::WorkspacesFinder.execute(
- current_user: current_user,
- agent_ids: [agent.id],
- ids: resolve_ids(args[:ids]).map(&:to_i),
- project_ids: resolve_ids(args[:project_ids]).map(&:to_i),
- actual_states: args[:actual_states] || []
- )
- end
- end
- end
-end
diff --git a/ee/app/graphql/resolvers/remote_development/workspaces_for_current_user_resolver.rb b/ee/app/graphql/resolvers/remote_development/workspaces_resolver.rb
similarity index 96%
rename from ee/app/graphql/resolvers/remote_development/workspaces_for_current_user_resolver.rb
rename to ee/app/graphql/resolvers/remote_development/workspaces_resolver.rb
index 1d79ba49357c7b6f7e13e69aafdb094ac29d79ff..c8fd4f3d76efee4d10af6fe1c8a306c09ee20660 100644
--- a/ee/app/graphql/resolvers/remote_development/workspaces_for_current_user_resolver.rb
+++ b/ee/app/graphql/resolvers/remote_development/workspaces_resolver.rb
@@ -2,7 +2,7 @@
module Resolvers
module RemoteDevelopment
- class WorkspacesForCurrentUserResolver < ::Resolvers::BaseResolver
+ class WorkspacesResolver < ::Resolvers::BaseResolver
include ResolvesIds
include Gitlab::Graphql::Authorize::AuthorizeResource
diff --git a/ee/lib/remote_development/README.md b/ee/lib/remote_development/README.md
index cc126c83e749466fd3e7be3810ca45f58c96d631..d04fa9b138a3298a20f40e5df437b1d6aff9d874 100644
--- a/ee/lib/remote_development/README.md
+++ b/ee/lib/remote_development/README.md
@@ -530,6 +530,7 @@ However, when exercising the backend/fullstack code where the business logic liv
- Unit Tests: This lowest level of testing, and only responsible for testing the logic directly contained in the class under test.
- not-quite-unit tests (e.g. GraphQL tests): Sometimes we test groups of collaborating classes, and do not have direct unit tests. For example, GraphQL mutations and resolvers are tested at the `spec/requests` level, and exercise not just the resolver, but also the relevant finder and authorization policy code. This follows the [standard GitLab recommendations for testing resolvers](https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#testing)
+ See [`ee/spec/requests/api/graphql/remote_development/README.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/requests/api/graphql/remote_development/README.md) for more details on the GraphQL request specs.
- ROP main-method intergration tests: These test the behavior of a single entire ROP chain via the main method entry point. They are a good balance of speed and thorough integration coverage of the domain logic implemented by the ROP chain. Individual ROP steps leverage `fast_spec_helper` and use `instance_double` to mock db models, this prevents coupling to Rails.
These main-method integration tests use real DB models and allow us to catch edge cases or false positive tests due to incorrect or outdated mocks from unit tests using `instance_double`.
- Request Integration Test: This spec is [at `ee/spec/requests/remote_development/integration_spec.rb`](../../spec/requests/remote_development/integration_spec.rb). It serves to fully exercise all of the Rails stack logic, as a near-the-top-of-the-testing-pyramid, happy-path scenario testing of the full lifecycle of creating a workspace. It uses the same use-case and scenario as the Feature Testing specs, except that it does not exercise the Web UI. It mocks out the agent reconciliation requests. This means that it is a "sweet spot" for integration testing because it is comprehensive, while still remaining both fast and reliable (compared to other integration-level specs which involve the web UI). Thus, we should prefer this spec to add the majority of our happy-path integration testing coverage.
diff --git a/ee/spec/finders/remote_development/cluster_agents_finder_spec.rb b/ee/spec/finders/remote_development/cluster_agents_finder_spec.rb
index 169ec5a1d4d5e8d9193d96c70c6f563c1f596f81..3ff788097fbdd467c6fc611c90f8e9d1e8d521c7 100644
--- a/ee/spec/finders/remote_development/cluster_agents_finder_spec.rb
+++ b/ee/spec/finders/remote_development/cluster_agents_finder_spec.rb
@@ -131,8 +131,8 @@
context 'when user does not have adequate permissions' do
let(:user) { developer }
- it 'raises an AccessDeniedError' do
- expect { response }.to raise_error(Gitlab::Access::AccessDeniedError)
+ it 'returns an empty response' do
+ expect(response).to eq([])
end
end
end
@@ -158,8 +158,8 @@
context 'when user does not have adequate permissions' do
let(:user) { developer }
- it 'raises an AccessDeniedError' do
- expect { response }.to raise_error(Gitlab::Access::AccessDeniedError)
+ it 'returns an empty response' do
+ expect(response).to eq([])
end
end
end
diff --git a/ee/spec/graphql/types/current_user_type_spec.rb b/ee/spec/graphql/types/current_user_type_spec.rb
index eaeefd57c354b517396f500df38941317ffc8a6f..cd268975d487e1797fa64628be3ef2b118f16389 100644
--- a/ee/spec/graphql/types/current_user_type_spec.rb
+++ b/ee/spec/graphql/types/current_user_type_spec.rb
@@ -16,7 +16,7 @@
it 'returns workspaces' do
is_expected.to have_graphql_type(Types::RemoteDevelopment::WorkspaceType.connection_type)
- is_expected.to have_graphql_resolver(Resolvers::RemoteDevelopment::WorkspacesForCurrentUserResolver)
+ is_expected.to have_graphql_resolver(Resolvers::RemoteDevelopment::WorkspacesResolver)
end
end
end
diff --git a/ee/spec/requests/api/graphql/remote_development/README.md b/ee/spec/requests/api/graphql/remote_development/README.md
index 40b18a371f83643d98449f4c62ef91a1293f4c3e..b7e0d69d659c31fa69d031e9f37335f50ccf5e72 100644
--- a/ee/spec/requests/api/graphql/remote_development/README.md
+++ b/ee/spec/requests/api/graphql/remote_development/README.md
@@ -1,20 +1,61 @@
-NOTE: The directory structure of this folder mirrors the structure of the GraphQL API schema
+# Workspaces GraphQL API resolver request integration specs
+
+## Directory structure
+
+The directory structure of this folder mirrors the structure of the GraphQL API schema
under the root `Query` type.
-For example:
+Each GraphQL field and its corresponding resolver has a corresponding spec folder containing specs which test the related resolver+finder functionality.
-- `ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces`
- contains specs which test the `Query.project.clusterAgent.workspaces` field in the GraphQL API schema,
- as well as any other field which contains a `clusterAgent` field or collection.
-- `ee/spec/requests/api/graphql/remote_development/current_user/workspaces`
- contains specs which test the `Query.currentUser.workspaces` field in the GraphQL API schema.
-- `ee/spec/requests/api/graphql/remote_development/workspace`
- contains specs which test the `Query.workspace` field in the GraphQL API schema.
-- `ee/spec/requests/api/graphql/remote_development/workspaces`
- contains specs which test the `Query.workspaces` field in the GraphQL API schema (note that
- only admins may use this field).
+Note that some entries may be reachable by other GraphQL query traversal paths, e.g., a `ClusterAgent` is reachable via `Query.project.clusterAgent...` and `Query.group.clusterAgents...`. In these cases, a single representatative example query is used in the specs, since the path used to reach a GraphQL node has no impact on the functionality of the nested fields and their resolvers.
-If you add new spec files, you should update `tests.yml` and `scripts/verify-tff-mapping` accordingly.
+Here are the related spec folders for the fields (in alphabetical order by resolver source file path)
+
+- GraphQL Field: `Query.workspaces`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/workspaces`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#queryworkspaces
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/admin_workspaces_resolver.rb`
+ - Notes: Only admins may use this field.
+
+- GraphQL Field: `Query.project.clusterAgent.remoteDevelopmentAgentConfig`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#clusteragentremotedevelopmentagentconfig
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/cluster_agent/remote_development_agent_config_resolver.rb`
+ - Note: THIS FIELD IS DEPRECATED, AND WILL BE REMOVED IN A FUTURE RELEASE.
+
+- Field: `Query.project.clusterAgent.workspaces`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#clusteragentworkspaces
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces.rb`
+
+- GraphQL Field: `Query.project.clusterAgent.workspacesAgentConfig`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#clusteragentworkspacesagentconfig
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_agent_config_resolver.rb`
+
+- GraphQL Field: `Query.namespace.remote_development_cluster_agents`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#namespaceremotedevelopmentclusteragents
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver.rb`
+ - Notes: This is the same resolver used by `Query.currentUser.namespace.workspaces_cluster_agents`. THIS FIELD IS DEPRECATED AND WILL BE REMOVED IN THE 18.0 RELEASE.
+
+- GraphQL Field: `Query.namespace.namespace.workspaces_cluster_agents`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#namespaceworkspacesclusteragents
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver.rb`
+ - Notes: This is the same resolver used by `Query.currentUser.namespace.remote_development_cluster_agents`.
+
+- GraphQL Field: `Query.workspace`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/workspace`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#queryworkspace
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/namespace/workspaces_resolver.rb`
+ - Notes: This is the same resolver used by `Query.currentUser.workspaces`
+
+- GraphQL Field: `Query.currentUser.workspaces`
+ - Spec folder: `ee/spec/requests/api/graphql/remote_development/current_user/workspaces`
+ - API docs: https://docs.gitlab.com/ee/api/graphql/reference/index.html#currentuserworkspaces
+ - Resolver source file for `tests.yml` and `verify-tff-mapping`: `ee/app/graphql/resolvers/remote_development/workspaces_resolver.rb`
+ - Notes: This is the same resolver used by `Query.currentUser.workspace`
The `shared.rb` file in the root contains RSpec shared contexts and examples used by all
specs in this directory.
@@ -22,4 +63,30 @@ specs in this directory.
The `shared.rb` files in the subdirectories contain shared rspec contexts and examples
specific to the query being tested.
-This allows the individual spec files to be very DRY and cohesive, yet provide thorough coverage.
+## These are kind of complex and hard to follow. Why?
+
+They do heavily leverage RSpec shared contexts and examples across multiple files, which requires more effort to understand how they work.
+
+However, this allows the individual spec files to be very DRY and cohesive, yet still provide thorough coverage across multiple aspects of behavior.
+
+Without this approach, achieving equivalent coverage across all of this same GraphQL API behavior would result in specs with significantly more verbosity and duplication.
+
+## Adding new spec files
+
+If you add new spec files, you should update `tests.yml` and `scripts/verify-tff-mapping` accordingly.
+
+## Why aren't all individual fields of graphql types tested in these specs?
+
+None of these other graphql API request specs test the actual fields because that’s not necessary.
+
+This is because between the finder specs, the GraphQL type specs, and the way GraphQL works
+to automatically populate the fields into a type, the population of the individual fields in
+the returned GraphQL objects is already adequately covered.
+
+Thus, the only things these request integration specs assert are the actual logic and behavior of the resolvers
+and finders, and how they integrate:
+- whether they process all the arguments correctly
+- whether they return the right records or not
+- whether they handle errors properly
+- whether they do proper authorization
+- etc.
diff --git a/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/TODO_DEPRECATED.md b/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/TODO_DEPRECATED.md
new file mode 100644
index 0000000000000000000000000000000000000000..2fed024ee29ee6f0eeff6daccd6436d69b37016a
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/TODO_DEPRECATED.md
@@ -0,0 +1,6 @@
+TODO: clusterAgent.remoteDevelopmentAgentConfig GraphQL is deprecated.
+
+Remove this entire folder `ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config`
+and its contents in 18.0
+
+https://gitlab.com/gitlab-org/gitlab/-/issues/509049
diff --git a/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/shared.rb b/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/shared.rb
new file mode 100644
index 0000000000000000000000000000000000000000..abd965c0dc7b7d33690d03eef368f12b2aedd807
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/shared.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+require_relative '../../shared'
+
+RSpec.shared_context 'for a Query.project.clusterAgent.remoteDevelopmentAgentConfig query' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :in_group) }
+ let_it_be(:agent) { create(:cluster_agent, project: project) }
+ let_it_be(:remote_development_agent_config) { create(:workspaces_agent_config, agent: agent) }
+
+ let_it_be(:authorized_user) do
+ # create the minimum privileged user that should have the project and namespace
+ # permissions to access the remote_development_agent_config.
+ create(:user, developer_of: project.namespace)
+ end
+
+ let_it_be(:unauthorized_user) do
+ # create the maximum privileged user that should NOT have the project and namespace
+ # permissions to access the agent.
+ create(:user, reporter_of: project.namespace)
+ end
+
+ let_it_be(:unauthorized_remote_development_agent_config) { create(:workspaces_agent_config) }
+
+ let(:args) { { full_path: project.full_path } }
+ let(:attributes) { { name: agent.name } }
+ let(:fields) do
+ query_graphql_field(
+ :cluster_agent,
+ attributes,
+ [
+ query_graphql_field(
+ :remote_development_agent_config,
+ all_graphql_fields_for("remote_development_agent_configs".classify, max_depth: 1)
+ )
+ ]
+ )
+ end
+
+ let(:query) { graphql_query_for(:project, args, fields) }
+
+ subject(:actual_remote_development_agent_config) do
+ graphql_dig_at(graphql_data, :project, :clusterAgent, :remoteDevelopmentAgentConfig)
+ end
+end
+
+RSpec.shared_examples 'single remoteDevelopmentAgentConfig query' do
+ include_context 'in licensed environment'
+
+ context 'when user is authorized' do
+ include_context 'with authorized user as current user'
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns single remote_development_agent_config'
+
+ context 'when the user requests a remote_development_agent_config that they are not authorized for' do
+ let(:agent) { unauthorized_remote_development_agent_config.agent }
+ let(:project) { agent.project }
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns blank'
+ end
+ end
+
+ context 'when user is not authorized' do
+ include_context 'with unauthorized user as current user'
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns blank'
+ end
+
+ it_behaves_like 'query in unlicensed environment'
+end
+
+RSpec.shared_examples 'query returns single remote_development_agent_config' do
+ include GraphqlHelpers
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it "returns correct object" do
+ expect(actual_remote_development_agent_config.fetch('id'))
+ .to eq("gid://gitlab/RemoteDevelopment::RemoteDevelopmentAgentConfig/#{remote_development_agent_config.id}")
+ end
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/with_no_args_spec.rb b/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/with_no_args_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bdcab3be29559540fdf52bf0052979acf688eddb
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/with_no_args_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_relative './shared'
+
+# NOTE: Even though this `single remoteDevelopmentAgentConfig` spec only has no fields to test, we still use similar
+# shared examples patterns and structure as the other multi-model query specs, for consistency.
+
+RSpec.describe 'Query.project.clusterAgent.remoteDevelopmentAgentConfig', feature_category: :workspaces do
+ include_context 'for a Query.project.clusterAgent.remoteDevelopmentAgentConfig query'
+
+ it_behaves_like 'single remoteDevelopmentAgentConfig query'
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/shared.rb b/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/shared.rb
index 3d5777fc65b7fdd633aeab94e82e1d1b16f73fea..91b15e500f4928d4a5b2b5cd059249f54735bb7e 100644
--- a/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/shared.rb
+++ b/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/shared.rb
@@ -41,5 +41,5 @@
workspace.reload # Ensure loaded workspace fixture's agent reflects updated created_by_user
end
- subject { graphql_data.dig('project', 'clusterAgent', 'workspaces', 'nodes') }
+ subject(:actual_workspaces) { graphql_dig_at(graphql_data, :project, :clusterAgent, :workspaces, :nodes) }
end
diff --git a/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/shared.rb b/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/shared.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d9c0f35dae601aca21eab7eaa9db084a675dceed
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/shared.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require_relative '../../shared'
+
+RSpec.shared_context 'for a Query.project.clusterAgent.workspacesAgentConfig query' do
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project, :in_group) }
+ let_it_be(:agent) { create(:cluster_agent, project: project) }
+ let_it_be(:workspaces_agent_config) { create(:workspaces_agent_config, agent: agent) }
+
+ let_it_be(:authorized_user) do
+ # create the minimum privileged user that should have the project and namespace
+ # permissions to access the workspaces_agent_config.
+ create(:user, developer_of: project.namespace)
+ end
+
+ let_it_be(:unauthorized_user) do
+ # create the maximum privileged user that should NOT have the project and namespace
+ # permissions to access the agent.
+ create(:user, reporter_of: project.namespace)
+ end
+
+ let_it_be(:unauthorized_workspaces_agent_config) { create(:workspaces_agent_config) }
+
+ let(:args) { { full_path: project.full_path } }
+ let(:attributes) { { name: agent.name } }
+ let(:fields) do
+ query_graphql_field(
+ :cluster_agent,
+ attributes,
+ [
+ query_graphql_field(
+ :workspaces_agent_config,
+ all_graphql_fields_for("workspaces_agent_configs".classify, max_depth: 1)
+ )
+ ]
+ )
+ end
+
+ let(:query) { graphql_query_for(:project, args, fields) }
+
+ subject(:actual_workspaces_agent_config) do
+ graphql_dig_at(graphql_data, :project, :clusterAgent, :workspacesAgentConfig)
+ end
+end
+
+RSpec.shared_examples 'single workspacesAgentConfig query' do
+ include_context 'in licensed environment'
+
+ context 'when user is authorized' do
+ include_context 'with authorized user as current user'
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns single workspaces_agent_config'
+
+ context 'when the user requests a workspaces_agent_config that they are not authorized for' do
+ let(:agent) { unauthorized_workspaces_agent_config.agent }
+ let(:project) { agent.project }
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns blank'
+ end
+ end
+
+ context 'when user is not authorized' do
+ include_context 'with unauthorized user as current user'
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns blank'
+ end
+
+ it_behaves_like 'query in unlicensed environment'
+end
+
+RSpec.shared_examples 'query returns single workspaces_agent_config' do
+ include GraphqlHelpers
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it { expect(actual_workspaces_agent_config.fetch('id')).to eq(workspaces_agent_config.to_gid.to_s) }
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/with_no_args_spec.rb b/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/with_no_args_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..214e929168a938f721d9d8e0a494f028de439a53
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/with_no_args_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_relative './shared'
+
+# NOTE: Even though this `single workspacesAgentConfig` spec only has no fields to test, we still use similar
+# shared examples patterns and structure as the other multi-model query specs, for consistency.
+
+RSpec.describe 'Query.project.clusterAgent.workspacesAgentConfig', feature_category: :workspaces do
+ include_context 'for a Query.project.clusterAgent.workspacesAgentConfig query'
+
+ it_behaves_like 'single workspacesAgentConfig query'
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/current_user/workspaces/shared.rb b/ee/spec/requests/api/graphql/remote_development/current_user/workspaces/shared.rb
index a57a35e4d8ae2f3e1df09107ebe0644c764263e3..ea53ac8916900c4c21c72c05913e2aa6a7f64f90 100644
--- a/ee/spec/requests/api/graphql/remote_development/current_user/workspaces/shared.rb
+++ b/ee/spec/requests/api/graphql/remote_development/current_user/workspaces/shared.rb
@@ -25,5 +25,5 @@
)
end
- subject { graphql_data.dig('currentUser', 'workspaces', 'nodes') }
+ subject(:actual_workspaces) { graphql_dig_at(graphql_data, :currentUser, :workspaces, :nodes) }
end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/TODO_DEPRECATED.md b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/TODO_DEPRECATED.md
new file mode 100644
index 0000000000000000000000000000000000000000..9e4a99f59ce95700a017c98bd321d4062d5814ae
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/TODO_DEPRECATED.md
@@ -0,0 +1,6 @@
+TODO: namespace.remoteDevelopmentClusterAgents GraphQL is deprecated.
+
+Remove this entire folder `ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents`
+and its contents in 17.10
+
+https://gitlab.com/gitlab-org/gitlab/-/issues/480769
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/remote_development_agent_config_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/remote_development_agent_config_spec.rb
deleted file mode 100644
index c0fecd1883f2ef0edff49b692af581f9e0a921e1..0000000000000000000000000000000000000000
--- a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/remote_development_agent_config_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_relative './shared'
-
-# TODO: clusterAgent.remoteDevelopmentAgentConfig GraphQL is deprecated - remove in 17.10 - https://gitlab.com/gitlab-org/gitlab/-/issues/480769
-RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: AVAILABLE) for deprecated remote_development_agent_config field', feature_category: :workspaces do
- include GraphqlHelpers
- include StubFeatureFlags
-
- let_it_be(:user) { create(:user) }
- let(:agent_config_id) { subject['id'] }
- let_it_be(:current_user) { user }
- let_it_be(:available_agent) do
- create(:ee_cluster_agent, :in_group, :with_existing_workspaces_agent_config).tap do |agent|
- agent.project.namespace.add_maintainer(user)
- end
- end
-
- let_it_be(:agent_config) { available_agent.remote_development_agent_config }
- let_it_be(:namespace) { available_agent.project.namespace }
- let_it_be(:namespace_agent_mapping) do
- create(
- :remote_development_namespace_cluster_agent_mapping,
- user: user,
- agent: available_agent,
- namespace: namespace
- )
- end
-
- let(:fields) do
- <<~QUERY
- nodes {
- remoteDevelopmentAgentConfig {
- #{all_graphql_fields_for('remote_development_agent_config'.classify, max_depth: 1)}
- }
- }
- QUERY
- end
-
- let(:query) do
- graphql_query_for(
- :namespace,
- { full_path: namespace.full_path },
- query_graphql_field(
- :remote_development_cluster_agents,
- { filter: :AVAILABLE },
- fields
- )
- )
- end
-
- subject do
- graphql_data.dig('namespace', 'remoteDevelopmentClusterAgents', 'nodes', 0, 'remoteDevelopmentAgentConfig')
- end
-
- before do
- stub_licensed_features(remote_development: true)
- end
-
- context 'when the params are valid' do
- let(:expected_agent_config_id) do
- "gid://gitlab/RemoteDevelopment::RemoteDevelopmentAgentConfig/" \
- "#{agent_config.id}"
- end
-
- let(:expected_agent_config) do
- {
- 'id' => expected_agent_config_id,
- 'projectId' => agent_config.project_id,
- 'enabled' => agent_config.enabled,
- 'dnsZone' => agent_config.dns_zone,
- 'networkPolicyEnabled' => agent_config.network_policy_enabled,
- 'gitlabWorkspacesProxyNamespace' => agent_config.gitlab_workspaces_proxy_namespace,
- 'workspacesQuota' => agent_config.workspaces_quota,
- 'workspacesPerUserQuota' => agent_config.workspaces_per_user_quota,
- # noinspection RubyResolve -- https://handbook.gitlab.com/handbook/tools-and-tips/editors-and-ides/jetbrains-ides/tracked-jetbrains-issues/#ruby-32301
- 'defaultMaxHoursBeforeTermination' => agent_config.default_maxHours_before_termination,
- 'maxHoursBeforeTerminationLimit' => agent_config.max_hours_before_termination_limit,
- 'createdAt' => agent_config.created_at,
- 'updatedAt' => agent_config.updated_at
- }
- end
-
- it 'returns cluster agents that are available for remote development in the namespace' do
- get_graphql(query, current_user: current_user)
-
- expect(agent_config_id).to eq(expected_agent_config_id)
- end
- end
-
- include_examples "checks for remote_development licensed feature"
-end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/shared.rb b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/shared.rb
index ce2105928dd2d60bb7d47b1a3511ac958d823bbb..fa6220b7ba78478ec4e612871d535853aa3c7e8f 100644
--- a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/shared.rb
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/shared.rb
@@ -1,17 +1,22 @@
# frozen_string_literal: true
-require_relative '../../shared'
+require_relative "../workspaces_cluster_agents/shared"
-RSpec.shared_examples 'checks for remote_development licensed feature' do
- context 'when remote_development feature is unlicensed' do
- before do
- stub_licensed_features(remote_development: false)
- end
+RSpec.shared_context "for a Query.namespace.remote_development_cluster_agents query" do
+ include_context "for a Query.namespace.workspaces_cluster_agents query"
- it 'returns an error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include "'remote_development' licensed feature is not available"
- end
+ let(:fields) do
+ query_graphql_field(
+ :remote_development_cluster_agents,
+ attributes,
+ [
+ query_graphql_field(
+ :nodes,
+ all_graphql_fields_for("cluster_agents".classify, max_depth: 1)
+ )
+ ]
+ )
end
+
+ subject(:actual_agents) { graphql_dig_at(graphql_data, :namespace, :remoteDevelopmentClusterAgents, :nodes) }
end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_available_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_available_filter_arg_spec.rb
index 5070cc13212628ca7bfc72a433dff3674d5bdd5c..6915a0c645c1f8d154068a9ff8a514a387b5a218 100644
--- a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_available_filter_arg_spec.rb
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_available_filter_arg_spec.rb
@@ -1,94 +1,19 @@
# frozen_string_literal: true
-require 'spec_helper'
-require_relative './shared'
-
-RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: AVAILABLE)',
- feature_category: :workspaces do
- include GraphqlHelpers
- include StubFeatureFlags
-
- let_it_be(:user) { create(:user) }
- let_it_be(:current_user) { user }
- # Setup cluster and user such that the user has the bare minimum permissions
- # to be able to receive the agent when calling the API i.e. the user has Developer access
- # to the agent project ONLY (and not a group-level access)
- let_it_be(:agent) do
- create(:ee_cluster_agent, :in_group, :with_existing_workspaces_agent_config).tap do |agent|
- agent.project.add_developer(user)
- end
- end
-
- let_it_be(:namespace) { agent.project.namespace }
- let_it_be(:namespace_agent_mapping) do
- create(
- :remote_development_namespace_cluster_agent_mapping,
- user: user,
- agent: agent,
- namespace: namespace
- )
- end
-
- let(:fields) do
- <<~QUERY
- nodes {
- #{all_graphql_fields_for('cluster_agents'.classify, max_depth: 1)}
- }
- QUERY
- end
-
- let(:agent_names_in_response) { subject.pluck('name') }
- let(:query) do
- graphql_query_for(
- :namespace,
- { full_path: namespace.full_path },
- query_graphql_field(
- :remote_development_cluster_agents,
- { filter: :AVAILABLE },
- fields
- )
- )
- end
-
- subject { graphql_data.dig('namespace', 'remoteDevelopmentClusterAgents', 'nodes') }
-
- before do
- stub_licensed_features(remote_development: true)
- end
-
- context 'when the params are valid' do
- it 'returns a cluster agent' do
- post_graphql(query, current_user: current_user)
-
- expect(agent_names_in_response).to eq([agent.name])
- end
- end
-
- include_examples "checks for remote_development licensed feature"
-
- context 'when the provided namespace is not a group namespace' do
- let(:namespace) { agent.project.project_namespace }
-
- it 'returns an error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include "does not exist or you don't have permission to perform this action"
- end
- end
-
- context 'when user does not have access to the project' do
- # simulate test conditions by creating the maximum privileged user that does/should
- # not have the permission to access the agent
- let(:current_user) do
- create(:user).tap do |user|
- agent.project.add_reporter(user)
- end
- end
-
- it 'skips agents for which the user does not have access' do
- post_graphql(query, current_user: current_user)
-
- expect(agent_names_in_response).to eq([])
- end
- end
+require "spec_helper"
+require_relative "./shared"
+
+RSpec.describe "Query.namespace.remote_development_cluster_agents(filter: AVAILABLE)", feature_category: :workspaces do
+ let(:filter) { :AVAILABLE }
+ let(:agent) { available_agent }
+ let(:expected_agents) { [available_agent] }
+ let_it_be(:authorized_user_project_access_level) { :developer }
+ let_it_be(:authorized_user_namespace_access_level) { nil }
+ let_it_be(:unauthorized_user_project_access_level) { :reporter }
+ let_it_be(:unauthorized_user_namespace_access_level) { nil }
+
+ include_context "with filter argument"
+ include_context "for a Query.namespace.remote_development_cluster_agents query"
+
+ it_behaves_like "multiple agents query"
end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_directly_mapped_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_directly_mapped_filter_arg_spec.rb
index 0d3d602a3732f532133dab610d3eee5ab7c1edcd..3296e20f3cd3bf3e005d2e6f497b254fea14480c 100644
--- a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_directly_mapped_filter_arg_spec.rb
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_directly_mapped_filter_arg_spec.rb
@@ -1,98 +1,19 @@
# frozen_string_literal: true
-require 'spec_helper'
-require_relative './shared'
-
-RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: DIRECTLY_MAPPED)',
- feature_category: :workspaces do
- include GraphqlHelpers
- include StubFeatureFlags
-
- let_it_be(:user) { create(:user) }
- let_it_be(:current_user) { user }
- # Setup cluster and user such that the user has the bare minimum permissions
- # to be able to retrieve directly mapped agent when calling the API i.e.
- # the user has Maintainer access for the group
- let_it_be(:mapped_agent) do
- create(:ee_cluster_agent, :in_group, :with_existing_workspaces_agent_config).tap do |agent|
- agent.project.namespace.add_maintainer(user)
- end
- end
-
- let_it_be(:unmapped_agent) do
- create(:ee_cluster_agent, :with_existing_workspaces_agent_config, project: mapped_agent.project)
- end
-
- let_it_be(:namespace) { mapped_agent.project.namespace }
- let_it_be(:namespace_agent_mapping) do
- create(
- :remote_development_namespace_cluster_agent_mapping,
- user: user,
- agent: mapped_agent,
- namespace: namespace
- )
- end
-
- let(:fields) do
- <<~QUERY
- nodes {
- #{all_graphql_fields_for('cluster_agents'.classify, max_depth: 1)}
- }
- QUERY
- end
-
- let(:agent_names_in_response) { subject.pluck('name') }
- let(:query) do
- graphql_query_for(
- :namespace,
- { full_path: namespace.full_path },
- query_graphql_field(
- :remote_development_cluster_agents,
- { filter: :DIRECTLY_MAPPED },
- fields
- )
- )
- end
-
- subject { graphql_data.dig('namespace', 'remoteDevelopmentClusterAgents', 'nodes') }
-
- before do
- stub_licensed_features(remote_development: true)
- end
-
- context 'when the params are valid' do
- it 'returns cluster agents that are directly mapped to the namespace' do
- post_graphql(query, current_user: current_user)
-
- expect(agent_names_in_response).to eq([mapped_agent.name])
- end
- end
-
- context 'when the passed namespace is not a group' do
- let(:namespace) { mapped_agent.project.project_namespace }
-
- it 'returns an error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include "does not exist or you don't have permission to perform this action"
- end
- end
-
- include_examples "checks for remote_development licensed feature"
-
- context 'when user does not have access to view the mappings' do
- # simulate test conditions by creating the maximum privileged user that does/should
- # not have the permission to access the agent
- let(:current_user) do
- create(:user).tap do |user|
- namespace.add_developer(user)
- end
- end
-
- it 'returns an error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include "does not exist or you don't have permission to perform this action"
- end
- end
+require "spec_helper"
+require_relative "./shared"
+
+RSpec.describe "Query.namespace.remote_development_cluster_agents(filter: DIRECTLY_MAPPED)", feature_category: :workspaces do
+ let(:filter) { :DIRECTLY_MAPPED }
+ let(:agent) { directly_mapped_agent }
+ let(:expected_agents) { [directly_mapped_agent, available_agent] }
+ let_it_be(:authorized_user_project_access_level) { nil }
+ let_it_be(:authorized_user_namespace_access_level) { :maintainer }
+ let_it_be(:unauthorized_user_project_access_level) { nil }
+ let_it_be(:unauthorized_user_namespace_access_level) { :developer }
+
+ include_context "with filter argument"
+ include_context "for a Query.namespace.remote_development_cluster_agents query"
+
+ it_behaves_like "multiple agents query"
end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_unmapped_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_unmapped_filter_arg_spec.rb
index 6f8e8bd6e190c0cd182f21a532ce859835821768..16cee30710f391be28e2e7414a35d88c1b11503c 100644
--- a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_unmapped_filter_arg_spec.rb
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_unmapped_filter_arg_spec.rb
@@ -3,93 +3,17 @@
require 'spec_helper'
require_relative './shared'
-RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: UNMAPPED)',
- feature_category: :workspaces do
- include GraphqlHelpers
- include StubFeatureFlags
-
- let_it_be(:user) { create(:user) }
- let_it_be(:current_user) { user }
- let_it_be(:mapped_agent) do
- create(:ee_cluster_agent, :in_group, :with_existing_workspaces_agent_config).tap do |agent|
- agent.project.namespace.add_maintainer(user)
- end
- end
-
- let_it_be(:unmapped_agent) do
- create(:ee_cluster_agent, :with_existing_workspaces_agent_config, project: mapped_agent.project)
- end
-
- let_it_be(:namespace) { mapped_agent.project.namespace }
- let_it_be(:namespace_agent_mapping) do
- create(
- :remote_development_namespace_cluster_agent_mapping,
- user: user,
- agent: mapped_agent,
- namespace: namespace
- )
- end
-
- let(:fields) do
- <<~QUERY
- nodes {
- #{all_graphql_fields_for('cluster_agents'.classify, max_depth: 1)}
- }
- QUERY
- end
-
- let(:agent_names_in_response) { subject.pluck('name') }
- let(:query) do
- graphql_query_for(
- :namespace,
- { full_path: namespace.full_path },
- query_graphql_field(
- :remote_development_cluster_agents,
- { filter: :UNMAPPED },
- fields
- )
- )
- end
-
- subject { graphql_data.dig('namespace', 'remoteDevelopmentClusterAgents', 'nodes') }
-
- before do
- stub_licensed_features(remote_development: true)
- end
-
- context 'when the params are valid' do
- it 'returns cluster agents that are not mapped to the namespace' do
- post_graphql(query, current_user: current_user)
-
- expect(agent_names_in_response).to eq([unmapped_agent.name])
- end
- end
-
- include_examples "checks for remote_development licensed feature"
-
- context 'when the passed namespace is not a group' do
- let(:namespace) { mapped_agent.project.project_namespace }
-
- it 'returns an error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include "does not exist or you don't have permission to perform this action"
- end
- end
-
- context 'when user does not have access to view the mappings' do
- # simulate test conditions by creating the maximum privileged user that does/should
- # not have the permission to access the agent
- let(:current_user) do
- create(:user).tap do |user|
- namespace.add_developer(user)
- end
- end
-
- it 'returns an error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include "does not exist or you don't have permission to perform this action"
- end
- end
+RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: UNMAPPED)', feature_category: :workspaces do
+ let(:filter) { :UNMAPPED }
+ let(:agent) { unmapped_agent }
+ let(:expected_agents) { [unmapped_agent] }
+ let_it_be(:authorized_user_project_access_level) { nil }
+ let_it_be(:authorized_user_namespace_access_level) { :maintainer }
+ let_it_be(:unauthorized_user_project_access_level) { nil }
+ let_it_be(:unauthorized_user_namespace_access_level) { :developer }
+
+ include_context "with filter argument"
+ include_context "for a Query.namespace.remote_development_cluster_agents query"
+
+ it_behaves_like "multiple agents query"
end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/workspaces_agent_config_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/workspaces_agent_config_spec.rb
deleted file mode 100644
index 7cb936b6fe3345966c88b3e5d175de23261d2f7c..0000000000000000000000000000000000000000
--- a/ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/workspaces_agent_config_spec.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_relative './shared'
-
-RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: AVAILABLE)', feature_category: :workspaces do
- include GraphqlHelpers
- include StubFeatureFlags
-
- let_it_be(:user) { create(:user) }
- let(:agent_config_id) { subject['id'] }
- let_it_be(:current_user) { user }
- let_it_be(:available_agent) do
- create(:ee_cluster_agent, :in_group, :with_existing_workspaces_agent_config).tap do |agent|
- agent.project.namespace.add_maintainer(user)
- end
- end
-
- let_it_be(:agent_config) { available_agent.unversioned_latest_workspaces_agent_config }
- let_it_be(:namespace) { available_agent.project.namespace }
- let_it_be(:namespace_agent_mapping) do
- create(
- :remote_development_namespace_cluster_agent_mapping,
- user: user,
- agent: available_agent,
- namespace: namespace
- )
- end
-
- let(:fields) do
- <<~QUERY
- nodes {
- workspacesAgentConfig {
- #{all_graphql_fields_for('workspaces_agent_config'.classify, max_depth: 1)}
- }
- }
- QUERY
- end
-
- let(:query) do
- graphql_query_for(
- :namespace,
- { full_path: namespace.full_path },
- query_graphql_field(
- :remote_development_cluster_agents,
- { filter: :AVAILABLE },
- fields
- )
- )
- end
-
- subject do
- graphql_data.dig('namespace', 'remoteDevelopmentClusterAgents', 'nodes', 0, 'workspacesAgentConfig')
- end
-
- before do
- stub_licensed_features(remote_development: true)
- end
-
- context 'when the params are valid' do
- let(:expected_agent_config_id) do
- "gid://gitlab/RemoteDevelopment::WorkspacesAgentConfig/" \
- "#{agent_config.id}"
- end
-
- let(:expected_agent_config) do
- {
- 'id' => expected_agent_config_id,
- 'projectId' => agent_config.project_id,
- 'enabled' => agent_config.enabled,
- 'dnsZone' => agent_config.dns_zone,
- 'networkPolicyEnabled' => agent_config.network_policy_enabled,
- 'gitlabWorkspacesProxyNamespace' => agent_config.gitlab_workspaces_proxy_namespace,
- 'workspacesQuota' => agent_config.workspaces_quota,
- 'workspacesPerUserQuota' => agent_config.workspaces_per_user_quota,
- # noinspection RubyResolve -- https://handbook.gitlab.com/handbook/tools-and-tips/editors-and-ides/jetbrains-ides/tracked-jetbrains-issues/#ruby-32301
- 'defaultMaxHoursBeforeTermination' => agent_config.default_maxHours_before_termination,
- 'maxHoursBeforeTerminationLimit' => agent_config.max_hours_before_termination_limit,
- 'createdAt' => agent_config.created_at,
- 'updatedAt' => agent_config.updated_at
- }
- end
-
- it 'returns cluster agents that are available for remote development in the namespace' do
- get_graphql(query, current_user: current_user)
-
- expect(agent_config_id).to eq(expected_agent_config_id)
- end
- end
-
- include_examples "checks for remote_development licensed feature"
-end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/shared.rb b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/shared.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ffd020990191ee32cd9a1cd3be089f7d3d02ef0d
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/shared.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+require_relative "../../shared"
+
+#-------------------------------------------------
+# SHARED CONTEXTS - INDIVIDUAL ARGUMENTS SCENARIOS
+#-------------------------------------------------
+
+# noinspection RubyArgCount
+RSpec.shared_context "with filter argument" do
+ let_it_be(:namespace) { create(:group, name: "group-namespace") }
+ let_it_be(:project) do
+ create(:project, :in_group, path: "project", namespace: namespace)
+ end
+
+ let_it_be(:authorized_user) do
+ create(:user).tap do |user|
+ # create the minimum privileged user that should have the project and namespace
+ # permissions to access the agent.
+ project.add_member(user, authorized_user_project_access_level) if authorized_user_project_access_level
+ namespace.add_member(user, authorized_user_namespace_access_level) if authorized_user_namespace_access_level
+ end
+ end
+
+ let_it_be(:unauthorized_user) do
+ # create the maximum privileged user that should NOT have the project and namespace
+ # permissions to access the agent.
+ create(:user).tap do |user|
+ project.add_member(user, unauthorized_user_project_access_level) if unauthorized_user_project_access_level
+ namespace.add_member(user, unauthorized_user_namespace_access_level) if unauthorized_user_namespace_access_level
+ end
+ end
+
+ let_it_be(:project_namespace) { project.project_namespace }
+
+ let_it_be(:available_agent) do
+ create(:ee_cluster_agent, :with_existing_workspaces_agent_config, project: project,
+ created_by_user: authorized_user, name: "available-agent").tap do |agent|
+ create(
+ :remote_development_namespace_cluster_agent_mapping,
+ user: authorized_user,
+ agent: agent,
+ namespace: namespace
+ )
+ end
+ end
+
+ let_it_be(:directly_mapped_agent) do
+ create(:cluster_agent, project: project, created_by_user: authorized_user,
+ name: "directly-mapped-agent").tap do |agent|
+ create(
+ :remote_development_namespace_cluster_agent_mapping,
+ user: authorized_user,
+ agent: agent,
+ namespace: namespace
+ )
+ end
+ end
+
+ let_it_be(:unmapped_agent) do
+ create(:cluster_agent, project: project, created_by_user: authorized_user, name: "unmapped-agent")
+ end
+
+ let_it_be(:unauthorized_agent) { create(:cluster_agent, :in_group) }
+end
+
+RSpec.shared_context "for a Query.namespace.workspaces_cluster_agents query" do
+ include GraphqlHelpers
+
+ let(:args) { { full_path: namespace.full_path } }
+
+ let(:attributes) { { filter: filter } }
+
+ let(:fields) do
+ query_graphql_field(
+ :workspaces_cluster_agents,
+ attributes,
+ [
+ query_graphql_field(
+ :nodes,
+ all_graphql_fields_for("cluster_agents".classify, max_depth: 1)
+ )
+ ]
+ )
+ end
+
+ let(:query) { graphql_query_for(:namespace, args, fields) }
+
+ subject(:actual_agents) { graphql_dig_at(graphql_data, :namespace, :workspacesClusterAgents, :nodes) }
+end
+
+#------------------------------------------------
+# SHARED EXAMPLES - MAIN ENTRY POINTS FOR TESTING
+#------------------------------------------------
+
+RSpec.shared_examples "multiple agents query" do
+ include_context "in licensed environment"
+
+ let(:agent_names) { actual_agents.pluck("name") }
+ let(:expected_agent_names) { expected_agents.pluck("name").sort }
+
+ context "when user is authorized" do
+ include_context "with authorized user as current user"
+
+ it_behaves_like "query is a working graphql query"
+
+ context "when the user requests an agent that they are authorized for" do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it "includes only the expected agent", :unlimited_max_formatted_output_length do
+ expect(agent_names.sort).to eq(expected_agent_names)
+ end
+ end
+
+ context "when the user requests an agent that they are not authorized for" do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it "does not return the unauthorized agent" do
+ expect(agent_names).not_to include(unauthorized_agent.name)
+ end
+
+ it "still returns the authorized agent" do
+ expect(agent_names).to include(agent.name)
+ end
+ end
+
+ context "when the provided namespace is not a group namespace" do
+ let(:namespace) { project_namespace }
+
+ it_behaves_like "query returns blank"
+ it_behaves_like "query includes graphql error",
+ "does not exist or you don't have permission to perform this action"
+ end
+ end
+
+ context "when user is not authorized" do
+ include_context "with unauthorized user as current user"
+
+ it_behaves_like "query is a working graphql query"
+ it_behaves_like "query returns blank"
+ end
+
+ it_behaves_like "query in unlicensed environment"
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_available_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_available_filter_arg_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ac2c7b256f8fdec7a71fd9a5fe8bd46e2fa455e1
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_available_filter_arg_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+require_relative "./shared"
+
+RSpec.describe "Query.namespace.remote_development_cluster_agents(filter: AVAILABLE)", feature_category: :workspaces do
+ let(:filter) { :AVAILABLE }
+ let(:agent) { available_agent }
+ let(:expected_agents) { [available_agent] }
+ let_it_be(:authorized_user_project_access_level) { :developer }
+ let_it_be(:authorized_user_namespace_access_level) { nil }
+ let_it_be(:unauthorized_user_project_access_level) { :reporter }
+ let_it_be(:unauthorized_user_namespace_access_level) { nil }
+
+ include_context "with filter argument"
+ include_context "for a Query.namespace.workspaces_cluster_agents query"
+
+ it_behaves_like "multiple agents query"
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c0db7505acc9d9e6aa9b2dde8063f57a27a8e52a
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+require_relative "./shared"
+
+RSpec.describe "Query.namespace.remote_development_cluster_agents(filter: DIRECTLY_MAPPED)", feature_category: :workspaces do
+ let(:filter) { :DIRECTLY_MAPPED }
+ let(:agent) { directly_mapped_agent }
+ let(:expected_agents) { [directly_mapped_agent, available_agent] }
+ let_it_be(:authorized_user_project_access_level) { nil }
+ let_it_be(:authorized_user_namespace_access_level) { :maintainer }
+ let_it_be(:unauthorized_user_project_access_level) { nil }
+ let_it_be(:unauthorized_user_namespace_access_level) { :developer }
+
+ include_context "with filter argument"
+ include_context "for a Query.namespace.workspaces_cluster_agents query"
+
+ it_behaves_like "multiple agents query"
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9246ca1598448bef98f5a7f83f05feb9ce20dc4c
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_relative './shared'
+
+RSpec.describe 'Query.namespace.remote_development_cluster_agents(filter: UNMAPPED)', feature_category: :workspaces do
+ let(:filter) { :UNMAPPED }
+ let(:agent) { unmapped_agent }
+ let(:expected_agents) { [unmapped_agent] }
+ let_it_be(:authorized_user_project_access_level) { nil }
+ let_it_be(:authorized_user_namespace_access_level) { :maintainer }
+ let_it_be(:unauthorized_user_project_access_level) { nil }
+ let_it_be(:unauthorized_user_namespace_access_level) { :developer }
+
+ include_context "with filter argument"
+ include_context "for a Query.namespace.workspaces_cluster_agents query"
+
+ it_behaves_like "multiple agents query"
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/shared.rb b/ee/spec/requests/api/graphql/remote_development/shared.rb
index ce4c26aa9e214ee6c9c11e7529b455c352fc3922..f3ad366f35fa76332b66027cf10dbb65ea7ae083 100644
--- a/ee/spec/requests/api/graphql/remote_development/shared.rb
+++ b/ee/spec/requests/api/graphql/remote_development/shared.rb
@@ -16,20 +16,6 @@
let_it_be(:args) { {} }
end
-RSpec.shared_context 'with id arg' do
- include_context 'with unauthorized workspace created'
-
- let_it_be(:workspace, reload: true) { create(:workspace, name: 'matching-workspace') }
-
- # create workspace with different ID but still owned by the same user, to ensure isn't returned by the query
- let_it_be(:non_matching_workspace, reload: true) do
- create(:workspace, user: workspace.user, name: 'non-matching-workspace')
- end
-
- let(:id) { workspace.to_global_id.to_s }
- let(:args) { { id: id } }
-end
-
RSpec.shared_context 'with ids argument' do
include_context 'with unauthorized workspace created'
@@ -97,35 +83,6 @@
# SHARED EXAMPLES - MAIN ENTRY POINTS FOR TESTING
#------------------------------------------------
-RSpec.shared_examples 'single workspace query' do |authorized_user_is_admin: false|
- include_context 'in licensed environment'
-
- context 'when user is authorized' do
- include_context 'with authorized user as current user'
-
- it_behaves_like 'query is a working graphql query'
- it_behaves_like 'query returns single workspace'
-
- unless authorized_user_is_admin
- context 'when the user requests a workspace that they are not authorized for' do
- let(:id) { unauthorized_workspace.to_global_id.to_s }
-
- it_behaves_like 'query is a working graphql query'
- it_behaves_like 'query returns blank'
- end
- end
- end
-
- context 'when user is not authorized' do
- include_context 'with unauthorized user as current user'
-
- it_behaves_like 'query is a working graphql query'
- it_behaves_like 'query returns blank'
- end
-
- it_behaves_like 'query in unlicensed environment'
-end
-
RSpec.shared_examples 'multiple workspaces query' do |authorized_user_is_admin: false, expected_error_regex: nil|
include_context 'in licensed environment'
@@ -243,6 +200,8 @@
end
RSpec.shared_examples 'query returns single workspace' do
+ include GraphqlHelpers
+
before do
post_graphql(query, current_user: current_user)
end
diff --git a/ee/spec/requests/api/graphql/remote_development/workspace/shared.rb b/ee/spec/requests/api/graphql/remote_development/workspace/shared.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bf7b532ebd1f14aad516e1f17ef76f980e20c1f9
--- /dev/null
+++ b/ee/spec/requests/api/graphql/remote_development/workspace/shared.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require_relative '../shared'
+
+RSpec.shared_context 'with id arg' do
+ include_context 'with unauthorized workspace created'
+
+ let_it_be(:workspace, reload: true) { create(:workspace, name: 'matching-workspace') }
+
+ # create workspace with different ID but still owned by the same user, to ensure isn't returned by the query
+ let_it_be(:non_matching_workspace, reload: true) do
+ create(:workspace, user: workspace.user, name: 'non-matching-workspace')
+ end
+
+ let(:id) { workspace.to_global_id.to_s }
+ let(:args) { { id: id } }
+end
+
+RSpec.shared_context 'for a Query.workspace query' do
+ include GraphqlHelpers
+
+ include_context "with authorized user as developer on workspace's project"
+
+ let(:fields) do
+ <<~QUERY
+ #{all_graphql_fields_for('workspace'.classify, max_depth: 1)}
+ QUERY
+ end
+
+ let(:query) { graphql_query_for('workspace', args, fields) }
+
+ subject(:actual_workspace) { graphql_data['workspace'] }
+end
+
+RSpec.shared_examples 'single workspace query' do |authorized_user_is_admin: false|
+ include_context 'in licensed environment'
+
+ context 'when user is authorized' do
+ include_context 'with authorized user as current user'
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns single workspace'
+
+ unless authorized_user_is_admin
+ context 'when the user requests a workspace that they are not authorized for' do
+ let(:id) { unauthorized_workspace.to_global_id.to_s }
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns blank'
+ end
+ end
+ end
+
+ context 'when user is not authorized' do
+ include_context 'with unauthorized user as current user'
+
+ it_behaves_like 'query is a working graphql query'
+ it_behaves_like 'query returns blank'
+ end
+
+ it_behaves_like 'query in unlicensed environment'
+end
diff --git a/ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb b/ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb
index 29aa4a19ec45dd9b6e34a2b6d73798b2de08d8e5..dbf8f4a4f3a3aa30b68c929b1b1c9d24a25707e1 100644
--- a/ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb
+++ b/ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb
@@ -1,28 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
-require_relative '../shared'
+require_relative './shared'
-RSpec.describe 'Query.workspace(id: RemoteDevelopmentWorkspaceID!)', feature_category: :workspaces do
- include GraphqlHelpers
-
- # NOTE: Even though this single-workspace spec only has one field scenario to test, we still use the same
- # shared examples patterns and structure as the other multi-workspace query specs, for consistency.
-
- RSpec.shared_context 'for a Query.workspace query' do
- include_context "with authorized user as developer on workspace's project"
-
- let(:fields) do
- <<~QUERY
- #{all_graphql_fields_for('workspace'.classify, max_depth: 1)}
- QUERY
- end
-
- let(:query) { graphql_query_for('workspace', args, fields) }
-
- subject { graphql_data['workspace'] }
- end
+# NOTE: Even though this single-workspace spec only has one field scenario to test, we still use similar
+# shared examples patterns and structure as the other multi-workspace query specs, for consistency.
+RSpec.describe 'Query.workspace(id: RemoteDevelopmentWorkspaceID!)', feature_category: :workspaces do
include_context 'with id arg'
include_context 'for a Query.workspace query'
diff --git a/ee/spec/requests/api/graphql/remote_development/workspaces/shared.rb b/ee/spec/requests/api/graphql/remote_development/workspaces/shared.rb
index 57500dca65b137204f5ec7e1ad26afc8c8d5b0f4..dde1f92233e1e6da087faf6b1a8aa4a63f4ee3a7 100644
--- a/ee/spec/requests/api/graphql/remote_development/workspaces/shared.rb
+++ b/ee/spec/requests/api/graphql/remote_development/workspaces/shared.rb
@@ -21,7 +21,7 @@
let(:query) { graphql_query_for('workspaces', args, fields) }
- subject { graphql_data.dig('workspaces', 'nodes') }
+ subject(:actual_workspaces) { graphql_dig_at(graphql_data, :workspaces, :nodes) }
before do
workspace.project.add_developer(workspace_owner)
diff --git a/scripts/verify-tff-mapping b/scripts/verify-tff-mapping
index 561cea8f7f8e43bef9ca88d0179794e7aeb71bd0..f2c43baa3235bb43434edde7a87e4ef4e07258af 100755
--- a/scripts/verify-tff-mapping
+++ b/scripts/verify-tff-mapping
@@ -436,6 +436,25 @@ tests = [
changed_file: 'ee/app/graphql/mutations/boards/epic_lists/destroy.rb',
expected: ['ee/spec/requests/api/graphql/mutations/boards/epic_lists/destroy_spec.rb']
},
+ ## BEGIN Remote development GraphQL mutations
+ {
+ explanation: 'Map Remote Development GraphQL mutations to request specs',
+ changed_file: 'ee/app/graphql/mutations/remote_development/namespace_cluster_agent_mapping_operations/create.rb',
+ # rubocop:disable Layout/LineLength -- fix CI failures - not sure why other lines in this file don't get errors
+ expected: %w[
+ ee/spec/requests/api/graphql/mutations/remote_development/namespace_cluster_agent_mapping_operations/create_spec.rb
+ ]
+ # rubocop:enable Layout/LineLength
+ },
+ {
+ explanation: 'Map Remote Development GraphQL mutations to request specs',
+ changed_file: 'ee/app/graphql/mutations/remote_development/namespace_cluster_agent_mapping_operations/delete.rb',
+ # rubocop:disable Layout/LineLength -- fix CI failures - not sure why other lines in this file don't get errors
+ expected: %w[
+ ee/spec/requests/api/graphql/mutations/remote_development/namespace_cluster_agent_mapping_operations/delete_spec.rb
+ ]
+ # rubocop:enable Layout/LineLength
+ },
{
explanation: 'Map Remote Development GraphQL mutations to request specs',
changed_file: 'ee/app/graphql/mutations/remote_development/workspace_operations/create.rb',
@@ -444,8 +463,40 @@ tests = [
]
},
{
- explanation: 'Map Remote Development GraphQL cluster_agent workspaces resolvers to request specs',
- changed_file: 'ee/app/graphql/resolvers/remote_development/workspaces_for_agent_resolver.rb',
+ explanation: 'Map Remote Development GraphQL mutations to request specs',
+ changed_file: 'ee/app/graphql/mutations/remote_development/workspace_operations/update.rb',
+ expected: %w[
+ ee/spec/requests/api/graphql/mutations/remote_development/workspace_operations/update_spec.rb
+ ]
+ },
+ ## END Remote development GraphQL mutations
+
+ ## BEGIN Remote development GraphQL resolvers (in alphabetical order by resolver source file path)
+ {
+ explanation: 'Map Remote Development GraphQL query root admin_workspaces_resolver.rb to request specs',
+ changed_file: 'ee/app/graphql/resolvers/remote_development/admin_workspaces_resolver.rb',
+ expected: %w[
+ ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/workspaces/with_actual_states_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/workspaces/with_agent_ids_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/workspaces/with_ids_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/workspaces/with_no_args_spec.rb
+ ee/spec/requests/api/graphql/remote_development/workspaces/with_project_ids_arg_spec.rb
+ ]
+ },
+ {
+ explanation:
+ 'Map Remote Development GraphQL cluster_agent/remote_development_agent_config_resolver.rb to request specs',
+ changed_file:
+ 'ee/app/graphql/resolvers/remote_development/cluster_agent/remote_development_agent_config_resolver.rb',
+ expected: %w[
+ ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/with_no_args_spec.rb
+ ]
+ },
+ {
+ explanation:
+ 'Map Remote Development GraphQL cluster_agent/workspaces_resolver.rb to request specs',
+ changed_file: 'ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_resolver.rb',
expected: %w[
ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/with_actual_states_arg_spec.rb
ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/with_ids_arg_spec.rb
@@ -454,9 +505,32 @@ tests = [
]
},
{
- explanation: 'Map Remote Development GraphQL current_user workspaces resolvers to request specs',
- changed_file: 'ee/app/graphql/resolvers/remote_development/workspaces_for_current_user_resolver.rb',
+ explanation:
+ 'Map Remote Development GraphQL cluster_agent/workspaces_agent_config_resolver.rb to request specs',
+ changed_file: 'ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_agent_config_resolver.rb',
+ expected: %w[
+ ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/with_no_args_spec.rb
+ ]
+ },
+ {
+ explanation: 'Map Remote Development GraphQL namespace/cluster_agents_resolver.rb to request specs',
+ changed_file: 'ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver.rb',
+ # rubocop:disable Layout/LineLength -- fix CI failures - not sure why other lines in this file don't get errors
+ expected: %w[
+ ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_available_filter_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_directly_mapped_filter_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/with_unmapped_filter_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_available_filter_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_directly_mapped_filter_arg_spec.rb
+ ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/with_unmapped_filter_arg_spec.rb
+ ]
+ # rubocop:enable Layout/LineLength
+ },
+ {
+ explanation: 'Map Remote Development GraphQL workspaces_resolver.rb to request specs',
+ changed_file: 'ee/app/graphql/resolvers/remote_development/workspaces_resolver.rb',
expected: %w[
+ ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb
ee/spec/requests/api/graphql/remote_development/current_user/workspaces/with_actual_states_arg_spec.rb
ee/spec/requests/api/graphql/remote_development/current_user/workspaces/with_agent_ids_arg_spec.rb
ee/spec/requests/api/graphql/remote_development/current_user/workspaces/with_ids_arg_spec.rb
@@ -464,17 +538,7 @@ tests = [
ee/spec/requests/api/graphql/remote_development/current_user/workspaces/with_project_ids_arg_spec.rb
]
},
- {
- explanation: 'Map Remote Development GraphQL query root workspaces resolvers to request specs',
- changed_file: 'ee/app/graphql/resolvers/remote_development/workspaces_for_query_root_resolver.rb',
- expected: %w[
- ee/spec/requests/api/graphql/remote_development/workspaces/with_actual_states_arg_spec.rb
- ee/spec/requests/api/graphql/remote_development/workspaces/with_agent_ids_arg_spec.rb
- ee/spec/requests/api/graphql/remote_development/workspaces/with_ids_arg_spec.rb
- ee/spec/requests/api/graphql/remote_development/workspaces/with_no_args_spec.rb
- ee/spec/requests/api/graphql/remote_development/workspaces/with_project_ids_arg_spec.rb
- ]
- },
+
{
explanation: 'Map Remote Development GraphQL query root workspace type resolver to request specs',
changed_file: 'ee/app/graphql/types/remote_development/workspace_type.rb',
@@ -483,6 +547,7 @@ tests = [
ee/spec/requests/api/graphql/remote_development/workspace/with_id_arg_spec.rb
]
},
+ ## END Remote development GraphQL resolvers
{
explanation: 'https://gitlab.com/gitlab-org/gitlab/-/issues/466068#note_1987834618',
diff --git a/tests.yml b/tests.yml
index 57dbd2b02f9dbf0d3a41418a811f6bfa9b615caa..826dee564e592a27907ee5bea6d4bc78fe02c716 100644
--- a/tests.yml
+++ b/tests.yml
@@ -123,18 +123,39 @@ mapping:
- source: '(?ee/)?app/mailers/(?ee/)?previews/.+\.rb'
test: 'spec/mailers/previews_spec.rb'
- ## Remote development GraphQL resolvers
- - source: 'ee/app/graphql/resolvers/remote_development/workspaces_for_agent_resolver\.rb'
+ ## BEGIN Remote development GraphQL resolvers (in alphabetical order by resolver source file path)
+ - source: 'ee/app/graphql/resolvers/remote_development/admin_workspaces_resolver\.rb'
+ test:
+ - 'ee/spec/requests/api/graphql/remote_development/workspace/*_spec.rb'
+ - 'ee/spec/requests/api/graphql/remote_development/workspaces/*_spec.rb'
+
+ - source: 'ee/app/graphql/resolvers/remote_development/cluster_agent/remote_development_agent_config_resolver\.rb'
+ test:
+ - 'ee/spec/requests/api/graphql/remote_development/cluster_agent/remote_development_agent_config/*_spec.rb'
+
+ - source: 'ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_agent_config_resolver\.rb'
+ test:
+ - 'ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces_agent_config/*_spec.rb'
+
+ - source: 'ee/app/graphql/resolvers/remote_development/cluster_agent/workspaces_resolver\.rb'
test:
- 'ee/spec/requests/api/graphql/remote_development/cluster_agent/workspaces/*_spec.rb'
- - source: 'ee/app/graphql/resolvers/remote_development/workspaces_for_current_user_resolver\.rb'
+ - source: 'ee/app/graphql/resolvers/remote_development/workspaces_resolver\.rb'
test:
- 'ee/spec/requests/api/graphql/remote_development/current_user/workspaces/*_spec.rb'
- - source: 'ee/app/graphql/resolvers/remote_development/workspaces_for_query_root_resolver\.rb'
+ - source: 'ee/app/graphql/resolvers/remote_development/namespace/cluster_agents_resolver\.rb'
test:
- - 'ee/spec/requests/api/graphql/remote_development/workspaces/*_spec.rb'
+ - 'ee/spec/requests/api/graphql/remote_development/namespace/remote_development_cluster_agents/*_spec.rb'
+ - 'ee/spec/requests/api/graphql/remote_development/namespace/workspaces_cluster_agents/*_spec.rb'
+
+ - source: 'ee/app/graphql/resolvers/remote_development/workspaces_resolver\.rb'
+ test:
+ - 'ee/spec/requests/api/graphql/remote_development/current_user/workspaces/*_spec.rb'
+ - 'ee/spec/requests/api/graphql/remote_development/workspace/*_spec.rb'
+
+ ## END Remote development GraphQL resolvers
- source: 'ee/app/graphql/types/remote_development/workspace_type\.rb'
test: