diff options
Diffstat (limited to 'spec/lib/gitlab/ci/config/entry')
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/bridge_spec.rb | 46 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/cache_spec.rb | 344 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/environment_spec.rb | 33 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/job_spec.rb | 40 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/need_spec.rb | 86 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/needs_spec.rb | 16 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb | 34 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/root_spec.rb | 229 |
8 files changed, 604 insertions, 224 deletions
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb index b3b7901074a..179578fe0a8 100644 --- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb @@ -244,6 +244,52 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do end end end + + context 'when bridge config contains parallel' do + let(:config) { { trigger: 'some/project', parallel: parallel_config } } + + context 'when parallel config is a number' do + let(:parallel_config) { 2 } + + describe '#valid?' do + it { is_expected.not_to be_valid } + end + + describe '#errors' do + it 'returns an error message' do + expect(subject.errors) + .to include(/cannot use "parallel: <number>"/) + end + end + end + + context 'when parallel config is a matrix' do + let(:parallel_config) do + { matrix: [{ PROVIDER: 'aws', STACK: %w[monitoring app1] }, + { PROVIDER: 'gcp', STACK: %w[data] }] } + end + + describe '#valid?' do + it { is_expected.to be_valid } + end + + describe '#value' do + it 'is returns a bridge job configuration' do + expect(subject.value).to eq( + name: :my_bridge, + trigger: { project: 'some/project' }, + ignore: false, + stage: 'test', + only: { refs: %w[branches tags] }, + parallel: { matrix: [{ 'PROVIDER' => ['aws'], 'STACK' => %w(monitoring app1) }, + { 'PROVIDER' => ['gcp'], 'STACK' => %w(data) }] }, + variables: {}, + scheduling_type: :stage + ) + end + end + end + end end describe '#manual_action?' do diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb index 247f4b63910..064990667d5 100644 --- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb @@ -7,225 +7,285 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do subject(:entry) { described_class.new(config) } - describe 'validations' do + context 'with multiple caches' do before do entry.compose! end - context 'when entry config value is correct' do - let(:policy) { nil } - let(:key) { 'some key' } - let(:when_config) { nil } - - let(:config) do - { - key: key, - untracked: true, - paths: ['some/path/'] - }.tap do |config| - config[:policy] = policy if policy - config[:when] = when_config if when_config + describe '#valid?' do + context 'when configuration is valid with a single cache' do + let(:config) { { key: 'key', paths: ["logs/"], untracked: true } } + + it 'is valid' do + expect(entry).to be_valid end end - describe '#value' do - shared_examples 'hash key value' do - it 'returns hash value' do - expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push', when: 'on_success') - end + context 'when configuration is valid with multiple caches' do + let(:config) do + [ + { key: 'key', paths: ["logs/"], untracked: true }, + { key: 'key2', paths: ["logs/"], untracked: true }, + { key: 'key3', paths: ["logs/"], untracked: true } + ] end - it_behaves_like 'hash key value' + it 'is valid' do + expect(entry).to be_valid + end + end - context 'with files' do - let(:key) { { files: %w[a-file other-file] } } + context 'when configuration is not a Hash or Array' do + let(:config) { 'invalid' } - it_behaves_like 'hash key value' + it 'is invalid' do + expect(entry).not_to be_valid end + end - context 'with files and prefix' do - let(:key) { { files: %w[a-file other-file], prefix: 'prefix-value' } } + context 'when entry values contain more than four caches' do + let(:config) do + [ + { key: 'key', paths: ["logs/"], untracked: true }, + { key: 'key2', paths: ["logs/"], untracked: true }, + { key: 'key3', paths: ["logs/"], untracked: true }, + { key: 'key4', paths: ["logs/"], untracked: true }, + { key: 'key5', paths: ["logs/"], untracked: true } + ] + end - it_behaves_like 'hash key value' + it 'is invalid' do + expect(entry.errors).to eq(["caches config no more than 4 caches can be created"]) + expect(entry).not_to be_valid end + end + end + end + + context 'with a single cache' do + before do + stub_feature_flags(multiple_cache_per_job: false) + end + describe 'validations' do + before do + entry.compose! + end - context 'with prefix' do - let(:key) { { prefix: 'prefix-value' } } + context 'when entry config value is correct' do + let(:policy) { nil } + let(:key) { 'some key' } + let(:when_config) { nil } - it 'key is nil' do - expect(entry.value).to match(a_hash_including(key: nil)) + let(:config) do + { + key: key, + untracked: true, + paths: ['some/path/'] + }.tap do |config| + config[:policy] = policy if policy + config[:when] = when_config if when_config end end - context 'with `policy`' do - where(:policy, :result) do - 'pull-push' | 'pull-push' - 'push' | 'push' - 'pull' | 'pull' - 'unknown' | 'unknown' # invalid + describe '#value' do + shared_examples 'hash key value' do + it 'returns hash value' do + expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push', when: 'on_success') + end end - with_them do - it { expect(entry.value).to include(policy: result) } + it_behaves_like 'hash key value' + + context 'with files' do + let(:key) { { files: %w[a-file other-file] } } + + it_behaves_like 'hash key value' end - end - context 'without `policy`' do - it 'assigns policy to default' do - expect(entry.value).to include(policy: 'pull-push') + context 'with files and prefix' do + let(:key) { { files: %w[a-file other-file], prefix: 'prefix-value' } } + + it_behaves_like 'hash key value' end - end - context 'with `when`' do - where(:when_config, :result) do - 'on_success' | 'on_success' - 'on_failure' | 'on_failure' - 'always' | 'always' - 'unknown' | 'unknown' # invalid + context 'with prefix' do + let(:key) { { prefix: 'prefix-value' } } + + it 'key is nil' do + expect(entry.value).to match(a_hash_including(key: nil)) + end end - with_them do - it { expect(entry.value).to include(when: result) } + context 'with `policy`' do + where(:policy, :result) do + 'pull-push' | 'pull-push' + 'push' | 'push' + 'pull' | 'pull' + 'unknown' | 'unknown' # invalid + end + + with_them do + it { expect(entry.value).to include(policy: result) } + end end - end - context 'without `when`' do - it 'assigns when to default' do - expect(entry.value).to include(when: 'on_success') + context 'without `policy`' do + it 'assigns policy to default' do + expect(entry.value).to include(policy: 'pull-push') + end end - end - end - describe '#valid?' do - it { is_expected.to be_valid } + context 'with `when`' do + where(:when_config, :result) do + 'on_success' | 'on_success' + 'on_failure' | 'on_failure' + 'always' | 'always' + 'unknown' | 'unknown' # invalid + end - context 'with files' do - let(:key) { { files: %w[a-file other-file] } } + with_them do + it { expect(entry.value).to include(when: result) } + end + end - it { is_expected.to be_valid } + context 'without `when`' do + it 'assigns when to default' do + expect(entry.value).to include(when: 'on_success') + end + end end - end - context 'with `policy`' do - where(:policy, :valid) do - 'pull-push' | true - 'push' | true - 'pull' | true - 'unknown' | false - end + describe '#valid?' do + it { is_expected.to be_valid } + + context 'with files' do + let(:key) { { files: %w[a-file other-file] } } - with_them do - it 'returns expected validity' do - expect(entry.valid?).to eq(valid) + it { is_expected.to be_valid } end end - end - context 'with `when`' do - where(:when_config, :valid) do - 'on_success' | true - 'on_failure' | true - 'always' | true - 'unknown' | false - end + context 'with `policy`' do + where(:policy, :valid) do + 'pull-push' | true + 'push' | true + 'pull' | true + 'unknown' | false + end - with_them do - it 'returns expected validity' do - expect(entry.valid?).to eq(valid) + with_them do + it 'returns expected validity' do + expect(entry.valid?).to eq(valid) + end end end - end - context 'with key missing' do - let(:config) do - { untracked: true, - paths: ['some/path/'] } + context 'with `when`' do + where(:when_config, :valid) do + 'on_success' | true + 'on_failure' | true + 'always' | true + 'unknown' | false + end + + with_them do + it 'returns expected validity' do + expect(entry.valid?).to eq(valid) + end + end end - describe '#value' do - it 'sets key with the default' do - expect(entry.value[:key]) - .to eq(Gitlab::Ci::Config::Entry::Key.default) + context 'with key missing' do + let(:config) do + { untracked: true, + paths: ['some/path/'] } + end + + describe '#value' do + it 'sets key with the default' do + expect(entry.value[:key]) + .to eq(Gitlab::Ci::Config::Entry::Key.default) + end end end end - end - context 'when entry value is not correct' do - describe '#errors' do - subject { entry.errors } + context 'when entry value is not correct' do + describe '#errors' do + subject { entry.errors } - context 'when is not a hash' do - let(:config) { 'ls' } + context 'when is not a hash' do + let(:config) { 'ls' } - it 'reports errors with config value' do - is_expected.to include 'cache config should be a hash' + it 'reports errors with config value' do + is_expected.to include 'cache config should be a hash' + end end - end - context 'when policy is unknown' do - let(:config) { { policy: 'unknown' } } + context 'when policy is unknown' do + let(:config) { { policy: 'unknown' } } - it 'reports error' do - is_expected.to include('cache policy should be pull-push, push, or pull') + it 'reports error' do + is_expected.to include('cache policy should be pull-push, push, or pull') + end end - end - context 'when `when` is unknown' do - let(:config) { { when: 'unknown' } } + context 'when `when` is unknown' do + let(:config) { { when: 'unknown' } } - it 'reports error' do - is_expected.to include('cache when should be on_success, on_failure or always') + it 'reports error' do + is_expected.to include('cache when should be on_success, on_failure or always') + end end - end - context 'when descendants are invalid' do - context 'with invalid keys' do - let(:config) { { key: 1 } } + context 'when descendants are invalid' do + context 'with invalid keys' do + let(:config) { { key: 1 } } - it 'reports error with descendants' do - is_expected.to include 'key should be a hash, a string or a symbol' + it 'reports error with descendants' do + is_expected.to include 'key should be a hash, a string or a symbol' + end end - end - context 'with empty key' do - let(:config) { { key: {} } } + context 'with empty key' do + let(:config) { { key: {} } } - it 'reports error with descendants' do - is_expected.to include 'key config missing required keys: files' + it 'reports error with descendants' do + is_expected.to include 'key config missing required keys: files' + end end - end - context 'with invalid files' do - let(:config) { { key: { files: 'a-file' } } } + context 'with invalid files' do + let(:config) { { key: { files: 'a-file' } } } - it 'reports error with descendants' do - is_expected.to include 'key:files config should be an array of strings' + it 'reports error with descendants' do + is_expected.to include 'key:files config should be an array of strings' + end end - end - context 'with prefix without files' do - let(:config) { { key: { prefix: 'a-prefix' } } } + context 'with prefix without files' do + let(:config) { { key: { prefix: 'a-prefix' } } } - it 'reports error with descendants' do - is_expected.to include 'key config missing required keys: files' + it 'reports error with descendants' do + is_expected.to include 'key config missing required keys: files' + end end - end - context 'when there is an unknown key present' do - let(:config) { { key: { unknown: 'a-file' } } } + context 'when there is an unknown key present' do + let(:config) { { key: { unknown: 'a-file' } } } - it 'reports error with descendants' do - is_expected.to include 'key config contains unknown keys: unknown' + it 'reports error with descendants' do + is_expected.to include 'key config contains unknown keys: unknown' + end end end - end - context 'when there is an unknown key present' do - let(:config) { { invalid: true } } + context 'when there is an unknown key present' do + let(:config) { { invalid: true } } - it 'reports error with descendants' do - is_expected.to include 'cache config contains unknown keys: invalid' + it 'reports error with descendants' do + is_expected.to include 'cache config contains unknown keys: invalid' + end end end end diff --git a/spec/lib/gitlab/ci/config/entry/environment_spec.rb b/spec/lib/gitlab/ci/config/entry/environment_spec.rb index 0c18a7fb71e..dd8a79f0d84 100644 --- a/spec/lib/gitlab/ci/config/entry/environment_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/environment_spec.rb @@ -305,4 +305,37 @@ RSpec.describe Gitlab::Ci::Config::Entry::Environment do it { expect(entry).to be_valid } end end + + describe 'deployment_tier' do + let(:config) do + { name: 'customer-portal', deployment_tier: deployment_tier } + end + + context 'is a string' do + let(:deployment_tier) { 'production' } + + it { expect(entry).to be_valid } + end + + context 'is a hash' do + let(:deployment_tier) { Hash(tier: 'production') } + + it { expect(entry).not_to be_valid } + end + + context 'is nil' do + let(:deployment_tier) { nil } + + it { expect(entry).to be_valid } + end + + context 'is unknown value' do + let(:deployment_tier) { 'unknown' } + + it 'is invalid and adds an error' do + expect(entry).not_to be_valid + expect(entry.errors).to include("environment deployment tier must be one of #{::Environment.tiers.keys.join(', ')}") + end + end + end end diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index a3b5f32b9f9..a4167003987 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -537,7 +537,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do it 'overrides default config' do expect(entry[:image].value).to eq(name: 'some_image') - expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success') + expect(entry[:cache].value).to eq([key: 'test', policy: 'pull-push', when: 'on_success']) end end @@ -552,7 +552,43 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do it 'uses config from default entry' do expect(entry[:image].value).to eq 'specified' - expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success') + expect(entry[:cache].value).to eq([key: 'test', policy: 'pull-push', when: 'on_success']) + end + end + + context 'with multiple_cache_per_job FF disabled' do + before do + stub_feature_flags(multiple_cache_per_job: false) + end + + context 'when job config overrides default config' do + before do + entry.compose!(deps) + end + + let(:config) do + { script: 'rspec', image: 'some_image', cache: { key: 'test' } } + end + + it 'overrides default config' do + expect(entry[:image].value).to eq(name: 'some_image') + expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success') + end + end + + context 'when job config does not override default config' do + before do + allow(default).to receive('[]').with(:image).and_return(specified) + + entry.compose!(deps) + end + + let(:config) { { script: 'ls', cache: { key: 'test' } } } + + it 'uses config from default entry' do + expect(entry[:image].value).to eq 'specified' + expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success') + end end end diff --git a/spec/lib/gitlab/ci/config/entry/need_spec.rb b/spec/lib/gitlab/ci/config/entry/need_spec.rb index 983e95fae42..a0a5dd52ad4 100644 --- a/spec/lib/gitlab/ci/config/entry/need_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/need_spec.rb @@ -23,7 +23,17 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do describe '#value' do it 'returns job needs configuration' do - expect(need.value).to eq(name: 'job_name', artifacts: true) + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) + end + + context 'when the FF ci_needs_optional is disabled' do + before do + stub_feature_flags(ci_needs_optional: false) + end + + it 'returns job needs configuration without `optional`' do + expect(need.value).to eq(name: 'job_name', artifacts: true) + end end end @@ -58,7 +68,7 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do describe '#value' do it 'returns job needs configuration' do - expect(need.value).to eq(name: 'job_name', artifacts: true) + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) end end @@ -74,7 +84,7 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do describe '#value' do it 'returns job needs configuration' do - expect(need.value).to eq(name: 'job_name', artifacts: false) + expect(need.value).to eq(name: 'job_name', artifacts: false, optional: false) end end @@ -90,7 +100,7 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do describe '#value' do it 'returns job needs configuration' do - expect(need.value).to eq(name: 'job_name', artifacts: true) + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) end end @@ -106,11 +116,77 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do describe '#value' do it 'returns job needs configuration' do - expect(need.value).to eq(name: 'job_name', artifacts: true) + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) + end + end + + it_behaves_like 'job type' + end + + context 'with job name and optional true' do + let(:config) { { job: 'job_name', optional: true } } + + it { is_expected.to be_valid } + + it_behaves_like 'job type' + + describe '#value' do + it 'returns job needs configuration' do + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: true) + end + + context 'when the FF ci_needs_optional is disabled' do + before do + stub_feature_flags(ci_needs_optional: false) + end + + it 'returns job needs configuration without `optional`' do + expect(need.value).to eq(name: 'job_name', artifacts: true) + end end end + end + + context 'with job name and optional false' do + let(:config) { { job: 'job_name', optional: false } } + + it { is_expected.to be_valid } it_behaves_like 'job type' + + describe '#value' do + it 'returns job needs configuration' do + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) + end + end + end + + context 'with job name and optional nil' do + let(:config) { { job: 'job_name', optional: nil } } + + it { is_expected.to be_valid } + + it_behaves_like 'job type' + + describe '#value' do + it 'returns job needs configuration' do + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) + end + end + end + + context 'without optional key' do + let(:config) { { job: 'job_name' } } + + it { is_expected.to be_valid } + + it_behaves_like 'job type' + + describe '#value' do + it 'returns job needs configuration' do + expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) + end + end end context 'when job name is empty' do diff --git a/spec/lib/gitlab/ci/config/entry/needs_spec.rb b/spec/lib/gitlab/ci/config/entry/needs_spec.rb index f11f2a56f5f..489fbac68b2 100644 --- a/spec/lib/gitlab/ci/config/entry/needs_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/needs_spec.rb @@ -111,8 +111,8 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Needs do it 'returns key value' do expect(needs.value).to eq( job: [ - { name: 'first_job_name', artifacts: true }, - { name: 'second_job_name', artifacts: true } + { name: 'first_job_name', artifacts: true, optional: false }, + { name: 'second_job_name', artifacts: true, optional: false } ] ) end @@ -124,8 +124,8 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Needs do context 'with complex job entries composed' do let(:config) do [ - { job: 'first_job_name', artifacts: true }, - { job: 'second_job_name', artifacts: false } + { job: 'first_job_name', artifacts: true, optional: false }, + { job: 'second_job_name', artifacts: false, optional: false } ] end @@ -137,8 +137,8 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Needs do it 'returns key value' do expect(needs.value).to eq( job: [ - { name: 'first_job_name', artifacts: true }, - { name: 'second_job_name', artifacts: false } + { name: 'first_job_name', artifacts: true, optional: false }, + { name: 'second_job_name', artifacts: false, optional: false } ] ) end @@ -163,8 +163,8 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Needs do it 'returns key value' do expect(needs.value).to eq( job: [ - { name: 'first_job_name', artifacts: true }, - { name: 'second_job_name', artifacts: false } + { name: 'first_job_name', artifacts: true, optional: false }, + { name: 'second_job_name', artifacts: false, optional: false } ] ) end diff --git a/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb b/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb index bc09e20d748..937642f07e7 100644 --- a/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb @@ -4,21 +4,23 @@ require 'fast_spec_helper' require_dependency 'active_model' RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Parallel do - subject(:parallel) { described_class.new(config) } + let(:metadata) { {} } - context 'with invalid config' do - shared_examples 'invalid config' do |error_message| - describe '#valid?' do - it { is_expected.not_to be_valid } - end + subject(:parallel) { described_class.new(config, **metadata) } - describe '#errors' do - it 'returns error about invalid type' do - expect(parallel.errors).to match(a_collection_including(error_message)) - end + shared_examples 'invalid config' do |error_message| + describe '#valid?' do + it { is_expected.not_to be_valid } + end + + describe '#errors' do + it 'returns error about invalid type' do + expect(parallel.errors).to match(a_collection_including(error_message)) end end + end + context 'with invalid config' do context 'when it is not a numeric value' do let(:config) { true } @@ -63,6 +65,12 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Parallel do expect(parallel.value).to match(number: config) end end + + context 'when :numeric is not allowed' do + let(:metadata) { { allowed_strategies: [:matrix] } } + + it_behaves_like 'invalid config', /cannot use "parallel: <number>"/ + end end end @@ -89,6 +97,12 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Parallel do ]) end end + + context 'when :matrix is not allowed' do + let(:metadata) { { allowed_strategies: [:numeric] } } + + it_behaves_like 'invalid config', /cannot use "parallel: matrix"/ + end end end end diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb index 54c7a5c3602..7b38c21788f 100644 --- a/spec/lib/gitlab/ci/config/entry/root_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb @@ -126,49 +126,105 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do expect(root.jobs_value.keys).to eq([:rspec, :spinach, :release]) expect(root.jobs_value[:rspec]).to eq( { name: :rspec, - script: %w[rspec ls], - before_script: %w(ls pwd), - image: { name: 'ruby:2.7' }, - services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], - stage: 'test', - cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, - variables: { 'VAR' => 'root', 'VAR2' => 'val 2' }, - ignore: false, - after_script: ['make clean'], - only: { refs: %w[branches tags] }, - scheduling_type: :stage } + script: %w[rspec ls], + before_script: %w(ls pwd), + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + variables: { 'VAR' => 'root', 'VAR2' => 'val 2' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage } ) expect(root.jobs_value[:spinach]).to eq( { name: :spinach, - before_script: [], - script: %w[spinach], - image: { name: 'ruby:2.7' }, - services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], - stage: 'test', - cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, - variables: { 'VAR' => 'root', 'VAR2' => 'val 2' }, - ignore: false, - after_script: ['make clean'], - only: { refs: %w[branches tags] }, - scheduling_type: :stage } + before_script: [], + script: %w[spinach], + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + variables: { 'VAR' => 'root', 'VAR2' => 'val 2' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage } ) expect(root.jobs_value[:release]).to eq( { name: :release, - stage: 'release', - before_script: [], - script: ["make changelog | tee release_changelog.txt"], - release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" }, - image: { name: "ruby:2.7" }, - services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }], - cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }, - only: { refs: %w(branches tags) }, - variables: { 'VAR' => 'job', 'VAR2' => 'val 2' }, - after_script: [], - ignore: false, - scheduling_type: :stage } + stage: 'release', + before_script: [], + script: ["make changelog | tee release_changelog.txt"], + release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" }, + image: { name: "ruby:2.7" }, + services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }], + cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }], + only: { refs: %w(branches tags) }, + variables: { 'VAR' => 'job', 'VAR2' => 'val 2' }, + after_script: [], + ignore: false, + scheduling_type: :stage } ) end end + + context 'with multuple_cache_per_job FF disabled' do + before do + stub_feature_flags(multiple_cache_per_job: false) + root.compose! + end + + describe '#jobs_value' do + it 'returns jobs configuration' do + expect(root.jobs_value.keys).to eq([:rspec, :spinach, :release]) + expect(root.jobs_value[:rspec]).to eq( + { name: :rspec, + script: %w[rspec ls], + before_script: %w(ls pwd), + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, + variables: { 'VAR' => 'root', 'VAR2' => 'val 2' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage } + ) + expect(root.jobs_value[:spinach]).to eq( + { name: :spinach, + before_script: [], + script: %w[spinach], + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, + variables: { 'VAR' => 'root', 'VAR2' => 'val 2' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage } + ) + expect(root.jobs_value[:release]).to eq( + { name: :release, + stage: 'release', + before_script: [], + script: ["make changelog | tee release_changelog.txt"], + release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" }, + image: { name: "ruby:2.7" }, + services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }], + cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }, + only: { refs: %w(branches tags) }, + variables: { 'VAR' => 'job', 'VAR2' => 'val 2' }, + after_script: [], + ignore: false, + scheduling_type: :stage } + ) + end + end + end end end @@ -187,6 +243,52 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do spinach: { before_script: [], variables: { VAR: 'job' }, script: 'spinach' } } end + context 'with multiple_cache_per_job FF disabled' do + context 'when composed' do + before do + stub_feature_flags(multiple_cache_per_job: false) + root.compose! + end + + describe '#errors' do + it 'has no errors' do + expect(root.errors).to be_empty + end + end + + describe '#jobs_value' do + it 'returns jobs configuration' do + expect(root.jobs_value).to eq( + rspec: { name: :rspec, + script: %w[rspec ls], + before_script: %w(ls pwd), + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, + variables: { 'VAR' => 'root' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage }, + spinach: { name: :spinach, + before_script: [], + script: %w[spinach], + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, + variables: { 'VAR' => 'job' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage } + ) + end + end + end + end + context 'when composed' do before do root.compose! @@ -202,29 +304,29 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do it 'returns jobs configuration' do expect(root.jobs_value).to eq( rspec: { name: :rspec, - script: %w[rspec ls], - before_script: %w(ls pwd), - image: { name: 'ruby:2.7' }, - services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], - stage: 'test', - cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, - variables: { 'VAR' => 'root' }, - ignore: false, - after_script: ['make clean'], - only: { refs: %w[branches tags] }, - scheduling_type: :stage }, + script: %w[rspec ls], + before_script: %w(ls pwd), + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + variables: { 'VAR' => 'root' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage }, spinach: { name: :spinach, - before_script: [], - script: %w[spinach], - image: { name: 'ruby:2.7' }, - services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], - stage: 'test', - cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }, - variables: { 'VAR' => 'job' }, - ignore: false, - after_script: ['make clean'], - only: { refs: %w[branches tags] }, - scheduling_type: :stage } + before_script: [], + script: %w[spinach], + image: { name: 'ruby:2.7' }, + services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], + stage: 'test', + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + variables: { 'VAR' => 'job' }, + ignore: false, + after_script: ['make clean'], + only: { refs: %w[branches tags] }, + scheduling_type: :stage } ) end end @@ -265,7 +367,20 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do describe '#cache_value' do it 'returns correct cache definition' do - expect(root.cache_value).to eq(key: 'a', policy: 'pull-push', when: 'on_success') + expect(root.cache_value).to eq([key: 'a', policy: 'pull-push', when: 'on_success']) + end + end + + context 'with multiple_cache_per_job FF disabled' do + before do + stub_feature_flags(multiple_cache_per_job: false) + root.compose! + end + + describe '#cache_value' do + it 'returns correct cache definition' do + expect(root.cache_value).to eq(key: 'a', policy: 'pull-push', when: 'on_success') + end end end end |