Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2016-08-11 17:27:42 +0300
committerRémy Coutable <remy@rymai.me>2016-08-11 17:27:42 +0300
commit7e9b41896d8c2ffae36152401f35479b39297e78 (patch)
treef488221fceef5952f9d3495cff0026ed67169484 /spec
parenta081b842f9b4e0205cf08656403e6bd9bf0d367f (diff)
parent39203f1adfc6fee3eca50f0cab99ffc597865200 (diff)
Merge branch 'refactor-builds-creation-service' into 'master'
Refactor pipeline creation service ## What does this MR do? This refactors GitLab CI build processing: all builds for pipeline are pre-created when a pipeline object is created. The builds are created with a new introduced status `created`. The builds are then automatically promoted to `pending` when a previous stage do succeed. This significantly simplifies pipeline processing code solving a lot of problems of lazily initialisation of previous approach (builds were created on-demand). ## Why was this MR needed? The previous mechanism had a lot of flows (shown in related issues) in how it work, but also in code design. Removing cross model-service-library dependencies. The current approach moves a build creation to single place `CreatePipelineService` and removes a dynamic dependency on `config_processor` significantly simplifying a build creation and pipeline processing. Pipeline processing is implemented in `ProcessPipelineService`. This also allows to easily extend GitLab with Manual Actions which is part of 8.10 direction issue. ## Migration problem ~~This MR removes the a on-demand creation of builds in pipelines. Pipelines that are running and are in mid-stage (some stages started, but not all) will not be fully evaluated after application restart. This happens, because the code responsible for on-demand creation is removed. There's no easy way to migrate existing pipelines, other than doing offline migration and putting pipeline processing in migration code (which seems to be a really bad idea).~~ To support old pipelines I added a lazy initialization of builds if none is found. ## What are the relevant issue numbers? Fixes: https://gitlab.com/gitlab-org/gitlab-ce/issues/12839 Solves: https://gitlab.com/gitlab-org/gitlab-ce/issues/18644 https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/issues/289 Allows to easily implement: https://gitlab.com/gitlab-org/gitlab-ce/issues/17010 ## Does this MR meet the acceptance criteria? - [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added - [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md) - [x] API support added - Tests - [x] Added for this feature/bug - [ ] All builds are passing - [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides) - [x] Branch has no merge conflicts with `master` (if you do - rebase it please) - [ ] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits) See merge request !5295
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/ci/builds.rb5
-rw-r--r--spec/factories/ci/pipelines.rb2
-rw-r--r--spec/factories/commit_statuses.rb24
-rw-r--r--spec/features/merge_requests/created_from_fork_spec.rb12
-rw-r--r--spec/features/pipelines_spec.rb24
-rw-r--r--spec/lib/ci/charts_spec.rb1
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb14
-rw-r--r--spec/lib/gitlab/badge/build_spec.rb7
-rw-r--r--spec/models/build_spec.rb47
-rw-r--r--spec/models/ci/pipeline_spec.rb316
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb3
-rw-r--r--spec/requests/api/builds_spec.rb4
-rw-r--r--spec/requests/api/commits_spec.rb13
-rw-r--r--spec/requests/api/triggers_spec.rb3
-rw-r--r--spec/requests/ci/api/builds_spec.rb163
-rw-r--r--spec/requests/ci/api/triggers_spec.rb3
-rw-r--r--spec/services/ci/create_builds_service_spec.rb32
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb214
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb5
-rw-r--r--spec/services/ci/image_for_build_service_spec.rb6
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb288
-rw-r--r--spec/services/create_commit_builds_service_spec.rb241
-rw-r--r--spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb10
-rw-r--r--spec/workers/post_receive_spec.rb8
24 files changed, 746 insertions, 699 deletions
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 1b32d560b16..0c93bbdfe26 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -7,6 +7,7 @@ FactoryGirl.define do
stage_idx 0
ref 'master'
tag false
+ status 'pending'
created_at 'Di 29. Okt 09:50:00 CET 2013'
started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013'
@@ -45,6 +46,10 @@ FactoryGirl.define do
status 'pending'
end
+ trait :created do
+ status 'created'
+ end
+
trait :manual do
status 'skipped'
self.when 'manual'
diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb
index a039bef6f3c..04d66020c87 100644
--- a/spec/factories/ci/pipelines.rb
+++ b/spec/factories/ci/pipelines.rb
@@ -18,7 +18,9 @@
FactoryGirl.define do
factory :ci_empty_pipeline, class: Ci::Pipeline do
+ ref 'master'
sha '97de212e80737a608d939f648d959671fb0a0142'
+ status 'pending'
project factory: :empty_project
diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb
index 1e5c479616c..995f2080f10 100644
--- a/spec/factories/commit_statuses.rb
+++ b/spec/factories/commit_statuses.rb
@@ -7,6 +7,30 @@ FactoryGirl.define do
started_at 'Tue, 26 Jan 2016 08:21:42 +0100'
finished_at 'Tue, 26 Jan 2016 08:23:42 +0100'
+ trait :success do
+ status 'success'
+ end
+
+ trait :failed do
+ status 'failed'
+ end
+
+ trait :canceled do
+ status 'canceled'
+ end
+
+ trait :running do
+ status 'running'
+ end
+
+ trait :pending do
+ status 'pending'
+ end
+
+ trait :created do
+ status 'created'
+ end
+
after(:build) do |build, evaluator|
build.project = build.pipeline.project
end
diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb
index f676200ecf3..4d5d4aa121a 100644
--- a/spec/features/merge_requests/created_from_fork_spec.rb
+++ b/spec/features/merge_requests/created_from_fork_spec.rb
@@ -29,12 +29,16 @@ feature 'Merge request created from fork' do
include WaitForAjax
given(:pipeline) do
- create(:ci_pipeline_with_two_job, project: fork_project,
- sha: merge_request.diff_head_sha,
- ref: merge_request.source_branch)
+ create(:ci_pipeline,
+ project: fork_project,
+ sha: merge_request.diff_head_sha,
+ ref: merge_request.source_branch)
end
- background { pipeline.create_builds(user) }
+ background do
+ create(:ci_build, pipeline: pipeline, name: 'rspec')
+ create(:ci_build, pipeline: pipeline, name: 'spinach')
+ end
scenario 'user visits a pipelines page', js: true do
visit_merge_request(merge_request)
diff --git a/spec/features/pipelines_spec.rb b/spec/features/pipelines_spec.rb
index eace76c370f..f88b8f8e60b 100644
--- a/spec/features/pipelines_spec.rb
+++ b/spec/features/pipelines_spec.rb
@@ -33,7 +33,10 @@ describe "Pipelines" do
context 'cancelable pipeline' do
let!(:running) { create(:ci_build, :running, pipeline: pipeline, stage: 'test', commands: 'test') }
- before { visit namespace_project_pipelines_path(project.namespace, project) }
+ before do
+ pipeline.reload_status!
+ visit namespace_project_pipelines_path(project.namespace, project)
+ end
it { expect(page).to have_link('Cancel') }
it { expect(page).to have_selector('.ci-running') }
@@ -49,7 +52,10 @@ describe "Pipelines" do
context 'retryable pipelines' do
let!(:failed) { create(:ci_build, :failed, pipeline: pipeline, stage: 'test', commands: 'test') }
- before { visit namespace_project_pipelines_path(project.namespace, project) }
+ before do
+ pipeline.reload_status!
+ visit namespace_project_pipelines_path(project.namespace, project)
+ end
it { expect(page).to have_link('Retry') }
it { expect(page).to have_selector('.ci-failed') }
@@ -80,7 +86,10 @@ describe "Pipelines" do
context 'when running' do
let!(:running) { create(:generic_commit_status, status: 'running', pipeline: pipeline, stage: 'test') }
- before { visit namespace_project_pipelines_path(project.namespace, project) }
+ before do
+ pipeline.reload_status!
+ visit namespace_project_pipelines_path(project.namespace, project)
+ end
it 'is not cancelable' do
expect(page).not_to have_link('Cancel')
@@ -92,9 +101,12 @@ describe "Pipelines" do
end
context 'when failed' do
- let!(:running) { create(:generic_commit_status, status: 'failed', pipeline: pipeline, stage: 'test') }
+ let!(:failed) { create(:generic_commit_status, status: 'failed', pipeline: pipeline, stage: 'test') }
- before { visit namespace_project_pipelines_path(project.namespace, project) }
+ before do
+ pipeline.reload_status!
+ visit namespace_project_pipelines_path(project.namespace, project)
+ end
it 'is not retryable' do
expect(page).not_to have_link('Retry')
@@ -211,7 +223,7 @@ describe "Pipelines" do
context 'for invalid commit' do
before do
- fill_in('Create for', with: 'invalid reference')
+ fill_in('Create for', with: 'invalid-reference')
click_on 'Create pipeline'
end
diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb
index 034ea098193..2cd6b00dad6 100644
--- a/spec/lib/ci/charts_spec.rb
+++ b/spec/lib/ci/charts_spec.rb
@@ -5,6 +5,7 @@ describe Ci::Charts, lib: true do
before do
@pipeline = FactoryGirl.create(:ci_pipeline)
FactoryGirl.create(:ci_build, pipeline: @pipeline)
+ @pipeline.reload_status!
end
it 'returns build times in minutes' do
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index 85374b8761d..be51d942af7 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -19,7 +19,7 @@ module Ci
expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({
stage: "test",
stage_idx: 1,
- name: :rspec,
+ name: "rspec",
commands: "pwd\nrspec",
tag_list: [],
options: {},
@@ -433,7 +433,7 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
stage: "test",
stage_idx: 1,
- name: :rspec,
+ name: "rspec",
commands: "pwd\nrspec",
tag_list: [],
options: {
@@ -461,7 +461,7 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
stage: "test",
stage_idx: 1,
- name: :rspec,
+ name: "rspec",
commands: "pwd\nrspec",
tag_list: [],
options: {
@@ -700,7 +700,7 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
stage: "test",
stage_idx: 1,
- name: :rspec,
+ name: "rspec",
commands: "pwd\nrspec",
tag_list: [],
options: {
@@ -837,7 +837,7 @@ module Ci
expect(subject.first).to eq({
stage: "test",
stage_idx: 1,
- name: :normal_job,
+ name: "normal_job",
commands: "test",
tag_list: [],
options: {},
@@ -882,7 +882,7 @@ module Ci
expect(subject.first).to eq({
stage: "build",
stage_idx: 0,
- name: :job1,
+ name: "job1",
commands: "execute-script-for-job",
tag_list: [],
options: {},
@@ -894,7 +894,7 @@ module Ci
expect(subject.second).to eq({
stage: "build",
stage_idx: 0,
- name: :job2,
+ name: "job2",
commands: "execute-script-for-job",
tag_list: [],
options: {},
diff --git a/spec/lib/gitlab/badge/build_spec.rb b/spec/lib/gitlab/badge/build_spec.rb
index ef9d9e7fef4..bb8144d5122 100644
--- a/spec/lib/gitlab/badge/build_spec.rb
+++ b/spec/lib/gitlab/badge/build_spec.rb
@@ -96,9 +96,10 @@ describe Gitlab::Badge::Build do
end
def create_build(project, sha, branch)
- pipeline = create(:ci_pipeline, project: project,
- sha: sha,
- ref: branch)
+ pipeline = create(:ci_empty_pipeline,
+ project: project,
+ sha: sha,
+ ref: branch)
create(:ci_build, pipeline: pipeline, stage: 'notify')
end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 9ecc9aac84b..60a221eba50 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -764,6 +764,53 @@ describe Ci::Build, models: true do
end
end
+ describe '#when' do
+ subject { build.when }
+
+ context 'if is undefined' do
+ before do
+ build.when = nil
+ end
+
+ context 'use from gitlab-ci.yml' do
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ context 'if config is not found' do
+ let(:config) { nil }
+
+ it { is_expected.to eq('on_success') }
+ end
+
+ context 'if config does not have a questioned job' do
+ let(:config) do
+ YAML.dump({
+ test_other: {
+ script: 'Hello World'
+ }
+ })
+ end
+
+ it { is_expected.to eq('on_success') }
+ end
+
+ context 'if config has when' do
+ let(:config) do
+ YAML.dump({
+ test: {
+ script: 'Hello World',
+ when: 'always'
+ }
+ })
+ end
+
+ it { is_expected.to eq('always') }
+ end
+ end
+ end
+ end
+
describe '#retryable?' do
context 'when build is running' do
before do
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index ccee591cf7a..fdb579ab45c 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -38,9 +38,6 @@ describe Ci::Pipeline, models: true do
it { expect(pipeline.sha).to start_with(subject) }
end
- describe '#create_next_builds' do
- end
-
describe '#retried' do
subject { pipeline.retried }
@@ -54,304 +51,20 @@ describe Ci::Pipeline, models: true do
end
end
- describe '#create_builds' do
- let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project, ref: 'master', tag: false }
-
- def create_builds(trigger_request = nil)
- pipeline.create_builds(nil, trigger_request)
- end
-
- def create_next_builds
- pipeline.create_next_builds(pipeline.builds.order(:id).last)
- end
-
- it 'creates builds' do
- expect(create_builds).to be_truthy
- pipeline.builds.update_all(status: "success")
- expect(pipeline.builds.count(:all)).to eq(2)
-
- expect(create_next_builds).to be_truthy
- pipeline.builds.update_all(status: "success")
- expect(pipeline.builds.count(:all)).to eq(4)
-
- expect(create_next_builds).to be_truthy
- pipeline.builds.update_all(status: "success")
- expect(pipeline.builds.count(:all)).to eq(5)
-
- expect(create_next_builds).to be_falsey
- end
-
- context 'custom stage with first job allowed to fail' do
- let(:yaml) do
- {
- stages: ['clean', 'test'],
- clean_job: {
- stage: 'clean',
- allow_failure: true,
- script: 'BUILD',
- },
- test_job: {
- stage: 'test',
- script: 'TEST',
- },
- }
- end
-
- before do
- stub_ci_pipeline_yaml_file(YAML.dump(yaml))
- create_builds
- end
-
- it 'properly schedules builds' do
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending')
- pipeline.builds.running_or_pending.each(&:drop)
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending', 'failed')
- end
- end
-
- context 'properly creates builds when "when" is defined' do
- let(:yaml) do
- {
- stages: ["build", "test", "test_failure", "deploy", "cleanup"],
- build: {
- stage: "build",
- script: "BUILD",
- },
- test: {
- stage: "test",
- script: "TEST",
- },
- test_failure: {
- stage: "test_failure",
- script: "ON test failure",
- when: "on_failure",
- },
- deploy: {
- stage: "deploy",
- script: "PUBLISH",
- },
- cleanup: {
- stage: "cleanup",
- script: "TIDY UP",
- when: "always",
- }
- }
- end
-
- before do
- stub_ci_pipeline_yaml_file(YAML.dump(yaml))
- end
-
- context 'when builds are successful' do
- it 'properly creates builds' do
- expect(create_builds).to be_truthy
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success')
- pipeline.reload
- expect(pipeline.status).to eq('success')
- end
- end
-
- context 'when test job fails' do
- it 'properly creates builds' do
- expect(create_builds).to be_truthy
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending')
- pipeline.builds.running_or_pending.each(&:drop)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success')
- pipeline.reload
- expect(pipeline.status).to eq('failed')
- end
- end
-
- context 'when test and test_failure jobs fail' do
- it 'properly creates builds' do
- expect(create_builds).to be_truthy
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending')
- pipeline.builds.running_or_pending.each(&:drop)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
- pipeline.builds.running_or_pending.each(&:drop)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success')
- pipeline.reload
- expect(pipeline.status).to eq('failed')
- end
- end
-
- context 'when deploy job fails' do
- it 'properly creates builds' do
- expect(create_builds).to be_truthy
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
- pipeline.builds.running_or_pending.each(&:drop)
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success')
- pipeline.reload
- expect(pipeline.status).to eq('failed')
- end
- end
-
- context 'when build is canceled in the second stage' do
- it 'does not schedule builds after build has been canceled' do
- expect(create_builds).to be_truthy
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('pending')
- pipeline.builds.running_or_pending.each(&:success)
-
- expect(pipeline.builds.running_or_pending).not_to be_empty
-
- expect(pipeline.builds.pluck(:name)).to contain_exactly('build', 'test')
- expect(pipeline.builds.pluck(:status)).to contain_exactly('success', 'pending')
- pipeline.builds.running_or_pending.each(&:cancel)
-
- expect(pipeline.builds.running_or_pending).to be_empty
- expect(pipeline.reload.status).to eq('canceled')
- end
- end
-
- context 'when listing manual actions' do
- let(:yaml) do
- {
- stages: ["build", "test", "staging", "production", "cleanup"],
- build: {
- stage: "build",
- script: "BUILD",
- },
- test: {
- stage: "test",
- script: "TEST",
- },
- staging: {
- stage: "staging",
- script: "PUBLISH",
- },
- production: {
- stage: "production",
- script: "PUBLISH",
- when: "manual",
- },
- cleanup: {
- stage: "cleanup",
- script: "TIDY UP",
- when: "always",
- },
- clear_cache: {
- stage: "cleanup",
- script: "CLEAR CACHE",
- when: "manual",
- }
- }
- end
-
- it 'returns only for skipped builds' do
- # currently all builds are created
- expect(create_builds).to be_truthy
- expect(manual_actions).to be_empty
-
- # succeed stage build
- pipeline.builds.running_or_pending.each(&:success)
- expect(manual_actions).to be_empty
-
- # succeed stage test
- pipeline.builds.running_or_pending.each(&:success)
- expect(manual_actions).to be_empty
-
- # succeed stage staging and skip stage production
- pipeline.builds.running_or_pending.each(&:success)
- expect(manual_actions).to be_many # production and clear cache
-
- # succeed stage cleanup
- pipeline.builds.running_or_pending.each(&:success)
-
- # after processing a pipeline we should have 6 builds, 5 succeeded
- expect(pipeline.builds.count).to eq(6)
- expect(pipeline.builds.success.count).to eq(4)
- end
-
- def manual_actions
- pipeline.manual_actions
- end
- end
- end
-
- context 'when no builds created' do
- let(:pipeline) { build(:ci_pipeline) }
-
- before do
- stub_ci_pipeline_yaml_file(YAML.dump(before_script: ['ls']))
- end
-
- it 'returns false' do
- expect(pipeline.create_builds(nil)).to be_falsey
- expect(pipeline).not_to be_persisted
- end
- end
- end
-
describe "#finished_at" do
let(:pipeline) { FactoryGirl.create :ci_pipeline }
it "returns finished_at of latest build" do
build = FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 60
FactoryGirl.create :ci_build, pipeline: pipeline, finished_at: Time.now - 120
+ pipeline.reload_status!
expect(pipeline.finished_at.to_i).to eq(build.finished_at.to_i)
end
it "returns nil if there is no finished build" do
FactoryGirl.create :ci_not_started_build, pipeline: pipeline
+ pipeline.reload_status!
expect(pipeline.finished_at).to be_nil
end
@@ -359,7 +72,7 @@ describe Ci::Pipeline, models: true do
describe "coverage" do
let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" }
- let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
+ let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project }
it "calculates average when there are two builds with coverage" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
@@ -426,31 +139,30 @@ describe Ci::Pipeline, models: true do
end
end
- describe '#update_state' do
- it 'executes update_state after touching object' do
- expect(pipeline).to receive(:update_state).and_return(true)
- pipeline.touch
- end
+ describe '#reload_status!' do
+ let(:pipeline) { create :ci_empty_pipeline, project: project }
context 'dependent objects' do
- let(:commit_status) { build :commit_status, pipeline: pipeline }
+ let(:commit_status) { create :commit_status, :pending, pipeline: pipeline }
+
+ it 'executes reload_status! after succeeding dependent object' do
+ expect(pipeline).to receive(:reload_status!).and_return(true)
- it 'executes update_state after saving dependent object' do
- expect(pipeline).to receive(:update_state).and_return(true)
- commit_status.save
+ commit_status.success
end
end
- context 'update state' do
+ context 'updates' do
let(:current) { Time.now.change(usec: 0) }
- let(:build) { FactoryGirl.create :ci_build, :success, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 }
+ let(:build) { FactoryGirl.create :ci_build, pipeline: pipeline, started_at: current - 120, finished_at: current - 60 }
before do
build
+ pipeline.reload_status!
end
[:status, :started_at, :finished_at, :duration].each do |param|
- it "update #{param}" do
+ it "#{param}" do
expect(pipeline.send(param)).to eq(build.send(param))
end
end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index bf438b26690..1b383219eb9 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -291,7 +291,8 @@ describe HipchatService, models: true do
end
context 'build events' do
- let(:build) { create(:ci_build) }
+ let(:pipeline) { create(:ci_empty_pipeline) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
let(:data) { Gitlab::BuildDataBuilder.build(build) }
context 'for failed' do
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index 966d302dfd3..a4cdd8f3140 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -238,6 +238,10 @@ describe API::API, api: true do
it { expect(response.headers).to include(download_headers) }
end
+ before do
+ pipeline.reload_status!
+ end
+
context 'with regular branch' do
before do
pipeline.update(ref: 'master',
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 4379fcb3c1e..7ca75d77673 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -89,16 +89,29 @@ describe API::API, api: true do
it "returns nil for commit without CI" do
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
expect(response).to have_http_status(200)
expect(json_response['status']).to be_nil
end
it "returns status for CI" do
pipeline = project.ensure_pipeline(project.repository.commit.sha, 'master')
+ pipeline.update(status: 'success')
+
get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
expect(response).to have_http_status(200)
expect(json_response['status']).to eq(pipeline.status)
end
+
+ it "returns status for CI when pipeline is created" do
+ project.ensure_pipeline(project.repository.commit.sha, 'master')
+
+ get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to be_nil
+ end
end
context "unauthorized user" do
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
index 5702682fc7d..82bba1ce8a4 100644
--- a/spec/requests/api/triggers_spec.rb
+++ b/spec/requests/api/triggers_spec.rb
@@ -50,7 +50,8 @@ describe API::API do
post api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'master')
expect(response).to have_http_status(201)
pipeline.builds.reload
- expect(pipeline.builds.size).to eq(2)
+ expect(pipeline.builds.pending.size).to eq(2)
+ expect(pipeline.builds.size).to eq(5)
end
it 'returns bad request with no builds created if there\'s no commit for that ref' do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 05b309096cb..ca7932dc5da 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -6,112 +6,102 @@ describe Ci::API::API do
let(:runner) { FactoryGirl.create(:ci_runner, tag_list: ["mysql", "ruby"]) }
let(:project) { FactoryGirl.create(:empty_project) }
- before do
- stub_ci_pipeline_to_return_yaml_file
- end
-
describe "Builds API for runners" do
- let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
- let(:shared_project) { FactoryGirl.create(:empty_project, name: "SharedProject") }
+ let(:pipeline) { create(:ci_pipeline_without_jobs, project: project, ref: 'master') }
before do
- FactoryGirl.create :ci_runner_project, project: project, runner: runner
+ project.runners << runner
end
describe "POST /builds/register" do
- it "starts a build" do
- pipeline = FactoryGirl.create(:ci_pipeline, project: project, ref: 'master')
- pipeline.create_builds(nil)
- build = pipeline.builds.first
+ let!(:build) { create(:ci_build, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
- post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
+ it "starts a build" do
+ register_builds info: { platform: :darwin }
expect(response).to have_http_status(201)
expect(json_response['sha']).to eq(build.sha)
expect(runner.reload.platform).to eq("darwin")
+ expect(json_response["options"]).to eq({ "image" => "ruby:2.1", "services" => ["postgres"] })
+ expect(json_response["variables"]).to include(
+ { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
+ { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
+ { "key" => "DB_NAME", "value" => "postgres", "public" => true }
+ )
end
- it "returns 404 error if no pending build found" do
- post ci_api("/builds/register"), token: runner.token
-
- expect(response).to have_http_status(404)
- end
-
- it "returns 404 error if no builds for specific runner" do
- pipeline = FactoryGirl.create(:ci_pipeline, project: shared_project)
- FactoryGirl.create(:ci_build, pipeline: pipeline, status: 'pending')
+ context 'when builds are finished' do
+ before do
+ build.success
+ end
- post ci_api("/builds/register"), token: runner.token
+ it "returns 404 error if no builds for specific runner" do
+ register_builds
- expect(response).to have_http_status(404)
+ expect(response).to have_http_status(404)
+ end
end
- it "returns 404 error if no builds for shared runner" do
- pipeline = FactoryGirl.create(:ci_pipeline, project: project)
- FactoryGirl.create(:ci_build, pipeline: pipeline, status: 'pending')
+ context 'for other project with builds' do
+ before do
+ build.success
+ create(:ci_build, :pending)
+ end
- post ci_api("/builds/register"), token: shared_runner.token
+ it "returns 404 error if no builds for shared runner" do
+ register_builds
- expect(response).to have_http_status(404)
+ expect(response).to have_http_status(404)
+ end
end
- it "returns options" do
- pipeline = FactoryGirl.create(:ci_pipeline, project: project, ref: 'master')
- pipeline.create_builds(nil)
+ context 'for shared runner' do
+ let(:shared_runner) { create(:ci_runner, token: "SharedRunner") }
- post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
+ it "should return 404 error if no builds for shared runner" do
+ register_builds shared_runner.token
- expect(response).to have_http_status(201)
- expect(json_response["options"]).to eq({ "image" => "ruby:2.1", "services" => ["postgres"] })
+ expect(response).to have_http_status(404)
+ end
end
- it "returns variables" do
- pipeline = FactoryGirl.create(:ci_pipeline, project: project, ref: 'master')
- pipeline.create_builds(nil)
- project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
-
- post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
+ context 'for triggered build' do
+ before do
+ trigger = create(:ci_trigger, project: project)
+ create(:ci_trigger_request_with_variables, pipeline: pipeline, builds: [build], trigger: trigger)
+ project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
+ end
- expect(response).to have_http_status(201)
- expect(json_response["variables"]).to include(
- { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
- { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
- { "key" => "DB_NAME", "value" => "postgres", "public" => true },
- { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false }
- )
+ it "returns variables for triggers" do
+ register_builds info: { platform: :darwin }
+
+ expect(response).to have_http_status(201)
+ expect(json_response["variables"]).to include(
+ { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
+ { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
+ { "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
+ { "key" => "DB_NAME", "value" => "postgres", "public" => true },
+ { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
+ { "key" => "TRIGGER_KEY_1", "value" => "TRIGGER_VALUE_1", "public" => false },
+ )
+ end
end
- it "returns variables for triggers" do
- trigger = FactoryGirl.create(:ci_trigger, project: project)
- pipeline = FactoryGirl.create(:ci_pipeline, project: project, ref: 'master')
-
- trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger)
- pipeline.create_builds(nil, trigger_request)
- project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
-
- post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
-
- expect(response).to have_http_status(201)
- expect(json_response["variables"]).to include(
- { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
- { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
- { "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
- { "key" => "DB_NAME", "value" => "postgres", "public" => true },
- { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
- { "key" => "TRIGGER_KEY_1", "value" => "TRIGGER_VALUE_1", "public" => false }
- )
- end
+ context 'with multiple builds' do
+ before do
+ build.success
+ end
- it "returns dependent builds" do
- pipeline = FactoryGirl.create(:ci_pipeline, project: project, ref: 'master')
- pipeline.create_builds(nil, nil)
- pipeline.builds.where(stage: 'test').each(&:success)
+ let!(:test_build) { create(:ci_build, pipeline: pipeline, name: 'deploy', stage: 'deploy', stage_idx: 1) }
- post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
+ it "returns dependent builds" do
+ register_builds info: { platform: :darwin }
- expect(response).to have_http_status(201)
- expect(json_response["depends_on_builds"].count).to eq(2)
- expect(json_response["depends_on_builds"][0]["name"]).to eq("rspec")
+ expect(response).to have_http_status(201)
+ expect(json_response["id"]).to eq(test_build.id)
+ expect(json_response["depends_on_builds"].count).to eq(1)
+ expect(json_response["depends_on_builds"][0]).to include('id' => build.id, 'name' => 'spinach')
+ end
end
%w(name version revision platform architecture).each do |param|
@@ -121,8 +111,9 @@ describe Ci::API::API do
subject { runner.read_attribute(param.to_sym) }
it do
- post ci_api("/builds/register"), token: runner.token, info: { param => value }
- expect(response).to have_http_status(404)
+ register_builds info: { param => value }
+
+ expect(response).to have_http_status(201)
runner.reload
is_expected.to eq(value)
end
@@ -131,8 +122,7 @@ describe Ci::API::API do
context 'when build has no tags' do
before do
- pipeline = create(:ci_pipeline, project: project)
- create(:ci_build, pipeline: pipeline, tags: [])
+ build.update(tags: [])
end
context 'when runner is allowed to pick untagged builds' do
@@ -154,17 +144,15 @@ describe Ci::API::API do
expect(response).to have_http_status 404
end
end
+ end
- def register_builds
- post ci_api("/builds/register"), token: runner.token,
- info: { platform: :darwin }
- end
+ def register_builds(token = runner.token, **params)
+ post ci_api("/builds/register"), params.merge(token: token)
end
end
describe "PUT /builds/:id" do
- let(:pipeline) {create(:ci_pipeline, project: project)}
- let(:build) { create(:ci_build, :trace, pipeline: pipeline, runner_id: runner.id) }
+ let(:build) { create(:ci_build, :pending, :trace, pipeline: pipeline, runner_id: runner.id) }
before do
build.run!
@@ -189,7 +177,7 @@ describe Ci::API::API do
end
describe 'PATCH /builds/:id/trace.txt' do
- let(:build) { create(:ci_build, :trace, runner_id: runner.id) }
+ let(:build) { create(:ci_build, :pending, :trace, runner_id: runner.id) }
let(:headers) { { Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token, 'Content-Type' => 'text/plain' } }
let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) }
@@ -237,8 +225,7 @@ describe Ci::API::API do
context "Artifacts" do
let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') }
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline, runner_id: runner.id) }
+ let(:build) { create(:ci_build, :pending, pipeline: pipeline, runner_id: runner.id) }
let(:authorize_url) { ci_api("/builds/#{build.id}/artifacts/authorize") }
let(:post_url) { ci_api("/builds/#{build.id}/artifacts") }
let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") }
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index 3312bd11669..0a0f979f57d 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -42,7 +42,8 @@ describe Ci::API::API do
post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options
expect(response).to have_http_status(201)
pipeline.builds.reload
- expect(pipeline.builds.size).to eq(2)
+ expect(pipeline.builds.pending.size).to eq(2)
+ expect(pipeline.builds.size).to eq(5)
end
it 'returns bad request with no builds created if there\'s no commit for that ref' do
diff --git a/spec/services/ci/create_builds_service_spec.rb b/spec/services/ci/create_builds_service_spec.rb
deleted file mode 100644
index 8b0becd83d3..00000000000
--- a/spec/services/ci/create_builds_service_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'spec_helper'
-
-describe Ci::CreateBuildsService, services: true do
- let(:pipeline) { create(:ci_pipeline, ref: 'master') }
- let(:user) { create(:user) }
-
- describe '#execute' do
- # Using stubbed .gitlab-ci.yml created in commit factory
- #
-
- subject do
- described_class.new(pipeline).execute('test', user, status, nil)
- end
-
- context 'next builds available' do
- let(:status) { 'success' }
-
- it { is_expected.to be_an_instance_of Array }
- it { is_expected.to all(be_an_instance_of Ci::Build) }
-
- it 'does not persist created builds' do
- expect(subject.first).not_to be_persisted
- end
- end
-
- context 'builds skipped' do
- let(:status) { 'skipped' }
-
- it { is_expected.to be_empty }
- end
- end
-end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
new file mode 100644
index 00000000000..4aadd009f3e
--- /dev/null
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -0,0 +1,214 @@
+require 'spec_helper'
+
+describe Ci::CreatePipelineService, services: true do
+ let(:project) { FactoryGirl.create(:project) }
+ let(:user) { create(:admin) }
+
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
+
+ describe '#execute' do
+ def execute(params)
+ described_class.new(project, user, params).execute
+ end
+
+ context 'valid params' do
+ let(:pipeline) do
+ execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: [{ message: "Message" }])
+ end
+
+ it { expect(pipeline).to be_kind_of(Ci::Pipeline) }
+ it { expect(pipeline).to be_valid }
+ it { expect(pipeline).to be_persisted }
+ it { expect(pipeline).to eq(project.pipelines.last) }
+ it { expect(pipeline).to have_attributes(user: user) }
+ it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) }
+ end
+
+ context "skip tag if there is no build for it" do
+ it "creates commit if there is appropriate job" do
+ result = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: [{ message: "Message" }])
+ expect(result).to be_persisted
+ end
+
+ it "creates commit if there is no appropriate job but deploy job has right ref setting" do
+ config = YAML.dump({ deploy: { script: "ls", only: ["master"] } })
+ stub_ci_pipeline_yaml_file(config)
+ result = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: [{ message: "Message" }])
+
+ expect(result).to be_persisted
+ end
+ end
+
+ it 'skips creating pipeline for refs without .gitlab-ci.yml' do
+ stub_ci_pipeline_yaml_file(nil)
+ result = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: [{ message: 'Message' }])
+
+ expect(result).not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+
+ it 'fails commits if yaml is invalid' do
+ message = 'message'
+ allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
+ stub_ci_pipeline_yaml_file('invalid: file: file')
+ commits = [{ message: message }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq('failed')
+ expect(pipeline.yaml_errors).not_to be_nil
+ end
+
+ context 'when commit contains a [ci skip] directive' do
+ let(:message) { "some message[ci skip]" }
+ let(:messageFlip) { "some message[skip ci]" }
+ let(:capMessage) { "some message[CI SKIP]" }
+ let(:capMessageFlip) { "some message[SKIP CI]" }
+
+ before do
+ allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
+ end
+
+ it "skips builds creation if there is [ci skip] tag in commit message" do
+ commits = [{ message: message }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq("skipped")
+ end
+
+ it "skips builds creation if there is [skip ci] tag in commit message" do
+ commits = [{ message: messageFlip }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq("skipped")
+ end
+
+ it "skips builds creation if there is [CI SKIP] tag in commit message" do
+ commits = [{ message: capMessage }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq("skipped")
+ end
+
+ it "skips builds creation if there is [SKIP CI] tag in commit message" do
+ commits = [{ message: capMessageFlip }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq("skipped")
+ end
+
+ it "does not skips builds creation if there is no [ci skip] or [skip ci] tag in commit message" do
+ allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { "some message" }
+
+ commits = [{ message: "some message" }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.first.name).to eq("rspec")
+ end
+
+ it "fails builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
+ stub_ci_pipeline_yaml_file('invalid: file: fiile')
+ commits = [{ message: message }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq("failed")
+ expect(pipeline.yaml_errors).not_to be_nil
+ end
+ end
+
+ it "creates commit with failed status if yaml is invalid" do
+ stub_ci_pipeline_yaml_file('invalid: file')
+ commits = [{ message: "some message" }]
+ pipeline = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: commits)
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.status).to eq("failed")
+ expect(pipeline.builds.any?).to be false
+ end
+
+ context 'when there are no jobs for this pipeline' do
+ before do
+ config = YAML.dump({ test: { script: 'ls', only: ['feature'] } })
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'does not create a new pipeline' do
+ result = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: [{ message: 'some msg' }])
+
+ expect(result).not_to be_persisted
+ expect(Ci::Build.all).to be_empty
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'with manual actions' do
+ before do
+ config = YAML.dump({ deploy: { script: 'ls', when: 'manual' } })
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'does not create a new pipeline' do
+ result = execute(ref: 'refs/heads/master',
+ before: '00000000',
+ after: project.commit.id,
+ commits: [{ message: 'some msg' }])
+
+ expect(result).to be_persisted
+ expect(result.manual_actions).not_to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index b72e0bd3dbe..d8c443d29d5 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Ci::CreateTriggerRequestService, services: true do
- let(:service) { Ci::CreateTriggerRequestService.new }
+ let(:service) { described_class.new }
let(:project) { create(:project) }
let(:trigger) { create(:ci_trigger, project: project) }
@@ -27,8 +27,7 @@ describe Ci::CreateTriggerRequestService, services: true do
subject { service.execute(project, trigger, 'master') }
before do
- stub_ci_pipeline_yaml_file('{}')
- FactoryGirl.create :ci_pipeline, project: project
+ stub_ci_pipeline_yaml_file('script: { only: [develop], script: hello World }')
end
it { expect(subject).to be_nil }
diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb
index 3a3e3efe709..259062406c7 100644
--- a/spec/services/ci/image_for_build_service_spec.rb
+++ b/spec/services/ci/image_for_build_service_spec.rb
@@ -5,8 +5,8 @@ module Ci
let(:service) { ImageForBuildService.new }
let(:project) { FactoryGirl.create(:empty_project) }
let(:commit_sha) { '01234567890123456789' }
- let(:commit) { project.ensure_pipeline(commit_sha, 'master') }
- let(:build) { FactoryGirl.create(:ci_build, pipeline: commit) }
+ let(:pipeline) { project.ensure_pipeline(commit_sha, 'master') }
+ let(:build) { FactoryGirl.create(:ci_build, pipeline: pipeline) }
describe '#execute' do
before { build }
@@ -14,6 +14,7 @@ module Ci
context 'branch name' do
before { allow(project).to receive(:commit).and_return(OpenStruct.new(sha: commit_sha)) }
before { build.run! }
+ before { pipeline.reload_status! }
let(:image) { service.execute(project, ref: 'master') }
it { expect(image).to be_kind_of(OpenStruct) }
@@ -31,6 +32,7 @@ module Ci
context 'commit sha' do
before { build.run! }
+ before { pipeline.reload_status! }
let(:image) { service.execute(project, sha: build.sha) }
it { expect(image).to be_kind_of(OpenStruct) }
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
new file mode 100644
index 00000000000..ad8c2485888
--- /dev/null
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -0,0 +1,288 @@
+require 'spec_helper'
+
+describe Ci::ProcessPipelineService, services: true do
+ let(:pipeline) { create(:ci_pipeline, ref: 'master') }
+ let(:user) { create(:user) }
+ let(:all_builds) { pipeline.builds }
+ let(:builds) { all_builds.where.not(status: [:created, :skipped]) }
+ let(:config) { nil }
+
+ before do
+ allow(pipeline).to receive(:ci_yaml_file).and_return(config)
+ end
+
+ describe '#execute' do
+ def create_builds
+ described_class.new(pipeline.project, user).execute(pipeline)
+ end
+
+ def succeed_pending
+ builds.pending.update_all(status: 'success')
+ end
+
+ context 'start queuing next builds' do
+ before do
+ create(:ci_build, :created, pipeline: pipeline, name: 'linux', stage_idx: 0)
+ create(:ci_build, :created, pipeline: pipeline, name: 'mac', stage_idx: 0)
+ create(:ci_build, :created, pipeline: pipeline, name: 'rspec', stage_idx: 1)
+ create(:ci_build, :created, pipeline: pipeline, name: 'rubocop', stage_idx: 1)
+ create(:ci_build, :created, pipeline: pipeline, name: 'deploy', stage_idx: 2)
+ end
+
+ it 'processes a pipeline' do
+ expect(create_builds).to be_truthy
+ succeed_pending
+ expect(builds.success.count).to eq(2)
+
+ expect(create_builds).to be_truthy
+ succeed_pending
+ expect(builds.success.count).to eq(4)
+
+ expect(create_builds).to be_truthy
+ succeed_pending
+ expect(builds.success.count).to eq(5)
+
+ expect(create_builds).to be_falsey
+ end
+
+ it 'does not process pipeline if existing stage is running' do
+ expect(create_builds).to be_truthy
+ expect(builds.pending.count).to eq(2)
+
+ expect(create_builds).to be_falsey
+ expect(builds.pending.count).to eq(2)
+ end
+ end
+
+ context 'custom stage with first job allowed to fail' do
+ before do
+ create(:ci_build, :created, pipeline: pipeline, name: 'clean_job', stage_idx: 0, allow_failure: true)
+ create(:ci_build, :created, pipeline: pipeline, name: 'test_job', stage_idx: 1, allow_failure: true)
+ end
+
+ it 'automatically triggers a next stage when build finishes' do
+ expect(create_builds).to be_truthy
+ expect(builds.pluck(:status)).to contain_exactly('pending')
+
+ pipeline.builds.running_or_pending.each(&:drop)
+ expect(builds.pluck(:status)).to contain_exactly('failed', 'pending')
+ end
+ end
+
+ context 'properly creates builds when "when" is defined' do
+ before do
+ create(:ci_build, :created, pipeline: pipeline, name: 'build', stage_idx: 0)
+ create(:ci_build, :created, pipeline: pipeline, name: 'test', stage_idx: 1)
+ create(:ci_build, :created, pipeline: pipeline, name: 'test_failure', stage_idx: 2, when: 'on_failure')
+ create(:ci_build, :created, pipeline: pipeline, name: 'deploy', stage_idx: 3)
+ create(:ci_build, :created, pipeline: pipeline, name: 'production', stage_idx: 3, when: 'manual')
+ create(:ci_build, :created, pipeline: pipeline, name: 'cleanup', stage_idx: 4, when: 'always')
+ create(:ci_build, :created, pipeline: pipeline, name: 'clear cache', stage_idx: 4, when: 'manual')
+ end
+
+ context 'when builds are successful' do
+ it 'properly creates builds' do
+ expect(create_builds).to be_truthy
+ expect(builds.pluck(:name)).to contain_exactly('build')
+ expect(builds.pluck(:status)).to contain_exactly('pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success')
+ pipeline.reload
+ expect(pipeline.status).to eq('success')
+ end
+ end
+
+ context 'when test job fails' do
+ it 'properly creates builds' do
+ expect(create_builds).to be_truthy
+ expect(builds.pluck(:name)).to contain_exactly('build')
+ expect(builds.pluck(:status)).to contain_exactly('pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
+ pipeline.builds.running_or_pending.each(&:drop)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success')
+ pipeline.reload
+ expect(pipeline.status).to eq('failed')
+ end
+ end
+
+ context 'when test and test_failure jobs fail' do
+ it 'properly creates builds' do
+ expect(create_builds).to be_truthy
+ expect(builds.pluck(:name)).to contain_exactly('build')
+ expect(builds.pluck(:status)).to contain_exactly('pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
+ pipeline.builds.running_or_pending.each(&:drop)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
+ pipeline.builds.running_or_pending.each(&:drop)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success')
+ pipeline.reload
+ expect(pipeline.status).to eq('failed')
+ end
+ end
+
+ context 'when deploy job fails' do
+ it 'properly creates builds' do
+ expect(create_builds).to be_truthy
+ expect(builds.pluck(:name)).to contain_exactly('build')
+ expect(builds.pluck(:status)).to contain_exactly('pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
+ pipeline.builds.running_or_pending.each(&:drop)
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success')
+ pipeline.reload
+ expect(pipeline.status).to eq('failed')
+ end
+ end
+
+ context 'when build is canceled in the second stage' do
+ it 'does not schedule builds after build has been canceled' do
+ expect(create_builds).to be_truthy
+ expect(builds.pluck(:name)).to contain_exactly('build')
+ expect(builds.pluck(:status)).to contain_exactly('pending')
+ pipeline.builds.running_or_pending.each(&:success)
+
+ expect(builds.running_or_pending).not_to be_empty
+
+ expect(builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
+ pipeline.builds.running_or_pending.each(&:cancel)
+
+ expect(builds.running_or_pending).to be_empty
+ expect(pipeline.reload.status).to eq('canceled')
+ end
+ end
+
+ context 'when listing manual actions' do
+ it 'returns only for skipped builds' do
+ # currently all builds are created
+ expect(create_builds).to be_truthy
+ expect(manual_actions).to be_empty
+
+ # succeed stage build
+ pipeline.builds.running_or_pending.each(&:success)
+ expect(manual_actions).to be_empty
+
+ # succeed stage test
+ pipeline.builds.running_or_pending.each(&:success)
+ expect(manual_actions).to be_one # production
+
+ # succeed stage deploy
+ pipeline.builds.running_or_pending.each(&:success)
+ expect(manual_actions).to be_many # production and clear cache
+ end
+
+ def manual_actions
+ pipeline.manual_actions
+ end
+ end
+ end
+
+ context 'creates a builds from .gitlab-ci.yml' do
+ let(:config) do
+ YAML.dump({
+ rspec: {
+ stage: 'test',
+ script: 'rspec'
+ },
+ rubocop: {
+ stage: 'test',
+ script: 'rubocop'
+ },
+ deploy: {
+ stage: 'deploy',
+ script: 'deploy'
+ }
+ })
+ end
+
+ # Using stubbed .gitlab-ci.yml created in commit factory
+ #
+
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ create(:ci_build, :created, pipeline: pipeline, name: 'linux', stage: 'build', stage_idx: 0)
+ create(:ci_build, :created, pipeline: pipeline, name: 'mac', stage: 'build', stage_idx: 0)
+ end
+
+ it 'when processing a pipeline' do
+ # Currently we have two builds with state created
+ expect(builds.count).to eq(0)
+ expect(all_builds.count).to eq(2)
+
+ # Create builds will mark the created as pending
+ expect(create_builds).to be_truthy
+ expect(builds.count).to eq(2)
+ expect(all_builds.count).to eq(2)
+
+ # When we builds succeed we will create a rest of pipeline from .gitlab-ci.yml
+ # We will have 2 succeeded, 2 pending (from stage test), total 5 (one more build from deploy)
+ succeed_pending
+ expect(create_builds).to be_truthy
+ expect(builds.success.count).to eq(2)
+ expect(builds.pending.count).to eq(2)
+ expect(all_builds.count).to eq(5)
+
+ # When we succeed the 2 pending from stage test,
+ # We will queue a deploy stage, no new builds will be created
+ succeed_pending
+ expect(create_builds).to be_truthy
+ expect(builds.pending.count).to eq(1)
+ expect(builds.success.count).to eq(4)
+ expect(all_builds.count).to eq(5)
+
+ # When we succeed last pending build, we will have a total of 5 succeeded builds, no new builds will be created
+ succeed_pending
+ expect(create_builds).to be_falsey
+ expect(builds.success.count).to eq(5)
+ expect(all_builds.count).to eq(5)
+ end
+ end
+ end
+end
diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb
deleted file mode 100644
index d4c5e584421..00000000000
--- a/spec/services/create_commit_builds_service_spec.rb
+++ /dev/null
@@ -1,241 +0,0 @@
-require 'spec_helper'
-
-describe CreateCommitBuildsService, services: true do
- let(:service) { CreateCommitBuildsService.new }
- let(:project) { FactoryGirl.create(:empty_project) }
- let(:user) { create(:user) }
-
- before do
- stub_ci_pipeline_to_return_yaml_file
- end
-
- describe '#execute' do
- context 'valid params' do
- let(:pipeline) do
- service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: [{ message: "Message" }]
- )
- end
-
- it { expect(pipeline).to be_kind_of(Ci::Pipeline) }
- it { expect(pipeline).to be_valid }
- it { expect(pipeline).to be_persisted }
- it { expect(pipeline).to eq(project.pipelines.last) }
- it { expect(pipeline).to have_attributes(user: user) }
- it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) }
- end
-
- context "skip tag if there is no build for it" do
- it "creates commit if there is appropriate job" do
- result = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: [{ message: "Message" }]
- )
- expect(result).to be_persisted
- end
-
- it "creates commit if there is no appropriate job but deploy job has right ref setting" do
- config = YAML.dump({ deploy: { script: "ls", only: ["0_1"] } })
- stub_ci_pipeline_yaml_file(config)
-
- result = service.execute(project, user,
- ref: 'refs/heads/0_1',
- before: '00000000',
- after: '31das312',
- commits: [{ message: "Message" }]
- )
- expect(result).to be_persisted
- end
- end
-
- it 'skips creating pipeline for refs without .gitlab-ci.yml' do
- stub_ci_pipeline_yaml_file(nil)
- result = service.execute(project, user,
- ref: 'refs/heads/0_1',
- before: '00000000',
- after: '31das312',
- commits: [{ message: 'Message' }]
- )
- expect(result).to be_falsey
- expect(Ci::Pipeline.count).to eq(0)
- end
-
- it 'fails commits if yaml is invalid' do
- message = 'message'
- allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
- stub_ci_pipeline_yaml_file('invalid: file: file')
- commits = [{ message: message }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(pipeline).to be_persisted
- expect(pipeline.builds.any?).to be false
- expect(pipeline.status).to eq('failed')
- expect(pipeline.yaml_errors).not_to be_nil
- end
-
- context 'when commit contains a [ci skip] directive' do
- let(:message) { "some message[ci skip]" }
- let(:messageFlip) { "some message[skip ci]" }
- let(:capMessage) { "some message[CI SKIP]" }
- let(:capMessageFlip) { "some message[SKIP CI]" }
-
- before do
- allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
- end
-
- it "skips builds creation if there is [ci skip] tag in commit message" do
- commits = [{ message: message }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(pipeline).to be_persisted
- expect(pipeline.builds.any?).to be false
- expect(pipeline.status).to eq("skipped")
- end
-
- it "skips builds creation if there is [skip ci] tag in commit message" do
- commits = [{ message: messageFlip }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(pipeline).to be_persisted
- expect(pipeline.builds.any?).to be false
- expect(pipeline.status).to eq("skipped")
- end
-
- it "skips builds creation if there is [CI SKIP] tag in commit message" do
- commits = [{ message: capMessage }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(pipeline).to be_persisted
- expect(pipeline.builds.any?).to be false
- expect(pipeline.status).to eq("skipped")
- end
-
- it "skips builds creation if there is [SKIP CI] tag in commit message" do
- commits = [{ message: capMessageFlip }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(pipeline).to be_persisted
- expect(pipeline.builds.any?).to be false
- expect(pipeline.status).to eq("skipped")
- end
-
- it "does not skips builds creation if there is no [ci skip] or [skip ci] tag in commit message" do
- allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { "some message" }
-
- commits = [{ message: "some message" }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(pipeline).to be_persisted
- expect(pipeline.builds.first.name).to eq("staging")
- end
-
- it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
- stub_ci_pipeline_yaml_file('invalid: file: fiile')
- commits = [{ message: message }]
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(pipeline).to be_persisted
- expect(pipeline.builds.any?).to be false
- expect(pipeline.status).to eq("skipped")
- expect(pipeline.yaml_errors).to be_nil
- end
- end
-
- it "skips build creation if there are already builds" do
- allow_any_instance_of(Ci::Pipeline).to receive(:ci_yaml_file) { gitlab_ci_yaml }
-
- commits = [{ message: "message" }]
- pipeline = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(pipeline).to be_persisted
- expect(pipeline.builds.count(:all)).to eq(2)
-
- pipeline = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
- expect(pipeline).to be_persisted
- expect(pipeline.builds.count(:all)).to eq(2)
- end
-
- it "creates commit with failed status if yaml is invalid" do
- stub_ci_pipeline_yaml_file('invalid: file')
-
- commits = [{ message: "some message" }]
-
- pipeline = service.execute(project, user,
- ref: 'refs/tags/0_1',
- before: '00000000',
- after: '31das312',
- commits: commits
- )
-
- expect(pipeline).to be_persisted
- expect(pipeline.status).to eq("failed")
- expect(pipeline.builds.any?).to be false
- end
-
- context 'when there are no jobs for this pipeline' do
- before do
- config = YAML.dump({ test: { script: 'ls', only: ['feature'] } })
- stub_ci_pipeline_yaml_file(config)
- end
-
- it 'does not create a new pipeline' do
- result = service.execute(project, user,
- ref: 'refs/heads/master',
- before: '00000000',
- after: '31das312',
- commits: [{ message: 'some msg' }])
-
- expect(result).to be_falsey
- expect(Ci::Build.all).to be_empty
- expect(Ci::Pipeline.count).to eq(0)
- end
- end
- end
-end
diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
index 4da8146e3d6..520e906b21f 100644
--- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
+++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
@@ -110,19 +110,15 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
context 'properly handles multiple stages' do
let(:ref) { mr_merge_if_green_enabled.source_branch }
- let(:build) { create(:ci_build, pipeline: pipeline, ref: ref, name: 'build', stage: 'build') }
- let(:test) { create(:ci_build, pipeline: pipeline, ref: ref, name: 'test', stage: 'test') }
+ let!(:build) { create(:ci_build, :created, pipeline: pipeline, ref: ref, name: 'build', stage: 'build') }
+ let!(:test) { create(:ci_build, :created, pipeline: pipeline, ref: ref, name: 'test', stage: 'test') }
+ let(:pipeline) { create(:ci_empty_pipeline, ref: mr_merge_if_green_enabled.source_branch, project: project) }
before do
# This behavior of MergeRequest: we instantiate a new object
allow_any_instance_of(MergeRequest).to receive(:pipeline).and_wrap_original do
Ci::Pipeline.find(pipeline.id)
end
-
- # We create test after the build
- allow(pipeline).to receive(:create_next_builds).and_wrap_original do
- test
- end
end
it "doesn't merge if some stages failed" do
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 7f803a06902..1d2cf7acddd 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -53,7 +53,13 @@ describe PostReceive do
subject { PostReceive.new.perform(pwd(project), key_id, base64_changes) }
context "creates a Ci::Pipeline for every change" do
- before { stub_ci_pipeline_to_return_yaml_file }
+ before do
+ allow_any_instance_of(Ci::CreatePipelineService).to receive(:commit) do
+ OpenStruct.new(id: '123456')
+ end
+ allow_any_instance_of(Ci::CreatePipelineService).to receive(:branch?).and_return(true)
+ stub_ci_pipeline_to_return_yaml_file
+ end
it { expect{ subject }.to change{ Ci::Pipeline.count }.by(2) }
end