diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb index b2bdbda9da95d73538c743f9ba38372e0bcb4e76..b1f768825059c3b9747a8ac5d4e1ea5d54430d5f 100644 --- a/app/models/ci/bridge.rb +++ b/app/models/ci/bridge.rb @@ -288,7 +288,11 @@ def downstream_yaml_variables(expand_variables) return [] unless forward_yaml_variables? yaml_variables.to_a.map do |hash| - { key: hash[:key], value: ::ExpandVariables.expand(hash[:value], expand_variables) } + if hash[:raw] && ci_raw_variables_in_yaml_config_enabled? + { key: hash[:key], value: hash[:value], raw: true } + else + { key: hash[:key], value: ::ExpandVariables.expand(hash[:value], expand_variables) } + end end end @@ -296,7 +300,11 @@ def downstream_pipeline_variables(expand_variables) return [] unless forward_pipeline_variables? pipeline.variables.to_a.map do |variable| - { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) } + if variable.raw? && ci_raw_variables_in_yaml_config_enabled? + { key: variable.key, value: variable.value, raw: true } + else + { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) } + end end end @@ -305,7 +313,11 @@ def downstream_pipeline_schedule_variables(expand_variables) return [] unless pipeline.pipeline_schedule pipeline.pipeline_schedule.variables.to_a.map do |variable| - { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) } + if variable.raw? && ci_raw_variables_in_yaml_config_enabled? + { key: variable.key, value: variable.value, raw: true } + else + { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) } + end end end @@ -324,6 +336,12 @@ def forward_pipeline_variables? result.nil? ? FORWARD_DEFAULTS[:pipeline_variables] : result end end + + def ci_raw_variables_in_yaml_config_enabled? + strong_memoize(:ci_raw_variables_in_yaml_config_enabled) do + ::Feature.enabled?(:ci_raw_variables_in_yaml_config, project) + end + end end end diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb index 3df278a49dda0ef9eee4eb2d0fb94cc607e41d91..5370aae3c70c5f5bdb9ae44bc8a37b95919192ac 100644 --- a/spec/models/ci/bridge_spec.rb +++ b/spec/models/ci/bridge_spec.rb @@ -206,6 +206,8 @@ end describe '#downstream_variables' do + subject(:downstream_variables) { bridge.downstream_variables } + it 'returns variables that are going to be passed downstream' do expect(bridge.downstream_variables) .to include(key: 'BRIDGE', value: 'cross') @@ -330,6 +332,79 @@ end end end + + context 'when using raw variables' do + let(:options) do + { + trigger: { + project: 'my/project', + branch: 'master', + forward: { yaml_variables: true, + pipeline_variables: true }.compact + } + } + end + + let(:yaml_variables) do + [ + { + key: 'VAR6', + value: 'value6 $VAR1' + }, + { + key: 'VAR7', + value: 'value7 $VAR1', + raw: true + } + ] + end + + let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) } + let(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) } + + before do + create(:ci_pipeline_variable, pipeline: pipeline, key: 'VAR1', value: 'value1') + create(:ci_pipeline_variable, pipeline: pipeline, key: 'VAR2', value: 'value2 $VAR1') + create(:ci_pipeline_variable, pipeline: pipeline, key: 'VAR3', value: 'value3 $VAR1', raw: true) + + pipeline_schedule.variables.create!(key: 'VAR4', value: 'value4 $VAR1') + pipeline_schedule.variables.create!(key: 'VAR5', value: 'value5 $VAR1', raw: true) + + bridge.yaml_variables.concat(yaml_variables) + end + + it 'expands variables according to their raw attributes' do + expect(downstream_variables).to contain_exactly( + { key: 'BRIDGE', value: 'cross' }, + { key: 'VAR1', value: 'value1' }, + { key: 'VAR2', value: 'value2 value1' }, + { key: 'VAR3', value: 'value3 $VAR1', raw: true }, + { key: 'VAR4', value: 'value4 value1' }, + { key: 'VAR5', value: 'value5 $VAR1', raw: true }, + { key: 'VAR6', value: 'value6 value1' }, + { key: 'VAR7', value: 'value7 $VAR1', raw: true } + ) + end + + context 'when the FF ci_raw_variables_in_yaml_config is disabled' do + before do + stub_feature_flags(ci_raw_variables_in_yaml_config: false) + end + + it 'ignores the raw attribute' do + expect(downstream_variables).to contain_exactly( + { key: 'BRIDGE', value: 'cross' }, + { key: 'VAR1', value: 'value1' }, + { key: 'VAR2', value: 'value2 value1' }, + { key: 'VAR3', value: 'value3 value1' }, + { key: 'VAR4', value: 'value4 value1' }, + { key: 'VAR5', value: 'value5 value1' }, + { key: 'VAR6', value: 'value6 value1' }, + { key: 'VAR7', value: 'value7 value1' } + ) + end + end + end end describe 'metadata support' do diff --git a/spec/services/ci/create_pipeline_service/variables_spec.rb b/spec/services/ci/create_pipeline_service/variables_spec.rb index c0ed8ad2a9e77ae179b066637b8dfa73f5788405..e9e0cf2c6e048c35d74713bb1f7d3193daeb8f58 100644 --- a/spec/services/ci/create_pipeline_service/variables_spec.rb +++ b/spec/services/ci/create_pipeline_service/variables_spec.rb @@ -82,6 +82,50 @@ end end end + + context 'when trigger variables have expand: true/false' do + let(:config) do + <<-YAML + child: + variables: + VAR1: "PROJECTID-$CI_PROJECT_ID" + VAR2: "PIPELINEID-$CI_PIPELINE_ID and $VAR1" + VAR3: + value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1" + expand: false + trigger: + include: child.yml + YAML + end + + let(:child) { find_job('child') } + + it 'creates the pipeline with a trigger job that has downstream_variables expanded according to "expand"' do + expect(pipeline).to be_created_successfully + + expect(child.downstream_variables).to include( + { key: 'VAR1', value: "PROJECTID-#{project.id}" }, + { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" }, + { key: 'VAR3', value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1", raw: true } + ) + end + + context 'when the FF ci_raw_variables_in_yaml_config is disabled' do + before do + stub_feature_flags(ci_raw_variables_in_yaml_config: false) + end + + it 'creates the pipeline with a job that has all variables expanded' do + expect(pipeline).to be_created_successfully + + expect(child.downstream_variables).to include( + { key: 'VAR1', value: "PROJECTID-#{project.id}" }, + { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" }, + { key: 'VAR3', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" } + ) + end + end + end end private