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