Commit 0b8c81b8 authored by Matija Čupić's avatar Matija Čupić

Flatten CI config rules

Flattens CI config rules. Nested rules arrays are now valid, this allows
including rules groups with !reference.

Changelog: changed
parent d323d728
...@@ -31,7 +31,7 @@ module Gitlab ...@@ -31,7 +31,7 @@ module Gitlab
with_options allow_nil: true do with_options allow_nil: true do
validates :extends, array_of_strings_or_string: true validates :extends, array_of_strings_or_string: true
validates :rules, array_of_hashes: true validates :rules, nested_array_of_hashes: true
validates :resource_group, type: String validates :resource_group, type: String
end end
end end
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
end end
def value def value
@config [@config].flatten
end end
def composable_class def composable_class
......
...@@ -78,10 +78,26 @@ module Gitlab ...@@ -78,10 +78,26 @@ module Gitlab
include LegacyValidationHelpers include LegacyValidationHelpers
def validate_each(record, attribute, value) def validate_each(record, attribute, value)
unless value.is_a?(Array) && value.map { |hsh| hsh.is_a?(Hash) }.all? unless validate_array_of_hashes(value)
record.errors.add(attribute, 'should be an array of hashes') record.errors.add(attribute, 'should be an array of hashes')
end end
end end
private
def validate_array_of_hashes(value)
value.is_a?(Array) && value.all? { |obj| obj.is_a?(Hash) }
end
end
class NestedArrayOfHashesValidator < ArrayOfHashesValidator
include NestedArrayHelpers
def validate_each(record, attribute, value)
unless validate_nested_array(value, 1, &method(:validate_array_of_hashes))
record.errors.add(attribute, 'should be an array containing hashes and arrays of hashes')
end
end
end end
class ArrayOrStringValidator < ActiveModel::EachValidator class ArrayOrStringValidator < ActiveModel::EachValidator
......
...@@ -17,6 +17,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do ...@@ -17,6 +17,10 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
describe '.new' do describe '.new' do
subject { entry } subject { entry }
before do
subject.compose!
end
context 'with a list of rule rule' do context 'with a list of rule rule' do
let(:config) do let(:config) do
[{ if: '$THIS == "that"', when: 'never' }] [{ if: '$THIS == "that"', when: 'never' }]
...@@ -24,14 +28,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do ...@@ -24,14 +28,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
it { is_expected.to be_a(described_class) } it { is_expected.to be_a(described_class) }
it { is_expected.to be_valid } it { is_expected.to be_valid }
context 'when composed' do
before do
subject.compose!
end
it { is_expected.to be_valid }
end
end end
context 'with a list of two rules' do context 'with a list of two rules' do
...@@ -42,21 +38,34 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do ...@@ -42,21 +38,34 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
] ]
end end
it { is_expected.to be_a(described_class) }
it { is_expected.to be_valid } it { is_expected.to be_valid }
end
context 'when composed' do context 'with a single rule object' do
before do let(:config) do
subject.compose! { if: '$SKIP', when: 'never' }
end end
it { is_expected.to be_valid } it { is_expected.not_to be_valid }
end
context 'with nested rules' do
let(:config) do
[
{ if: '$THIS == "that"', when: 'always' },
[{ if: '$SKIP', when: 'never' }]
]
end end
it { is_expected.to be_valid }
end end
context 'with a single rule object' do context 'with rules nested more than one level' do
let(:config) do let(:config) do
{ if: '$SKIP', when: 'never' } [
{ if: '$THIS == "that"', when: 'always' },
[{ if: '$SKIP', when: 'never' }, [{ if: '$THIS == "other"', when: 'aways' }]]
]
end end
it { is_expected.not_to be_valid } it { is_expected.not_to be_valid }
...@@ -90,7 +99,36 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do ...@@ -90,7 +99,36 @@ RSpec.describe Gitlab::Ci::Config::Entry::Rules do
{ if: '$SKIP', when: 'never' } { if: '$SKIP', when: 'never' }
end end
it { is_expected.to eq(config) } it { is_expected.to eq([config]) }
end
context 'with nested rules' do
let(:first_rule) { { if: '$THIS == "that"', when: 'always' } }
let(:second_rule) { { if: '$SKIP', when: 'never' } }
let(:config) do
[
first_rule,
[second_rule]
]
end
it { is_expected.to contain_exactly(first_rule, second_rule) }
end
context 'with rules nested more than one level' do
let(:first_rule) { { if: '$THIS == "that"', when: 'always' } }
let(:second_rule) { { if: '$SKIP', when: 'never' } }
let(:third_rule) { { if: '$THIS == "other"', when: 'aways' } }
let(:config) do
[
first_rule,
[second_rule, [third_rule]]
]
end
it { is_expected.to contain_exactly(first_rule, second_rule, third_rule) }
end end
end end
......
...@@ -2777,7 +2777,7 @@ module Gitlab ...@@ -2777,7 +2777,7 @@ module Gitlab
expect(subject.valid?).to eq(false) expect(subject.valid?).to eq(false)
expect(subject.errors).to contain_exactly( expect(subject.errors).to contain_exactly(
'jobs:rspec config contains unknown keys: bad_tags', 'jobs:rspec config contains unknown keys: bad_tags',
'jobs:rspec rules should be an array of hashes') 'jobs:rspec rules should be an array containing hashes and arrays of hashes')
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