diff options
Diffstat (limited to 'spec/services/ci/create_pipeline_service_spec.rb')
-rw-r--r-- | spec/services/ci/create_pipeline_service_spec.rb | 335 |
1 files changed, 315 insertions, 20 deletions
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index d8880819d9f..fe86982af91 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -760,33 +760,32 @@ describe Ci::CreatePipelineService do end context 'when builds with auto-retries are configured' do + let(:pipeline) { execute_service } + let(:rspec_job) { pipeline.builds.find_by(name: 'rspec') } + + before do + stub_ci_pipeline_yaml_file(YAML.dump({ + rspec: { script: 'rspec', retry: retry_value } + })) + end + context 'as an integer' do - before do - config = YAML.dump(rspec: { script: 'rspec', retry: 2 }) - stub_ci_pipeline_yaml_file(config) - end + let(:retry_value) { 2 } it 'correctly creates builds with auto-retry value configured' do - pipeline = execute_service - expect(pipeline).to be_persisted - expect(pipeline.builds.find_by(name: 'rspec').retries_max).to eq 2 - expect(pipeline.builds.find_by(name: 'rspec').retry_when).to eq ['always'] + expect(rspec_job.retries_max).to eq 2 + expect(rspec_job.retry_when).to eq ['always'] end end context 'as hash' do - before do - config = YAML.dump(rspec: { script: 'rspec', retry: { max: 2, when: 'runner_system_failure' } }) - stub_ci_pipeline_yaml_file(config) - end + let(:retry_value) { { max: 2, when: 'runner_system_failure' } } it 'correctly creates builds with auto-retry value configured' do - pipeline = execute_service - expect(pipeline).to be_persisted - expect(pipeline.builds.find_by(name: 'rspec').retries_max).to eq 2 - expect(pipeline.builds.find_by(name: 'rspec').retry_when).to eq ['runner_system_failure'] + expect(rspec_job.retries_max).to eq 2 + expect(rspec_job.retry_when).to eq ['runner_system_failure'] end end end @@ -1174,7 +1173,7 @@ describe Ci::CreatePipelineService do expect(pipeline).to be_persisted expect(pipeline).to be_merge_request_event expect(pipeline.merge_request).to eq(merge_request) - expect(pipeline.builds.order(:stage_id).map(&:name)).to eq(%w[test]) + expect(pipeline.builds.order(:stage_id).pluck(:name)).to eq(%w[test]) end it 'persists the specified source sha' do @@ -1439,7 +1438,7 @@ describe Ci::CreatePipelineService do expect(pipeline).to be_persisted expect(pipeline).to be_web expect(pipeline.merge_request).to be_nil - expect(pipeline.builds.order(:stage_id).map(&:name)).to eq(%w[build pages]) + expect(pipeline.builds.order(:stage_id).pluck(:name)).to eq(%w[build pages]) end end end @@ -1479,7 +1478,7 @@ describe Ci::CreatePipelineService do it 'creates a pipeline with build_a and test_a' do expect(pipeline).to be_persisted - expect(pipeline.builds.map(&:name)).to contain_exactly("build_a", "test_a") + expect(pipeline.builds.pluck(:name)).to contain_exactly("build_a", "test_a") end end @@ -1514,7 +1513,303 @@ describe Ci::CreatePipelineService do it 'does create a pipeline only with deploy' do expect(pipeline).to be_persisted - expect(pipeline.builds.map(&:name)).to contain_exactly("deploy") + expect(pipeline.builds.pluck(:name)).to contain_exactly("deploy") + end + end + end + + context 'when rules are used' do + let(:ref_name) { 'refs/heads/master' } + let(:pipeline) { execute_service } + let(:build_names) { pipeline.builds.pluck(:name) } + let(:regular_job) { pipeline.builds.find_by(name: 'regular-job') } + let(:rules_job) { pipeline.builds.find_by(name: 'rules-job') } + let(:delayed_job) { pipeline.builds.find_by(name: 'delayed-job') } + + shared_examples 'rules jobs are excluded' do + it 'only persists the job without rules' do + expect(pipeline).to be_persisted + expect(regular_job).to be_persisted + expect(rules_job).to be_nil + expect(delayed_job).to be_nil + end + end + + before do + stub_ci_pipeline_yaml_file(config) + allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true) + end + + context 'with simple if: clauses' do + let(:config) do + <<-EOY + regular-job: + script: 'echo Hello, World!' + + master-job: + script: "echo hello world, $CI_COMMIT_REF_NAME" + rules: + - if: $CI_COMMIT_REF_NAME == "nonexistant-branch" + when: never + - if: $CI_COMMIT_REF_NAME =~ /master/ + when: manual + + delayed-job: + script: "echo See you later, World!" + rules: + - if: $CI_COMMIT_REF_NAME =~ /master/ + when: delayed + start_in: 1 hour + + never-job: + script: "echo Goodbye, World!" + rules: + - if: $CI_COMMIT_REF_NAME + when: never + EOY + end + + context 'with matches' do + it 'creates a pipeline with the vanilla and manual jobs' do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('regular-job', 'delayed-job', 'master-job') + end + + it 'assigns job:when values to the builds' do + expect(pipeline.builds.pluck(:when)).to contain_exactly('on_success', 'delayed', 'manual') + end + + it 'assigns start_in for delayed jobs' do + expect(delayed_job.options[:start_in]).to eq('1 hour') + end + end + + context 'with no matches' do + let(:ref_name) { 'refs/heads/feature' } + + it_behaves_like 'rules jobs are excluded' + end + end + + context 'with complex if: clauses' do + let(:config) do + <<-EOY + regular-job: + script: 'echo Hello, World!' + rules: + - if: $VAR == 'present' && $OTHER || $CI_COMMIT_REF_NAME + when: manual + EOY + end + + it 'matches the first rule' do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('regular-job') + expect(regular_job.when).to eq('manual') + end + end + + context 'with changes:' do + let(:config) do + <<-EOY + regular-job: + script: 'echo Hello, World!' + + rules-job: + script: "echo hello world, $CI_COMMIT_REF_NAME" + rules: + - changes: + - README.md + when: manual + - changes: + - app.rb + when: on_success + + delayed-job: + script: "echo See you later, World!" + rules: + - changes: + - README.md + when: delayed + start_in: 4 hours + EOY + end + + context 'and matches' do + before do + allow_any_instance_of(Ci::Pipeline) + .to receive(:modified_paths).and_return(%w[README.md]) + end + + it 'creates two jobs' do + expect(pipeline).to be_persisted + expect(build_names) + .to contain_exactly('regular-job', 'rules-job', 'delayed-job') + end + + it 'sets when: for all jobs' do + expect(regular_job.when).to eq('on_success') + expect(rules_job.when).to eq('manual') + expect(delayed_job.when).to eq('delayed') + expect(delayed_job.options[:start_in]).to eq('4 hours') + end + end + + context 'and matches the second rule' do + before do + allow_any_instance_of(Ci::Pipeline) + .to receive(:modified_paths).and_return(%w[app.rb]) + end + + it 'includes both jobs' do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('regular-job', 'rules-job') + end + + it 'sets when: for the created rules job based on the second clause' do + expect(regular_job.when).to eq('on_success') + expect(rules_job.when).to eq('on_success') + end + end + + context 'and does not match' do + before do + allow_any_instance_of(Ci::Pipeline) + .to receive(:modified_paths).and_return(%w[useless_script.rb]) + end + + it_behaves_like 'rules jobs are excluded' + + it 'sets when: for the created job' do + expect(regular_job.when).to eq('on_success') + end + end + end + + context 'with mixed if: and changes: rules' do + let(:config) do + <<-EOY + regular-job: + script: 'echo Hello, World!' + + rules-job: + script: "echo hello world, $CI_COMMIT_REF_NAME" + rules: + - changes: + - README.md + when: manual + - if: $CI_COMMIT_REF_NAME == "master" + when: on_success + + delayed-job: + script: "echo See you later, World!" + rules: + - changes: + - README.md + when: delayed + start_in: 4 hours + - if: $CI_COMMIT_REF_NAME == "master" + when: delayed + start_in: 1 hour + EOY + end + + context 'and changes: matches before if' do + before do + allow_any_instance_of(Ci::Pipeline) + .to receive(:modified_paths).and_return(%w[README.md]) + end + + it 'creates two jobs' do + expect(pipeline).to be_persisted + expect(build_names) + .to contain_exactly('regular-job', 'rules-job', 'delayed-job') + end + + it 'sets when: for all jobs' do + expect(regular_job.when).to eq('on_success') + expect(rules_job.when).to eq('manual') + expect(delayed_job.when).to eq('delayed') + expect(delayed_job.options[:start_in]).to eq('4 hours') + end + end + + context 'and if: matches after changes' do + it 'includes both jobs' do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('regular-job', 'rules-job', 'delayed-job') + end + + it 'sets when: for the created rules job based on the second clause' do + expect(regular_job.when).to eq('on_success') + expect(rules_job.when).to eq('on_success') + expect(delayed_job.when).to eq('delayed') + expect(delayed_job.options[:start_in]).to eq('1 hour') + end + end + + context 'and does not match' do + let(:ref_name) { 'refs/heads/wip' } + + it_behaves_like 'rules jobs are excluded' + + it 'sets when: for the created job' do + expect(regular_job.when).to eq('on_success') + end + end + end + + context 'with mixed if: and changes: clauses' do + let(:config) do + <<-EOY + regular-job: + script: 'echo Hello, World!' + + rules-job: + script: "echo hello world, $CI_COMMIT_REF_NAME" + rules: + - if: $CI_COMMIT_REF_NAME =~ /master/ + changes: [README.md] + when: on_success + - if: $CI_COMMIT_REF_NAME =~ /master/ + changes: [app.rb] + when: manual + EOY + end + + context 'with if matches and changes matches' do + before do + allow_any_instance_of(Ci::Pipeline) + .to receive(:modified_paths).and_return(%w[app.rb]) + end + + it 'persists all jobs' do + expect(pipeline).to be_persisted + expect(regular_job).to be_persisted + expect(rules_job).to be_persisted + expect(rules_job.when).to eq('manual') + end + end + + context 'with if matches and no change matches' do + it_behaves_like 'rules jobs are excluded' + end + + context 'with change matches and no if matches' do + let(:ref_name) { 'refs/heads/feature' } + + before do + allow_any_instance_of(Ci::Pipeline) + .to receive(:modified_paths).and_return(%w[README.md]) + end + + it_behaves_like 'rules jobs are excluded' + end + + context 'and no matches' do + let(:ref_name) { 'refs/heads/feature' } + + it_behaves_like 'rules jobs are excluded' end end end |