From 3c5a921cc23bfb7e9ccbcc06841c45d5feb6b065 Mon Sep 17 00:00:00 2001
From: Alishan Ladhani <aladhani@gitlab.com>
Date: Tue, 19 Apr 2022 16:34:59 -0400
Subject: [PATCH] Add verify action for environments

Changelog: added
---
 Gemfile                                           |  1 +
 Gemfile.lock                                      |  1 +
 app/assets/javascripts/editor/schema/ci.json      |  4 ++--
 doc/ci/environments/index.md                      | 15 ++++++---------
 doc/ci/yaml/index.md                              |  5 +++--
 lib/gitlab/ci/config/entry/environment.rb         |  2 +-
 .../gitlab/ci/config/entry/environment_spec.rb    | 13 ++++++++++++-
 .../gitlab/ci/pipeline/seed/deployment_spec.rb    | 13 +++++++++++++
 8 files changed, 39 insertions(+), 15 deletions(-)

diff --git a/Gemfile b/Gemfile
index 1a574ee1d6d00..5c231f8178ece 100644
--- a/Gemfile
+++ b/Gemfile
@@ -345,6 +345,7 @@ gem 'warning', '~> 1.2.0'
 
 group :development do
   gem 'lefthook', '~> 0.7.0', require: false
+  gem 'rubocop'
   gem 'solargraph', '~> 0.44.3', require: false
 
   gem 'letter_opener_web', '~> 2.0.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 9be5324ef1112..86e9d18b31d33 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1644,6 +1644,7 @@ DEPENDENCIES
   rspec-retry (~> 0.6.1)
   rspec_junit_formatter
   rspec_profiling (~> 0.0.6)
+  rubocop
   ruby-fogbugz (~> 0.2.1)
   ruby-magic (~> 0.5)
   ruby-prof (~> 1.3.0)
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index fe3229ac91b10..620edf3adc7da 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -1093,8 +1093,8 @@
                   "description": "The name of a job to execute when the environment is about to be stopped."
                 },
                 "action": {
-                  "enum": ["start", "prepare", "stop"],
-                  "description": "Specifies what this job will do. 'start' (default) indicates the job will start the deployment. 'prepare' indicates this will not affect the deployment. 'stop' indicates this will stop the deployment.",
+                  "enum": ["start", "prepare", "stop", "verify"],
+                  "description": "Specifies what this job will do. 'start' (default) indicates the job will start the deployment. 'prepare'/'verify' indicates this will not affect the deployment. 'stop' indicates this will stop the deployment.",
                   "default": "start"
                 },
                 "auto_stop_in": {
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index 3822b32181f91..e0777a27b194b 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -645,17 +645,14 @@ To delete a stopped environment in the GitLab UI:
 1. Next to the environment you want to delete, select **Delete environment**.
 1. On the confirmation dialog box, select **Delete environment**.
 
-### Prepare an environment without creating a deployment
+### Access an environment for preparation or verification purposes
 
 > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208655) in GitLab 13.2.
 
-By default, when GitLab CI/CD runs a job for a specific environment, it
-triggers a deployment and [(optionally) cancels outdated
-deployments](deployment_safety.md#ensure-only-one-deployment-job-runs-at-a-time).
+You can define a job that accesses an environment for various purposes, such as verification or preparation. This 
+effectively bypasses deployment creation, so that you can adjust your CD workflow more accurately.
 
-To use an environment without creating a new deployment, and without
-cancelling outdated deployments, append the keyword `action: prepare` to your
-job:
+To do so, add either  `action: prepare` or `action: verify` to the `environment` section of your job:
 
 ```yaml
 build:
@@ -668,8 +665,8 @@ build:
     url: https://staging.example.com
 ```
 
-This gives you access to [environment-scoped variables](#scope-environments-with-specs),
-and can be used to [protect builds from unauthorized access](protected_environments.md).
+This gives you access to environment-scoped variables, and can be used to protect builds from unauthorized access. Also,
+it's effective to avoid the [skip outdated deployment jobs](deployment_safety.md#skip-outdated-deployment-jobs) feature.
 
 ### Group similar environments
 
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index 869508738a58c..3f8c17e9c1154 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -1559,7 +1559,7 @@ environment.
 
 #### `environment:action`
 
-Use the `action` keyword to specify jobs that prepare, start, or stop environments.
+Use the `action` keyword to specify jobs that prepare, start, stop, or verify environments.
 
 **Keyword type**: Job keyword. You can use it only as part of a job.
 
@@ -1568,8 +1568,9 @@ Use the `action` keyword to specify jobs that prepare, start, or stop environmen
 | **Value** | **Description** |
 |:----------|:----------------|
 | `start`   | Default value. Indicates that the job starts the environment. The deployment is created after the job starts. |
-| `prepare` | Indicates that the job is only preparing the environment. It does not trigger deployments. [Read more about preparing environments](../environments/index.md#prepare-an-environment-without-creating-a-deployment). |
+| `prepare` | Indicates that the job is only preparing the environment. It does not trigger deployments. [Read more about preparing environments](../environments/index.md#access-an-environment-for-preparation-or-verification-purposes). |
 | `stop`    | Indicates that the job stops a deployment. For more detail, read [Stop an environment](../environments/index.md#stop-an-environment). |
+| `verify`  | Indicates that the job is only verifying the environment. It does not trigger deployments. [Read more about verifying environments](../environments/index.md#access-an-environment-for-preparation-or-verification-purposes). |
 
 **Example of `environment:action`**:
 
diff --git a/lib/gitlab/ci/config/entry/environment.rb b/lib/gitlab/ci/config/entry/environment.rb
index 2066e9be3b135..7897b54a69fb2 100644
--- a/lib/gitlab/ci/config/entry/environment.rb
+++ b/lib/gitlab/ci/config/entry/environment.rb
@@ -44,7 +44,7 @@ class Environment < ::Gitlab::Config::Entry::Node
 
               validates :action,
                         type: String,
-                        inclusion: { in: %w[start stop prepare], message: 'should be start, stop or prepare' },
+                        inclusion: { in: %w[start stop prepare verify], message: 'should be start, stop, prepare, or verify' },
                         allow_nil: true
 
               validates :deployment_tier,
diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
index dd8a79f0d84c3..af3c157d85726 100644
--- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb
@@ -113,6 +113,17 @@
     end
   end
 
+  context 'when verify action is used' do
+    let(:config) do
+      { name: 'production',
+        action: 'verify' }
+    end
+
+    it 'is valid' do
+      expect(entry).to be_valid
+    end
+  end
+
   context 'when wrong action type is used' do
     let(:config) do
       { name: 'production',
@@ -148,7 +159,7 @@
     describe '#errors' do
       it 'contains error about invalid action' do
         expect(entry.errors)
-          .to include 'environment action should be start, stop or prepare'
+          .to include 'environment action should be start, stop, prepare, or verify'
       end
     end
   end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
index 9f7281fb71431..cb6a77ce37ff1 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
@@ -116,6 +116,19 @@
       end
     end
 
+    context 'when job has environment attribute with verify action' do
+      let(:attributes) do
+        {
+          environment: 'production',
+          options: { environment: { name: 'production', action: 'verify' } }
+        }
+      end
+
+      it 'returns nothing' do
+        is_expected.to be_nil
+      end
+    end
+
     context 'when job does not have environment attribute' do
       let(:attributes) { { name: 'test' } }
 
-- 
GitLab