2018-12-13 13:39:08 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
module Gitlab
|
|
|
|
module Ci
|
|
|
|
module Variables
|
|
|
|
class Collection
|
|
|
|
include Enumerable
|
|
|
|
|
2021-04-17 20:07:23 +05:30
|
|
|
attr_reader :errors
|
|
|
|
|
|
|
|
def initialize(variables = [], errors = nil)
|
2018-05-09 12:01:36 +05:30
|
|
|
@variables = []
|
2021-11-11 11:23:49 +05:30
|
|
|
@variables_by_key = Hash.new { |h, k| h[k] = [] }
|
2021-04-17 20:07:23 +05:30
|
|
|
@errors = errors
|
2018-05-09 12:01:36 +05:30
|
|
|
|
|
|
|
variables.each { |variable| self.append(variable) }
|
|
|
|
end
|
|
|
|
|
|
|
|
def append(resource)
|
2021-04-17 20:07:23 +05:30
|
|
|
item = Collection::Item.fabricate(resource)
|
|
|
|
@variables.append(item)
|
2021-11-11 11:23:49 +05:30
|
|
|
@variables_by_key[item[:key]] << item
|
2021-04-17 20:07:23 +05:30
|
|
|
|
|
|
|
self
|
2018-05-09 12:01:36 +05:30
|
|
|
end
|
|
|
|
|
2021-09-04 01:27:46 +05:30
|
|
|
def compact
|
|
|
|
Collection.new(select { |variable| !variable.value.nil? })
|
|
|
|
end
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
def concat(resources)
|
2019-07-07 11:18:12 +05:30
|
|
|
return self if resources.nil?
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
tap { resources.each { |variable| self.append(variable) } }
|
|
|
|
end
|
|
|
|
|
|
|
|
def each
|
|
|
|
@variables.each { |variable| yield variable }
|
|
|
|
end
|
|
|
|
|
|
|
|
def +(other)
|
|
|
|
self.class.new.tap do |collection|
|
|
|
|
self.each { |variable| collection.append(variable) }
|
|
|
|
other.each { |variable| collection.append(variable) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-17 20:07:23 +05:30
|
|
|
def [](key)
|
2021-11-11 11:23:49 +05:30
|
|
|
all(key)&.last
|
|
|
|
end
|
|
|
|
|
|
|
|
def all(key)
|
|
|
|
vars = @variables_by_key[key]
|
|
|
|
vars unless vars.empty?
|
2021-04-17 20:07:23 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def size
|
|
|
|
@variables.size
|
|
|
|
end
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
def to_runner_variables
|
|
|
|
self.map(&:to_runner_variable)
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_hash
|
|
|
|
self.to_runner_variables
|
2021-04-17 20:07:23 +05:30
|
|
|
.to_h { |env| [env.fetch(:key), env.fetch(:value)] }
|
|
|
|
.with_indifferent_access
|
2018-05-09 12:01:36 +05:30
|
|
|
end
|
2021-04-17 20:07:23 +05:30
|
|
|
|
|
|
|
def reject(&block)
|
|
|
|
Collection.new(@variables.reject(&block))
|
|
|
|
end
|
|
|
|
|
2023-01-13 00:05:48 +05:30
|
|
|
# `expand_raw_refs` will be deleted with the FF `ci_raw_variables_in_yaml_config`.
|
|
|
|
def expand_value(value, keep_undefined: false, expand_file_refs: true, expand_raw_refs: true, project: nil)
|
2021-09-04 01:27:46 +05:30
|
|
|
value.gsub(Item::VARIABLES_REGEXP) do
|
2022-08-27 11:52:29 +05:30
|
|
|
match = Regexp.last_match # it is either a valid variable definition or a ($$ / %%)
|
|
|
|
full_match = match[0]
|
|
|
|
variable_name = match[:key]
|
|
|
|
|
|
|
|
next full_match unless variable_name # it is a ($$ / %%), so we don't touch it
|
|
|
|
|
|
|
|
# now we know that it is a valid variable definition: $VARIABLE_NAME / %VARIABLE_NAME / ${VARIABLE_NAME}
|
|
|
|
|
|
|
|
# we are trying to find a variable with key VARIABLE_NAME
|
|
|
|
variable = self[variable_name]
|
|
|
|
|
|
|
|
if variable # VARIABLE_NAME is an existing variable
|
2023-01-13 00:05:48 +05:30
|
|
|
if variable.file?
|
|
|
|
# Will be cleaned up with https://gitlab.com/gitlab-org/gitlab/-/issues/378266
|
|
|
|
if project
|
|
|
|
# We only log if `project` exists to make sure it is called from `Ci::BuildRunnerPresenter`
|
|
|
|
# when the variables are sent to Runner.
|
|
|
|
Gitlab::AppJsonLogger.info(event: 'file_variable_is_referenced_in_another_variable',
|
|
|
|
project_id: project.id,
|
|
|
|
variable: variable_name)
|
|
|
|
end
|
|
|
|
|
|
|
|
expand_file_refs ? variable.value : full_match
|
|
|
|
elsif variable.raw?
|
|
|
|
# With `full_match`, we defer the expansion of raw variables to the runner. If we expand them here,
|
|
|
|
# the runner will not know the expanded value is a raw variable and it tries to expand it again.
|
|
|
|
# Discussion: https://gitlab.com/gitlab-org/gitlab/-/issues/353991#note_1103274951
|
|
|
|
expand_raw_refs ? variable.value : full_match
|
|
|
|
else
|
|
|
|
variable.value
|
2022-11-25 23:54:43 +05:30
|
|
|
end
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
elsif keep_undefined
|
|
|
|
full_match # we do not touch the variable definition
|
2021-09-04 01:27:46 +05:30
|
|
|
else
|
2022-08-27 11:52:29 +05:30
|
|
|
nil # we remove the variable definition
|
2021-09-04 01:27:46 +05:30
|
|
|
end
|
2021-04-17 20:07:23 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-01-13 00:05:48 +05:30
|
|
|
# `expand_raw_refs` will be deleted with the FF `ci_raw_variables_in_yaml_config`.
|
|
|
|
def sort_and_expand_all(keep_undefined: false, expand_file_refs: true, expand_raw_refs: true, project: nil)
|
2021-04-17 20:07:23 +05:30
|
|
|
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
|
2022-08-27 11:52:29 +05:30
|
|
|
variable[:value] = new_collection.expand_value(variable[:value], keep_undefined: keep_undefined,
|
2023-01-13 00:05:48 +05:30
|
|
|
expand_file_refs: expand_file_refs,
|
|
|
|
expand_raw_refs: expand_raw_refs,
|
2022-11-25 23:54:43 +05:30
|
|
|
project: project)
|
2021-04-17 20:07:23 +05:30
|
|
|
new_collection.append(variable)
|
|
|
|
end
|
|
|
|
|
|
|
|
new_collection
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
"#{@variables_by_key.keys}, @errors='#{@errors}'"
|
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
|
|
|
attr_reader :variables
|
2018-05-09 12:01:36 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|