diff options
Diffstat (limited to 'spec/services/ci/create_pipeline_service')
8 files changed, 192 insertions, 64 deletions
diff --git a/spec/services/ci/create_pipeline_service/cache_spec.rb b/spec/services/ci/create_pipeline_service/cache_spec.rb index 5f74c2f1cef..f9767a794db 100644 --- a/spec/services/ci/create_pipeline_service/cache_spec.rb +++ b/spec/services/ci/create_pipeline_service/cache_spec.rb @@ -33,11 +33,11 @@ RSpec.describe Ci::CreatePipelineService do it 'uses the provided key' do expected = { - 'key' => 'a-key', - 'paths' => ['logs/', 'binaries/'], - 'policy' => 'pull-push', - 'untracked' => true, - 'when' => 'on_success' + key: 'a-key', + paths: ['logs/', 'binaries/'], + policy: 'pull-push', + untracked: true, + when: 'on_success' } expect(pipeline).to be_persisted @@ -66,10 +66,10 @@ RSpec.describe Ci::CreatePipelineService do it 'builds a cache key' do expected = { - 'key' => /[a-f0-9]{40}/, - 'paths' => ['logs/'], - 'policy' => 'pull-push', - 'when' => 'on_success' + key: /[a-f0-9]{40}/, + paths: ['logs/'], + policy: 'pull-push', + when: 'on_success' } expect(pipeline).to be_persisted @@ -82,10 +82,10 @@ RSpec.describe Ci::CreatePipelineService do it 'uses default cache key' do expected = { - 'key' => /default/, - 'paths' => ['logs/'], - 'policy' => 'pull-push', - 'when' => 'on_success' + key: /default/, + paths: ['logs/'], + policy: 'pull-push', + when: 'on_success' } expect(pipeline).to be_persisted @@ -115,10 +115,10 @@ RSpec.describe Ci::CreatePipelineService do it 'builds a cache key' do expected = { - 'key' => /\$ENV_VAR-[a-f0-9]{40}/, - 'paths' => ['logs/'], - 'policy' => 'pull-push', - 'when' => 'on_success' + key: /\$ENV_VAR-[a-f0-9]{40}/, + paths: ['logs/'], + policy: 'pull-push', + when: 'on_success' } expect(pipeline).to be_persisted @@ -131,10 +131,10 @@ RSpec.describe Ci::CreatePipelineService do it 'uses default cache key' do expected = { - 'key' => /\$ENV_VAR-default/, - 'paths' => ['logs/'], - 'policy' => 'pull-push', - 'when' => 'on_success' + key: /\$ENV_VAR-default/, + paths: ['logs/'], + policy: 'pull-push', + when: 'on_success' } expect(pipeline).to be_persisted diff --git a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb index 7193e5bd7d4..a42770aae20 100644 --- a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb +++ b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb @@ -69,7 +69,7 @@ RSpec.describe Ci::CreatePipelineService do end it 'contains both errors and warnings' do - error_message = 'build job: need test is not defined in prior stages' + error_message = 'build job: need test is not defined in current or prior stages' warning_message = /jobs:test may allow multiple pipelines to run/ expect(pipeline.yaml_errors).to eq(error_message) diff --git a/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb index 4cf52223e38..5dceb9f57f0 100644 --- a/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb +++ b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb @@ -39,8 +39,8 @@ RSpec.describe Ci::CreatePipelineService do it 'creates a pipeline' do expect(pipeline).to be_persisted expect(pipeline.builds.first.options).to match(a_hash_including({ - 'before_script' => ['ls'], - 'script' => [ + before_script: ['ls'], + script: [ 'echo doing my first step', 'echo doing step 1 of job 1', 'echo doing my last step' diff --git a/spec/services/ci/create_pipeline_service/dry_run_spec.rb b/spec/services/ci/create_pipeline_service/dry_run_spec.rb index 0fb500f5729..01df7772eef 100644 --- a/spec/services/ci/create_pipeline_service/dry_run_spec.rb +++ b/spec/services/ci/create_pipeline_service/dry_run_spec.rb @@ -84,7 +84,7 @@ RSpec.describe Ci::CreatePipelineService do it_behaves_like 'returns a non persisted pipeline' it 'returns a pipeline with errors', :aggregate_failures do - error_message = 'build job: need test is not defined in prior stages' + error_message = 'build job: need test is not defined in current or prior stages' expect(subject.error_messages.map(&:content)).to eq([error_message]) expect(subject.errors).not_to be_empty @@ -109,7 +109,7 @@ RSpec.describe Ci::CreatePipelineService do it_behaves_like 'returns a non persisted pipeline' it 'returns a pipeline with errors', :aggregate_failures do - error_message = "'test' job needs 'build' job, but it was not added to the pipeline" + error_message = "'test' job needs 'build' job, but 'build' is not in any previous stage" expect(subject.error_messages.map(&:content)).to eq([error_message]) expect(subject.errors).not_to be_empty diff --git a/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb new file mode 100644 index 00000000000..df881c1ac8f --- /dev/null +++ b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::CreatePipelineService do + let_it_be(:group) { create(:group, :private) } + let_it_be(:group_variable) { create(:ci_group_variable, group: group, key: 'RUNNER_TAG', value: 'group')} + let_it_be(:project) { create(:project, :repository, group: group) } + let_it_be(:user) { create(:user) } + + let(:service) { described_class.new(project, user, ref: 'master') } + let(:pipeline) { service.execute(:push) } + let(:job) { pipeline.builds.find_by(name: 'job') } + + before do + project.add_developer(user) + stub_ci_pipeline_yaml_file config + end + + context 'when the variable is set' do + let(:config) do + <<~EOS + variables: + KUBERNETES_RUNNER: kubernetes + + job: + tags: + - docker + - $KUBERNETES_RUNNER + script: + - echo "Hello runner selector feature" + EOS + end + + it 'uses the evaluated variable' do + expect(pipeline).to be_created_successfully + expect(job.tags.pluck(:name)).to match_array(%w[docker kubernetes]) + end + end + + context 'when the tag is composed by two variables' do + let(:config) do + <<~EOS + variables: + CLOUD_PROVIDER: aws + KUBERNETES_RUNNER: kubernetes + ENVIRONMENT_NAME: prod + + job: + tags: + - docker + - $CLOUD_PROVIDER-$KUBERNETES_RUNNER-$ENVIRONMENT_NAME + script: + - echo "Hello runner selector feature" + EOS + end + + it 'uses the evaluated variables' do + expect(pipeline).to be_created_successfully + expect(job.tags.pluck(:name)).to match_array(%w[docker aws-kubernetes-prod]) + end + end + + context 'when the variable is not set' do + let(:config) do + <<~EOS + job: + tags: + - docker + - $KUBERNETES_RUNNER + script: + - echo "Hello runner selector feature" + EOS + end + + it 'uses the variable as a regular string' do + expect(pipeline).to be_created_successfully + expect(job.tags.pluck(:name)).to match_array(%w[docker $KUBERNETES_RUNNER]) + end + end + + context 'when the tag uses group variables' do + let(:config) do + <<~EOS + job: + tags: + - docker + - $RUNNER_TAG + script: + - echo "Hello runner selector feature" + EOS + end + + it 'uses the evaluated variables' do + expect(pipeline).to be_created_successfully + expect(job.tags.pluck(:name)).to match_array(%w[docker group]) + end + end + + context 'when the tag has the same variable name defined for both group and project' do + let_it_be(:project_variable) { create(:ci_variable, project: project, key: 'RUNNER_TAG', value: 'project') } + + let(:config) do + <<~EOS + variables: + RUNNER_TAG: pipeline + job: + tags: + - docker + - $RUNNER_TAG + script: + - echo "Hello runner selector feature" + EOS + end + + it 'uses the project variable instead of group due to variable precedence' do + expect(pipeline).to be_created_successfully + expect(job.tags.pluck(:name)).to match_array(%w[docker project]) + end + end + + context 'with parallel:matrix config' do + let(:tags) { pipeline.builds.map(&:tags).flatten.pluck(:name) } + + let(:config) do + <<~EOS + job: + parallel: + matrix: + - PROVIDER: [aws, gcp] + STACK: [monitoring, backup, app] + tags: + - ${PROVIDER}-${STACK} + script: + - echo "Hello runner selector feature" + EOS + end + + it 'uses the evaluated variables' do + expect(pipeline).to be_created_successfully + expect(tags).to match_array(%w[aws-monitoring aws-backup aws-app gcp-monitoring gcp-backup gcp-app]) + end + end +end diff --git a/spec/services/ci/create_pipeline_service/needs_spec.rb b/spec/services/ci/create_pipeline_service/needs_spec.rb index 3b4a6178b8f..d096db10d0b 100644 --- a/spec/services/ci/create_pipeline_service/needs_spec.rb +++ b/spec/services/ci/create_pipeline_service/needs_spec.rb @@ -104,7 +104,7 @@ RSpec.describe Ci::CreatePipelineService do it 'saves dependencies' do expect(test_a_build.options) - .to match(a_hash_including('dependencies' => ['build_a'])) + .to match(a_hash_including(dependencies: ['build_a'])) end it 'artifacts default to true' do @@ -257,7 +257,7 @@ RSpec.describe Ci::CreatePipelineService do it 'returns error' do expect(pipeline.yaml_errors) - .to eq("'test' job needs 'build' job, but it was not added to the pipeline") + .to eq("'test' job needs 'build' job, but 'build' is not in any previous stage") end context 'when need is optional' do diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb index 512cf546e6a..7a6535ed3fa 100644 --- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb +++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb @@ -69,9 +69,9 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do it_behaves_like 'successful creation' do let(:expected_bridge_options) do { - 'trigger' => { - 'include' => [ - { 'local' => 'path/to/child.yml' } + trigger: { + include: [ + { local: 'path/to/child.yml' } ] } } @@ -149,9 +149,9 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do it_behaves_like 'successful creation' do let(:expected_bridge_options) do { - 'trigger' => { - 'include' => [ - { 'local' => 'path/to/child.yml' } + trigger: { + include: [ + { local: 'path/to/child.yml' } ] } } @@ -175,8 +175,8 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do it_behaves_like 'successful creation' do let(:expected_bridge_options) do { - 'trigger' => { - 'include' => 'path/to/child.yml' + trigger: { + include: 'path/to/child.yml' } } end @@ -202,8 +202,8 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do it_behaves_like 'successful creation' do let(:expected_bridge_options) do { - 'trigger' => { - 'include' => ['path/to/child.yml', 'path/to/child2.yml'] + trigger: { + include: ['path/to/child.yml', 'path/to/child2.yml'] } } end @@ -252,7 +252,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do end it_behaves_like 'creation failure' do - let(:expected_error) { /test job: dependency generator is not defined in prior stages/ } + let(:expected_error) { /test job: dependency generator is not defined in current or prior stages/ } end end @@ -295,12 +295,12 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do it_behaves_like 'successful creation' do let(:expected_bridge_options) do { - 'trigger' => { - 'include' => [ + trigger: { + include: [ { - 'file' => 'path/to/child.yml', - 'project' => 'my-namespace/my-project', - 'ref' => 'master' + file: 'path/to/child.yml', + project: 'my-namespace/my-project', + ref: 'master' } ] } @@ -353,11 +353,11 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do it_behaves_like 'successful creation' do let(:expected_bridge_options) do { - 'trigger' => { - 'include' => [ + trigger: { + include: [ { - 'file' => ["path/to/child1.yml", "path/to/child2.yml"], - 'project' => 'my-namespace/my-project' + file: ["path/to/child1.yml", "path/to/child2.yml"], + project: 'my-namespace/my-project' } ] } diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index 33ec6aacc44..acdf38bbc13 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -230,22 +230,6 @@ RSpec.describe Ci::CreatePipelineService do [nil, nil, nil, 'job var 4', nil, nil, 'overridden var 7'] ) end - - context 'when FF ci_workflow_rules_variables is disabled' do - before do - stub_feature_flags(ci_workflow_rules_variables: false) - end - - it 'does not affect workflow variables but job variables' do - expect(job1.scoped_variables.to_hash.values_at(*variable_keys)).to eq( - ['overridden var 1', 'job var 2', nil, 'workflow var 4', 'job var 5', nil, 'workflow var 7'] - ) - - expect(job2.scoped_variables.to_hash.values_at(*variable_keys)).to eq( - [nil, nil, nil, 'job var 4', nil, nil, 'overridden var 7'] - ) - end - end end context 'when matching to the second rule' do |