diff --git a/app/graphql/mutations/environments/create.rb b/app/graphql/mutations/environments/create.rb
index cb81095129d51ca5f4718cf2a1f8e69fc2af083a..1a942365d21a3aa86fe13b4826dd56ee4ea59b04 100644
--- a/app/graphql/mutations/environments/create.rb
+++ b/app/graphql/mutations/environments/create.rb
@@ -50,6 +50,11 @@ class Create < ::Mutations::BaseMutation
required: false,
description: 'Flux resource path of the environment.'
+ argument :auto_stop_setting,
+ Types::Environments::AutoStopSettingEnum,
+ required: false,
+ description: 'Auto stop setting of the environment.'
+
field :environment,
Types::EnvironmentType,
null: true,
diff --git a/app/graphql/mutations/environments/update.rb b/app/graphql/mutations/environments/update.rb
index 81f0900eacf74cdb5ac0ab5d445acfe4b39358ea..ef2e98edd84d659bb87107529101a2d52cfa8a1c 100644
--- a/app/graphql/mutations/environments/update.rb
+++ b/app/graphql/mutations/environments/update.rb
@@ -43,6 +43,11 @@ class Update < ::Mutations::BaseMutation
required: false,
description: 'Flux resource path of the environment.'
+ argument :auto_stop_setting,
+ Types::Environments::AutoStopSettingEnum,
+ required: false,
+ description: 'Auto stop setting of the environment.'
+
field :environment,
Types::EnvironmentType,
null: true,
diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb
index a766a3bb0395b9d79b8b5c952079f3711e45d683..16dbce061a7a88416d6c156b60d4d061183f5fd0 100644
--- a/app/graphql/types/environment_type.rb
+++ b/app/graphql/types/environment_type.rb
@@ -94,6 +94,9 @@ class EnvironmentType < BaseObject
extension ::Gitlab::Graphql::Limit::FieldCallCount, limit: 1
end
+ field :auto_stop_setting, Types::Environments::AutoStopSettingEnum,
+ description: 'Auto stop setting of the environment.'
+
markdown_field :description_html, null: true
def tier
diff --git a/app/graphql/types/environments/auto_stop_setting_enum.rb b/app/graphql/types/environments/auto_stop_setting_enum.rb
new file mode 100644
index 0000000000000000000000000000000000000000..30430d7cdf66abbb1731aa73ee9d955041ec0d96
--- /dev/null
+++ b/app/graphql/types/environments/auto_stop_setting_enum.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Types
+ module Environments
+ class AutoStopSettingEnum < BaseEnum
+ graphql_name 'AutoStopSetting'
+ description 'Auto stop setting.'
+
+ ::Environment.auto_stop_settings.each_key do |key|
+ value key.upcase, value: key, description: key.titleize
+ end
+ end
+ end
+end
diff --git a/app/services/environments/create_service.rb b/app/services/environments/create_service.rb
index f4da8eabfd1494073a93ad99a7ab791f3b5e980e..8a576c923287e7d590b175c9649b28ae8833a34a 100644
--- a/app/services/environments/create_service.rb
+++ b/app/services/environments/create_service.rb
@@ -3,7 +3,7 @@
module Environments
class CreateService < BaseService
ALLOWED_ATTRIBUTES = %i[name description external_url tier cluster_agent kubernetes_namespace
- flux_resource_path].freeze
+ flux_resource_path auto_stop_setting].freeze
def execute
unless can?(current_user, :create_environment, project)
@@ -19,15 +19,13 @@ def execute
payload: { environment: nil })
end
- environment = project.environments.create(**params.slice(*ALLOWED_ATTRIBUTES))
-
- if environment.persisted?
+ begin
+ environment = project.environments.create!(**params.slice(*ALLOWED_ATTRIBUTES))
ServiceResponse.success(payload: { environment: environment })
- else
- ServiceResponse.error(
- message: environment.errors.full_messages,
- payload: { environment: nil }
- )
+ rescue ActiveRecord::RecordInvalid => err
+ ServiceResponse.error(message: err.record.errors.full_messages, payload: { environment: nil })
+ rescue ArgumentError => err
+ ServiceResponse.error(message: [err.message], payload: { environment: nil })
end
end
diff --git a/app/services/environments/update_service.rb b/app/services/environments/update_service.rb
index 7b34fce41d0b5b3240726eddfac5afc90e599eed..eceb7ab46697ca3263b20a262cb18ba9d9efd03e 100644
--- a/app/services/environments/update_service.rb
+++ b/app/services/environments/update_service.rb
@@ -3,7 +3,7 @@
module Environments
class UpdateService < BaseService
ALLOWED_ATTRIBUTES = %i[description external_url tier cluster_agent kubernetes_namespace
- flux_resource_path].freeze
+ flux_resource_path auto_stop_setting].freeze
def execute(environment)
unless can?(current_user, :update_environment, environment)
@@ -19,13 +19,13 @@ def execute(environment)
payload: { environment: environment })
end
- if environment.update(**params.slice(*ALLOWED_ATTRIBUTES))
+ begin
+ environment.update!(**params.slice(*ALLOWED_ATTRIBUTES))
ServiceResponse.success(payload: { environment: environment })
- else
- ServiceResponse.error(
- message: environment.errors.full_messages,
- payload: { environment: environment }
- )
+ rescue ActiveRecord::RecordInvalid => err
+ ServiceResponse.error(message: err.record.errors.full_messages, payload: { environment: environment })
+ rescue ArgumentError => err
+ ServiceResponse.error(message: [err.message], payload: { environment: environment })
end
end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index f8633332bdb89fd0a9175a93d74751b335b43439..8b958ec56f547b6374c11bb27e9a74bda93b880b 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -5174,6 +5174,7 @@ Input type: `EnvironmentCreateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
+| `autoStopSetting` | [`AutoStopSetting`](#autostopsetting) | Auto stop setting of the environment. |
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| `clusterAgentId` | [`ClustersAgentID`](#clustersagentid) | Cluster agent of the environment. |
| `description` | [`String`](#string) | Description of the environment. |
@@ -5244,6 +5245,7 @@ Input type: `EnvironmentUpdateInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
+| `autoStopSetting` | [`AutoStopSetting`](#autostopsetting) | Auto stop setting of the environment. |
| `clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| `clusterAgentId` | [`ClustersAgentID`](#clustersagentid) | Cluster agent of the environment. |
| `description` | [`String`](#string) | Description of the environment. |
@@ -23736,6 +23738,7 @@ Describes where code is deployed for a project.
| ---- | ---- | ----------- |
| `autoDeleteAt` | [`Time`](#time) | When the environment is going to be deleted automatically. |
| `autoStopAt` | [`Time`](#time) | When the environment is going to be stopped automatically. |
+| `autoStopSetting` | [`AutoStopSetting`](#autostopsetting) | Auto stop setting of the environment. |
| `clusterAgent` | [`ClusterAgent`](#clusteragent) | Cluster agent of the environment. |
| `createdAt` | [`Time`](#time) | When the environment was created. |
| `deployFreezes` | [`[CiFreezePeriod!]`](#cifreezeperiod) | Deployment freeze periods of the environment. |
@@ -38718,6 +38721,15 @@ Assignee ID wildcard values.
| `ANY` | An assignee is assigned. |
| `NONE` | No assignee is assigned. |
+### `AutoStopSetting`
+
+Auto stop setting.
+
+| Value | Description |
+| ----- | ----------- |
+| `ALWAYS` | Always. |
+| `WITH_ACTION` | With Action. |
+
### `AvailabilityEnum`
User availability status.
diff --git a/spec/graphql/types/environments/auto_stop_setting_enum_spec.rb b/spec/graphql/types/environments/auto_stop_setting_enum_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..912d62b321f32fce6fb9490e21594c83f7d0e0ae
--- /dev/null
+++ b/spec/graphql/types/environments/auto_stop_setting_enum_spec.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Environments::AutoStopSettingEnum, feature_category: :environment_management do
+ it 'exposes all auto stop settings' do
+ expect(described_class.values.keys).to include(*%w[ALWAYS WITH_ACTION])
+ end
+end
diff --git a/spec/services/environments/create_service_spec.rb b/spec/services/environments/create_service_spec.rb
index 96dc1c75c573194f3999043c9955cb4ca84614ab..5e57311e9ec3b06bd25fb033db14f6b8f1d245c5 100644
--- a/spec/services/environments/create_service_spec.rb
+++ b/spec/services/environments/create_service_spec.rb
@@ -14,7 +14,7 @@
describe '#execute' do
subject { service.execute }
- let(:params) { { name: 'production', description: 'description', external_url: 'https://gitlab.com', tier: :production } }
+ let(:params) { { name: 'production', description: 'description', external_url: 'https://gitlab.com', tier: :production, auto_stop_setting: :always } }
it 'creates an environment' do
expect { subject }.to change { ::Environment.count }.by(1)
@@ -28,6 +28,7 @@
expect(response.payload[:environment].description).to eq('description')
expect(response.payload[:environment].external_url).to eq('https://gitlab.com')
expect(response.payload[:environment].tier).to eq('production')
+ expect(response.payload[:environment].auto_stop_setting).to eq('always')
end
context 'with a cluster agent' do
@@ -66,8 +67,8 @@
end
end
- context 'when params contain invalid value' do
- let(:params) { { name: 'production', external_url: 'http://${URL}' } }
+ context 'when params contain invalid values' do
+ let(:params) { { name: 'production', external_url: 'http://${URL}', kubernetes_namespace: "invalid" } }
it 'does not create an environment' do
expect { subject }.not_to change { ::Environment.count }
@@ -77,7 +78,24 @@
response = subject
expect(response).to be_error
- expect(response.message).to match_array("External url URI is invalid")
+ expect(response.message).to match_array(["External url URI is invalid",
+ "Kubernetes namespace cannot be set without a cluster agent"])
+ expect(response.payload[:environment]).to be_nil
+ end
+ end
+
+ context 'when params contain invalid auto_stop_setting' do
+ let(:params) { { name: 'production', auto_stop_setting: :invalid } }
+
+ it 'does not create an environment' do
+ expect { subject }.not_to change { ::Environment.count }
+ end
+
+ it 'returns an error' do
+ response = subject
+
+ expect(response).to be_error
+ expect(response.message).to match_array("'invalid' is not a valid auto_stop_setting")
expect(response.payload[:environment]).to be_nil
end
end
diff --git a/spec/services/environments/update_service_spec.rb b/spec/services/environments/update_service_spec.rb
index b7c9c3bcd74f8c56f2350baa710a5618c1535d16..45dbf837b224a0c232cb255ac3596e25b6d78a3f 100644
--- a/spec/services/environments/update_service_spec.rb
+++ b/spec/services/environments/update_service_spec.rb
@@ -15,7 +15,7 @@
describe '#execute' do
subject { service.execute(environment) }
- let(:params) { { external_url: 'https://gitlab.com/', description: 'description' } }
+ let(:params) { { external_url: 'https://gitlab.com/', description: 'description', auto_stop_setting: :with_action } }
it 'updates the external URL' do
expect { subject }.to change { environment.reload.external_url }.to('https://gitlab.com/')
@@ -25,6 +25,10 @@
expect { subject }.to change { environment.reload.description }.to('description')
end
+ it 'updates the auto stop setting' do
+ expect { subject }.to change { environment.reload.auto_stop_setting }.to('with_action')
+ end
+
it 'returns successful response' do
response = subject
@@ -84,14 +88,27 @@
end
end
- context 'when params contain invalid value' do
- let(:params) { { external_url: 'http://${URL}' } }
+ context 'when params contain invalid values' do
+ let(:params) { { external_url: 'http://${URL}', kubernetes_namespace: "invalid" } }
+
+ it 'returns an error' do
+ response = subject
+
+ expect(response).to be_error
+ expect(response.message).to match_array(["External url URI is invalid",
+ "Kubernetes namespace cannot be set without a cluster agent"])
+ expect(response.payload[:environment]).to eq(environment)
+ end
+ end
+
+ context 'when params contain invalid auto_stop_setting' do
+ let(:params) { { auto_stop_setting: :invalid } }
it 'returns an error' do
response = subject
expect(response).to be_error
- expect(response.message).to match_array("External url URI is invalid")
+ expect(response.message).to match_array("'invalid' is not a valid auto_stop_setting")
expect(response.payload[:environment]).to eq(environment)
end
end