Expand variables only when needed
This makes us to expand variables only when needed, instead of requesting all variables each time. This specifically helps in situation when explicit name of `environment: production` is used.
This commit is contained in:
parent
a55869483d
commit
6150c3ff0d
4 changed files with 139 additions and 58 deletions
|
@ -384,7 +384,7 @@ module Ci
|
|||
return unless has_environment?
|
||||
|
||||
strong_memoize(:expanded_environment_name) do
|
||||
ExpandVariables.expand(environment, simple_variables)
|
||||
ExpandVariables.expand(environment, -> { simple_variables })
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class UpdateDeploymentService
|
|||
return unless environment_url
|
||||
|
||||
@expanded_environment_url =
|
||||
ExpandVariables.expand(environment_url, variables)
|
||||
ExpandVariables.expand(environment_url, -> { variables })
|
||||
end
|
||||
|
||||
def environment_url
|
||||
|
|
|
@ -3,6 +3,20 @@
|
|||
module ExpandVariables
|
||||
class << self
|
||||
def expand(value, variables)
|
||||
variables_hash = nil
|
||||
|
||||
value.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) do
|
||||
variables_hash ||= transform_variables(variables)
|
||||
variables_hash[$1 || $2]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def transform_variables(variables)
|
||||
# Lazily initialise variables
|
||||
variables = variables.call if variables.is_a?(Proc)
|
||||
|
||||
# Convert hash array to variables
|
||||
if variables.is_a?(Array)
|
||||
variables = variables.reduce({}) do |hash, variable|
|
||||
|
@ -11,9 +25,7 @@ module ExpandVariables
|
|||
end
|
||||
end
|
||||
|
||||
value.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) do
|
||||
variables[$1 || $2]
|
||||
end
|
||||
variables
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,62 +4,131 @@ require 'spec_helper'
|
|||
|
||||
describe ExpandVariables do
|
||||
describe '#expand' do
|
||||
subject { described_class.expand(value, variables) }
|
||||
context 'table tests' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
tests = [
|
||||
{ value: 'key',
|
||||
result: 'key',
|
||||
variables: [] },
|
||||
{ value: 'key$variable',
|
||||
result: 'key',
|
||||
variables: [] },
|
||||
{ value: 'key$variable',
|
||||
result: 'keyvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' }
|
||||
] },
|
||||
{ value: 'key${variable}',
|
||||
result: 'keyvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' }
|
||||
] },
|
||||
{ value: 'key$variable$variable2',
|
||||
result: 'keyvalueresult',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
] },
|
||||
{ value: 'key${variable}${variable2}',
|
||||
result: 'keyvalueresult',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
] },
|
||||
{ value: 'key$variable2$variable',
|
||||
result: 'keyresultvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
] },
|
||||
{ value: 'key${variable2}${variable}',
|
||||
result: 'keyresultvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
] },
|
||||
{ value: 'review/$CI_COMMIT_REF_NAME',
|
||||
result: 'review/feature/add-review-apps',
|
||||
variables: [
|
||||
{ key: 'CI_COMMIT_REF_NAME', value: 'feature/add-review-apps' }
|
||||
] }
|
||||
]
|
||||
where do
|
||||
{
|
||||
"no expansion": {
|
||||
value: 'key',
|
||||
result: 'key',
|
||||
variables: []
|
||||
},
|
||||
"missing variable": {
|
||||
value: 'key$variable',
|
||||
result: 'key',
|
||||
variables: []
|
||||
},
|
||||
"simple expansion": {
|
||||
value: 'key$variable',
|
||||
result: 'keyvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' }
|
||||
]
|
||||
},
|
||||
"simple with hash of variables": {
|
||||
value: 'key$variable',
|
||||
result: 'keyvalue',
|
||||
variables: {
|
||||
'variable' => 'value'
|
||||
}
|
||||
},
|
||||
"complex expansion": {
|
||||
value: 'key${variable}',
|
||||
result: 'keyvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' }
|
||||
]
|
||||
},
|
||||
"simple expansions": {
|
||||
value: 'key$variable$variable2',
|
||||
result: 'keyvalueresult',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
]
|
||||
},
|
||||
"complex expansions": {
|
||||
value: 'key${variable}${variable2}',
|
||||
result: 'keyvalueresult',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
]
|
||||
},
|
||||
"complex expansions with missing variable": {
|
||||
value: 'key${variable}${variable2}',
|
||||
result: 'keyvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' }
|
||||
]
|
||||
},
|
||||
"out-of-order expansion": {
|
||||
value: 'key$variable2$variable',
|
||||
result: 'keyresultvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
]
|
||||
},
|
||||
"out-of-order complex expansion": {
|
||||
value: 'key${variable2}${variable}',
|
||||
result: 'keyresultvalue',
|
||||
variables: [
|
||||
{ key: 'variable', value: 'value' },
|
||||
{ key: 'variable2', value: 'result' }
|
||||
]
|
||||
},
|
||||
"review-apps expansion": {
|
||||
value: 'review/$CI_COMMIT_REF_NAME',
|
||||
result: 'review/feature/add-review-apps',
|
||||
variables: [
|
||||
{ key: 'CI_COMMIT_REF_NAME', value: 'feature/add-review-apps' }
|
||||
]
|
||||
},
|
||||
"do not lazily access variables when no expansion": {
|
||||
value: 'key',
|
||||
result: 'key',
|
||||
variables: -> { raise NotImplementedError }
|
||||
},
|
||||
"lazily access variables": {
|
||||
value: 'key$variable',
|
||||
result: 'keyvalue',
|
||||
variables: -> { [{ key: 'variable', value: 'value' }] }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
tests.each do |test|
|
||||
context "#{test[:value]} resolves to #{test[:result]}" do
|
||||
let(:value) { test[:value] }
|
||||
let(:variables) { test[:variables] }
|
||||
with_them do
|
||||
subject { ExpandVariables.expand(value, variables) } # rubocop:disable RSpec/DescribedClass
|
||||
|
||||
it { is_expected.to eq(test[:result]) }
|
||||
it { is_expected.to eq(result) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'lazily inits variables' do
|
||||
let(:variables) { -> { [{ key: 'variable', value: 'result' }] } }
|
||||
|
||||
subject { described_class.expand(value, variables) }
|
||||
|
||||
context 'when expanding variable' do
|
||||
let(:value) { 'key$variable$variable2' }
|
||||
|
||||
it 'calls block at most once' do
|
||||
expect(variables).to receive(:call).once.and_call_original
|
||||
|
||||
is_expected.to eq('keyresult')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no expansion is needed' do
|
||||
let(:value) { 'key' }
|
||||
|
||||
it 'does not call block' do
|
||||
expect(variables).not_to receive(:call)
|
||||
|
||||
is_expected.to eq('key')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue