Commit 42ea80cc authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'pedropombeiro/26345/6-add-expand_variable_collection' into 'master'

Add #expand_variable_collection to Variables::Collection

See merge request gitlab-org/gitlab!54507
parents 3611732d df1457dd
......@@ -154,8 +154,8 @@ module Gitlab
end
def variable_expansion_errors
sorted_collection = evaluate_context.variables.sorted_collection(@pipeline.project)
errors = sorted_collection.errors
expanded_collection = evaluate_context.variables.sort_and_expand_all(@pipeline.project)
errors = expanded_collection.errors
["#{name}: #{errors}"] if errors
end
......
......@@ -63,10 +63,45 @@ module Gitlab
Collection.new(@variables.reject(&block))
end
# Returns a sorted Collection object, and sets errors property in case of an error
def sorted_collection(project)
Sort.new(self, project).collection
def expand_value(value, keep_undefined: false)
value.gsub(ExpandVariables::VARIABLES_REGEXP) do
match = Regexp.last_match
result = @variables_by_key[match[1] || match[2]]&.value
result ||= match[0] if keep_undefined
result
end
end
def sort_and_expand_all(project, keep_undefined: false)
return self if Feature.disabled?(:variable_inside_variable, project)
sorted = Sort.new(self)
return self.class.new(self, sorted.errors) unless sorted.valid?
new_collection = self.class.new
sorted.tsort.each do |item|
unless item.depends_on
new_collection.append(item)
next
end
# expand variables as they are added
variable = item.to_runner_variable
variable[:value] = new_collection.expand_value(variable[:value], keep_undefined: keep_undefined)
new_collection.append(variable)
end
new_collection
end
def to_s
"#{@variables_by_key.keys}, @errors='#{@errors}'"
end
protected
attr_reader :variables
end
end
end
......
......@@ -7,20 +7,21 @@ module Gitlab
class Item
include Gitlab::Utils::StrongMemoize
attr_reader :raw
def initialize(key:, value:, public: true, file: false, masked: false, raw: false)
raise ArgumentError, "`#{key}` must be of type String or nil value, while it was: #{value.class}" unless
value.is_a?(String) || value.nil?
@variable = { key: key, value: value, public: public, file: file, masked: masked }
@raw = raw
@variable = { key: key, value: value, public: public, file: file, masked: masked, raw: raw }
end
def value
@variable.fetch(:value)
end
def raw
@variable.fetch(:raw)
end
def [](key)
@variable.fetch(key)
end
......@@ -46,7 +47,7 @@ module Gitlab
#
def to_runner_variable
@variable.reject do |hash_key, hash_value|
hash_key == :file && hash_value == false
(hash_key == :file || hash_key == :raw) && hash_value == false
end
end
......@@ -62,6 +63,12 @@ module Gitlab
raise ArgumentError, "Unknown `#{resource.class}` variable resource!"
end
end
def to_s
return to_runner_variable.to_s unless depends_on
"#{to_runner_variable}, depends_on=#{depends_on}"
end
end
end
end
......
......@@ -8,12 +8,11 @@ module Gitlab
include TSort
include Gitlab::Utils::StrongMemoize
def initialize(collection, project)
def initialize(collection)
raise(ArgumentError, "A Gitlab::Ci::Variables::Collection object was expected") unless
collection.is_a?(Collection)
@collection = collection
@project = project
end
def valid?
......@@ -23,8 +22,6 @@ module Gitlab
# errors sorts an array of variables, ignoring unknown variable references,
# and returning an error string if a circular variable reference is found
def errors
return if Feature.disabled?(:variable_inside_variable, @project)
strong_memoize(:errors) do
# Check for cyclic dependencies and build error message in that case
cyclic_vars = each_strongly_connected_component.filter_map do |component|
......@@ -35,16 +32,6 @@ module Gitlab
end
end
# collection sorts a collection of variables, ignoring unknown variable references.
# If a circular variable reference is found, a new collection with the original array and an error is returned
def collection
return @collection if Feature.disabled?(:variable_inside_variable, @project)
return Gitlab::Ci::Variables::Collection.new(@collection, errors) if errors
Gitlab::Ci::Variables::Collection.new(tsort)
end
private
def tsort_each_node(&block)
......
......@@ -202,6 +202,26 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
end
end
context 'when variable is raw' do
it 'does not export raw value when it is false' do
runner_variable = described_class
.new(key: 'VAR', value: 'value', raw: false)
.to_runner_variable
expect(runner_variable)
.to eq(key: 'VAR', value: 'value', public: true, masked: false)
end
it 'exports raw value when it is true' do
runner_variable = described_class
.new(key: 'VAR', value: 'value', raw: true)
.to_runner_variable
expect(runner_variable)
.to eq(key: 'VAR', value: 'value', public: true, raw: true, masked: false)
end
end
context 'when referencing a variable' do
it '#depends_on contains names of dependencies' do
runner_variable = described_class.new(key: 'CI_VAR', value: '${CI_VAR_2}-123-$CI_VAR_3')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment