From 2f0e358d61b7052336c4e35b9df99f7057b64bb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Hern=C3=A1ndez=20Remedios?=
 <6065567-renehernandez@users.noreply.gitlab.com>
Date: Fri, 1 Dec 2023 16:40:06 +0000
Subject: [PATCH] Full dotenv vars support in downstream pipelines

Changelog: added
---
 doc/ci/pipelines/downstream_pipelines.md      |  4 +--
 .../ci/variables/downstream/generator.rb      |  8 ++++++
 .../ci/variables/downstream/generator_spec.rb | 28 +++++++++++++++++--
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md
index 21ed66ef939cf..ec1b6a4dba308 100644
--- a/doc/ci/pipelines/downstream_pipelines.md
+++ b/doc/ci/pipelines/downstream_pipelines.md
@@ -671,9 +671,7 @@ the ones defined in the upstream project take precedence.
 
 ### Pass dotenv variables created in a job **(PREMIUM ALL)**
 
-You can pass variables to a downstream job with [`dotenv` variable inheritance](../variables/index.md#pass-an-environment-variable-to-another-job)
-and [`needs:project`](../yaml/index.md#needsproject). These variables are only available in
-the script of the job and can't be used to configure it, for example with `rules` or `artifact:paths`.
+You can pass variables to a downstream pipeline with [`dotenv` variable inheritance](../variables/index.md#pass-an-environment-variable-to-another-job).
 
 For example, in a [multi-project pipeline](#multi-project-pipelines):
 
diff --git a/lib/gitlab/ci/variables/downstream/generator.rb b/lib/gitlab/ci/variables/downstream/generator.rb
index 350d29958cfc1..b0e45ac0413cc 100644
--- a/lib/gitlab/ci/variables/downstream/generator.rb
+++ b/lib/gitlab/ci/variables/downstream/generator.rb
@@ -33,6 +33,7 @@ def calculate_downstream_variables
             # The order of this list refers to the priority of the variables
             # The variables added later takes priority.
             downstream_yaml_variables +
+              downstream_pipeline_dotenv_variables +
               downstream_pipeline_variables +
               downstream_pipeline_schedule_variables
           end
@@ -57,6 +58,13 @@ def downstream_pipeline_schedule_variables
             build_downstream_variables_from(pipeline_schedule_variables)
           end
 
+          def downstream_pipeline_dotenv_variables
+            return [] unless bridge.forward_pipeline_variables?
+
+            pipeline_dotenv_variables = bridge.dependency_variables.to_a
+            build_downstream_variables_from(pipeline_dotenv_variables)
+          end
+
           def build_downstream_variables_from(variables)
             Gitlab::Ci::Variables::Collection.fabricate(variables).flat_map do |item|
               if item.raw?
diff --git a/spec/lib/gitlab/ci/variables/downstream/generator_spec.rb b/spec/lib/gitlab/ci/variables/downstream/generator_spec.rb
index cd68b0cdf2bb7..f5845e492bcdf 100644
--- a/spec/lib/gitlab/ci/variables/downstream/generator_spec.rb
+++ b/spec/lib/gitlab/ci/variables/downstream/generator_spec.rb
@@ -39,6 +39,15 @@
     ]
   end
 
+  let(:pipeline_dotenv_variables) do
+    [
+      { key: 'PIPELINE_DOTENV_VAR1', value: 'variable 1' },
+      { key: 'PIPELINE_DOTENV_VAR2', value: 'variable 2' },
+      { key: 'PIPELINE_DOTENV_RAW_VAR3', value: '$REF1', raw: true },
+      { key: 'PIPELINE_DOTENV_INTERPOLATION_VAR4', value: 'interpolate $REF1 $REF2' }
+    ]
+  end
+
   let(:bridge) do
     instance_double(
       'Ci::Bridge',
@@ -48,7 +57,8 @@
       expand_file_refs?: false,
       yaml_variables: yaml_variables,
       pipeline_variables: pipeline_variables,
-      pipeline_schedule_variables: pipeline_schedule_variables
+      pipeline_schedule_variables: pipeline_schedule_variables,
+      dependency_variables: pipeline_dotenv_variables
     )
   end
 
@@ -69,7 +79,12 @@
         { key: 'PIPELINE_SCHEDULE_VAR1', value: 'variable 1' },
         { key: 'PIPELINE_SCHEDULE_VAR2', value: 'variable 2' },
         { key: 'PIPELINE_SCHEDULE_RAW_VAR3', value: '$REF1', raw: true },
-        { key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR4', value: 'interpolate ref 1 ref 2' }
+        { key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR4', value: 'interpolate ref 1 ref 2' },
+        { key: 'PIPELINE_DOTENV_VAR1', value: 'variable 1' },
+        { key: 'PIPELINE_DOTENV_VAR2', value: 'variable 2' },
+        { key: 'PIPELINE_DOTENV_RAW_VAR3', value: '$REF1', raw: true },
+        { key: 'PIPELINE_DOTENV_INTERPOLATION_VAR4', value: 'interpolate ref 1 ref 2' }
+
       ]
 
       expect(generator.calculate).to contain_exactly(*expected)
@@ -79,6 +94,7 @@
       allow(bridge).to receive(:yaml_variables).and_return([])
       allow(bridge).to receive(:pipeline_variables).and_return([])
       allow(bridge).to receive(:pipeline_schedule_variables).and_return([])
+      allow(bridge).to receive(:dependency_variables).and_return([])
 
       expect(generator.calculate).to be_empty
     end
@@ -105,6 +121,10 @@
         [{ key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate $REF1 $REF2 $FILE_REF3 $FILE_REF4' }]
       end
 
+      let(:pipeline_dotenv_variables) do
+        [{ key: 'PIPELINE_DOTENV_INTERPOLATION_VAR', value: 'interpolate $REF1 $REF2 $FILE_REF3 $FILE_REF4' }]
+      end
+
       context 'when expand_file_refs is true' do
         before do
           allow(bridge).to receive(:expand_file_refs?).and_return(true)
@@ -114,7 +134,8 @@
           expected = [
             { key: 'INTERPOLATION_VAR', value: 'interpolate ref 1  ref 3 ' },
             { key: 'PIPELINE_INTERPOLATION_VAR', value: 'interpolate ref 1  ref 3 ' },
-            { key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate ref 1  ref 3 ' }
+            { key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate ref 1  ref 3 ' },
+            { key: 'PIPELINE_DOTENV_INTERPOLATION_VAR', value: 'interpolate ref 1  ref 3 ' }
           ]
 
           expect(generator.calculate).to contain_exactly(*expected)
@@ -131,6 +152,7 @@
             { key: 'INTERPOLATION_VAR', value: 'interpolate ref 1  $FILE_REF3 ' },
             { key: 'PIPELINE_INTERPOLATION_VAR', value: 'interpolate ref 1  $FILE_REF3 ' },
             { key: 'PIPELINE_SCHEDULE_INTERPOLATION_VAR', value: 'interpolate ref 1  $FILE_REF3 ' },
+            { key: 'PIPELINE_DOTENV_INTERPOLATION_VAR', value: 'interpolate ref 1  $FILE_REF3 ' },
             { key: 'FILE_REF3', value: 'ref 3', variable_type: :file }
           ]
 
-- 
GitLab