Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
250fede4
Commit
250fede4
authored
Mar 11, 2021
by
Pedro Pombeiro
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Address MR review comments
parent
d565ff04
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
510 additions
and
683 deletions
+510
-683
lib/expand_variables.rb
lib/expand_variables.rb
+0
-23
lib/gitlab/ci/pipeline/seed/build.rb
lib/gitlab/ci/pipeline/seed/build.rb
+2
-2
lib/gitlab/ci/variables/collection.rb
lib/gitlab/ci/variables/collection.rb
+28
-8
lib/gitlab/ci/variables/collection/item.rb
lib/gitlab/ci/variables/collection/item.rb
+6
-9
lib/gitlab/ci/variables/collection/sort.rb
lib/gitlab/ci/variables/collection/sort.rb
+1
-14
spec/lib/expand_variables_spec.rb
spec/lib/expand_variables_spec.rb
+0
-232
spec/lib/gitlab/ci/variables/collection/item_spec.rb
spec/lib/gitlab/ci/variables/collection/item_spec.rb
+20
-10
spec/lib/gitlab/ci/variables/collection/sort_spec.rb
spec/lib/gitlab/ci/variables/collection/sort_spec.rb
+134
-279
spec/lib/gitlab/ci/variables/collection_spec.rb
spec/lib/gitlab/ci/variables/collection_spec.rb
+319
-106
No files found.
lib/expand_variables.rb
View file @
250fede4
...
...
@@ -16,18 +16,6 @@ module ExpandVariables
end
end
# expand_variables_collection expands a Gitlab::Ci::Variables::Collection, ignoring unknown variable references.
# If a circular variable reference is found, the original Collection is returned
def
expand_variables_collection
(
variables
,
project
)
return
Gitlab
::
Ci
::
Variables
::
Collection
.
new
(
variables
)
if
Feature
.
disabled?
(
:variable_inside_variable
,
project
)
sorted_variables
=
variables
.
sorted_collection
(
project
)
return
sorted_variables
if
sorted_variables
.
errors
expand_sorted_variables_collection
(
sorted_variables
)
end
def
possible_var_reference?
(
value
)
return
unless
value
...
...
@@ -74,16 +62,5 @@ module ExpandVariables
variables
end
def
expand_sorted_variables_collection
(
sorted_variables
)
expanded_vars
=
{}
sorted_variables
.
each_with_object
(
Gitlab
::
Ci
::
Variables
::
Collection
.
new
)
do
|
item
,
collection
|
item
=
item
.
merge
(
value:
expand_existing
(
item
.
value
,
expanded_vars
))
if
item
.
depends_on
expanded_vars
.
store
(
item
[
:key
],
item
)
collection
.
append
(
item
)
end
end
end
end
lib/gitlab/ci/pipeline/seed/build.rb
View file @
250fede4
...
...
@@ -162,8 +162,8 @@ module Gitlab
end
def
variable_expansion_errors
sorted_collection
=
evaluate_context
.
variables
.
sorted_collection
(
@pipeline
.
project
)
errors
=
sort
ed_collection
.
errors
expanded_collection
=
evaluate_context
.
variables
.
expand_all
(
@pipeline
.
project
)
errors
=
expand
ed_collection
.
errors
[
"
#{
name
}
:
#{
errors
}
"
]
if
errors
end
...
...
lib/gitlab/ci/variables/collection.rb
View file @
250fede4
...
...
@@ -63,16 +63,36 @@ module Gitlab
Collection
.
new
(
@variables
.
reject
(
&
block
))
end
def
==
(
other
)
return
@variables
==
other
if
other
.
is_a?
(
Array
)
return
false
unless
other
.
class
==
self
.
class
@variables
==
other
.
variables
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
# 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_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
protected
...
...
lib/gitlab/ci/variables/collection/item.rb
View file @
250fede4
...
...
@@ -7,26 +7,23 @@ 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
[]
(
key
)
@variable
.
fetch
(
key
)
def
raw
@variable
.
fetch
(
:raw
)
end
def
merge
(
*
other_hashes
)
self
.
class
.
fabricate
(
@variable
.
merge
(
*
other_hashes
)
)
def
[]
(
key
)
@variable
.
fetch
(
key
)
end
def
==
(
other
)
...
...
@@ -50,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
...
...
lib/gitlab/ci/variables/collection/sort.rb
View file @
250fede4
...
...
@@ -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
)
...
...
spec/lib/expand_variables_spec.rb
View file @
250fede4
...
...
@@ -268,236 +268,4 @@ RSpec.describe ExpandVariables do
end
end
end
describe
'#expand_variables_collection'
do
context
'when FF :variable_inside_variable is disabled'
do
let_it_be
(
:project_with_flag_disabled
)
{
create
(
:project
)
}
let_it_be
(
:project_with_flag_enabled
)
{
create
(
:project
)
}
before
do
stub_feature_flags
(
variable_inside_variable:
[
project_with_flag_enabled
])
end
context
'table tests'
do
using
RSpec
::
Parameterized
::
TableSyntax
where
do
{
"empty array"
:
{
variables:
[]
},
"simple expansions"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'key$variable$variable2'
}
]
},
"complex expansion"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'key${variable}'
}
]
},
"out-of-order variable reference"
:
{
variables:
[
{
key:
'variable2'
,
value:
'key${variable}'
},
{
key:
'variable'
,
value:
'value'
}
]
},
"complex expansions with raw variable"
:
{
variables:
[
{
key:
'variable3'
,
value:
'key_${variable}_${variable2}'
},
{
key:
'variable'
,
value:
'$variable2'
,
raw:
true
},
{
key:
'variable2'
,
value:
'value2'
}
]
},
"array with cyclic dependency"
:
{
variables:
[
{
key:
'variable'
,
value:
'$variable2'
},
{
key:
'variable2'
,
value:
'$variable3'
},
{
key:
'variable3'
,
value:
'key$variable$variable2'
}
]
}
}
end
with_them
do
subject
{
ExpandVariables
.
expand_variables_collection
(
variables
,
project_with_flag_disabled
)
}
it
'returns Collection'
do
is_expected
.
to
be_an_instance_of
(
Gitlab
::
Ci
::
Variables
::
Collection
)
end
it
'does not expand variables'
do
is_expected
.
to
eq
(
variables
)
end
end
end
end
context
'when FF :variable_inside_variable is enabled'
do
let_it_be
(
:project_with_flag_disabled
)
{
create
(
:project
)
}
let_it_be
(
:project_with_flag_enabled
)
{
create
(
:project
)
}
before
do
stub_feature_flags
(
variable_inside_variable:
[
project_with_flag_enabled
])
end
context
'table tests'
do
using
RSpec
::
Parameterized
::
TableSyntax
where
do
{
"empty array"
:
{
variables:
[],
result:
[]
},
"simple expansions"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'key$variable$variable2'
},
{
key:
'variable4'
,
value:
'key$variable$variable3'
}
],
result:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'keyvalueresult'
},
{
key:
'variable4'
,
value:
'keyvaluekeyvalueresult'
}
]
},
"complex expansion"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'key${variable}'
}
],
result:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'keyvalue'
}
]
},
"unused variables"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result2'
},
{
key:
'variable3'
,
value:
'result3'
},
{
key:
'variable4'
,
value:
'key$variable$variable3'
}
],
result:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result2'
},
{
key:
'variable3'
,
value:
'result3'
},
{
key:
'variable4'
,
value:
'keyvalueresult3'
}
]
},
"complex expansions"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'key${variable}${variable2}'
}
],
result:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'keyvalueresult'
}
]
},
"out-of-order expansion"
:
{
variables:
[
{
key:
'variable3'
,
value:
'key$variable2$variable'
},
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
}
],
result:
[
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable3'
,
value:
'keyresultvalue'
}
]
},
"out-of-order complex expansion"
:
{
variables:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'key${variable2}${variable}'
}
],
result:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable2'
,
value:
'result'
},
{
key:
'variable3'
,
value:
'keyresultvalue'
}
]
},
"missing variable"
:
{
variables:
[
{
key:
'variable2'
,
value:
'key$variable'
}
],
result:
[
{
key:
'variable2'
,
value:
'key$variable'
}
]
},
"complex expansions with missing variable"
:
{
variables:
[
{
key:
'variable4'
,
value:
'key${variable}${variable2}${variable3}'
},
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable3'
,
value:
'value3'
}
],
result:
[
{
key:
'variable'
,
value:
'value'
},
{
key:
'variable3'
,
value:
'value3'
},
{
key:
'variable4'
,
value:
'keyvalue${variable2}value3'
}
]
},
"complex expansions with raw variable"
:
{
variables:
[
{
key:
'variable3'
,
value:
'key_${variable}_${variable2}'
},
{
key:
'variable'
,
value:
'$variable2'
,
raw:
true
},
{
key:
'variable2'
,
value:
'value2'
}
],
result:
[
{
key:
'variable'
,
value:
'$variable2'
,
raw:
true
},
{
key:
'variable2'
,
value:
'value2'
},
{
key:
'variable3'
,
value:
'key_$variable2_value2'
}
]
},
"cyclic dependency causes original array to be returned"
:
{
variables:
[
{
key:
'variable'
,
value:
'$variable2'
},
{
key:
'variable2'
,
value:
'$variable3'
},
{
key:
'variable3'
,
value:
'key$variable$variable2'
}
],
result:
[
{
key:
'variable'
,
value:
'$variable2'
},
{
key:
'variable2'
,
value:
'$variable3'
},
{
key:
'variable3'
,
value:
'key$variable$variable2'
}
]
}
}
end
with_them
do
let!
(
:collection
)
{
Gitlab
::
Ci
::
Variables
::
Collection
.
new
(
variables
)
}
subject!
do
ExpandVariables
.
expand_variables_collection
(
collection
,
project_with_flag_enabled
)
end
it
'returns Collection'
do
is_expected
.
to
be_an_instance_of
(
Gitlab
::
Ci
::
Variables
::
Collection
)
end
it
'expands variables'
do
is_expected
.
to
eq
(
result
)
end
it
'preserves raw attribute'
do
collection
.
each
do
|
v
|
k
=
v
[
:key
]
subject_item
=
subject
.
find
{
|
sv
|
sv
[
:key
]
==
k
}
expect
(
subject_item
.
raw
).
to
eq
(
v
.
raw
)
end
end
end
end
end
end
end
spec/lib/gitlab/ci/variables/collection/item_spec.rb
View file @
250fede4
...
...
@@ -180,16 +180,6 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
end
end
describe
'#merge'
do
it
'behaves like hash merge'
do
item
=
described_class
.
new
(
**
variable
)
subject
=
item
.
merge
(
value:
'another thing'
)
expect
(
subject
).
not_to
eq
item
expect
(
subject
[
:value
]).
to
eq
'another thing'
end
end
describe
'#to_runner_variable'
do
context
'when variable is not a file-related'
do
it
'returns a runner-compatible hash representation'
do
...
...
@@ -212,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'
)
...
...
spec/lib/gitlab/ci/variables/collection/sort_spec.rb
View file @
250fede4
This diff is collapsed.
Click to expand it.
spec/lib/gitlab/ci/variables/collection_spec.rb
View file @
250fede4
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment