diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-01-18 22:00:14 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-01-18 22:00:14 +0300 |
commit | 05f0ebba3a2c8ddf39e436f412dc2ab5bf1353b2 (patch) | |
tree | 11d0f2a6ec31c7793c184106cedc2ded3d9a2cc5 /spec/lib/gitlab/ci | |
parent | ec73467c23693d0db63a797d10194da9e72a74af (diff) |
Add latest changes from gitlab-org/gitlab@15-8-stable-eev15.8.0-rc42
Diffstat (limited to 'spec/lib/gitlab/ci')
31 files changed, 558 insertions, 505 deletions
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb index 414cbb169b9..67252eed938 100644 --- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb @@ -16,12 +16,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do let(:policy) { nil } let(:key) { 'some key' } let(:when_config) { nil } + let(:unprotect) { false } let(:config) do { key: key, untracked: true, - paths: ['some/path/'] + paths: ['some/path/'], + unprotect: unprotect }.tap do |config| config[:policy] = policy if policy config[:when] = when_config if when_config @@ -31,7 +33,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do 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') + expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push', when: 'on_success', unprotect: false) end end @@ -57,6 +59,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do end end + context 'with option `unprotect` specified' do + let(:unprotect) { true } + + it 'returns true' do + expect(entry.value).to match(a_hash_including(unprotect: true)) + end + end + context 'with `policy`' do where(:policy, :result) do 'pull-push' | 'pull-push' diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index becb46ac2e7..c1b9bd58d98 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::Entry::Job do +RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_authoring do let(:entry) { described_class.new(config, name: :rspec) } it_behaves_like 'with inheritable CI config' do @@ -337,100 +337,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do end end - context 'when only: is used with rules:' do - let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }] } } - - it 'returns error about mixing only: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - - context 'and only: is blank' do - let(:config) { { only: nil, rules: [{ if: '$THIS' }] } } - - it 'returns error about mixing only: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - end - - context 'and rules: is blank' do - let(:config) { { only: ['merge_requests'], rules: nil } } - - it 'returns error about mixing only: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - end - end - - context 'when except: is used with rules:' do - let(:config) { { except: { refs: %w[master] }, rules: [{ if: '$THIS' }] } } - - it 'returns error about mixing except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - - context 'and except: is blank' do - let(:config) { { except: nil, rules: [{ if: '$THIS' }] } } - - it 'returns error about mixing except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - end - - context 'and rules: is blank' do - let(:config) { { except: { refs: %w[master] }, rules: nil } } - - it 'returns error about mixing except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - end - end - - context 'when only: and except: are both used with rules:' do - let(:config) do - { - only: %w[merge_requests], - except: { refs: %w[master] }, - rules: [{ if: '$THIS' }] - } - end - - it 'returns errors about mixing both only: and except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - expect(entry.errors).to include /may not be used with `rules`/ - end - - context 'when only: and except: as both blank' do - let(:config) do - { only: nil, except: nil, rules: [{ if: '$THIS' }] } - end - - it 'returns errors about mixing both only: and except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - expect(entry.errors).to include /may not be used with `rules`/ - end - end - - context 'when rules: is blank' do - let(:config) do - { only: %w[merge_requests], except: { refs: %w[master] }, rules: nil } - end - - it 'returns errors about mixing both only: and except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - expect(entry.errors).to include /may not be used with `rules`/ - end - end - end - context 'when start_in specified without delayed specification' do let(:config) { { start_in: '1 day' } } @@ -603,6 +509,92 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do end end end + + context 'when only: is used with rules:' do + let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }], script: 'echo' } } + + it 'returns error about mixing only: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`: only/ + end + + context 'and only: is blank' do + let(:config) { { only: nil, rules: [{ if: '$THIS' }], script: 'echo' } } + + it 'is valid:' do + expect(entry).to be_valid + end + end + + context 'and rules: is blank' do + let(:config) { { only: ['merge_requests'], rules: nil, script: 'echo' } } + + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when except: is used with rules:' do + let(:config) { { except: { refs: %w[master] }, rules: [{ if: '$THIS' }], script: 'echo' } } + + it 'returns error about mixing except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`: except/ + end + + context 'and except: is blank' do + let(:config) { { except: nil, rules: [{ if: '$THIS' }], script: 'echo' } } + + it 'is valid' do + expect(entry).to be_valid + end + end + + context 'and rules: is blank' do + let(:config) { { except: { refs: %w[master] }, rules: nil, script: 'echo' } } + + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when only: and except: are both used with rules:' do + let(:config) do + { + only: %w[merge_requests], + except: { refs: %w[master] }, + rules: [{ if: '$THIS' }], + script: 'echo' + } + end + + it 'returns errors about mixing both only: and except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`: only, except/ + end + + context 'when only: and except: as both blank' do + let(:config) do + { only: nil, except: nil, rules: [{ if: '$THIS' }], script: 'echo' } + end + + it 'is valid' do + expect(entry).to be_valid + end + end + + context 'when rules: is blank' do + let(:config) do + { only: %w[merge_requests], except: { refs: %w[master] }, rules: nil, script: 'echo' } + end + + it 'is valid' do + expect(entry).to be_valid + end + end + end end describe '#relevant?' do @@ -639,7 +631,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', unprotect: false]) end end @@ -654,7 +646,7 @@ 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', unprotect: false]) end end diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb index f1578a068b9..b28562ba2ea 100644 --- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::Entry::Processable do +RSpec.describe Gitlab::Ci::Config::Entry::Processable, feature_category: :pipeline_authoring do let(:node_class) do Class.new(::Gitlab::Config::Entry::Node) do include Gitlab::Ci::Config::Entry::Processable @@ -104,111 +104,102 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do end end - context 'when only: is used with rules:' do - let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }] } } + context 'when a variable has an invalid data attribute' do + let(:config) do + { + script: 'echo', + variables: { 'VAR1' => 'val 1', 'VAR2' => { value: 'val 2', description: 'hello var 2' } } + } + end - it 'returns error about mixing only: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ + it 'reports error about variable' do + expect(entry.errors) + .to include 'variables:var2 config uses invalid data keys: description' end + end + end - context 'and only: is blank' do - let(:config) { { only: nil, rules: [{ if: '$THIS' }] } } + context 'when only: is used with rules:' do + let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }] } } - it 'returns error about mixing only: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - end + it 'returns error about mixing only: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`: only/ + end - context 'and rules: is blank' do - let(:config) { { only: ['merge_requests'], rules: nil } } + context 'and only: is blank' do + let(:config) { { only: nil, rules: [{ if: '$THIS' }] } } - it 'returns error about mixing only: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end + it 'is valid' do + expect(entry).to be_valid end end - context 'when except: is used with rules:' do - let(:config) { { except: { refs: %w[master] }, rules: [{ if: '$THIS' }] } } + context 'and rules: is blank' do + let(:config) { { only: ['merge_requests'], rules: nil } } - it 'returns error about mixing except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ + it 'is valid' do + expect(entry).to be_valid end + end + end - context 'and except: is blank' do - let(:config) { { except: nil, rules: [{ if: '$THIS' }] } } + context 'when except: is used with rules:' do + let(:config) { { except: { refs: %w[master] }, rules: [{ if: '$THIS' }] } } - it 'returns error about mixing except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end - end + it 'returns error about mixing except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`: except/ + end - context 'and rules: is blank' do - let(:config) { { except: { refs: %w[master] }, rules: nil } } + context 'and except: is blank' do + let(:config) { { except: nil, rules: [{ if: '$THIS' }] } } - it 'returns error about mixing except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - end + it 'is valid' do + expect(entry).to be_valid end end - context 'when only: and except: are both used with rules:' do - let(:config) do - { - only: %w[merge_requests], - except: { refs: %w[master] }, - rules: [{ if: '$THIS' }] - } - end + context 'and rules: is blank' do + let(:config) { { except: { refs: %w[master] }, rules: nil } } - it 'returns errors about mixing both only: and except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - expect(entry.errors).to include /may not be used with `rules`/ + it 'is valid' do + expect(entry).to be_valid end + end + end - context 'when only: and except: as both blank' do - let(:config) do - { only: nil, except: nil, rules: [{ if: '$THIS' }] } - end + context 'when only: and except: are both used with rules:' do + let(:config) do + { + only: %w[merge_requests], + except: { refs: %w[master] }, + rules: [{ if: '$THIS' }] + } + end - it 'returns errors about mixing both only: and except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - expect(entry.errors).to include /may not be used with `rules`/ - end - end + it 'returns errors about mixing both only: and except: with rules:' do + expect(entry).not_to be_valid + expect(entry.errors).to include /may not be used with `rules`: only, except/ + end - context 'when rules: is blank' do - let(:config) do - { only: %w[merge_requests], except: { refs: %w[master] }, rules: nil } - end + context 'when only: and except: as both blank' do + let(:config) do + { only: nil, except: nil, rules: [{ if: '$THIS' }] } + end - it 'returns errors about mixing both only: and except: with rules:' do - expect(entry).not_to be_valid - expect(entry.errors).to include /may not be used with `rules`/ - expect(entry.errors).to include /may not be used with `rules`/ - end + it 'is valid' do + expect(entry).to be_valid end end - context 'when a variable has an invalid data attribute' do + context 'when rules: is blank' do let(:config) do - { - script: 'echo', - variables: { 'VAR1' => 'val 1', 'VAR2' => { value: 'val 2', description: 'hello var 2' } } - } + { only: %w[merge_requests], except: { refs: %w[master] }, rules: nil } end - it 'reports error about variable' do - expect(entry.errors) - .to include 'variables:var2 config uses invalid data keys: description' + it 'is valid' do + expect(entry).to be_valid end end end diff --git a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb index 394d91466bf..cbd3109522c 100644 --- a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb @@ -29,7 +29,7 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do [ { 'VAR_1' => (1..10).to_a, - 'VAR_2' => (11..20).to_a + 'VAR_2' => (11..31).to_a } ] end @@ -41,7 +41,7 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do describe '#errors' do it 'returns error about too many jobs' do expect(matrix.errors) - .to include('matrix config generates too many jobs (maximum is 50)') + .to include('matrix config generates too many jobs (maximum is 200)') end end 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 a16f1cf9e43..ec21519a8f6 100644 --- a/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb @@ -33,10 +33,10 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Parallel do it_behaves_like 'invalid config', /must be greater than or equal to 2/ end - context 'when it is bigger than 50' do - let(:config) { 51 } + context 'when it is bigger than 200' do + let(:config) { 201 } - it_behaves_like 'invalid config', /must be less than or equal to 50/ + it_behaves_like 'invalid config', /must be less than or equal to 200/ end context 'when it is not an integer' do diff --git a/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb b/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb index 0fd9a83a4fa..ccd6f6ab427 100644 --- a/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports/coverage_report_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::Entry::Reports::CoverageReport do +RSpec.describe Gitlab::Ci::Config::Entry::Reports::CoverageReport, feature_category: :pipeline_authoring do let(:entry) { described_class.new(config) } describe 'validations' do @@ -14,6 +14,16 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports::CoverageReport do it { expect(entry.value).to eq(config) } end + context 'when it is not a hash' do + where(:config) { ['string', true, []] } + + with_them do + it { expect(entry).not_to be_valid } + + it { expect(entry.errors).to include /should be a hash/ } + end + end + context 'with unsupported coverage format' do let(:config) { { coverage_format: 'jacoco', path: 'jacoco.xml' } } diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb index 45aa859a356..715cb18fb92 100644 --- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::Entry::Reports do +RSpec.describe Gitlab::Ci::Config::Entry::Reports, feature_category: :pipeline_authoring do let(:entry) { described_class.new(config) } describe 'validates ALLOWED_KEYS' do @@ -90,6 +90,18 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports do end end end + + context 'when coverage_report is nil' do + let(:config) { { coverage_report: nil } } + + it 'is valid' do + expect(entry).to be_valid + end + + it 'returns artifacts configuration as an empty hash' do + expect(entry.value).to eq({}) + end + end end context 'when entry value is not correct' do diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb index c40589104cd..9722609aef6 100644 --- a/spec/lib/gitlab/ci/config/entry/root_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb @@ -127,7 +127,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do image: { name: 'image:1.0' }, services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], stage: 'test', - cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success', + unprotect: false }], job_variables: {}, root_variables_inheritance: true, ignore: false, @@ -142,7 +143,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do image: { name: 'image:1.0' }, services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], stage: 'test', - cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success', + unprotect: false }], job_variables: {}, root_variables_inheritance: true, ignore: false, @@ -158,7 +160,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" }, image: { name: "image:1.0" }, services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }], - cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }], + cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success', + unprotect: false }], only: { refs: %w(branches tags) }, job_variables: { 'VAR' => { value: 'job' } }, root_variables_inheritance: true, @@ -206,7 +209,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do image: { name: 'image:1.0' }, services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], stage: 'test', - cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success', unprotect: false }], job_variables: {}, root_variables_inheritance: true, ignore: false, @@ -219,7 +222,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do image: { name: 'image:1.0' }, services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }], stage: 'test', - cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }], + cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success', unprotect: false }], job_variables: { 'VAR' => { value: 'job' } }, root_variables_inheritance: true, ignore: false, @@ -274,7 +277,7 @@ 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', unprotect: false]) end end end diff --git a/spec/lib/gitlab/ci/config/entry/variable_spec.rb b/spec/lib/gitlab/ci/config/entry/variable_spec.rb index 97b06c8b1a5..1067db6d124 100644 --- a/spec/lib/gitlab/ci/config/entry/variable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/variable_spec.rb @@ -257,14 +257,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do subject(:value_with_data) { entry.value_with_data } it { is_expected.to eq(value: 'value', raw: true) } - - context 'when the FF ci_raw_variables_in_yaml_config is disabled' do - before do - stub_feature_flags(ci_raw_variables_in_yaml_config: false) - end - - it { is_expected.to eq(value: 'value') } - end end context 'when config expand is true' do diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb index f5b36ebfa45..a77acb45978 100644 --- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb @@ -2,11 +2,13 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::External::File::Local do +RSpec.describe Gitlab::Ci::Config::External::File::Local, feature_category: :pipeline_authoring do + include RepoHelpers + let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } - let(:sha) { '12345' } + let(:sha) { project.commit.sha } let(:variables) { project.predefined_variables.to_runner_variables } let(:context) { Gitlab::Ci::Config::External::Context.new(**context_params) } let(:params) { { local: location } } @@ -172,14 +174,17 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do let(:another_location) { 'another-config.yml' } let(:another_content) { 'rspec: JOB' } - before do - allow(project.repository).to receive(:blob_data_at).with(sha, location) - .and_return(content) - - allow(project.repository).to receive(:blob_data_at).with(sha, another_location) - .and_return(another_content) + let(:project_files) do + { + location => content, + another_location => another_content + } + end - local_file.validate! + around(:all) do |example| + create_and_delete_files(project, project_files) do + example.run + end end it 'does expand hash to include the template' do @@ -196,11 +201,11 @@ RSpec.describe Gitlab::Ci::Config::External::File::Local do it { is_expected.to eq( context_project: project.full_path, - context_sha: '12345', + context_sha: sha, type: :local, - location: location, - blob: "http://localhost/#{project.full_path}/-/blob/12345/lib/gitlab/ci/templates/existent-file.yml", - raw: "http://localhost/#{project.full_path}/-/raw/12345/lib/gitlab/ci/templates/existent-file.yml", + location: '/lib/gitlab/ci/templates/existent-file.yml', + blob: "http://localhost/#{project.full_path}/-/blob/#{sha}/lib/gitlab/ci/templates/existent-file.yml", + raw: "http://localhost/#{project.full_path}/-/raw/#{sha}/lib/gitlab/ci/templates/existent-file.yml", extra: {} ) } diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb index b7e58d4dfa1..9d0e57d4292 100644 --- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb +++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -# This will be removed with FF ci_refactoring_external_mapper and moved to below. +# This will be use with the FF ci_refactoring_external_mapper_verifier in the next MR. +# It can be removed when the FF is removed. RSpec.shared_context 'gitlab_ci_config_external_mapper' do include StubRequests include RepoHelpers @@ -466,12 +467,4 @@ end RSpec.describe Gitlab::Ci::Config::External::Mapper, feature_category: :pipeline_authoring do it_behaves_like 'gitlab_ci_config_external_mapper' - - context 'when the FF ci_refactoring_external_mapper is disabled' do - before do - stub_feature_flags(ci_refactoring_external_mapper: false) - end - - it_behaves_like 'gitlab_ci_config_external_mapper' - end end diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb index b48a89059bf..5cdc9c21561 100644 --- a/spec/lib/gitlab/ci/config_spec.rb +++ b/spec/lib/gitlab/ci/config_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do include StubRequests + include RepoHelpers let_it_be(:user) { create(:user) } @@ -313,9 +314,12 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do context "when using 'include' directive" do let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, :repository, group: group) } + let_it_be(:main_project) { create(:project, :repository, :public, group: group) } + + let(:project_sha) { project.commit.id } + let(:main_project_sha) { main_project.commit.id } - let(:project) { create(:project, :repository, group: group) } - let(:main_project) { create(:project, :repository, :public, group: group) } let(:pipeline) { build(:ci_pipeline, project: project) } let(:remote_location) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' } @@ -356,36 +360,38 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do end let(:config) do - described_class.new(gitlab_ci_yml, project: project, pipeline: pipeline, sha: '12345', user: user) + described_class.new(gitlab_ci_yml, project: project, pipeline: pipeline, sha: project_sha, user: user) end - before do - stub_full_request(remote_location).to_return(body: remote_file_content) - - allow(project.repository) - .to receive(:blob_data_at).and_return(local_file_content) + let(:project_files) do + { + local_location => local_file_content + } + end - main_project.repository.create_file( - main_project.creator, - '.gitlab-ci.yml', - local_file_content, - message: 'Add README.md', - branch_name: 'master' - ) + let(:main_project_files) do + { + '.gitlab-ci.yml' => local_file_content, + '.another-ci-file.yml' => local_file_content + } + end - main_project.repository.create_file( - main_project.creator, - '.another-ci-file.yml', - local_file_content, - message: 'Add README.md', - branch_name: 'master' - ) + before do + stub_full_request(remote_location).to_return(body: remote_file_content) create(:ci_variable, project: project, key: "REF", value: "HEAD") create(:ci_group_variable, group: group, key: "FILENAME", value: ".gitlab-ci.yml") create(:ci_instance_variable, key: 'MAIN_PROJECT', value: main_project.full_path) end + around do |example| + create_and_delete_files(project, project_files) do + create_and_delete_files(main_project, main_project_files) do + example.run + end + end + end + context "when gitlab_ci_yml has valid 'include' defined" do it 'returns a composed hash' do composed_hash = { @@ -434,25 +440,25 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do expect(config.metadata[:includes]).to contain_exactly( { type: :local, location: local_location, - blob: "http://localhost/#{project.full_path}/-/blob/12345/#{local_location}", - raw: "http://localhost/#{project.full_path}/-/raw/12345/#{local_location}", + blob: "http://localhost/#{project.full_path}/-/blob/#{project_sha}/#{local_location}", + raw: "http://localhost/#{project.full_path}/-/raw/#{project_sha}/#{local_location}", extra: {}, context_project: project.full_path, - context_sha: '12345' }, + context_sha: project_sha }, { type: :remote, location: remote_location, blob: nil, raw: remote_location, extra: {}, context_project: project.full_path, - context_sha: '12345' }, + context_sha: project_sha }, { type: :file, location: '.gitlab-ci.yml', - blob: "http://localhost/#{main_project.full_path}/-/blob/#{main_project.commit.sha}/.gitlab-ci.yml", - raw: "http://localhost/#{main_project.full_path}/-/raw/#{main_project.commit.sha}/.gitlab-ci.yml", + blob: "http://localhost/#{main_project.full_path}/-/blob/#{main_project_sha}/.gitlab-ci.yml", + raw: "http://localhost/#{main_project.full_path}/-/raw/#{main_project_sha}/.gitlab-ci.yml", extra: { project: main_project.full_path, ref: 'HEAD' }, context_project: project.full_path, - context_sha: '12345' } + context_sha: project_sha } ) end end @@ -511,16 +517,13 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do describe 'external file version' do context 'when external local file SHA is defined' do it 'is using a defined value' do - expect(project.repository).to receive(:blob_data_at) - .with('eeff1122', local_location) - - described_class.new(gitlab_ci_yml, project: project, sha: 'eeff1122', user: user, pipeline: pipeline) + described_class.new(gitlab_ci_yml, project: project, sha: project_sha, user: user, pipeline: pipeline) end end context 'when external local file SHA is not defined' do it 'is using latest SHA on the default branch' do - expect(project.repository).to receive(:root_ref_sha) + expect(project.repository).to receive(:root_ref_sha).and_call_original described_class.new(gitlab_ci_yml, project: project, sha: nil, user: user, pipeline: pipeline) end @@ -757,13 +760,11 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do before do project.add_developer(user) + end - allow_next_instance_of(Repository) do |repository| - allow(repository).to receive(:blob_data_at).with(an_instance_of(String), local_location) - .and_return(local_file_content) - - allow(repository).to receive(:blob_data_at).with(an_instance_of(String), other_file_location) - .and_return(other_file_content) + around do |example| + create_and_delete_files(project, { other_file_location => other_file_content }) do + example.run end end @@ -819,14 +820,10 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do HEREDOC end - before do - project.repository.create_file( - project.creator, - 'my_builds.yml', - local_file_content, - message: 'Add my_builds.yml', - branch_name: '12345' - ) + around do |example| + create_and_delete_files(project, { 'my_builds.yml' => local_file_content }) do + example.run + end end context 'when the exists file does not exist' do @@ -853,7 +850,7 @@ RSpec.describe Gitlab::Ci::Config, feature_category: :pipeline_authoring do include: - local: #{local_location} rules: - - if: $CI_COMMIT_SHA == "#{project.commit.sha}" + - if: $CI_COMMIT_REF_NAME == "master" HEREDOC end diff --git a/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb index 712dc00ec7a..acb7c122bcd 100644 --- a/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb +++ b/spec/lib/gitlab/ci/parsers/sbom/validators/cyclonedx_schema_validator_spec.rb @@ -62,6 +62,47 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Validators::CyclonedxSchemaValidator, it { is_expected.to be_valid } end + context 'when components have licenses' do + let(:components) do + [ + { + "type" => "library", + "name" => "activesupport", + "version" => "5.1.4", + "licenses" => [ + { "license" => { "id" => "MIT" } } + ] + } + ] + end + + it { is_expected.to be_valid } + end + + context 'when components have a signature' do + let(:components) do + [ + { + "type" => "library", + "name" => "activesupport", + "version" => "5.1.4", + "signature" => { + "algorithm" => "ES256", + "publicKey" => { + "kty" => "EC", + "crv" => "P-256", + "x" => "6BKxpty8cI-exDzCkh-goU6dXq3MbcY0cd1LaAxiNrU", + "y" => "mCbcvUzm44j3Lt2b5BPyQloQ91tf2D2V-gzeUxWaUdg" + }, + "value" => "ybT1qz5zHNi4Ndc6y7Zhamuf51IqXkPkZwjH1XcC-KSuBiaQplTw6Jasf2MbCLg3CF7PAdnMO__WSLwvI5r2jA" + } + } + ] + end + + it { is_expected.to be_valid } + end + context "when components are not valid" do let(:components) do [ diff --git a/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb b/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb index c94ed1f8d6d..12886c79d7d 100644 --- a/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb +++ b/spec/lib/gitlab/ci/parsers/security/validators/schema_validator_spec.rb @@ -2,9 +2,10 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do +RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator, feature_category: :vulnerability_management do let_it_be(:project) { create(:project) } + let(:current_dast_versions) { described_class::CURRENT_VERSIONS[:dast].join(', ') } let(:supported_dast_versions) { described_class::SUPPORTED_VERSIONS[:dast].join(', ') } let(:deprecated_schema_version_message) {} let(:missing_schema_version_message) do @@ -19,6 +20,14 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do } end + let(:analyzer_vendor) do + { 'name' => 'A DAST analyzer' } + end + + let(:scanner_vendor) do + { 'name' => 'A DAST scanner' } + end + let(:report_data) do { 'scan' => { @@ -26,7 +35,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do 'id' => 'my-dast-analyzer', 'name' => 'My DAST analyzer', 'version' => '0.1.0', - 'vendor' => { 'name' => 'A DAST analyzer' } + 'vendor' => analyzer_vendor }, 'end_time' => '2020-01-28T03:26:02', 'scanned_resources' => [], @@ -34,7 +43,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do 'id' => 'my-dast-scanner', 'name' => 'My DAST scanner', 'version' => '0.2.0', - 'vendor' => { 'name' => 'A DAST scanner' } + 'vendor' => scanner_vendor }, 'start_time' => '2020-01-28T03:26:01', 'status' => 'success', @@ -458,8 +467,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do let(:report_version) { described_class::DEPRECATED_VERSIONS[report_type].last } let(:expected_deprecation_message) do - "Version #{report_version} for report type #{report_type} has been deprecated, supported versions for this "\ - "report type are: #{supported_dast_versions}. GitLab will attempt to parse and ingest this report if valid." + "version #{report_version} for report type #{report_type} is deprecated. "\ + "However, GitLab will still attempt to parse and ingest this report. "\ + "Upgrade the security report to one of the following versions: #{current_dast_versions}." end let(:expected_deprecation_warnings) do @@ -492,6 +502,22 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Validators::SchemaValidator do it_behaves_like 'report with expected warnings' end + + context 'and the report passes schema validation as a GitLab-vendored analyzer' do + let(:analyzer_vendor) do + { 'name' => 'GitLab' } + end + + it { is_expected.to be_empty } + end + + context 'and the report passes schema validation as a GitLab-vendored scanner' do + let(:scanner_vendor) do + { 'name' => 'GitLab' } + end + + it { is_expected.to be_empty } + end end context 'when given an unsupported schema version' do diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb index be5d3a96126..bec80a43a76 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/create_deployments_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Pipeline::Chain::CreateDeployments do +RSpec.describe Gitlab::Ci::Pipeline::Chain::CreateDeployments, feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } @@ -19,6 +19,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CreateDeployments do subject { step.perform! } before do + stub_feature_flags(move_create_deployments_to_worker: false) job.pipeline = pipeline end diff --git a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb index eba0db0adfb..e13e78d0db8 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/create_spec.rb @@ -63,11 +63,11 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Create do end let(:job) do - build(:ci_build, stage: stage, pipeline: pipeline, project: project) + build(:ci_build, ci_stage: stage, pipeline: pipeline, project: project) end let(:bridge) do - build(:ci_bridge, stage: stage, pipeline: pipeline, project: project) + build(:ci_bridge, ci_stage: stage, pipeline: pipeline, project: project) end before do diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb index 35e1c48a942..00200b57b1e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb @@ -54,94 +54,76 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata do expect(step.break?).to be false end - context 'with feature flag disabled' do - before do - stub_feature_flags(pipeline_name: false) - end - - it 'does not build pipeline_metadata' do - run_chain + it 'builds pipeline_metadata' do + run_chain - expect(pipeline.pipeline_metadata).to be_nil - end + expect(pipeline.pipeline_metadata.name).to eq('Pipeline name') + expect(pipeline.pipeline_metadata.project).to eq(pipeline.project) + expect(pipeline.pipeline_metadata).not_to be_persisted end - context 'with feature flag enabled' do - before do - stub_feature_flags(pipeline_name: true) + context 'with empty name' do + let(:config) do + { workflow: { name: ' ' }, rspec: { script: 'rspec' } } end - it 'builds pipeline_metadata' do + it 'strips whitespace from name' do run_chain - expect(pipeline.pipeline_metadata.name).to eq('Pipeline name') - expect(pipeline.pipeline_metadata.project).to eq(pipeline.project) - expect(pipeline.pipeline_metadata).not_to be_persisted + expect(pipeline.pipeline_metadata).to be_nil end - context 'with empty name' do + context 'with empty name after variable substitution' do let(:config) do - { workflow: { name: ' ' }, rspec: { script: 'rspec' } } + { workflow: { name: '$VAR1' }, rspec: { script: 'rspec' } } end - it 'strips whitespace from name' do + it 'does not save empty name' do run_chain expect(pipeline.pipeline_metadata).to be_nil end - - context 'with empty name after variable substitution' do - let(:config) do - { workflow: { name: '$VAR1' }, rspec: { script: 'rspec' } } - end - - it 'does not save empty name' do - run_chain - - expect(pipeline.pipeline_metadata).to be_nil - end - end end + end - context 'with variables' do - let(:config) do - { - variables: { ROOT_VAR: 'value $WORKFLOW_VAR1' }, - workflow: { - name: 'Pipeline $ROOT_VAR $WORKFLOW_VAR2 $UNKNOWN_VAR', - rules: [{ variables: { WORKFLOW_VAR1: 'value1', WORKFLOW_VAR2: 'value2' } }] - }, - rspec: { script: 'rspec' } - } - end + context 'with variables' do + let(:config) do + { + variables: { ROOT_VAR: 'value $WORKFLOW_VAR1' }, + workflow: { + name: 'Pipeline $ROOT_VAR $WORKFLOW_VAR2 $UNKNOWN_VAR', + rules: [{ variables: { WORKFLOW_VAR1: 'value1', WORKFLOW_VAR2: 'value2' } }] + }, + rspec: { script: 'rspec' } + } + end - it 'substitutes variables' do - run_chain + it 'substitutes variables' do + run_chain - expect(pipeline.pipeline_metadata.name).to eq('Pipeline value value1 value2') - end + expect(pipeline.pipeline_metadata.name).to eq('Pipeline value value1 value2') end + end - context 'with invalid name' do - let(:config) do - { - variables: { ROOT_VAR: 'a' * 256 }, - workflow: { - name: 'Pipeline $ROOT_VAR' - }, - rspec: { script: 'rspec' } - } - end + context 'with invalid name' do + let(:config) do + { + variables: { ROOT_VAR: 'a' * 256 }, + workflow: { + name: 'Pipeline $ROOT_VAR' + }, + rspec: { script: 'rspec' } + } + end - it 'returns error and breaks chain' do - ret = run_chain + it 'returns error and breaks chain' do + ret = run_chain - expect(ret) - .to match_array(["Failed to build pipeline metadata! Name is too long (maximum is 255 characters)"]) - expect(pipeline.pipeline_metadata.errors.full_messages) - .to match_array(['Name is too long (maximum is 255 characters)']) - expect(step.break?).to be true - end + expect(ret) + .to match_array(["Failed to build pipeline metadata! Name is too long (maximum is 255 characters)"]) + expect(pipeline.pipeline_metadata.errors.full_messages) + .to match_array(['Name is too long (maximum is 255 characters)']) + expect(step.break?).to be true end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb index 62de4d2e96d..91bb94bbb11 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do +RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate, feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } @@ -90,7 +90,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do it 'appends an error about missing stages' do expect(pipeline.errors.to_a) - .to include 'No stages / jobs for this pipeline.' + .to include 'Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.' end it 'wastes pipeline iid' do diff --git a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb index fb8020bf43e..c264ea3bece 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb @@ -212,6 +212,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do paths: ['vendor/ruby'], untracked: true, policy: 'push', + unprotect: true, when: 'on_success' } end diff --git a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb index 6081f104e42..c13901a4776 100644 --- a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Status::Bridge::Factory do +RSpec.describe Gitlab::Ci::Status::Bridge::Factory, feature_category: :continuous_integration do let(:user) { create(:user) } let(:project) { bridge.project } let(:status) { factory.fabricate! } @@ -59,13 +59,15 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory do context 'failed with downstream_pipeline_creation_failed' do before do - bridge.options = { downstream_errors: ['No stages / jobs for this pipeline.', 'other error'] } + bridge.options = { downstream_errors: ['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.', 'other error'] } bridge.failure_reason = 'downstream_pipeline_creation_failed' end it 'fabricates correct status_tooltip' do expect(status.status_tooltip).to eq( - "#{s_('CiStatusText|failed')} - (downstream pipeline can not be created, No stages / jobs for this pipeline., other error)" + "#{s_('CiStatusText|failed')} - (downstream pipeline can not be created, Pipeline will not run for the selected trigger. " \ + "The rules configuration prevented any jobs from being added to the pipeline., other error)" ) end end diff --git a/spec/lib/gitlab/ci/status/build/manual_spec.rb b/spec/lib/gitlab/ci/status/build/manual_spec.rb index a1152cb77e3..8f5d1558314 100644 --- a/spec/lib/gitlab/ci/status/build/manual_spec.rb +++ b/spec/lib/gitlab/ci/status/build/manual_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Status::Build::Manual do +RSpec.describe Gitlab::Ci::Status::Build::Manual, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:job) { create(:ci_build, :manual) } @@ -18,11 +18,44 @@ RSpec.describe Gitlab::Ci::Status::Build::Manual do job.project.add_maintainer(user) end - it { expect(subject.illustration[:content]).to match /This job requires manual intervention to start/ } + context 'when the job has not been played' do + it 'instructs the user about possible actions' do + expect(subject.illustration[:content]).to eq( + _( + 'This job does not start automatically and must be started manually. ' \ + 'You can add CI/CD variables below for last-minute configuration changes before starting the job.' + ) + ) + end + end + + context 'when the job is retryable' do + before do + job.update!(status: :failed) + end + + it 'instructs the user about possible actions' do + expect(subject.illustration[:content]).to eq( + _("You can modify this job's CI/CD variables before running it again.") + ) + end + end + end + + context 'when the user can not trigger the job because of outdated deployment' do + before do + allow(job).to receive(:outdated_deployment?).and_return(true) + end + + it { expect(subject.illustration[:content]).to match /This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run/ } end - context 'when the user can not trigger the job' do - it { expect(subject.illustration[:content]).to match /This job does not run automatically and must be started manually/ } + context 'when the user can not trigger the job due to another reason' do + it 'informs the user' do + expect(subject.illustration[:content]).to eq( + _("This job does not run automatically and must be started manually, but you do not have access to it.") + ) + end end end diff --git a/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb index 16c5d7a4b6d..286f3d10b7f 100644 --- a/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do +RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml', feature_category: :continuous_integration do subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/Code-Quality') } describe 'the created pipeline' do @@ -63,7 +63,8 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do context 'on master' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end @@ -72,7 +73,8 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end @@ -81,7 +83,8 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end end diff --git a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb index 8a5aea7c0f0..68d249e31f9 100644 --- a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml' do +RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml', feature_category: :continuous_integration do subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/SAST-IaC') } describe 'the created pipeline' do @@ -50,7 +50,8 @@ RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml' do context 'on default branch' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end @@ -59,7 +60,8 @@ RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end end diff --git a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb index d540b035f81..039a6a739dd 100644 --- a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do +RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml', feature_category: :continuous_integration do subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/SAST-IaC.latest') } describe 'the created pipeline' do @@ -51,7 +51,8 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do context 'on default branch' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end @@ -60,7 +61,8 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end end diff --git a/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb index 7cf0cf3ed33..d73d8a15feb 100644 --- a/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Jobs/Test.gitlab-ci.yml' do +RSpec.describe 'Jobs/Test.gitlab-ci.yml', feature_category: :continuous_integration do subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/Test') } describe 'the created pipeline' do @@ -63,7 +63,8 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do context 'on master' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end @@ -72,7 +73,8 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end @@ -81,7 +83,8 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end end diff --git a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb index b2ca906e172..09ca2678de5 100644 --- a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Auto-DevOps.gitlab-ci.yml' do +RSpec.describe 'Auto-DevOps.gitlab-ci.yml', feature_category: :auto_devops do using RSpec::Parameterized::TableSyntax subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Auto-DevOps') } diff --git a/spec/lib/gitlab/ci/templates/npm_spec.rb b/spec/lib/gitlab/ci/templates/npm_spec.rb index 55fd4675f11..a949a7ccfb1 100644 --- a/spec/lib/gitlab/ci/templates/npm_spec.rb +++ b/spec/lib/gitlab/ci/templates/npm_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'npm.gitlab-ci.yml' do +RSpec.describe 'npm.gitlab-ci.yml', feature_category: :continuous_integration do subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('npm') } describe 'the created pipeline' do @@ -43,7 +43,8 @@ RSpec.describe 'npm.gitlab-ci.yml' do shared_examples 'no pipeline created' do it 'does not create a pipeline because the only job (publish) is not created' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end diff --git a/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb index 6ae51f9783b..a81f29d0d01 100644 --- a/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Terraform.latest.gitlab-ci.yml' do +RSpec.describe 'Terraform.latest.gitlab-ci.yml', feature_category: :continuous_integration do before do allow(Gitlab::Template::GitlabCiYmlTemplate).to receive(:excluded_patterns).and_return([]) end @@ -66,7 +66,12 @@ RSpec.describe 'Terraform.latest.gitlab-ci.yml' do it 'does not create a branch pipeline', :aggregate_failures do expect(branch_build_names).to be_empty - expect(branch_pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(branch_pipeline.errors.full_messages).to match_array( + [ + 'Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.' + ] + ) end end end diff --git a/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb index 157fd39f1cc..607db33f61a 100644 --- a/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb +++ b/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'ThemeKit.gitlab-ci.yml' do +RSpec.describe 'ThemeKit.gitlab-ci.yml', feature_category: :continuous_integration do before do allow(Gitlab::Template::GitlabCiYmlTemplate).to receive(:excluded_patterns).and_return([]) end @@ -52,7 +52,8 @@ RSpec.describe 'ThemeKit.gitlab-ci.yml' do it 'has no jobs' do expect(build_names).to be_empty - expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."]) + expect(pipeline.errors.full_messages).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end end diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb index 10b8f0065d9..4ee122cc607 100644 --- a/spec/lib/gitlab/ci/variables/collection_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Variables::Collection do +RSpec.describe Gitlab::Ci::Variables::Collection, feature_category: :pipeline_authoring do describe '.new' do it 'can be initialized with an array' do variable = { key: 'VAR', value: 'value', public: true, masked: false } @@ -295,69 +295,6 @@ RSpec.describe Gitlab::Ci::Variables::Collection do end end - describe '#expand_value' do - let(:collection) do - Gitlab::Ci::Variables::Collection.new - .append(key: 'CI_JOB_NAME', value: 'test-1') - .append(key: 'CI_BUILD_ID', value: '1') - .append(key: 'TEST1', value: 'test-3') - .append(key: 'FILEVAR1', value: 'file value 1', file: true) - end - - context 'table tests' do - using RSpec::Parameterized::TableSyntax - - where do - { - "empty value": { - value: '', - result: '' - }, - "simple expansions": { - value: 'key$TEST1-$CI_BUILD_ID', - result: 'keytest-3-1' - }, - "complex expansion": { - value: 'key${TEST1}-${CI_JOB_NAME}', - result: 'keytest-3-test-1' - }, - "missing variable not keeping original": { - value: 'key${MISSING_VAR}-${CI_JOB_NAME}', - result: 'key-test-1' - }, - "missing variable keeping original": { - value: 'key${MISSING_VAR}-${CI_JOB_NAME}', - result: 'key${MISSING_VAR}-test-1', - keep_undefined: true - }, - "escaped characters are kept intact": { - value: 'key-$TEST1-%%HOME%%-$${HOME}', - result: 'key-test-3-%%HOME%%-$${HOME}' - }, - "file variable with expand_file_refs: true": { - value: 'key-$FILEVAR1-$TEST1', - result: 'key-file value 1-test-3' - }, - "file variable with expand_file_refs: false": { - value: 'key-$FILEVAR1-$TEST1', - result: 'key-$FILEVAR1-test-3', - expand_file_refs: false - } - } - end - - with_them do - let(:options) { { keep_undefined: keep_undefined, expand_file_refs: expand_file_refs }.compact } - - subject(:expanded_result) { collection.expand_value(value, **options) } - - it 'matches expected expansion' do - is_expected.to eq(result) - end - end - end - end - describe '#sort_and_expand_all' do context 'table tests' do using RSpec::Parameterized::TableSyntax @@ -369,6 +306,14 @@ RSpec.describe Gitlab::Ci::Variables::Collection do keep_undefined: false, result: [] }, + "empty string": { + variables: [ + { key: 'variable', value: '' } + ], + result: [ + { key: 'variable', value: '' } + ] + }, "simple expansions": { variables: [ { key: 'variable', value: 'value' }, @@ -560,13 +505,42 @@ RSpec.describe Gitlab::Ci::Variables::Collection do { key: 'variable2', value: '$variable3' }, { key: 'variable3', value: 'key$variable$variable2' } ] + }, + "file variables with expand_file_refs: true": { + variables: [ + { key: 'file_var', value: 'secret content', file: true }, + { key: 'variable1', value: 'var one' }, + { key: 'variable2', value: 'var two $variable1 $file_var' } + ], + result: [ + { key: 'file_var', value: 'secret content' }, + { key: 'variable1', value: 'var one' }, + { key: 'variable2', value: 'var two var one secret content' } + ] + }, + "file variables with expand_file_refs: false": { + variables: [ + { key: 'file_var', value: 'secret content', file: true }, + { key: 'variable1', value: 'var one' }, + { key: 'variable2', value: 'var two $variable1 $file_var' } + ], + expand_file_refs: false, + result: [ + { key: 'file_var', value: 'secret content' }, + { key: 'variable1', value: 'var one' }, + { key: 'variable2', value: 'var two var one $file_var' } + ] } } end with_them do let(:collection) { Gitlab::Ci::Variables::Collection.new(variables) } - let(:options) { { keep_undefined: keep_undefined, expand_raw_refs: expand_raw_refs }.compact } + let(:options) do + { keep_undefined: keep_undefined, + expand_raw_refs: expand_raw_refs, + expand_file_refs: expand_file_refs }.compact + end subject(:expanded_result) { collection.sort_and_expand_all(**options) } @@ -585,43 +559,21 @@ RSpec.describe Gitlab::Ci::Variables::Collection do end end end + end - context 'with the file_variable_is_referenced_in_another_variable logging' do - let(:collection) do - Gitlab::Ci::Variables::Collection.new - .append(key: 'VAR1', value: 'test-1') - .append(key: 'VAR2', value: '$VAR1') - .append(key: 'VAR3', value: '$VAR1', raw: true) - .append(key: 'FILEVAR4', value: 'file-test-4', file: true) - .append(key: 'VAR5', value: '$FILEVAR4') - .append(key: 'VAR6', value: '$FILEVAR4', raw: true) - end - - subject(:sort_and_expand_all) { collection.sort_and_expand_all(project: project) } - - context 'when a project is not passed' do - let(:project) {} - - it 'does not log anything' do - expect(Gitlab::AppJsonLogger).not_to receive(:info) - - sort_and_expand_all - end - end + describe '#to_s' do + let(:variables) do + [ + { key: 'VAR', value: 'value', public: true }, + { key: 'VAR2', value: 'value2', public: false } + ] + end - context 'when a project is passed' do - let(:project) { create(:project) } + let(:errors) { 'circular variable reference detected' } + let(:collection) { Gitlab::Ci::Variables::Collection.new(variables, errors) } - it 'logs file_variable_is_referenced_in_another_variable once for VAR5' do - expect(Gitlab::AppJsonLogger).to receive(:info).with( - event: 'file_variable_is_referenced_in_another_variable', - project_id: project.id, - variable: 'FILEVAR4' - ).once + subject(:result) { collection.to_s } - sort_and_expand_all - end - end - end + it { is_expected.to eq("[\"VAR\", \"VAR2\"], @errors='circular variable reference detected'") } end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index ae98d2e0cad..b9f65ff749d 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -4,8 +4,9 @@ require 'spec_helper' module Gitlab module Ci - RSpec.describe YamlProcessor do + RSpec.describe YamlProcessor, feature_category: :pipeline_authoring do include StubRequests + include RepoHelpers subject(:processor) { described_class.new(config, user: nil).execute } @@ -1302,32 +1303,6 @@ module Gitlab 'VAR3' => { value: 'value3', raw: true } ) end - - context 'when the FF ci_raw_variables_in_yaml_config is disabled' do - before do - stub_feature_flags(ci_raw_variables_in_yaml_config: false) - end - - it 'returns variables without description and raw' do - expect(job_variables).to contain_exactly( - { key: 'VAR4', value: 'value4' }, - { key: 'VAR5', value: 'value5' }, - { key: 'VAR6', value: 'value6' } - ) - - expect(execute.root_variables).to contain_exactly( - { key: 'VAR1', value: 'value1' }, - { key: 'VAR2', value: 'value2' }, - { key: 'VAR3', value: 'value3' } - ) - - expect(execute.root_variables_with_prefill_data).to eq( - 'VAR1' => { value: 'value1' }, - 'VAR2' => { value: 'value2', description: 'description2' }, - 'VAR3' => { value: 'value3' } - ) - end - end end end @@ -1505,9 +1480,19 @@ module Gitlab let(:opts) { { project: project, sha: project.commit.sha } } context "when the included internal file is present" do - before do - expect(project.repository).to receive(:blob_data_at) - .and_return(YAML.dump({ job1: { script: 'hello' } })) + let(:project_files) do + { + 'local.gitlab-ci.yml' => <<~YAML + job1: + script: hello + YAML + } + end + + around do |example| + create_and_delete_files(project, project_files) do + example.run + end end it { is_expected.to be_valid } @@ -1699,7 +1684,8 @@ module Gitlab untracked: true, key: 'key', policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false ]) end @@ -1723,7 +1709,8 @@ module Gitlab untracked: true, key: { files: ['file'] }, policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false ]) end @@ -1749,14 +1736,16 @@ module Gitlab untracked: true, key: 'keya', policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false }, { paths: ['logs/', 'binaries/'], untracked: true, key: 'key', policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false } ] ) @@ -1783,7 +1772,8 @@ module Gitlab untracked: true, key: { files: ['file'] }, policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false ]) end @@ -1808,7 +1798,8 @@ module Gitlab untracked: true, key: { files: ['file'], prefix: 'prefix' }, policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false ]) end @@ -1831,7 +1822,8 @@ module Gitlab untracked: false, key: 'local', policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false ]) end end |