2019-10-12 21:52:04 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
require 'fast_spec_helper'
|
|
|
|
|
|
|
|
describe Gitlab::Ci::Config::Extendable do
|
|
|
|
subject { described_class.new(hash) }
|
|
|
|
|
|
|
|
describe '#each' do
|
|
|
|
context 'when there is extendable entry in the hash' do
|
|
|
|
let(:test) do
|
|
|
|
{ extends: 'something', only: %w[master] }
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:hash) do
|
|
|
|
{ something: { script: 'ls' }, test: test }
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'yields control' do
|
|
|
|
expect { |b| subject.each(&b) }.to yield_control
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#to_hash' do
|
|
|
|
context 'when hash does not contain extensions' do
|
|
|
|
let(:hash) do
|
|
|
|
{
|
|
|
|
test: { script: 'test' },
|
|
|
|
production: {
|
|
|
|
script: 'deploy',
|
|
|
|
only: { variables: %w[$SOMETHING] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not modify the hash' do
|
|
|
|
expect(subject.to_hash).to eq hash
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when hash has a single simple extension' do
|
|
|
|
let(:hash) do
|
|
|
|
{
|
|
|
|
something: {
|
|
|
|
script: 'deploy',
|
|
|
|
only: { variables: %w[$SOMETHING] }
|
|
|
|
},
|
|
|
|
|
|
|
|
test: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'ls',
|
|
|
|
only: { refs: %w[master] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'extends a hash with a deep reverse merge' do
|
|
|
|
expect(subject.to_hash).to eq(
|
|
|
|
something: {
|
|
|
|
script: 'deploy',
|
|
|
|
only: { variables: %w[$SOMETHING] }
|
|
|
|
},
|
|
|
|
|
|
|
|
test: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'ls',
|
|
|
|
only: {
|
|
|
|
refs: %w[master],
|
|
|
|
variables: %w[$SOMETHING]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when a hash uses recursive extensions' do
|
|
|
|
let(:hash) do
|
|
|
|
{
|
|
|
|
test: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'ls',
|
|
|
|
only: { refs: %w[master] }
|
|
|
|
},
|
|
|
|
|
|
|
|
build: {
|
|
|
|
extends: 'something',
|
|
|
|
stage: 'build'
|
|
|
|
},
|
|
|
|
|
|
|
|
deploy: {
|
|
|
|
stage: 'deploy',
|
|
|
|
extends: '.first'
|
|
|
|
},
|
|
|
|
|
|
|
|
something: {
|
|
|
|
extends: '.first',
|
|
|
|
script: 'exec',
|
|
|
|
only: { variables: %w[$SOMETHING] }
|
|
|
|
},
|
|
|
|
|
|
|
|
'.first': {
|
|
|
|
script: 'run',
|
|
|
|
only: { kubernetes: 'active' }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'extends a hash with a deep reverse merge' do
|
|
|
|
expect(subject.to_hash).to eq(
|
|
|
|
'.first': {
|
|
|
|
script: 'run',
|
|
|
|
only: { kubernetes: 'active' }
|
|
|
|
},
|
|
|
|
|
|
|
|
something: {
|
|
|
|
extends: '.first',
|
|
|
|
script: 'exec',
|
|
|
|
only: {
|
|
|
|
kubernetes: 'active',
|
|
|
|
variables: %w[$SOMETHING]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
deploy: {
|
|
|
|
script: 'run',
|
|
|
|
stage: 'deploy',
|
|
|
|
only: { kubernetes: 'active' },
|
|
|
|
extends: '.first'
|
|
|
|
},
|
|
|
|
|
|
|
|
build: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'exec',
|
|
|
|
stage: 'build',
|
|
|
|
only: {
|
|
|
|
kubernetes: 'active',
|
|
|
|
variables: %w[$SOMETHING]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
test: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'ls',
|
|
|
|
only: {
|
|
|
|
refs: %w[master],
|
|
|
|
variables: %w[$SOMETHING],
|
|
|
|
kubernetes: 'active'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when nested circular dependecy has been detected' do
|
|
|
|
let(:hash) do
|
|
|
|
{
|
|
|
|
test: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'ls',
|
|
|
|
only: { refs: %w[master] }
|
|
|
|
},
|
|
|
|
|
|
|
|
something: {
|
|
|
|
extends: '.first',
|
|
|
|
script: 'deploy',
|
|
|
|
only: { variables: %w[$SOMETHING] }
|
|
|
|
},
|
|
|
|
|
|
|
|
'.first': {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'run',
|
|
|
|
only: { kubernetes: 'active' }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'raises an error about circular dependency' do
|
|
|
|
expect { subject.to_hash }
|
|
|
|
.to raise_error(described_class::Entry::CircularDependencyError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when circular dependecy to self has been detected' do
|
|
|
|
let(:hash) do
|
|
|
|
{
|
|
|
|
test: {
|
|
|
|
extends: 'test',
|
|
|
|
script: 'ls',
|
|
|
|
only: { refs: %w[master] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'raises an error about circular dependency' do
|
|
|
|
expect { subject.to_hash }
|
|
|
|
.to raise_error(described_class::Entry::CircularDependencyError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when invalid extends value is specified' do
|
|
|
|
let(:hash) do
|
|
|
|
{ something: { extends: 1, script: 'ls' } }
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'raises an error about invalid extension' do
|
|
|
|
expect { subject.to_hash }
|
|
|
|
.to raise_error(described_class::Entry::InvalidExtensionError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when extensible entry has non-hash inheritance defined' do
|
|
|
|
let(:hash) do
|
|
|
|
{
|
|
|
|
test: {
|
|
|
|
extends: 'something',
|
|
|
|
script: 'ls',
|
|
|
|
only: { refs: %w[master] }
|
|
|
|
},
|
|
|
|
|
|
|
|
something: 'some text'
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'raises an error about invalid base' do
|
|
|
|
expect { subject.to_hash }
|
|
|
|
.to raise_error(described_class::Entry::InvalidExtensionError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|