Commit 2240807c authored by Grzegorz Bizon's avatar Grzegorz Bizon

Assume that unspecified CI config is undefined

We assume that when someone adds a key for the configuration entry, but
does not provide a valid value, which causes entry to be `nil`, then
entry should be considered as the undefined one. We also assume this is
semantically correct, this is also backwards compatible with legacy CI
config processor.

See issue #18775 for more details.
parent bc2348f2
...@@ -27,7 +27,6 @@ module Gitlab ...@@ -27,7 +27,6 @@ module Gitlab
def create_node(key, factory) def create_node(key, factory)
factory.with(value: @config[key], key: key) factory.with(value: @config[key], key: key)
factory.undefine! unless @config.has_key?(key)
factory.create! factory.create!
end end
......
...@@ -18,16 +18,20 @@ module Gitlab ...@@ -18,16 +18,20 @@ module Gitlab
self self
end end
def undefine!
@attributes[:value] = @node.dup
@node = Node::Undefined
self
end
def create! def create!
raise InvalidFactory unless @attributes.has_key?(:value) raise InvalidFactory unless @attributes.has_key?(:value)
@node.new(@attributes[:value]).tap do |entry| ##
# We assume unspecified entry is undefined.
# See issue #18775.
#
if @attributes[:value].nil?
node, value = Node::Undefined, @node
else
node, value = @node, @attributes[:value]
end
node.new(value).tap do |entry|
entry.description = @attributes[:description] entry.description = @attributes[:description]
entry.key = @attributes[:key] entry.key = @attributes[:key]
end end
......
...@@ -9,11 +9,7 @@ module Gitlab ...@@ -9,11 +9,7 @@ module Gitlab
include Validatable include Validatable
validations do validations do
validates :value, variables: true validates :config, variables: true
end
def value
@config || self.class.default
end end
def self.default def self.default
......
...@@ -551,8 +551,8 @@ module Ci ...@@ -551,8 +551,8 @@ module Ci
config_processor = GitlabCiYamlProcessor.new(config, path) config_processor = GitlabCiYamlProcessor.new(config, path)
## ##
# TODO, in next version of CI configuration processor this # When variables config is empty, we asumme this is a correct,
# should be invalid configuration, see #18775 and #15060 # see issue #18775
# #
expect(config_processor.job_variables(:rspec)) expect(config_processor.job_variables(:rspec))
.to be_an_instance_of(Array).and be_empty .to be_an_instance_of(Array).and be_empty
...@@ -1098,14 +1098,14 @@ EOT ...@@ -1098,14 +1098,14 @@ EOT
config = YAML.dump({ variables: "test", rspec: { script: "test" } }) config = YAML.dump({ variables: "test", rspec: { script: "test" } })
expect do expect do
GitlabCiYamlProcessor.new(config, path) GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Variables value should be a hash of key value pairs") end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Variables config should be a hash of key value pairs")
end end
it "returns errors if variables is not a map of key-value strings" do it "returns errors if variables is not a map of key-value strings" do
config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } })
expect do expect do
GitlabCiYamlProcessor.new(config, path) GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Variables value should be a hash of key value pairs") end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Variables config should be a hash of key value pairs")
end end
it "returns errors if job when is not on_success, on_failure or always" do it "returns errors if job when is not on_success, on_failure or always" do
......
...@@ -45,11 +45,10 @@ describe Gitlab::Ci::Config::Node::Factory do ...@@ -45,11 +45,10 @@ describe Gitlab::Ci::Config::Node::Factory do
end end
end end
context 'when creating undefined entry' do context 'when creating entry with nil value' do
it 'creates a null entry' do it 'creates an undefined entry' do
entry = factory entry = factory
.with(value: nil) .with(value: nil)
.undefine!
.create! .create!
expect(entry).to be_an_instance_of Gitlab::Ci::Config::Node::Undefined expect(entry).to be_an_instance_of Gitlab::Ci::Config::Node::Undefined
......
...@@ -20,84 +20,125 @@ describe Gitlab::Ci::Config::Node::Global do ...@@ -20,84 +20,125 @@ describe Gitlab::Ci::Config::Node::Global do
end end
context 'when hash is valid' do context 'when hash is valid' do
let(:hash) do context 'when all entries defined' do
{ before_script: ['ls', 'pwd'], let(:hash) do
image: 'ruby:2.2', { before_script: ['ls', 'pwd'],
services: ['postgres:9.1', 'mysql:5.5'], image: 'ruby:2.2',
variables: { VAR: 'value' }, services: ['postgres:9.1', 'mysql:5.5'],
after_script: ['make clean'] } variables: { VAR: 'value' },
end after_script: ['make clean'] }
end
describe '#process!' do describe '#process!' do
before { global.process! } before { global.process! }
it 'creates nodes hash' do it 'creates nodes hash' do
expect(global.nodes).to be_an Array expect(global.nodes).to be_an Array
end end
it 'creates node object for each entry' do it 'creates node object for each entry' do
expect(global.nodes.count).to eq 5 expect(global.nodes.count).to eq 5
end end
it 'creates node object using valid class' do it 'creates node object using valid class' do
expect(global.nodes.first) expect(global.nodes.first)
.to be_an_instance_of Gitlab::Ci::Config::Node::Script .to be_an_instance_of Gitlab::Ci::Config::Node::Script
expect(global.nodes.second) expect(global.nodes.second)
.to be_an_instance_of Gitlab::Ci::Config::Node::Image .to be_an_instance_of Gitlab::Ci::Config::Node::Image
end
it 'sets correct description for nodes' do
expect(global.nodes.first.description)
.to eq 'Script that will be executed before each job.'
expect(global.nodes.second.description)
.to eq 'Docker image that will be used to execute jobs.'
end
end end
it 'sets correct description for nodes' do describe '#leaf?' do
expect(global.nodes.first.description) it 'is not leaf' do
.to eq 'Script that will be executed before each job.' expect(global).not_to be_leaf
expect(global.nodes.second.description) end
.to eq 'Docker image that will be used to execute jobs.'
end end
end
describe '#leaf?' do context 'when not processed' do
it 'is not leaf' do describe '#before_script' do
expect(global).not_to be_leaf it 'returns nil' do
expect(global.before_script).to be nil
end
end
end end
end
context 'when not processed' do context 'when processed' do
describe '#before_script' do before { global.process! }
it 'returns nil' do
expect(global.before_script).to be nil describe '#before_script' do
it 'returns correct script' do
expect(global.before_script).to eq ['ls', 'pwd']
end
end
describe '#image' do
it 'returns valid image' do
expect(global.image).to eq 'ruby:2.2'
end
end
describe '#services' do
it 'returns array of services' do
expect(global.services).to eq ['postgres:9.1', 'mysql:5.5']
end
end
describe '#after_script' do
it 'returns after script' do
expect(global.after_script).to eq ['make clean']
end
end
describe '#variables' do
it 'returns variables' do
expect(global.variables).to eq(VAR: 'value')
end
end end
end end
end end
context 'when processed' do context 'when most of entires not defined' do
let(:hash) { { rspec: {} } }
before { global.process! } before { global.process! }
describe '#before_script' do describe '#nodes' do
it 'returns correct script' do it 'instantizes all nodes' do
expect(global.before_script).to eq ['ls', 'pwd'] expect(global.nodes.count).to eq 5
end end
end
describe '#image' do it 'contains undefined nodes' do
it 'returns valid image' do expect(global.nodes.last)
expect(global.image).to eq 'ruby:2.2' .to be_an_instance_of Gitlab::Ci::Config::Node::Undefined
end end
end end
describe '#services' do describe '#variables' do
it 'returns array of services' do it 'returns default value for variables' do
expect(global.services).to eq ['postgres:9.1', 'mysql:5.5'] expect(global.variables).to eq({})
end end
end end
end
describe '#after_script' do ##
it 'returns after script' do # When nodes are specified but not defined, we assume that
expect(global.after_script).to eq ['make clean'] # configuration is valid, and we asume that entry is simply undefined,
end # despite the fact, that key is present. See issue #18775 for more
end # details.
#
context 'when entires specified but not defined' do
let(:hash) { { variables: nil } }
before { global.process! }
describe '#variables' do describe '#variables' do
it 'returns variables' do it 'undefined entry returns a default value' do
expect(global.variables).to eq(VAR: 'value') expect(global.variables).to eq({})
end end
end end
end end
......
...@@ -3,9 +3,7 @@ require 'spec_helper' ...@@ -3,9 +3,7 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Node::Services do describe Gitlab::Ci::Config::Node::Services do
let(:entry) { described_class.new(config) } let(:entry) { described_class.new(config) }
describe '#process!' do describe 'validations' do
before { entry.process! }
context 'when entry config value is correct' do context 'when entry config value is correct' do
let(:config) { ['postgres:9.1', 'mysql:5.5'] } let(:config) { ['postgres:9.1', 'mysql:5.5'] }
......
...@@ -44,24 +44,5 @@ describe Gitlab::Ci::Config::Node::Variables do ...@@ -44,24 +44,5 @@ describe Gitlab::Ci::Config::Node::Variables do
end end
end end
end end
##
# See #18775
#
context 'when entry value is not defined' do
let(:config) { nil }
describe '#valid?' do
it 'is valid' do
expect(entry).to be_valid
end
end
describe '#values' do
it 'returns an empty hash' do
expect(entry.value).to eq({})
end
end
end
end end
end end
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