summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/ci
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/ci')
-rw-r--r--spec/lib/gitlab/ci/ansi2json/style_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb35
-rw-r--r--spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/lint_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb61
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb159
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb201
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb139
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb109
-rw-r--r--spec/lib/gitlab/ci/reports/codequality_reports_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/reports/test_failure_history_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/runner_instructions_spec.rb116
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/composite_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/trace_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/variables/helpers_spec.rb46
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/result_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb139
33 files changed, 1027 insertions, 259 deletions
diff --git a/spec/lib/gitlab/ci/ansi2json/style_spec.rb b/spec/lib/gitlab/ci/ansi2json/style_spec.rb
index ff70ff69aaa..87085950a9f 100644
--- a/spec/lib/gitlab/ci/ansi2json/style_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/style_spec.rb
@@ -160,9 +160,9 @@ RSpec.describe Gitlab::Ci::Ansi2json::Style do
with_them do
it 'change the style' do
style = described_class.new
- style.update(initial_state)
+ style.update(initial_state) # rubocop:disable Rails/SaveBang
- style.update(ansi_commands)
+ style.update(ansi_commands) # rubocop:disable Rails/SaveBang
expect(style.to_s).to eq(result)
end
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index 179578fe0a8..d294eca7f15 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -107,6 +107,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
stage: 'test',
only: { refs: %w[branches tags] },
variables: {},
+ job_variables: {},
+ root_variables_inheritance: true,
scheduling_type: :stage)
end
end
@@ -130,6 +132,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
stage: 'test',
only: { refs: %w[branches tags] },
variables: {},
+ job_variables: {},
+ root_variables_inheritance: true,
scheduling_type: :stage)
end
end
@@ -284,6 +288,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
parallel: { matrix: [{ 'PROVIDER' => ['aws'], 'STACK' => %w(monitoring app1) },
{ 'PROVIDER' => ['gcp'], 'STACK' => %w(data) }] },
variables: {},
+ job_variables: {},
+ root_variables_inheritance: true,
scheduling_type: :stage
)
end
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index 064990667d5..cec1c97085b 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -13,6 +13,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
describe '#valid?' do
+ context 'with an empty hash as cache' do
+ let(:config) { {} }
+
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
context 'when configuration is valid with a single cache' do
let(:config) { { key: 'key', paths: ["logs/"], untracked: true } }
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index a4167003987..ffcd029172a 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -663,6 +663,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
after_script: %w[cleanup],
only: { refs: %w[branches tags] },
variables: {},
+ job_variables: {},
+ root_variables_inheritance: true,
scheduling_type: :stage)
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index ac6b589ec6b..cb73044b62b 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -100,6 +100,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Jobs do
stage: 'test',
trigger: { project: 'my/project' },
variables: {},
+ job_variables: {},
+ root_variables_inheritance: true,
scheduling_type: :stage
},
regular_job: {
@@ -109,6 +111,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Jobs do
script: ['something'],
stage: 'test',
variables: {},
+ job_variables: {},
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index 04e80450263..016d59e98b9 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -382,7 +382,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
context 'with only job variables' do
it 'does return defined variables' do
expect(entry.value).to include(
- variables: { 'A' => 'job', 'B' => 'job' }
+ variables: { 'A' => 'job', 'B' => 'job' },
+ job_variables: { 'A' => 'job', 'B' => 'job' },
+ root_variables_inheritance: true
)
end
end
@@ -394,9 +396,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
).value
end
- it 'does return all variables and overwrite them' do
+ it 'does return job and root variables' do
expect(entry.value).to include(
- variables: { 'A' => 'job', 'B' => 'job', 'C' => 'root', 'D' => 'root' }
+ variables: { 'A' => 'job', 'B' => 'job', 'C' => 'root', 'D' => 'root' },
+ job_variables: { 'A' => 'job', 'B' => 'job' },
+ root_variables_inheritance: true
)
end
@@ -408,9 +412,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
}
end
- it 'does return only job variables' do
+ it 'does return job and root variables' do
expect(entry.value).to include(
- variables: { 'A' => 'job', 'B' => 'job' }
+ variables: { 'A' => 'job', 'B' => 'job' },
+ job_variables: { 'A' => 'job', 'B' => 'job' },
+ root_variables_inheritance: false
)
end
end
@@ -423,9 +429,11 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
}
end
- it 'does return only job variables' do
+ it 'does return job and root variables' do
expect(entry.value).to include(
- variables: { 'A' => 'job', 'B' => 'job', 'D' => 'root' }
+ variables: { 'A' => 'job', 'B' => 'job', 'D' => 'root' },
+ job_variables: { 'A' => 'job', 'B' => 'job' },
+ root_variables_inheritance: ['D']
)
end
end
@@ -493,7 +501,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
name: :rspec,
stage: 'test',
only: { refs: %w[branches tags] },
- variables: {}
+ variables: {},
+ job_variables: {},
+ root_variables_inheritance: true
)
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 7b38c21788f..041eb748fc9 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -133,6 +133,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
+ job_variables: {},
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -147,6 +149,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
+ job_variables: {},
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -163,6 +167,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }],
only: { refs: %w(branches tags) },
variables: { 'VAR' => 'job', 'VAR2' => 'val 2' },
+ job_variables: { 'VAR' => 'job' },
+ root_variables_inheritance: true,
after_script: [],
ignore: false,
scheduling_type: :stage }
@@ -188,6 +194,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
+ job_variables: {},
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -202,6 +210,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'root', 'VAR2' => 'val 2' },
+ job_variables: {},
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -218,6 +228,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' },
only: { refs: %w(branches tags) },
variables: { 'VAR' => 'job', 'VAR2' => 'val 2' },
+ job_variables: { 'VAR' => 'job' },
+ root_variables_inheritance: true,
after_script: [],
ignore: false,
scheduling_type: :stage }
@@ -267,6 +279,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'root' },
+ job_variables: {},
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -279,6 +293,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'job' },
+ job_variables: { 'VAR' => 'job' },
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -311,6 +327,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
variables: { 'VAR' => 'root' },
+ job_variables: {},
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
@@ -323,6 +341,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
variables: { 'VAR' => 'job' },
+ job_variables: { 'VAR' => 'job' },
+ root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
only: { refs: %w[branches tags] },
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index 99f546ceb37..e5b008a482e 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -324,5 +324,39 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
end
end
end
+
+ context 'when local file path has wildcard' do
+ let(:project) { create(:project, :repository) }
+
+ let(:values) do
+ { include: 'myfolder/*.yml' }
+ end
+
+ before do
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:search_files_by_wildcard_path).with('myfolder/*.yml', '123456') do
+ ['myfolder/file1.yml', 'myfolder/file2.yml']
+ end
+ end
+ end
+
+ it 'includes the matched local files' do
+ expect(subject).to contain_exactly(an_instance_of(Gitlab::Ci::Config::External::File::Local),
+ an_instance_of(Gitlab::Ci::Config::External::File::Local))
+
+ expect(subject.map(&:location)).to contain_exactly('myfolder/file1.yml', 'myfolder/file2.yml')
+ end
+
+ context 'when the FF ci_wildcard_file_paths is disabled' do
+ before do
+ stub_feature_flags(ci_wildcard_file_paths: false)
+ end
+
+ it 'cannot find any file returns an error message' do
+ expect(subject).to contain_exactly(an_instance_of(Gitlab::Ci::Config::External::File::Local))
+ expect(subject[0].errors).to eq(['Local file `myfolder/*.yml` does not exist!'])
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index d2d7116bb12..d657c3e943f 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -366,5 +366,40 @@ RSpec.describe Gitlab::Ci::Config::External::Processor do
expect(output.keys).to match_array([:image, :my_build, :my_test])
end
end
+
+ context 'when local file path has wildcard' do
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:values) do
+ { include: 'myfolder/*.yml', image: 'ruby:2.7' }
+ end
+
+ before do
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:search_files_by_wildcard_path).with('myfolder/*.yml', sha) do
+ ['myfolder/file1.yml', 'myfolder/file2.yml']
+ end
+
+ allow(repository).to receive(:blob_data_at).with(sha, 'myfolder/file1.yml') do
+ <<~HEREDOC
+ my_build:
+ script: echo Hello World
+ HEREDOC
+ end
+
+ allow(repository).to receive(:blob_data_at).with(sha, 'myfolder/file2.yml') do
+ <<~HEREDOC
+ my_test:
+ script: echo Hello World
+ HEREDOC
+ end
+ end
+ end
+
+ it 'fetches the matched files' do
+ output = processor.perform
+ expect(output.keys).to match_array([:image, :my_build, :my_test])
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb b/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb
index fbf86927bd9..e5f0341c5fe 100644
--- a/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb
+++ b/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb
@@ -1,8 +1,12 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'support/helpers/stubbed_feature'
+require 'support/helpers/stub_feature_flags'
RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
+ include StubFeatureFlags
+
describe '.applies_to?' do
subject { described_class.applies_to?(config) }
@@ -49,6 +53,10 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
variables: {
'PROVIDER' => 'aws',
'STACK' => 'app1'
+ },
+ job_variables: {
+ 'PROVIDER' => 'aws',
+ 'STACK' => 'app1'
}
},
{
@@ -58,6 +66,10 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
variables: {
'PROVIDER' => 'aws',
'STACK' => 'app2'
+ },
+ job_variables: {
+ 'PROVIDER' => 'aws',
+ 'STACK' => 'app2'
}
},
{
@@ -67,6 +79,10 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
variables: {
'PROVIDER' => 'ovh',
'STACK' => 'app'
+ },
+ job_variables: {
+ 'PROVIDER' => 'ovh',
+ 'STACK' => 'app'
}
},
{
@@ -76,6 +92,10 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
variables: {
'PROVIDER' => 'gcp',
'STACK' => 'app'
+ },
+ job_variables: {
+ 'PROVIDER' => 'gcp',
+ 'STACK' => 'app'
}
}
]
diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb
index 67324c09d86..aaa3a7a8b9d 100644
--- a/spec/lib/gitlab/ci/lint_spec.rb
+++ b/spec/lib/gitlab/ci/lint_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe Gitlab::Ci::Lint do
it 'sets merged_config' do
root_config = YAML.safe_load(content, [Symbol])
included_config = YAML.safe_load(included_content, [Symbol])
- expected_config = included_config.merge(root_config).except(:include)
+ expected_config = included_config.merge(root_config).except(:include).deep_stringify_keys
expect(subject.merged_yaml).to eq(expected_config.to_yaml)
end
diff --git a/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb b/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb
index c6b8cf2a985..6a08e8f0b7f 100644
--- a/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb
@@ -131,7 +131,6 @@ RSpec.describe Gitlab::Ci::Parsers::Codequality::CodeClimate do
expect { parse }.not_to raise_error
expect(codequality_report.degradations_count).to eq(0)
- expect(codequality_report.error_message).to eq("Invalid degradation format: The property '#/' did not contain a required property of 'location'")
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index 9ca5aeeea58..900dfec38e2 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -321,4 +321,25 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do
it { is_expected.to be_falsey }
end
end
+
+ describe '#increment_pipeline_failure_reason_counter' do
+ let(:command) { described_class.new }
+ let(:reason) { :size_limit_exceeded }
+
+ subject { command.increment_pipeline_failure_reason_counter(reason) }
+
+ it 'increments the error metric' do
+ counter = Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc')
+ expect { subject }.to change { counter.get(reason: reason.to_s) }.by(1)
+ end
+
+ context 'when the reason is nil' do
+ let(:reason) { nil }
+
+ it 'increments the error metric with unknown_failure' do
+ counter = Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc')
+ expect { subject }.to change { counter.get(reason: 'unknown_failure') }.by(1)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
index 4ae51ac8bf9..e30a78546af 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb
@@ -16,8 +16,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
describe '#perform!' do
context 'when pipeline has been skipped by workflow configuration' do
before do
- allow(step).to receive(:workflow_passed?)
- .and_return(false)
+ allow(step).to receive(:workflow_rules_result)
+ .and_return(
+ double(pass?: false, variables: {})
+ )
step.perform!
end
@@ -33,12 +35,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
it 'attaches an error to the pipeline' do
expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.')
end
+
+ it 'saves workflow_rules_result' do
+ expect(command.workflow_rules_result.variables).to eq({})
+ end
end
context 'when pipeline has not been skipped by workflow configuration' do
before do
- allow(step).to receive(:workflow_passed?)
- .and_return(true)
+ allow(step).to receive(:workflow_rules_result)
+ .and_return(
+ double(pass?: true, variables: { 'VAR1' => 'val2' })
+ )
step.perform!
end
@@ -55,6 +63,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do
it 'attaches no errors' do
expect(pipeline.errors).to be_empty
end
+
+ it 'saves workflow_rules_result' do
+ expect(command.workflow_rules_result.variables).to eq({ 'VAR1' => 'val2' })
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb
new file mode 100644
index 00000000000..bcea6462790
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers do
+ let(:helper_class) do
+ Class.new do
+ include Gitlab::Ci::Pipeline::Chain::Helpers
+
+ attr_accessor :pipeline, :command
+
+ def initialize(pipeline, command)
+ self.pipeline = pipeline
+ self.command = command
+ end
+ end
+ end
+
+ subject(:helper) { helper_class.new(pipeline, command) }
+
+ let(:pipeline) { build(:ci_empty_pipeline) }
+ let(:command) { double(save_incompleted: true) }
+ let(:message) { 'message' }
+
+ describe '.error' do
+ shared_examples 'error function' do
+ specify do
+ expect(pipeline).to receive(:drop!).with(drop_reason).and_call_original
+ expect(pipeline).to receive(:add_error_message).with(message).and_call_original
+ expect(pipeline).to receive(:ensure_project_iid!).twice.and_call_original
+
+ subject.error(message, config_error: config_error, drop_reason: drop_reason)
+
+ expect(pipeline.yaml_errors).to eq(yaml_error)
+ expect(pipeline.errors[:base]).to include(message)
+ end
+ end
+
+ context 'when given a drop reason' do
+ context 'when config error is true' do
+ context 'sets the yaml error and overrides the drop reason' do
+ let(:drop_reason) { :config_error }
+ let(:config_error) { true }
+ let(:yaml_error) { message }
+
+ it_behaves_like "error function"
+ end
+ end
+
+ context 'when config error is false' do
+ context 'does not set the yaml error or override the drop reason' do
+ let(:drop_reason) { :size_limit_exceeded }
+ let(:config_error) { false }
+ let(:yaml_error) { nil }
+
+ it_behaves_like "error function"
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb
index 78363be7f36..23cdec61bb3 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Deployments do
let(:save_incompleted) { false }
let(:command) do
- double(:command,
+ Gitlab::Ci::Pipeline::Chain::Command.new(
project: project,
pipeline_seed: pipeline_seed,
save_incompleted: save_incompleted
@@ -49,6 +49,11 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Deployments do
expect(pipeline.deployments_limit_exceeded?).to be true
end
+
+ it 'calls increment_pipeline_failure_reason_counter' do
+ counter = Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc')
+ expect { perform }.to change { counter.get(reason: 'deployments_limit_exceeded') }.by(1)
+ end
end
context 'when not saving incomplete pipelines' do
@@ -71,6 +76,12 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Deployments do
expect(pipeline.errors.messages).to include(base: ['Pipeline has too many deployments! Requested 2, but the limit is 1.'])
end
+
+ it 'increments the error metric' do
+ expect(command).to receive(:increment_pipeline_failure_reason_counter).with(:deployments_limit_exceeded)
+
+ perform
+ end
end
it 'logs the error' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb
new file mode 100644
index 00000000000..3885cea2d1b
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/pipeline/process_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Pipeline::Chain::Pipeline::Process do
+ let_it_be(:project) { build(:project) }
+ let_it_be(:user) { build(:user) }
+ let_it_be(:pipeline) { build(:ci_pipeline, project: project, id: 42) }
+
+ let_it_be(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(project: project, current_user: user)
+ end
+
+ let(:step) { described_class.new(pipeline, command) }
+
+ describe '#perform!' do
+ subject(:perform) { step.perform! }
+
+ it 'schedules a job to process the pipeline' do
+ expect(Ci::InitialPipelineProcessWorker)
+ .to receive(:perform_async)
+ .with(42)
+
+ perform
+ end
+ end
+
+ describe '#break?' do
+ it { expect(step.break?).to be_falsey }
+ 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 5506b079d0f..62de4d2e96d 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
[
Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules.new(pipeline, command),
Gitlab::Ci::Pipeline::Chain::SeedBlock.new(pipeline, command),
Gitlab::Ci::Pipeline::Chain::Seed.new(pipeline, command)
]
@@ -95,6 +96,11 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
it 'wastes pipeline iid' do
expect(InternalId.ci_pipelines.where(project_id: project.id).last.last_value).to be > 0
end
+
+ it 'increments the error metric' do
+ counter = Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc')
+ expect { run_chain }.to change { counter.get(reason: 'unknown_failure') }.by(1)
+ end
end
describe 'pipeline protect' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
index 80013cab6ee..264076859cb 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
@@ -3,24 +3,16 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user, developer_projects: [project]) }
- let(:seeds_block) { }
-
- let(:command) do
- Gitlab::Ci::Pipeline::Chain::Command.new(
- project: project,
- current_user: user,
- origin_ref: 'master',
- seeds_block: seeds_block)
- end
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user, developer_projects: [project]) }
+ let(:seeds_block) { }
+ let(:command) { initialize_command }
let(:pipeline) { build(:ci_pipeline, project: project) }
describe '#perform!' do
before do
stub_ci_pipeline_yaml_file(YAML.dump(config))
- run_chain
end
let(:config) do
@@ -28,23 +20,25 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
subject(:run_chain) do
- [
- Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
- Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command)
- ].map(&:perform!)
-
- described_class.new(pipeline, command).perform!
+ run_previous_chain(pipeline, command)
+ perform_seed(pipeline, command)
end
it 'allocates next IID' do
+ run_chain
+
expect(pipeline.iid).to be_present
end
it 'ensures ci_ref' do
+ run_chain
+
expect(pipeline.ci_ref).to be_present
end
it 'sets the seeds in the command object' do
+ run_chain
+
expect(command.pipeline_seed).to be_a(Gitlab::Ci::Pipeline::Seed::Pipeline)
expect(command.pipeline_seed.size).to eq 1
end
@@ -59,6 +53,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'correctly fabricates stages and builds' do
+ run_chain
+
seed = command.pipeline_seed
expect(seed.stages.size).to eq 2
@@ -84,6 +80,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'returns pipeline seed with jobs only assigned to master' do
+ run_chain
+
seed = command.pipeline_seed
expect(seed.size).to eq 1
@@ -103,6 +101,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'returns pipeline seed with jobs only assigned to schedules' do
+ run_chain
+
seed = command.pipeline_seed
expect(seed.size).to eq 1
@@ -130,6 +130,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
let(:pipeline) { build(:ci_pipeline, project: project) }
it 'returns seeds for kubernetes dependent job' do
+ run_chain
+
seed = command.pipeline_seed
expect(seed.size).to eq 2
@@ -141,6 +143,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
context 'when kubernetes is not active' do
it 'does not return seeds for kubernetes dependent job' do
+ run_chain
+
seed = command.pipeline_seed
expect(seed.size).to eq 1
@@ -158,6 +162,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'returns stage seeds only when variables expression is truthy' do
+ run_chain
+
seed = command.pipeline_seed
expect(seed.size).to eq 1
@@ -171,8 +177,125 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
it 'does not execute the block' do
+ run_chain
+
expect(pipeline.variables.size).to eq(0)
end
end
+
+ describe '#root_variables' do
+ let(:config) do
+ {
+ variables: { VAR1: 'var 1' },
+ workflow: {
+ rules: [{ if: '$CI_PIPELINE_SOURCE',
+ variables: { VAR1: 'overridden var 1' } },
+ { when: 'always' }]
+ },
+ rspec: { script: 'rake' }
+ }
+ end
+
+ let(:rspec_variables) { command.pipeline_seed.stages[0].statuses[0].variables.to_hash }
+
+ it 'sends root variable with overridden by rules' do
+ run_chain
+
+ expect(rspec_variables['VAR1']).to eq('overridden var 1')
+ end
+
+ context 'when the FF ci_workflow_rules_variables is disabled' do
+ before do
+ stub_feature_flags(ci_workflow_rules_variables: false)
+ end
+
+ it 'sends root variable' do
+ run_chain
+
+ expect(rspec_variables['VAR1']).to eq('var 1')
+ end
+ end
+ end
+
+ context 'N+1 queries' do
+ it 'avoids N+1 queries when calculating variables of jobs' do
+ pipeline1, command1 = prepare_pipeline1
+ pipeline2, command2 = prepare_pipeline2
+
+ control = ActiveRecord::QueryRecorder.new do
+ perform_seed(pipeline1, command1)
+ end
+
+ expect { perform_seed(pipeline2, command2) }.not_to exceed_query_limit(
+ control.count + expected_extra_queries
+ )
+ end
+
+ private
+
+ def prepare_pipeline1
+ config1 = { build: { stage: 'build', script: 'build' } }
+ stub_ci_pipeline_yaml_file(YAML.dump(config1))
+ pipeline1 = build(:ci_pipeline, project: project)
+ command1 = initialize_command
+
+ run_previous_chain(pipeline1, command1)
+
+ [pipeline1, command1]
+ end
+
+ def prepare_pipeline2
+ config2 = { build1: { stage: 'build', script: 'build1' },
+ build2: { stage: 'build', script: 'build2' },
+ test: { stage: 'build', script: 'test' } }
+ stub_ci_pipeline_yaml_file(YAML.dump(config2))
+ pipeline2 = build(:ci_pipeline, project: project)
+ command2 = initialize_command
+
+ run_previous_chain(pipeline2, command2)
+
+ [pipeline2, command2]
+ end
+
+ def expected_extra_queries
+ extra_jobs = 2
+ non_handled_sql_queries = 3
+
+ # 1. Ci::Build Load () SELECT "ci_builds".* FROM "ci_builds"
+ # WHERE "ci_builds"."type" = 'Ci::Build'
+ # AND "ci_builds"."commit_id" IS NULL
+ # AND ("ci_builds"."retried" = FALSE OR "ci_builds"."retried" IS NULL)
+ # AND (stage_idx < 1)
+ # 2. Ci::InstanceVariable Load => `Ci::InstanceVariable#cached_data` => already cached with `fetch_memory_cache`
+ # 3. Ci::Variable Load => `Project#ci_variables_for` => already cached with `Gitlab::SafeRequestStore`
+
+ extra_jobs * non_handled_sql_queries
+ end
+ end
+
+ private
+
+ def run_previous_chain(pipeline, command)
+ [
+ Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules.new(pipeline, command)
+ ].map(&:perform!)
+ end
+
+ def perform_seed(pipeline, command)
+ described_class.new(pipeline, command).perform!
+ end
+ end
+
+ private
+
+ def initialize_command
+ Gitlab::Ci::Pipeline::Chain::Command.new(
+ project: project,
+ current_user: user,
+ origin_ref: 'master',
+ seeds_block: seeds_block
+ )
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index e55281f9705..caf3a053c4e 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
let(:pipeline) { build(:ci_empty_pipeline, user: user, project: project) }
let!(:step) { described_class.new(pipeline, command) }
@@ -42,6 +42,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
let(:save_incompleted) { true }
+ let(:dot_com) { true }
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project, current_user: user, yaml_processor_result: yaml_processor_result, save_incompleted: save_incompleted
@@ -51,11 +52,79 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
describe '#perform!' do
subject(:perform!) { step.perform! }
- context 'when validation returns true' do
+ let(:validation_service_url) { 'https://validation-service.external/' }
+
+ before do
+ stub_env('EXTERNAL_VALIDATION_SERVICE_URL', validation_service_url)
+ allow(Gitlab).to receive(:com?).and_return(dot_com)
+ allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('correlation-id')
+ end
+
+ context 'with configuration values in ApplicationSetting' do
+ let(:alternate_validation_service_url) { 'https://alternate-validation-service.external/' }
+ let(:validation_service_token) { 'SECURE_TOKEN' }
+ let(:shorter_timeout) { described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT - 1 }
+
before do
- allow(step).to receive(:validate_external).and_return(true)
+ stub_env('EXTERNAL_VALIDATION_SERVICE_TOKEN', 'TOKEN_IN_ENV')
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:external_pipeline_validation_service_timeout).and_return(shorter_timeout)
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:external_pipeline_validation_service_token).and_return(validation_service_token)
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:external_pipeline_validation_service_url).and_return(alternate_validation_service_url)
+ end
+
+ it 'uses those values rather than env vars or defaults' do
+ expect(::Gitlab::HTTP).to receive(:post) do |url, params|
+ expect(url).to eq(alternate_validation_service_url)
+ expect(params[:timeout]).to eq(shorter_timeout)
+ expect(params[:headers]).to include('X-Gitlab-Token' => validation_service_token)
+ expect(params[:timeout]).to eq(shorter_timeout)
+ end
+
+ perform!
+ end
+ end
+
+ it 'respects the defined payload schema' do
+ expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
+ expect(params[:body]).to match_schema('/external_validation')
+ expect(params[:timeout]).to eq(described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT)
+ expect(params[:headers]).to eq({ 'X-Gitlab-Correlation-id' => 'correlation-id' })
+ end
+
+ perform!
+ end
+
+ context 'with EXTERNAL_VALIDATION_SERVICE_TIMEOUT defined' do
+ before do
+ stub_env('EXTERNAL_VALIDATION_SERVICE_TIMEOUT', validation_service_timeout)
+ end
+
+ context 'with valid value' do
+ let(:validation_service_timeout) { '1' }
+
+ it 'uses defined timeout' do
+ expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
+ expect(params[:timeout]).to eq(1)
+ end
+
+ perform!
+ end
+ end
+
+ context 'with invalid value' do
+ let(:validation_service_timeout) { '??' }
+
+ it 'uses default timeout' do
+ expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
+ expect(params[:timeout]).to eq(described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT)
+ end
+
+ perform!
+ end
end
+ end
+ shared_examples 'successful external authorization' do
it 'does not drop the pipeline' do
perform!
@@ -76,9 +145,117 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
end
- context 'when validation return false' do
+ context 'when EXTERNAL_VALIDATION_SERVICE_TOKEN is set' do
+ before do
+ stub_env('EXTERNAL_VALIDATION_SERVICE_TOKEN', '123')
+ end
+
+ it 'passes token in X-Gitlab-Token header' do
+ expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
+ expect(params[:headers]).to include({ 'X-Gitlab-Token' => '123' })
+ end
+
+ perform!
+ end
+ end
+
+ context 'when validation returns 200 OK' do
+ before do
+ stub_request(:post, validation_service_url).to_return(status: 200, body: "{}")
+ end
+
+ it_behaves_like 'successful external authorization'
+ end
+
+ context 'when validation returns 404 Not Found' do
before do
- allow(step).to receive(:validate_external).and_return(false)
+ stub_request(:post, validation_service_url).to_return(status: 404, body: "{}")
+ end
+
+ it_behaves_like 'successful external authorization'
+ end
+
+ context 'when validation returns 500 Internal Server Error' do
+ before do
+ stub_request(:post, validation_service_url).to_return(status: 500, body: "{}")
+ end
+
+ it_behaves_like 'successful external authorization'
+ end
+
+ context 'when validation raises exceptions' do
+ before do
+ stub_request(:post, validation_service_url).to_raise(Net::OpenTimeout)
+ end
+
+ it_behaves_like 'successful external authorization'
+
+ it 'logs exceptions' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ .with(instance_of(Net::OpenTimeout), { project_id: project.id })
+
+ perform!
+ end
+ end
+
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(ci_external_validation_service: false)
+ stub_request(:post, validation_service_url)
+ end
+
+ it 'does not drop the pipeline' do
+ perform!
+
+ expect(pipeline.status).not_to eq('failed')
+ expect(pipeline.errors).to be_empty
+ end
+
+ it 'does not break the chain' do
+ perform!
+
+ expect(step.break?).to be false
+ end
+
+ it 'does not make requests' do
+ perform!
+
+ expect(WebMock).not_to have_requested(:post, validation_service_url)
+ end
+ end
+
+ context 'when not on .com' do
+ let(:dot_com) { false }
+
+ before do
+ stub_feature_flags(ci_external_validation_service: false)
+ stub_request(:post, validation_service_url).to_return(status: 404, body: "{}")
+ end
+
+ it 'drops the pipeline' do
+ perform!
+
+ expect(pipeline.status).to eq('failed')
+ expect(pipeline).to be_persisted
+ expect(pipeline.errors.to_a).to include('External validation failed')
+ end
+
+ it 'breaks the chain' do
+ perform!
+
+ expect(step.break?).to be true
+ end
+
+ it 'logs the authorization' do
+ expect(Gitlab::AppLogger).to receive(:info).with(message: 'Pipeline not authorized', project_id: project.id, user_id: user.id)
+
+ perform!
+ end
+ end
+
+ context 'when validation returns 406 Not Acceptable' do
+ before do
+ stub_request(:post, validation_service_url).to_return(status: 406, body: "{}")
end
it 'drops the pipeline' do
@@ -126,16 +303,4 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
end
end
-
- describe '#validation_service_payload' do
- subject(:validation_service_payload) { step.send(:validation_service_payload, pipeline, command.yaml_processor_result.stages_attributes) }
-
- it 'respects the defined schema' do
- expect(validation_service_payload).to match_schema('/external_validation')
- end
-
- it 'does not fire sql queries' do
- expect { validation_service_payload }.not_to exceed_query_limit(1)
- end
- end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 7ec6949f852..f97935feb86 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -6,10 +6,12 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:head_sha) { project.repository.head_commit.id }
let(:pipeline) { build(:ci_empty_pipeline, project: project, sha: head_sha) }
+ let(:root_variables) { [] }
+ let(:seed_context) { double(pipeline: pipeline, root_variables: root_variables) }
let(:attributes) { { name: 'rspec', ref: 'master', scheduling_type: :stage } }
let(:previous_stages) { [] }
- let(:seed_build) { described_class.new(pipeline, attributes, previous_stages) }
+ let(:seed_build) { described_class.new(seed_context, attributes, previous_stages) }
describe '#attributes' do
subject { seed_build.attributes }
@@ -75,8 +77,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
let(:attributes) do
{ name: 'rspec',
ref: 'master',
- yaml_variables: [{ key: 'VAR1', value: 'var 1', public: true },
- { key: 'VAR2', value: 'var 2', public: true }],
+ job_variables: [{ key: 'VAR1', value: 'var 1', public: true },
+ { key: 'VAR2', value: 'var 2', public: true }],
rules: [{ if: '$VAR == null', variables: { VAR1: 'new var 1', VAR3: 'var 3' } }] }
end
@@ -301,6 +303,133 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
it { is_expected.to match a_hash_including(options: { allow_failure_criteria: nil }) }
end
end
+
+ context 'with workflow:rules:[variables:]' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ yaml_variables: [{ key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true }],
+ job_variables: [{ key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true }],
+ root_variables_inheritance: root_variables_inheritance }
+ end
+
+ context 'when the pipeline has variables' do
+ let(:root_variables) do
+ [{ key: 'VAR1', value: 'var overridden pipeline 1', public: true },
+ { key: 'VAR2', value: 'var pipeline 2', public: true },
+ { key: 'VAR3', value: 'var pipeline 3', public: true },
+ { key: 'VAR4', value: 'new var pipeline 4', public: true }]
+ end
+
+ context 'when root_variables_inheritance is true' do
+ let(:root_variables_inheritance) { true }
+
+ it 'returns calculated yaml variables' do
+ expect(subject[:yaml_variables]).to match_array(
+ [{ key: 'VAR1', value: 'var overridden pipeline 1', public: true },
+ { key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true },
+ { key: 'VAR4', value: 'new var pipeline 4', public: true }]
+ )
+ end
+
+ context 'when FF ci_workflow_rules_variables is disabled' do
+ before do
+ stub_feature_flags(ci_workflow_rules_variables: false)
+ end
+
+ it 'returns existing yaml variables' do
+ expect(subject[:yaml_variables]).to match_array(
+ [{ key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true }]
+ )
+ end
+ end
+ end
+
+ context 'when root_variables_inheritance is false' do
+ let(:root_variables_inheritance) { false }
+
+ it 'returns job variables' do
+ expect(subject[:yaml_variables]).to match_array(
+ [{ key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true }]
+ )
+ end
+ end
+
+ context 'when root_variables_inheritance is an array' do
+ let(:root_variables_inheritance) { %w(VAR1 VAR2 VAR3) }
+
+ it 'returns calculated yaml variables' do
+ expect(subject[:yaml_variables]).to match_array(
+ [{ key: 'VAR1', value: 'var overridden pipeline 1', public: true },
+ { key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true }]
+ )
+ end
+ end
+ end
+
+ context 'when the pipeline has not a variable' do
+ let(:root_variables_inheritance) { true }
+
+ it 'returns seed yaml variables' do
+ expect(subject[:yaml_variables]).to match_array(
+ [{ key: 'VAR2', value: 'var 2', public: true },
+ { key: 'VAR3', value: 'var 3', public: true }])
+ end
+ end
+ end
+
+ context 'when the job rule depends on variables' do
+ let(:attributes) do
+ { name: 'rspec',
+ ref: 'master',
+ yaml_variables: [{ key: 'VAR1', value: 'var 1', public: true }],
+ job_variables: [{ key: 'VAR1', value: 'var 1', public: true }],
+ root_variables_inheritance: root_variables_inheritance,
+ rules: rules }
+ end
+
+ let(:root_variables_inheritance) { true }
+
+ context 'when the rules use job variables' do
+ let(:rules) do
+ [{ if: '$VAR1 == "var 1"', variables: { VAR1: 'overridden var 1', VAR2: 'new var 2' } }]
+ end
+
+ it 'recalculates the variables' do
+ expect(subject[:yaml_variables]).to contain_exactly({ key: 'VAR1', value: 'overridden var 1', public: true },
+ { key: 'VAR2', value: 'new var 2', public: true })
+ end
+ end
+
+ context 'when the rules use root variables' do
+ let(:root_variables) do
+ [{ key: 'VAR2', value: 'var pipeline 2', public: true }]
+ end
+
+ let(:rules) do
+ [{ if: '$VAR2 == "var pipeline 2"', variables: { VAR1: 'overridden var 1', VAR2: 'overridden var 2' } }]
+ end
+
+ it 'recalculates the variables' do
+ expect(subject[:yaml_variables]).to contain_exactly({ key: 'VAR1', value: 'overridden var 1', public: true },
+ { key: 'VAR2', value: 'overridden var 2', public: true })
+ end
+
+ context 'when the root_variables_inheritance is false' do
+ let(:root_variables_inheritance) { false }
+
+ it 'does not recalculate the variables' do
+ expect(subject[:yaml_variables]).to contain_exactly({ key: 'VAR1', value: 'var 1', public: true })
+ end
+ end
+ end
+ end
end
describe '#bridge?' do
@@ -377,7 +506,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
it 'does not have environment' do
expect(subject).not_to be_has_environment
expect(subject.environment).to be_nil
- expect(subject.metadata).to be_nil
+ expect(subject.metadata&.expanded_environment_name).to be_nil
expect(Environment.exists?(name: expected_environment_name)).to eq(false)
end
end
@@ -1080,7 +1209,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
end
let(:stage_seed) do
- Gitlab::Ci::Pipeline::Seed::Stage.new(pipeline, stage_attributes, [])
+ Gitlab::Ci::Pipeline::Seed::Stage.new(seed_context, stage_attributes, [])
end
let(:previous_stages) { [stage_seed] }
diff --git a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb
index 860b07647bd..21be8660def 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb
@@ -6,6 +6,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:seed_context) { double(pipeline: pipeline, root_variables: []) }
+
let(:stages_attributes) do
[
{
@@ -29,7 +31,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do
end
subject(:seed) do
- described_class.new(pipeline, stages_attributes)
+ described_class.new(seed_context, stages_attributes)
end
describe '#stages' do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
index 4b9db9fa6c6..5b04d2abd88 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Stage do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:previous_stages) { [] }
+ let(:seed_context) { double(pipeline: pipeline, root_variables: []) }
let(:attributes) do
{ name: 'test',
@@ -16,7 +17,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Stage do
end
subject do
- described_class.new(pipeline, attributes, previous_stages)
+ described_class.new(seed_context, attributes, previous_stages)
end
describe '#size' do
diff --git a/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb
index b322e55cb5a..8378d096fcf 100644
--- a/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/codequality_reports_comparer_spec.rb
@@ -6,15 +6,17 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
let(:comparer) { described_class.new(base_report, head_report) }
let(:base_report) { Gitlab::Ci::Reports::CodequalityReports.new }
let(:head_report) { Gitlab::Ci::Reports::CodequalityReports.new }
- let(:degradation_1) { build(:codequality_degradation_1) }
- let(:degradation_2) { build(:codequality_degradation_2) }
+ let(:major_degradation) { build(:codequality_degradation, :major) }
+ let(:minor_degradation) { build(:codequality_degradation, :major) }
+ let(:critical_degradation) { build(:codequality_degradation, :critical) }
+ let(:blocker_degradation) { build(:codequality_degradation, :blocker) }
describe '#status' do
subject(:report_status) { comparer.status }
context 'when head report has an error' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'returns status failed' do
@@ -50,7 +52,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when head report has an error' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'returns the number of new errors' do
@@ -70,8 +72,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has an error and head has a different error' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(minor_degradation)
end
it 'counts the base report error as resolved' do
@@ -81,7 +83,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors head has no errors' do
before do
- base_report.add_degradation(degradation_1)
+ base_report.add_degradation(major_degradation)
end
it 'counts the base report errors as resolved' do
@@ -91,8 +93,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors and head has the same error' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_1)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(major_degradation)
end
it 'returns zero' do
@@ -102,7 +104,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report does not have errors and head has errors' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'returns zero' do
@@ -124,7 +126,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has an error' do
before do
- base_report.add_degradation(degradation_1)
+ base_report.add_degradation(major_degradation)
end
it 'returns zero' do
@@ -134,7 +136,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when head report has an error' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'includes the head report error in the count' do
@@ -144,8 +146,8 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors and head report has errors' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(minor_degradation)
end
it 'includes errors in the count' do
@@ -155,9 +157,9 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors and head report has the same error' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(major_degradation)
+ head_report.add_degradation(minor_degradation)
end
it 'includes errors in the count' do
@@ -179,20 +181,28 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors and head has the same error' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
- end
-
- it 'includes the base report errors' do
- expect(existing_errors).to contain_exactly(degradation_1)
+ base_report.add_degradation(major_degradation)
+ base_report.add_degradation(critical_degradation)
+ base_report.add_degradation(blocker_degradation)
+ head_report.add_degradation(critical_degradation)
+ head_report.add_degradation(blocker_degradation)
+ head_report.add_degradation(major_degradation)
+ head_report.add_degradation(minor_degradation)
+ end
+
+ it 'includes the base report errors sorted by severity' do
+ expect(existing_errors).to eq([
+ blocker_degradation,
+ critical_degradation,
+ major_degradation
+ ])
end
end
context 'when base report has errors and head has a different error' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(minor_degradation)
end
it 'returns an empty array' do
@@ -202,7 +212,7 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report does not have errors and head has errors' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'returns an empty array' do
@@ -224,19 +234,25 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors and head has more errors' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(critical_degradation)
+ head_report.add_degradation(minor_degradation)
+ head_report.add_degradation(blocker_degradation)
+ head_report.add_degradation(major_degradation)
end
- it 'includes errors not found in the base report' do
- expect(new_errors).to eq([degradation_2])
+ it 'includes errors not found in the base report sorted by severity' do
+ expect(new_errors).to eq([
+ blocker_degradation,
+ critical_degradation,
+ minor_degradation
+ ])
end
end
context 'when base report has an error and head has no errors' do
before do
- base_report.add_degradation(degradation_1)
+ base_report.add_degradation(major_degradation)
end
it 'returns an empty array' do
@@ -246,11 +262,11 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report does not have errors and head has errors' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'returns the head report error' do
- expect(new_errors).to eq([degradation_1])
+ expect(new_errors).to eq([major_degradation])
end
end
@@ -268,9 +284,9 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report errors are still found in the head report' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ head_report.add_degradation(major_degradation)
+ head_report.add_degradation(minor_degradation)
end
it 'returns an empty array' do
@@ -280,18 +296,25 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReportsComparer do
context 'when base report has errors and head has a different error' do
before do
- base_report.add_degradation(degradation_1)
- head_report.add_degradation(degradation_2)
+ base_report.add_degradation(major_degradation)
+ base_report.add_degradation(minor_degradation)
+ base_report.add_degradation(critical_degradation)
+ base_report.add_degradation(blocker_degradation)
+ head_report.add_degradation(major_degradation)
end
- it 'returns the base report error' do
- expect(resolved_errors).to eq([degradation_1])
+ it 'returns the base report errors not found in the head report, sorted by severity' do
+ expect(resolved_errors).to eq([
+ blocker_degradation,
+ critical_degradation,
+ minor_degradation
+ ])
end
end
context 'when base report does not have errors and head has errors' do
before do
- head_report.add_degradation(degradation_1)
+ head_report.add_degradation(major_degradation)
end
it 'returns an empty array' do
diff --git a/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb b/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb
index ae9b2f2c62b..3b0eaffc54e 100644
--- a/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/codequality_reports_spec.rb
@@ -34,8 +34,6 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReports do
it 'sets location as an error' do
codequality_report.add_degradation(invalid_degradation)
-
- expect(codequality_report.error_message).to eq("Invalid degradation format: The property '#/' did not contain a required property of 'location'")
end
end
end
@@ -79,4 +77,36 @@ RSpec.describe Gitlab::Ci::Reports::CodequalityReports do
end
end
end
+
+ describe '#sort_degradations!' do
+ let(:major) { build(:codequality_degradation, :major) }
+ let(:minor) { build(:codequality_degradation, :minor) }
+ let(:blocker) { build(:codequality_degradation, :blocker) }
+ let(:info) { build(:codequality_degradation, :info) }
+ let(:major_2) { build(:codequality_degradation, :major) }
+ let(:critical) { build(:codequality_degradation, :critical) }
+ let(:codequality_report) { described_class.new }
+
+ before do
+ codequality_report.add_degradation(major)
+ codequality_report.add_degradation(minor)
+ codequality_report.add_degradation(blocker)
+ codequality_report.add_degradation(major_2)
+ codequality_report.add_degradation(info)
+ codequality_report.add_degradation(critical)
+
+ codequality_report.sort_degradations!
+ end
+
+ it 'sorts degradations based on severity' do
+ expect(codequality_report.degradations.values).to eq([
+ blocker,
+ critical,
+ major,
+ major_2,
+ minor,
+ info
+ ])
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb b/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb
index 831bc5e9f37..9ee55177ca0 100644
--- a/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_failure_history_spec.rb
@@ -13,9 +13,9 @@ RSpec.describe Gitlab::Ci::Reports::TestFailureHistory, :aggregate_failures do
subject(:load_history) { described_class.new([failed_rspec, failed_java], project).load! }
before do
- allow(Ci::TestCaseFailure)
+ allow(Ci::UnitTestFailure)
.to receive(:recent_failures_count)
- .with(project: project, test_case_keys: [failed_rspec.key, failed_java.key])
+ .with(project: project, unit_test_keys: [failed_rspec.key, failed_java.key])
.and_return(
failed_rspec.key => 2,
failed_java.key => 1
diff --git a/spec/lib/gitlab/ci/runner_instructions_spec.rb b/spec/lib/gitlab/ci/runner_instructions_spec.rb
index d1020026fe6..f872c631a50 100644
--- a/spec/lib/gitlab/ci/runner_instructions_spec.rb
+++ b/spec/lib/gitlab/ci/runner_instructions_spec.rb
@@ -6,7 +6,6 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
using RSpec::Parameterized::TableSyntax
let(:params) { {} }
- let(:user) { create(:user) }
describe 'OS' do
Gitlab::Ci::RunnerInstructions::OS.each do |name, subject|
@@ -37,7 +36,7 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
end
describe '#install_script' do
- subject { described_class.new(current_user: user, **params) }
+ subject { described_class.new(**params) }
context 'invalid params' do
where(:current_params, :expected_error_message) do
@@ -106,117 +105,18 @@ RSpec.describe Gitlab::Ci::RunnerInstructions do
end
end
- context 'group' do
- let(:group) { create(:group) }
-
- subject { described_class.new(current_user: user, group: group, **params) }
-
- context 'user is owner' do
- before do
- group.add_owner(user)
- end
-
- with_them do
- let(:params) { { os: commands.each_key.first, arch: 'foo' } }
-
- it 'have correct configurations' do
- result = subject.register_command
-
- expect(result).to include("#{commands[commands.each_key.first]} register")
- expect(result).to include("--registration-token #{group.runners_token}")
- expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
- end
- end
- end
-
- context 'user is not owner' do
- where(:user_permission) do
- [:maintainer, :developer, :reporter, :guest]
- end
-
- with_them do
- before do
- create(:group_member, user_permission, group: group, user: user)
- end
-
- it 'raises error' do
- result = subject.register_command
-
- expect(result).to be_nil
- expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
- end
- end
- end
- end
-
- context 'project' do
- let(:project) { create(:project) }
-
- subject { described_class.new(current_user: user, project: project, **params) }
-
- context 'user is maintainer' do
- before do
- project.add_maintainer(user)
- end
-
- with_them do
- let(:params) { { os: commands.each_key.first, arch: 'foo' } }
-
- it 'have correct configurations' do
- result = subject.register_command
-
- expect(result).to include("#{commands[commands.each_key.first]} register")
- expect(result).to include("--registration-token #{project.runners_token}")
- expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
- end
- end
- end
-
- context 'user is not maintainer' do
- where(:user_permission) do
- [:developer, :reporter, :guest]
- end
-
- with_them do
- before do
- create(:project_member, user_permission, project: project, user: user)
- end
-
- it 'raises error' do
- result = subject.register_command
-
- expect(result).to be_nil
- expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
- end
- end
- end
- end
-
context 'instance' do
- subject { described_class.new(current_user: user, **params) }
-
- context 'user is admin' do
- let(:user) { create(:user, :admin) }
-
- with_them do
- let(:params) { { os: commands.each_key.first, arch: 'foo' } }
+ subject { described_class.new(**params) }
- it 'have correct configurations' do
- result = subject.register_command
-
- expect(result).to include("#{commands[commands.each_key.first]} register")
- expect(result).to include("--registration-token #{Gitlab::CurrentSettings.runners_registration_token}")
- expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
- end
- end
- end
+ with_them do
+ let(:params) { { os: commands.each_key.first, arch: 'foo' } }
- context 'user is not admin' do
- it 'raises error' do
+ it 'have correct configurations' do
result = subject.register_command
- expect(result).to be_nil
- expect(subject.errors).to include("Gitlab::Access::AccessDeniedError")
+ expect(result).to include("#{commands[commands.each_key.first]} register")
+ expect(result).to include("--registration-token $REGISTRATION_TOKEN")
+ expect(result).to include("--url #{Gitlab::Routing.url_helpers.root_url(only_path: false)}")
end
end
end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
index 924ee5ee1a4..c4e83c1796d 100644
--- a/spec/lib/gitlab/ci/status/build/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::Ci::Status::Build::Common do
context 'when user does not have access to read build' do
before do
- project.update(public_builds: false)
+ project.update!(public_builds: false)
end
it { is_expected.not_to have_details }
diff --git a/spec/lib/gitlab/ci/status/composite_spec.rb b/spec/lib/gitlab/ci/status/composite_spec.rb
index 543cfe874ca..2b9523bd83d 100644
--- a/spec/lib/gitlab/ci/status/composite_spec.rb
+++ b/spec/lib/gitlab/ci/status/composite_spec.rb
@@ -6,13 +6,13 @@ RSpec.describe Gitlab::Ci::Status::Composite do
let_it_be(:pipeline) { create(:ci_pipeline) }
before_all do
- @statuses = Ci::HasStatus::STATUSES_ENUM.map do |status, idx|
+ @statuses = Ci::HasStatus::STATUSES_ENUM.to_h do |status, idx|
[status, create(:ci_build, pipeline: pipeline, status: status, importing: true)]
- end.to_h
+ end
- @statuses_with_allow_failure = Ci::HasStatus::STATUSES_ENUM.map do |status, idx|
+ @statuses_with_allow_failure = Ci::HasStatus::STATUSES_ENUM.to_h do |status, idx|
[status, create(:ci_build, pipeline: pipeline, status: status, allow_failure: true, importing: true)]
- end.to_h
+ end
end
describe '#status' do
diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb
index 597e4ca9b03..0fe7c731f27 100644
--- a/spec/lib/gitlab/ci/trace_spec.rb
+++ b/spec/lib/gitlab/ci/trace_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state, factory_default: :keep do
let_it_be(:project) { create_default(:project).freeze }
- let_it_be_with_reload(:build) { create(:ci_build) }
+ let_it_be_with_reload(:build) { create(:ci_build, :success) }
let(:trace) { described_class.new(build) }
describe "associations" do
@@ -63,9 +63,7 @@ RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state, factory_defa
describe '#update_interval' do
context 'it is not being watched' do
- it 'returns 30 seconds' do
- expect(trace.update_interval).to eq(30.seconds)
- end
+ it { expect(trace.update_interval).to eq(60.seconds) }
end
context 'it is being watched' do
diff --git a/spec/lib/gitlab/ci/variables/helpers_spec.rb b/spec/lib/gitlab/ci/variables/helpers_spec.rb
index b45abf8c0e1..f13b334c10e 100644
--- a/spec/lib/gitlab/ci/variables/helpers_spec.rb
+++ b/spec/lib/gitlab/ci/variables/helpers_spec.rb
@@ -100,4 +100,50 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
it { is_expected.to eq(result) }
end
end
+
+ describe '.inherit_yaml_variables' do
+ let(:from) do
+ [{ key: 'key1', value: 'value1' },
+ { key: 'key2', value: 'value2' }]
+ end
+
+ let(:to) do
+ [{ key: 'key2', value: 'value22' },
+ { key: 'key3', value: 'value3' }]
+ end
+
+ let(:inheritance) { true }
+
+ let(:result) do
+ [{ key: 'key1', value: 'value1', public: true },
+ { key: 'key2', value: 'value22', public: true },
+ { key: 'key3', value: 'value3', public: true }]
+ end
+
+ subject { described_class.inherit_yaml_variables(from: from, to: to, inheritance: inheritance) }
+
+ it { is_expected.to eq(result) }
+
+ context 'when inheritance is false' do
+ let(:inheritance) { false }
+
+ let(:result) do
+ [{ key: 'key2', value: 'value22', public: true },
+ { key: 'key3', value: 'value3', public: true }]
+ end
+
+ it { is_expected.to eq(result) }
+ end
+
+ context 'when inheritance is array' do
+ let(:inheritance) { ['key2'] }
+
+ let(:result) do
+ [{ key: 'key2', value: 'value22', public: true },
+ { key: 'key3', value: 'value3', public: true }]
+ end
+
+ it { is_expected.to eq(result) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
index 7e3cd7ec254..e345cd4de9b 100644
--- a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
@@ -24,7 +24,7 @@ module Gitlab
let(:included_yml) do
YAML.dump(
- another_test: { stage: 'test', script: 'echo 2' }
+ { another_test: { stage: 'test', script: 'echo 2' } }.deep_stringify_keys
)
end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 5462a587d16..ad94dfc9160 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -43,6 +43,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -74,6 +76,8 @@ module Gitlab
allow_failure: false,
when: 'on_success',
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -111,7 +115,9 @@ module Gitlab
tag_list: %w[A B],
allow_failure: false,
when: "on_success",
- yaml_variables: []
+ yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true
})
end
end
@@ -158,6 +164,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -347,6 +355,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage,
options: { script: ["rspec"] },
only: { refs: ["branches"] } }] },
@@ -359,6 +369,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage,
options: { script: ["cap prod"] },
only: { refs: ["tags"] } }] },
@@ -372,7 +384,7 @@ module Gitlab
end
end
- describe '#workflow_attributes' do
+ describe 'workflow attributes' do
context 'with disallowed workflow:variables' do
let(:config) do
<<-EOYML
@@ -403,11 +415,11 @@ module Gitlab
end
it 'parses the workflow:rules configuration' do
- expect(subject.workflow_attributes[:rules]).to contain_exactly({ if: '$VAR == "value"' })
+ expect(subject.workflow_rules).to contain_exactly({ if: '$VAR == "value"' })
end
- it 'parses the root:variables as yaml_variables:' do
- expect(subject.workflow_attributes[:yaml_variables])
+ it 'parses the root:variables as #root_variables' do
+ expect(subject.root_variables)
.to contain_exactly({ key: 'SUPPORTED', value: 'parsed', public: true })
end
end
@@ -425,11 +437,11 @@ module Gitlab
end
it 'parses the workflow:rules configuration' do
- expect(subject.workflow_attributes[:rules]).to contain_exactly({ if: '$VAR == "value"' })
+ expect(subject.workflow_rules).to contain_exactly({ if: '$VAR == "value"' })
end
- it 'parses the root:variables as yaml_variables:' do
- expect(subject.workflow_attributes[:yaml_variables]).to eq([])
+ it 'parses the root:variables as #root_variables' do
+ expect(subject.root_variables).to eq([])
end
end
@@ -445,11 +457,11 @@ module Gitlab
end
it 'parses the workflow:rules configuration' do
- expect(subject.workflow_attributes[:rules]).to be_nil
+ expect(subject.workflow_rules).to be_nil
end
- it 'parses the root:variables as yaml_variables:' do
- expect(subject.workflow_attributes[:yaml_variables])
+ it 'parses the root:variables as #root_variables' do
+ expect(subject.root_variables)
.to contain_exactly({ key: 'SUPPORTED', value: 'parsed', public: true })
end
end
@@ -463,11 +475,11 @@ module Gitlab
end
it 'parses the workflow:rules configuration' do
- expect(subject.workflow_attributes[:rules]).to be_nil
+ expect(subject.workflow_rules).to be_nil
end
- it 'parses the root:variables as yaml_variables:' do
- expect(subject.workflow_attributes[:yaml_variables]).to eq([])
+ it 'parses the root:variables as #root_variables' do
+ expect(subject.root_variables).to eq([])
end
end
end
@@ -853,6 +865,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -861,7 +875,7 @@ module Gitlab
config = YAML.dump({ image: "ruby:2.7",
services: ["mysql"],
before_script: ["pwd"],
- rspec: { image: { name: "ruby:2.5", entrypoint: ["/usr/local/bin/init", "run"] },
+ rspec: { image: { name: "ruby:3.0", entrypoint: ["/usr/local/bin/init", "run"] },
services: [{ name: "postgresql", alias: "db-pg",
entrypoint: ["/usr/local/bin/init", "run"],
command: ["/usr/local/bin/init", "run"] }, "docker:dind"],
@@ -878,7 +892,7 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:2.5", entrypoint: ["/usr/local/bin/init", "run"] },
+ image: { name: "ruby:3.0", entrypoint: ["/usr/local/bin/init", "run"] },
services: [{ name: "postgresql", alias: "db-pg", entrypoint: ["/usr/local/bin/init", "run"],
command: ["/usr/local/bin/init", "run"] },
{ name: "docker:dind" }]
@@ -886,6 +900,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -915,6 +931,8 @@ module Gitlab
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -923,7 +941,7 @@ module Gitlab
config = YAML.dump({ image: "ruby:2.7",
services: ["mysql"],
before_script: ["pwd"],
- rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } })
+ rspec: { image: "ruby:3.0", services: ["postgresql", "docker:dind"], script: "rspec" } })
config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
@@ -936,12 +954,14 @@ module Gitlab
options: {
before_script: ["pwd"],
script: ["rspec"],
- image: { name: "ruby:2.5" },
+ image: { name: "ruby:3.0" },
services: [{ name: "postgresql" }, { name: "docker:dind" }]
},
allow_failure: false,
when: "on_success",
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -951,7 +971,10 @@ module Gitlab
describe 'Variables' do
subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
- let(:build_variables) { subject.builds.first[:yaml_variables] }
+ let(:build) { subject.builds.first }
+ let(:yaml_variables) { build[:yaml_variables] }
+ let(:job_variables) { build[:job_variables] }
+ let(:root_variables_inheritance) { build[:root_variables_inheritance] }
context 'when global variables are defined' do
let(:variables) do
@@ -967,10 +990,12 @@ module Gitlab
end
it 'returns global variables' do
- expect(build_variables).to contain_exactly(
+ expect(yaml_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
+ expect(job_variables).to eq([])
+ expect(root_variables_inheritance).to eq(true)
end
end
@@ -979,7 +1004,7 @@ module Gitlab
{ 'VAR1' => 'global1', 'VAR3' => 'global3', 'VAR4' => 'global4' }
end
- let(:job_variables) do
+ let(:build_variables) do
{ 'VAR1' => 'value1', 'VAR2' => 'value2' }
end
@@ -987,20 +1012,25 @@ module Gitlab
{
before_script: ['pwd'],
variables: global_variables,
- rspec: { script: 'rspec', variables: job_variables, inherit: inherit }
+ rspec: { script: 'rspec', variables: build_variables, inherit: inherit }
}
end
context 'when no inheritance is specified' do
let(:inherit) { }
- it 'returns all unique variables' do
- expect(build_variables).to contain_exactly(
- { key: 'VAR4', value: 'global4', public: true },
+ it 'returns all variables' do
+ expect(yaml_variables).to contain_exactly(
+ { key: 'VAR1', value: 'value1', public: true },
+ { key: 'VAR2', value: 'value2', public: true },
{ key: 'VAR3', value: 'global3', public: true },
+ { key: 'VAR4', value: 'global4', public: true }
+ )
+ expect(job_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
+ expect(root_variables_inheritance).to eq(true)
end
end
@@ -1008,22 +1038,32 @@ module Gitlab
let(:inherit) { { variables: false } }
it 'does not inherit variables' do
- expect(build_variables).to contain_exactly(
+ expect(yaml_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
+ expect(job_variables).to contain_exactly(
+ { key: 'VAR1', value: 'value1', public: true },
+ { key: 'VAR2', value: 'value2', public: true }
+ )
+ expect(root_variables_inheritance).to eq(false)
end
end
context 'when specific variables are to inherited' do
let(:inherit) { { variables: %w[VAR1 VAR4] } }
- it 'returns all unique variables and inherits only specified variables' do
- expect(build_variables).to contain_exactly(
- { key: 'VAR4', value: 'global4', public: true },
+ it 'returns all variables and inherits only specified variables' do
+ expect(yaml_variables).to contain_exactly(
+ { key: 'VAR1', value: 'value1', public: true },
+ { key: 'VAR2', value: 'value2', public: true },
+ { key: 'VAR4', value: 'global4', public: true }
+ )
+ expect(job_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
+ expect(root_variables_inheritance).to eq(%w[VAR1 VAR4])
end
end
end
@@ -1042,10 +1082,15 @@ module Gitlab
end
it 'returns job variables' do
- expect(build_variables).to contain_exactly(
+ expect(yaml_variables).to contain_exactly(
+ { key: 'VAR1', value: 'value1', public: true },
+ { key: 'VAR2', value: 'value2', public: true }
+ )
+ expect(job_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
+ expect(root_variables_inheritance).to eq(true)
end
end
@@ -1068,8 +1113,11 @@ module Gitlab
# When variables config is empty, we assume this is a valid
# configuration, see issue #18775
#
- expect(build_variables).to be_an_instance_of(Array)
- expect(build_variables).to be_empty
+ expect(yaml_variables).to be_an_instance_of(Array)
+ expect(yaml_variables).to be_empty
+
+ expect(job_variables).to eq([])
+ expect(root_variables_inheritance).to eq(true)
end
end
end
@@ -1084,8 +1132,11 @@ module Gitlab
end
it 'returns empty array' do
- expect(build_variables).to be_an_instance_of(Array)
- expect(build_variables).to be_empty
+ expect(yaml_variables).to be_an_instance_of(Array)
+ expect(yaml_variables).to be_empty
+
+ expect(job_variables).to eq([])
+ expect(root_variables_inheritance).to eq(true)
end
end
end
@@ -1717,6 +1768,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -2080,6 +2133,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
)
expect(subject.builds[4]).to eq(
@@ -2095,6 +2150,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :dag
)
end
@@ -2122,6 +2179,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
)
expect(subject.builds[4]).to eq(
@@ -2139,6 +2198,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :dag
)
end
@@ -2162,6 +2223,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :dag
)
end
@@ -2193,6 +2256,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :dag
)
end
@@ -2391,6 +2456,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end
@@ -2438,6 +2505,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
expect(subject.second).to eq({
@@ -2451,6 +2520,8 @@ module Gitlab
when: "on_success",
allow_failure: false,
yaml_variables: [],
+ job_variables: [],
+ root_variables_inheritance: true,
scheduling_type: :stage
})
end