summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrasimir Angelov <kangelov@gitlab.com>2019-06-19 13:47:48 +1200
committerKrasimir Angelov <kangelov@gitlab.com>2019-06-21 14:30:47 +1200
commit4930dfc2b917433e041762b65bd503d8e4b090b6 (patch)
treedffe185d69c06459e405c734b87aa55b42ac40bf
parent148516ba36855095fa995c2d4e8077919cdb6db6 (diff)
downloadgitlab-ce-27644-create-environments-when-needed.tar.gz
Delay creating build's environment and deployment27644-create-environments-when-needed
Instead of creating environment and deployment on build creation add this as a new prerequisite for builds. This way we are not going to unnecessary create records (e.g. for builds with manual start). Fix specs that assume environment and deployment will be created immediately when build is created. Related to https://gitlab.com/gitlab-org/gitlab-ce/issues/27644.
-rw-r--r--app/models/concerns/deployable.rb2
-rw-r--r--lib/gitlab/ci/build/prerequisite/deployment.rb21
-rw-r--r--lib/gitlab/ci/build/prerequisite/factory.rb5
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/deployment_spec.rb54
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb37
-rw-r--r--spec/models/ci/build_spec.rb45
-rw-r--r--spec/models/concerns/deployable_spec.rb49
-rw-r--r--spec/models/environment_status_spec.rb4
-rw-r--r--spec/models/merge_request_spec.rb14
-rw-r--r--spec/services/ci/stop_environments_service_spec.rb1
-rw-r--r--spec/services/update_deployment_service_spec.rb1
-rw-r--r--spec/workers/build_success_worker_spec.rb4
12 files changed, 160 insertions, 77 deletions
diff --git a/app/models/concerns/deployable.rb b/app/models/concerns/deployable.rb
index bc12b06b5af..2da5be696b0 100644
--- a/app/models/concerns/deployable.rb
+++ b/app/models/concerns/deployable.rb
@@ -4,8 +4,6 @@ module Deployable
extend ActiveSupport::Concern
included do
- after_create :create_deployment
-
def create_deployment
return unless starts_environment? && !has_deployment?
diff --git a/lib/gitlab/ci/build/prerequisite/deployment.rb b/lib/gitlab/ci/build/prerequisite/deployment.rb
new file mode 100644
index 00000000000..0442fda1dda
--- /dev/null
+++ b/lib/gitlab/ci/build/prerequisite/deployment.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Build
+ module Prerequisite
+ class Deployment < Base
+ def unmet?
+ build.starts_environment? && !build.has_deployment?
+ end
+
+ def complete!
+ return unless unmet?
+
+ build.create_deployment
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/build/prerequisite/factory.rb b/lib/gitlab/ci/build/prerequisite/factory.rb
index 60cdf7af418..19c0e1518f3 100644
--- a/lib/gitlab/ci/build/prerequisite/factory.rb
+++ b/lib/gitlab/ci/build/prerequisite/factory.rb
@@ -8,7 +8,10 @@ module Gitlab
attr_reader :build
def self.prerequisites
- [KubernetesNamespace]
+ [
+ Gitlab::Ci::Build::Prerequisite::KubernetesNamespace,
+ Gitlab::Ci::Build::Prerequisite::Deployment
+ ]
end
def initialize(build)
diff --git a/spec/lib/gitlab/ci/build/prerequisite/deployment_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/deployment_spec.rb
new file mode 100644
index 00000000000..0c6175be1a2
--- /dev/null
+++ b/spec/lib/gitlab/ci/build/prerequisite/deployment_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Ci::Build::Prerequisite::Deployment do
+ describe '#unmet?' do
+ context 'when the build starts an environment' do
+ it 'returns true if there is no deployment' do
+ build = instance_double(Ci::Build, starts_environment?: true, has_deployment?: false)
+ prerequisite = described_class.new(build)
+
+ expect(prerequisite).to be_unmet
+ end
+
+ it 'returns false if there is a deployment' do
+ build = instance_double(Ci::Build, starts_environment?: true, has_deployment?: true)
+ prerequisite = described_class.new(build)
+
+ expect(prerequisite).not_to be_unmet
+ end
+ end
+
+ it 'returns false if the build does not start an environment' do
+ build = instance_double(Ci::Build, starts_environment?: false)
+ prerequisite = described_class.new(build)
+
+ expect(prerequisite).not_to be_unmet
+ end
+ end
+
+ describe '#complete!' do
+ context 'when prerequisite is unmet' do
+ it 'creates a deployment and environment' do
+ build = instance_double(Ci::Build, starts_environment?: true, has_deployment?: false)
+ prerequisite = described_class.new(build)
+
+ expect(build).to receive(:create_deployment)
+
+ prerequisite.complete!
+ end
+ end
+
+ context 'when prerequisite is met' do
+ it 'creates a deployment and environment' do
+ build = instance_double(Ci::Build, starts_environment?: true, has_deployment?: true)
+ prerequisite = described_class.new(build)
+
+ expect(build).not_to receive(:create_deployment)
+
+ prerequisite.complete!
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb
index 5187f99a441..ff9d29f43a4 100644
--- a/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb
+++ b/spec/lib/gitlab/ci/build/prerequisite/factory_spec.rb
@@ -3,32 +3,39 @@
require 'spec_helper'
describe Gitlab::Ci::Build::Prerequisite::Factory do
- let(:build) { create(:ci_build) }
+ let(:build) { instance_double(Ci::Build) }
- describe '.for_build' do
+ describe '.prerequisites' do
+ it 'returns KubernetesNamespace and Deployment' do
+ expect(described_class.prerequisites).to contain_exactly(
+ Gitlab::Ci::Build::Prerequisite::KubernetesNamespace,
+ Gitlab::Ci::Build::Prerequisite::Deployment
+ )
+ end
+ end
+
+ describe '#unmet' do
let(:kubernetes_namespace) do
instance_double(
Gitlab::Ci::Build::Prerequisite::KubernetesNamespace,
- unmet?: unmet)
+ unmet?: true)
end
- subject { described_class.new(build).unmet }
+ let(:deployment) do
+ instance_double(
+ Gitlab::Ci::Build::Prerequisite::Deployment,
+ unmet?: false)
+ end
- before do
+ it 'returns only unmet prerequisites' do
expect(Gitlab::Ci::Build::Prerequisite::KubernetesNamespace)
.to receive(:new).with(build).and_return(kubernetes_namespace)
- end
-
- context 'prerequisite is unmet' do
- let(:unmet) { true }
-
- it { is_expected.to eq [kubernetes_namespace] }
- end
+ expect(Gitlab::Ci::Build::Prerequisite::Deployment)
+ .to receive(:new).with(build).and_return(deployment)
- context 'prerequisite is met' do
- let(:unmet) { false }
+ unmet = described_class.new(build).unmet
- it { is_expected.to be_empty }
+ expect(unmet).to contain_exactly(kubernetes_namespace)
end
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index d98db024f73..94256a00c0b 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -182,33 +182,22 @@ describe Ci::Build do
end
describe '#enqueue' do
- let(:build) { create(:ci_build, :created) }
-
- subject { build.enqueue }
-
- before do
- allow(build).to receive(:any_unmet_prerequisites?).and_return(has_prerequisites)
- allow(Ci::PrepareBuildService).to receive(:perform_async)
- end
-
- context 'build has unmet prerequisites' do
- let(:has_prerequisites) { true }
+ it 'transitions to preparing if build has unmet prerequisites' do
+ build = create(:ci_build, :start_review_app, status: 'created')
+ expect(Ci::BuildPrepareWorker).to receive(:perform_async).with(build.id)
- it 'transitions to preparing' do
- subject
+ build.enqueue
- expect(build).to be_preparing
- end
+ expect(build).to be_preparing
end
- context 'build has no prerequisites' do
- let(:has_prerequisites) { false }
+ it 'transitions to pending if build has no unmet prerequisites' do
+ build = create(:ci_build, :created)
+ expect(Ci::BuildPrepareWorker).not_to receive(:perform_async).with(build.id)
- it 'transitions to pending' do
- subject
+ build.enqueue
- expect(build).to be_pending
- end
+ expect(build).to be_pending
end
end
@@ -374,6 +363,7 @@ describe Ci::Build do
context 'build has unmet prerequisites' do
before do
allow(build).to receive(:prerequisites).and_return([double])
+ expect(Ci::BuildPrepareWorker).to receive(:perform_async).with(build.id)
end
it 'transits to preparing' do
@@ -791,13 +781,9 @@ describe Ci::Build do
allow(Deployments::FinishedWorker).to receive(:perform_async)
end
- it 'has deployments record with created status' do
- expect(deployment).to be_created
- expect(environment.name).to eq('review/master')
- end
-
context 'when transits to running' do
before do
+ build.create_deployment
build.run!
end
@@ -809,6 +795,7 @@ describe Ci::Build do
context 'when transits to success' do
before do
allow(Deployments::SuccessWorker).to receive(:perform_async)
+ build.create_deployment
build.success!
end
@@ -819,6 +806,7 @@ describe Ci::Build do
context 'when transits to failed' do
before do
+ build.create_deployment
build.drop!
end
@@ -829,6 +817,7 @@ describe Ci::Build do
context 'when transits to skipped' do
before do
+ build.create_deployment
build.skip!
end
@@ -839,6 +828,7 @@ describe Ci::Build do
context 'when transits to canceled' do
before do
+ build.create_deployment
build.cancel!
end
@@ -1781,7 +1771,8 @@ describe Ci::Build do
end
context 'when build has a start environment' do
- let(:build) { create(:ci_build, :deploy_to_production, pipeline: pipeline) }
+ let(:deployment) { create(:deployment) }
+ let(:build) { create(:ci_build, :deploy_to_production, pipeline: pipeline, deployment: deployment) }
it 'does not expand environment name' do
expect(build).not_to receive(:expanded_environment_name)
diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb
index 42bed9434f5..f4a1d510f9f 100644
--- a/spec/models/concerns/deployable_spec.rb
+++ b/spec/models/concerns/deployable_spec.rb
@@ -4,51 +4,47 @@ require 'rails_helper'
describe Deployable do
describe '#create_deployment' do
- let(:deployment) { job.deployment }
- let(:environment) { deployment&.environment }
-
- before do
- job.reload
- end
-
context 'when the deployable object will deploy to production' do
- let!(:job) { create(:ci_build, :start_review_app) }
+ let(:job) { create(:ci_build, :start_review_app) }
it 'creates a deployment and environment record' do
- expect(deployment.project).to eq(job.project)
- expect(deployment.ref).to eq(job.ref)
- expect(deployment.tag).to eq(job.tag)
- expect(deployment.sha).to eq(job.sha)
- expect(deployment.user).to eq(job.user)
- expect(deployment.deployable).to eq(job)
- expect(deployment.on_stop).to eq('stop_review_app')
- expect(environment.name).to eq('review/master')
+ job.create_deployment
+
+ expect(job.deployment.project).to eq(job.project)
+ expect(job.deployment.ref).to eq(job.ref)
+ expect(job.deployment.tag).to eq(job.tag)
+ expect(job.deployment.sha).to eq(job.sha)
+ expect(job.deployment.user).to eq(job.user)
+ expect(job.deployment.deployable).to eq(job)
+ expect(job.deployment.on_stop).to eq('stop_review_app')
+ expect(job.deployment.environment.name).to eq('review/master')
end
end
context 'when the deployable object will stop an environment' do
- let!(:job) { create(:ci_build, :stop_review_app) }
+ let(:job) { create(:ci_build, :stop_review_app) }
it 'does not create a deployment record' do
- expect(deployment).to be_nil
+ expect { job.create_deployment }.not_to change { job.reload.deployment }.from(nil)
end
end
context 'when the deployable object has already had a deployment' do
- let!(:job) { create(:ci_build, :start_review_app, deployment: race_deployment) }
- let!(:race_deployment) { create(:deployment, :success) }
+ let(:job) { create(:ci_build, :start_review_app, deployment: race_deployment) }
+ let(:race_deployment) { create(:deployment, :success) }
it 'does not create a new deployment' do
- expect(deployment).to eq(race_deployment)
+ expect { job.create_deployment }.not_to change { job.reload.deployment }.from(race_deployment)
end
end
context 'when the deployable object will not deploy' do
- let!(:job) { create(:ci_build) }
+ let(:job) { create(:ci_build) }
it 'does not create a deployment and environment record' do
- expect(deployment).to be_nil
- expect(environment).to be_nil
+ expect { job.create_deployment }.not_to change { job.reload.deployment }.from(nil)
+
+ expect(job.persisted_environment).to be_nil
end
end
@@ -68,8 +64,9 @@ describe Deployable do
end
it 'does not create a deployment and environment record' do
- expect(deployment).to be_nil
- expect(environment).to be_nil
+ expect { job.create_deployment }.not_to change { job.reload.deployment }.from(nil)
+
+ expect(job.persisted_environment).to be_nil
end
end
end
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index c503c35305f..7440be2f0a7 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -100,6 +100,10 @@ describe EnvironmentStatus do
let(:environment) { build.deployment.environment }
let(:user) { project.owner }
+ before do
+ build.create_deployment
+ end
+
context 'when environment is created on a forked project' do
let(:project) { create(:project, :repository) }
let(:forked) { fork_project(project, user, repository: true) }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index c6251326c22..acf8bc557c7 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2333,18 +2333,22 @@ describe MergeRequest do
merge_requests_as_head_pipeline: [merge_request])
end
- let!(:job) { create(:ci_build, :start_review_app, pipeline: pipeline, project: project) }
+ let(:job) { create(:ci_build, :start_review_app, pipeline: pipeline, project: project) }
it 'returns environments' do
- is_expected.to eq(pipeline.environments)
- expect(subject.count).to be(1)
+ job.create_deployment
+
+ expect(subject).to eq(pipeline.environments)
+ expect(subject.count).to eq(1)
end
context 'when pipeline is not associated with environments' do
- let!(:job) { create(:ci_build, pipeline: pipeline, project: project) }
+ let(:job) { create(:ci_build, pipeline: pipeline, project: project) }
it 'returns empty array' do
- is_expected.to be_empty
+ job.create_deployment
+
+ expect(subject).to be_empty
end
end
diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb
index 890fa5bc009..65fdc270605 100644
--- a/spec/services/ci/stop_environments_service_spec.rb
+++ b/spec/services/ci/stop_environments_service_spec.rb
@@ -125,6 +125,7 @@ describe Ci::StopEnvironmentsService do
let!(:stop_review_job) { create(:ci_build, :stop_review_app, :manual, pipeline: pipeline, project: project) }
before do
+ review_job.create_deployment
review_job.deployment.success!
end
diff --git a/spec/services/update_deployment_service_spec.rb b/spec/services/update_deployment_service_spec.rb
index 7dc52f6816a..9edf9a6660f 100644
--- a/spec/services/update_deployment_service_spec.rb
+++ b/spec/services/update_deployment_service_spec.rb
@@ -23,6 +23,7 @@ describe UpdateDeploymentService do
before do
allow(Deployments::FinishedWorker).to receive(:perform_async)
+ job.create_deployment
job.success! # Create/Succeed deployment
end
diff --git a/spec/workers/build_success_worker_spec.rb b/spec/workers/build_success_worker_spec.rb
index ffe8796ded9..530f3eb4b9b 100644
--- a/spec/workers/build_success_worker_spec.rb
+++ b/spec/workers/build_success_worker_spec.rb
@@ -31,10 +31,12 @@ describe BuildSuccessWorker do
end
end
- context 'when deployment was created with the build creation' do # Counter part of the above edge case
+ context 'when deployment was already created' do # Counter part of the above edge case
let!(:build) { create(:ci_build, :deploy_to_production) }
it 'does not create a new deployment' do
+ build.create_deployment
+
expect(build).to be_has_deployment
expect { subject }.not_to change { Deployment.count }