diff --git a/lib/ci/pipeline_creation/inputs/array_input.rb b/lib/ci/pipeline_creation/inputs/array_input.rb index dff5043fc47721eb6ce85a216529dca73a5ce32a..50ca14f47a35aa6668dc7d6516e283c5bf6c1378 100644 --- a/lib/ci/pipeline_creation/inputs/array_input.rb +++ b/lib/ci/pipeline_creation/inputs/array_input.rb @@ -16,6 +16,20 @@ def validate_type(value, default) error("#{default ? 'default' : 'provided'} value is not an array") end + + # Some array type inputs contain objects that get loaded as Ruby hashes. The YAML keys for those objects are + # loaded as symbols. When we cast those symbols to JSON during interpolation, the result gets mangled. + # { :"array.input.item" => "value" } becomes { ":\"array.input.item\": "value" }. + # To fix that, we stringify the keys. + def actual_value(param) + super.map do |item| + if item.is_a?(Hash) + item.stringify_keys + else + item + end + end + end end end end diff --git a/spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb b/spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..ceb806e3329947ca8568da8c643b0a7cc0549f0f --- /dev/null +++ b/spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative Rails.root.join('lib/ci/pipeline_creation/inputs/base_input.rb') + +RSpec.describe Ci::PipelineCreation::Inputs::ArrayInput, feature_category: :pipeline_composition do + describe '#actual_value' do + it 'returns the array given to the input' do + input = described_class.new(name: 'test', spec: { test: { type: 'array' } }) + + value = input.actual_value('[1, 2]') + + expect(value).to eq([1, 2]) + end + + context 'when the array contains objects/hashes' do + # Some array type inputs contain objects that get loaded as Ruby hashes. The YAML keys for those objects are + # loaded as symbols. When we cast those symbols to JSON during interpolation, the result gets mangled. + # { :"array.input.item" => "value" } becomes { ":\"array.input.item\": "value" }. + # To fix that, we stringify the keys when we return them from ArrayInput. + it 'stringifies the keys so they do not contain extra characters when cast to JSON during interpolation' do + input = described_class.new(name: 'test', spec: { test: { type: 'array' } }) + + value = input.actual_value([{ 'array.input.item': 'value' }]) + + expect(value).to eq([{ 'array.input.item' => 'value' }]) + end + end + end +end diff --git a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb index c8dd2ad00a822025f7396fbf28fadade95f0a566..55aff94a4485957d6aaa3f9fcb369fe860bcd02d 100644 --- a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb +++ b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb @@ -337,7 +337,7 @@ end end - context 'when the default is not a boolean' do + context 'when the default is not an array' do let(:specs) { { array_input: { default: 'string', type: 'array' } } } let(:args) { {} }