summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2017-06-05 07:03:39 +0000
committerKamil Trzciński <ayufan@ayufan.eu>2017-06-05 07:03:39 +0000
commitf71106425cc6f62c8e19457cc600e41a668fb89e (patch)
tree1e7e76837ca587ef883dd1da18d76817b5975676
parent761e376404265cfef77f61601944a22690d55b5e (diff)
parent2fa766e10796ba07872ce0a5554d237bd7b153ee (diff)
downloadgitlab-ce-f71106425cc6f62c8e19457cc600e41a668fb89e.tar.gz
Merge branch '25680-CI_ENVIRONMENT_URL' into 'master'
Add `$CI_ENVIRONMENT_URL` as a job variable Closes #25680 See merge request !11695
-rw-r--r--app/models/ci/build.rb27
-rw-r--r--app/services/create_deployment_service.rb76
-rw-r--r--app/workers/build_success_worker.rb11
-rw-r--r--changelogs/unreleased/25680-CI_ENVIRONMENT_URL.yml4
-rw-r--r--db/fixtures/development/14_pipelines.rb4
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb9
-rw-r--r--doc/ci/environments.md6
-rw-r--r--doc/ci/variables/README.md1
-rw-r--r--spec/factories/ci/builds.rb3
-rw-r--r--spec/models/ci/build_spec.rb96
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb15
-rw-r--r--spec/services/create_deployment_service_spec.rb246
-rw-r--r--spec/support/cycle_analytics_helpers.rb43
13 files changed, 313 insertions, 228 deletions
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 58dfdd87652..3bcc8be5cae 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -138,6 +138,17 @@ module Ci
ExpandVariables.expand(environment, simple_variables) if environment
end
+ def environment_url
+ return @environment_url if defined?(@environment_url)
+
+ @environment_url =
+ if unexpanded_url = options&.dig(:environment, :url)
+ ExpandVariables.expand(unexpanded_url, simple_variables)
+ else
+ persisted_environment&.external_url
+ end
+ end
+
def has_environment?
environment.present?
end
@@ -198,9 +209,7 @@ module Ci
# All variables, including those dependent on other variables
def variables
- variables = simple_variables
- variables += persisted_environment.predefined_variables if persisted_environment.present?
- variables
+ simple_variables.concat(persisted_environment_variables)
end
def merge_request
@@ -462,6 +471,18 @@ module Ci
variables.concat(legacy_variables)
end
+ def persisted_environment_variables
+ return [] unless persisted_environment
+
+ variables = persisted_environment.predefined_variables
+
+ if url = environment_url
+ variables << { key: 'CI_ENVIRONMENT_URL', value: url, public: true }
+ end
+
+ variables
+ end
+
def legacy_variables
variables = [
{ key: 'CI_BUILD_ID', value: id.to_s, public: true },
diff --git a/app/services/create_deployment_service.rb b/app/services/create_deployment_service.rb
index 47f9b2c621c..46823418bb0 100644
--- a/app/services/create_deployment_service.rb
+++ b/app/services/create_deployment_service.rb
@@ -1,71 +1,59 @@
-class CreateDeploymentService < BaseService
- def execute(deployable = nil)
+class CreateDeploymentService
+ attr_reader :job
+
+ delegate :expanded_environment_name,
+ :environment_url,
+ :project,
+ to: :job
+
+ def initialize(job)
+ @job = job
+ end
+
+ def execute
return unless executable?
ActiveRecord::Base.transaction do
- @deployable = deployable
+ environment.external_url = environment_url if environment_url
+ environment.fire_state_event(action)
- @environment = environment
- @environment.external_url = expanded_url if expanded_url
- @environment.fire_state_event(action)
+ return unless environment.save
+ return if environment.stopped?
- return unless @environment.save
- return if @environment.stopped?
-
- deploy.tap do |deployment|
- deployment.update_merge_request_metrics!
- end
+ deploy.tap(&:update_merge_request_metrics!)
end
end
private
def executable?
- project && name.present?
+ project && job.environment.present? && environment
end
def deploy
project.deployments.create(
- environment: @environment,
- ref: params[:ref],
- tag: params[:tag],
- sha: params[:sha],
- user: current_user,
- deployable: @deployable,
- on_stop: options[:on_stop])
+ environment: environment,
+ ref: job.ref,
+ tag: job.tag,
+ sha: job.sha,
+ user: job.user,
+ deployable: job,
+ on_stop: on_stop)
end
def environment
- @environment ||= project.environments.find_or_create_by(name: expanded_name)
- end
-
- def expanded_name
- ExpandVariables.expand(name, variables)
- end
-
- def expanded_url
- return unless url
-
- @expanded_url ||= ExpandVariables.expand(url, variables)
- end
-
- def name
- params[:environment]
- end
-
- def url
- options[:url]
+ @environment ||= job.persisted_environment
end
- def options
- params[:options] || {}
+ def environment_options
+ @environment_options ||= job.options&.dig(:environment) || {}
end
- def variables
- params[:variables] || []
+ def on_stop
+ environment_options[:on_stop]
end
def action
- options[:action] || 'start'
+ environment_options[:action] || 'start'
end
end
diff --git a/app/workers/build_success_worker.rb b/app/workers/build_success_worker.rb
index e17add7421f..bf009dfab0f 100644
--- a/app/workers/build_success_worker.rb
+++ b/app/workers/build_success_worker.rb
@@ -11,15 +11,6 @@ class BuildSuccessWorker
private
def create_deployment(build)
- service = CreateDeploymentService.new(
- build.project, build.user,
- environment: build.environment,
- sha: build.sha,
- ref: build.ref,
- tag: build.tag,
- options: build.options.to_h[:environment],
- variables: build.variables)
-
- service.execute(build)
+ CreateDeploymentService.new(build).execute
end
end
diff --git a/changelogs/unreleased/25680-CI_ENVIRONMENT_URL.yml b/changelogs/unreleased/25680-CI_ENVIRONMENT_URL.yml
new file mode 100644
index 00000000000..af9fe3b5041
--- /dev/null
+++ b/changelogs/unreleased/25680-CI_ENVIRONMENT_URL.yml
@@ -0,0 +1,4 @@
+---
+title: Add $CI_ENVIRONMENT_URL to predefined variables for pipelines
+merge_request: 11695
+author:
diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb
index 68767f0e585..5de5339b70e 100644
--- a/db/fixtures/development/14_pipelines.rb
+++ b/db/fixtures/development/14_pipelines.rb
@@ -112,6 +112,10 @@ class Gitlab::Seeder::Pipelines
setup_artifacts(build)
setup_build_log(build)
+
+ build.project.environments.
+ find_or_create_by(name: build.expanded_environment_name)
+
build.save
end
end
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 75457b2d369..7c1d758dada 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -212,12 +212,9 @@ class Gitlab::Seeder::CycleAnalytics
merge_requests.each do |merge_request|
Timecop.travel 12.hours.from_now
- CreateDeploymentService.new(merge_request.project, @user, {
- environment: 'production',
- ref: 'master',
- tag: false,
- sha: @project.repository.commit('master').sha
- }).execute
+ job = merge_request.head_pipeline.builds.where.not(environment: nil).last
+
+ CreateDeploymentService.new(job).execute
end
end
end
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index 169e0fbae3d..3393030210e 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -94,6 +94,12 @@ the name given in `.gitlab-ci.yml` (with any variables expanded), while the
second is a "cleaned-up" version of the name, suitable for use in URLs, DNS,
etc.
+>**Note:**
+Starting with GitLab 9.3, the environment URL is exposed to the Runner via
+`$CI_ENVIRONMENT_URL`. The URL would be expanded from `.gitlab-ci.yml`, or if
+the URL was not defined there, the external URL from the environment would be
+used.
+
To sum up, with the above `.gitlab-ci.yml` we have achieved that:
- All branches will run the `test` and `build` jobs.
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 656e261dff8..89b14b156cc 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -43,6 +43,7 @@ future GitLab releases.**
| **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled |
| **CI_ENVIRONMENT_NAME** | 8.15 | all | The name of the environment for this job |
| **CI_ENVIRONMENT_SLUG** | 8.15 | all | A simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, etc. |
+| **CI_ENVIRONMENT_URL** | 9.3 | all | The URL of the environment for this job |
| **CI_JOB_ID** | 9.0 | all | The unique id of the current job that GitLab CI uses internally |
| **CI_JOB_MANUAL** | 8.12 | all | The flag to indicate that job was manually started |
| **CI_JOB_NAME** | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` |
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index f5e99fdf00b..0bb5a86d9b9 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -64,7 +64,8 @@ FactoryGirl.define do
trait :teardown_environment do
environment 'staging'
options environment: { name: 'staging',
- action: 'stop' }
+ action: 'stop',
+ url: 'http://staging.example.com/$CI_JOB_NAME' }
end
trait :allowed_to_fail do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index e2406290c6c..22ee469dd86 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -427,6 +427,42 @@ describe Ci::Build, :models do
end
end
+ describe '#environment_url' do
+ subject { job.environment_url }
+
+ context 'when yaml environment uses $CI_COMMIT_REF_NAME' do
+ let(:job) do
+ create(:ci_build,
+ ref: 'master',
+ options: { environment: { url: 'http://review/$CI_COMMIT_REF_NAME' } })
+ end
+
+ it { is_expected.to eq('http://review/master') }
+ end
+
+ context 'when yaml environment uses yaml_variables containing symbol keys' do
+ let(:job) do
+ create(:ci_build,
+ yaml_variables: [{ key: :APP_HOST, value: 'host' }],
+ options: { environment: { url: 'http://review/$APP_HOST' } })
+ end
+
+ it { is_expected.to eq('http://review/host') }
+ end
+
+ context 'when yaml environment does not have url' do
+ let(:job) { create(:ci_build, environment: 'staging') }
+
+ let!(:environment) do
+ create(:environment, project: job.project, name: job.environment)
+ end
+
+ it 'returns the external_url from persisted environment' do
+ is_expected.to eq(environment.external_url)
+ end
+ end
+ end
+
describe '#starts_environment?' do
subject { build.starts_environment? }
@@ -918,6 +954,10 @@ describe Ci::Build, :models do
it { is_expected.to eq(environment) }
end
+
+ context 'when there is no environment' do
+ it { is_expected.to be_nil }
+ end
end
describe '#play' do
@@ -1176,11 +1216,6 @@ describe Ci::Build, :models do
end
context 'when build has an environment' do
- before do
- build.update(environment: 'production')
- create(:environment, project: build.project, name: 'production', slug: 'prod-slug')
- end
-
let(:environment_variables) do
[
{ key: 'CI_ENVIRONMENT_NAME', value: 'production', public: true },
@@ -1188,7 +1223,56 @@ describe Ci::Build, :models do
]
end
- it { environment_variables.each { |v| is_expected.to include(v) } }
+ let!(:environment) do
+ create(:environment,
+ project: build.project,
+ name: 'production',
+ slug: 'prod-slug',
+ external_url: '')
+ end
+
+ before do
+ build.update(environment: 'production')
+ end
+
+ shared_examples 'containing environment variables' do
+ it { environment_variables.each { |v| is_expected.to include(v) } }
+ end
+
+ context 'when no URL was set' do
+ it_behaves_like 'containing environment variables'
+
+ it 'does not have CI_ENVIRONMENT_URL' do
+ keys = subject.map { |var| var[:key] }
+
+ expect(keys).not_to include('CI_ENVIRONMENT_URL')
+ end
+ end
+
+ context 'when an URL was set' do
+ let(:url) { 'http://host/test' }
+
+ before do
+ environment_variables <<
+ { key: 'CI_ENVIRONMENT_URL', value: url, public: true }
+ end
+
+ context 'when the URL was set from the job' do
+ before do
+ build.update(options: { environment: { url: 'http://host/$CI_JOB_NAME' } })
+ end
+
+ it_behaves_like 'containing environment variables'
+ end
+
+ context 'when the URL was not set from the job, but environment' do
+ before do
+ environment.update(external_url: url)
+ end
+
+ it_behaves_like 'containing environment variables'
+ end
+ end
end
context 'when build started manually' do
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 06fbd7bad90..597c3947e71 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -296,5 +296,20 @@ describe Ci::CreatePipelineService, services: true do
expect(Environment.find_by(name: "review/master")).not_to be_nil
end
end
+
+ context 'when environment with invalid name' do
+ before do
+ config = YAML.dump(deploy: { environment: { name: 'name,with,commas' }, script: 'ls' })
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'does not create an environment' do
+ expect do
+ result = execute_service
+
+ expect(result).to be_persisted
+ end.not_to change { Environment.count }
+ end
+ end
end
end
diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb
index f35d7a33548..5398b5c3f7e 100644
--- a/spec/services/create_deployment_service_spec.rb
+++ b/spec/services/create_deployment_service_spec.rb
@@ -1,156 +1,117 @@
require 'spec_helper'
describe CreateDeploymentService, services: true do
- let(:project) { create(:empty_project) }
let(:user) { create(:user) }
+ let(:options) { nil }
+
+ let(:job) do
+ create(:ci_build,
+ ref: 'master',
+ tag: false,
+ environment: 'production',
+ options: { environment: options })
+ end
- let(:service) { described_class.new(project, user, params) }
+ let(:project) { job.project }
- describe '#execute' do
- let(:options) { nil }
- let(:params) do
- {
- environment: 'production',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142',
- options: options
- }
- end
+ let!(:environment) do
+ create(:environment, project: project, name: 'production')
+ end
- subject { service.execute }
+ let(:service) { described_class.new(job) }
- context 'when no environments exist' do
- it 'does create a new environment' do
- expect { subject }.to change { Environment.count }.by(1)
- end
+ describe '#execute' do
+ subject { service.execute }
- it 'does create a deployment' do
+ context 'when environment exists' do
+ it 'creates a deployment' do
expect(subject).to be_persisted
end
end
- context 'when environment exist' do
- let!(:environment) { create(:environment, project: project, name: 'production') }
-
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
+ context 'when environment does not exist' do
+ let(:environment) {}
- it 'does create a deployment' do
- expect(subject).to be_persisted
+ it 'does not create a deployment' do
+ expect do
+ expect(subject).to be_nil
+ end.not_to change { Deployment.count }
end
+ end
- context 'and start action is defined' do
- let(:options) { { action: 'start' } }
+ context 'when start action is defined' do
+ let(:options) { { action: 'start' } }
- context 'and environment is stopped' do
- before do
- environment.stop
- end
+ context 'and environment is stopped' do
+ before do
+ environment.stop
+ end
- it 'makes environment available' do
- subject
+ it 'makes environment available' do
+ subject
- expect(environment.reload).to be_available
- end
+ expect(environment.reload).to be_available
+ end
- it 'does create a deployment' do
- expect(subject).to be_persisted
- end
+ it 'creates a deployment' do
+ expect(subject).to be_persisted
end
end
+ end
- context 'and stop action is defined' do
- let(:options) { { action: 'stop' } }
-
- context 'and environment is available' do
- before do
- environment.start
- end
-
- it 'makes environment stopped' do
- subject
-
- expect(environment.reload).to be_stopped
- end
+ context 'when stop action is defined' do
+ let(:options) { { action: 'stop' } }
- it 'does not create a deployment' do
- expect(subject).to be_nil
- end
+ context 'and environment is available' do
+ before do
+ environment.start
end
- end
- end
- context 'for environment with invalid name' do
- let(:params) do
- {
- environment: 'name,with,commas',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142'
- }
- end
+ it 'makes environment stopped' do
+ subject
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
+ expect(environment.reload).to be_stopped
+ end
- it 'does not create a deployment' do
- expect(subject).to be_nil
+ it 'does not create a deployment' do
+ expect(subject).to be_nil
+ end
end
end
context 'when variables are used' do
- let(:params) do
- {
- environment: 'review-apps/$CI_COMMIT_REF_NAME',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142',
- options: {
- name: 'review-apps/$CI_COMMIT_REF_NAME',
- url: 'http://$CI_COMMIT_REF_NAME.review-apps.gitlab.com'
- },
- variables: [
- { key: 'CI_COMMIT_REF_NAME', value: 'feature-review-apps' }
- ]
- }
+ let(:options) do
+ { name: 'review-apps/$CI_COMMIT_REF_NAME',
+ url: 'http://$CI_COMMIT_REF_NAME.review-apps.gitlab.com' }
end
- it 'does create a new environment' do
- expect { subject }.to change { Environment.count }.by(1)
-
- expect(subject.environment.name).to eq('review-apps/feature-review-apps')
- expect(subject.environment.external_url).to eq('http://feature-review-apps.review-apps.gitlab.com')
+ before do
+ environment.update(name: 'review-apps/master')
+ job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME')
end
- it 'does create a new deployment' do
+ it 'creates a new deployment' do
expect(subject).to be_persisted
end
- context 'and environment exist' do
- let!(:environment) { create(:environment, project: project, name: 'review-apps/feature-review-apps') }
-
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
-
- it 'updates external url' do
- subject
+ it 'does not create a new environment' do
+ expect { subject }.not_to change { Environment.count }
+ end
- expect(subject.environment.name).to eq('review-apps/feature-review-apps')
- expect(subject.environment.external_url).to eq('http://feature-review-apps.review-apps.gitlab.com')
- end
+ it 'updates external url' do
+ subject
- it 'does create a new deployment' do
- expect(subject).to be_persisted
- end
+ expect(subject.environment.name).to eq('review-apps/master')
+ expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com')
end
end
context 'when project was removed' do
- let(:project) { nil }
+ let(:environment) {}
+
+ before do
+ job.update(project: nil)
+ end
it 'does not create deployment or environment' do
expect { subject }.not_to raise_error
@@ -162,34 +123,26 @@ describe CreateDeploymentService, services: true do
end
describe 'processing of builds' do
- let(:environment) { nil }
-
- shared_examples 'does not create environment and deployment' do
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
-
+ shared_examples 'does not create deployment' do
it 'does not create a new deployment' do
expect { subject }.not_to change { Deployment.count }
end
it 'does not call a service' do
expect_any_instance_of(described_class).not_to receive(:execute)
+
subject
end
end
- shared_examples 'does create environment and deployment' do
- it 'does create a new environment' do
- expect { subject }.to change { Environment.count }.by(1)
- end
-
- it 'does create a new deployment' do
+ shared_examples 'creates deployment' do
+ it 'creates a new deployment' do
expect { subject }.to change { Deployment.count }.by(1)
end
- it 'does call a service' do
+ it 'calls a service' do
expect_any_instance_of(described_class).to receive(:execute)
+
subject
end
@@ -199,7 +152,7 @@ describe CreateDeploymentService, services: true do
expect(Deployment.last.deployable).to eq(deployable)
end
- it 'create environment has URL set' do
+ it 'updates environment URL' do
subject
expect(Deployment.last.environment.external_url).not_to be_nil
@@ -207,41 +160,39 @@ describe CreateDeploymentService, services: true do
end
context 'without environment specified' do
- let(:build) { create(:ci_build, project: project) }
+ let(:job) { create(:ci_build) }
- it_behaves_like 'does not create environment and deployment' do
- subject { build.success }
+ it_behaves_like 'does not create deployment' do
+ subject { job.success }
end
end
context 'when environment is specified' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline, environment: 'production', options: options) }
+ let(:deployable) { job }
+
let(:options) do
{ environment: { name: 'production', url: 'http://gitlab.com' } }
end
- context 'when build succeeds' do
- it_behaves_like 'does create environment and deployment' do
- let(:deployable) { build }
-
- subject { build.success }
+ context 'when job succeeds' do
+ it_behaves_like 'creates deployment' do
+ subject { job.success }
end
end
- context 'when build fails' do
- it_behaves_like 'does not create environment and deployment' do
- subject { build.drop }
+ context 'when job fails' do
+ it_behaves_like 'does not create deployment' do
+ subject { job.drop }
end
end
- context 'when build is retried' do
- it_behaves_like 'does create environment and deployment' do
+ context 'when job is retried' do
+ it_behaves_like 'creates deployment' do
before do
project.add_developer(user)
end
- let(:deployable) { Ci::Build.retry(build, user) }
+ let(:deployable) { Ci::Build.retry(job, user) }
subject { deployable.success }
end
@@ -250,15 +201,6 @@ describe CreateDeploymentService, services: true do
end
describe "merge request metrics" do
- let(:params) do
- {
- environment: 'production',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142b'
- }
- end
-
let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
context "while updating the 'first_deployed_to_production_at' time" do
@@ -273,8 +215,8 @@ describe CreateDeploymentService, services: true do
end
it "doesn't set the time if the deploy's environment is not 'production'" do
- staging_params = params.merge(environment: 'staging')
- service = described_class.new(project, user, staging_params)
+ job.update(environment: 'staging')
+ service = described_class.new(job)
service.execute
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
@@ -298,7 +240,7 @@ describe CreateDeploymentService, services: true do
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time)
# Current deploy
- service = described_class.new(project, user, params)
+ service = described_class.new(job)
Timecop.freeze(time + 12.hours) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time)
@@ -318,7 +260,7 @@ describe CreateDeploymentService, services: true do
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
# Current deploy
- service = described_class.new(project, user, params)
+ service = described_class.new(job)
Timecop.freeze(time + 12.hours) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb
index 66545127a44..6e1eb5c678d 100644
--- a/spec/support/cycle_analytics_helpers.rb
+++ b/spec/support/cycle_analytics_helpers.rb
@@ -51,12 +51,43 @@ module CycleAnalyticsHelpers
end
def deploy_master(environment: 'production')
- CreateDeploymentService.new(project, user, {
- environment: environment,
- ref: 'master',
- tag: false,
- sha: project.repository.commit('master').sha
- }).execute
+ dummy_job =
+ case environment
+ when 'production'
+ dummy_production_job
+ when 'staging'
+ dummy_staging_job
+ else
+ raise ArgumentError
+ end
+
+ CreateDeploymentService.new(dummy_job).execute
+ end
+
+ def dummy_production_job
+ @dummy_job ||= new_dummy_job('production')
+ end
+
+ def dummy_staging_job
+ @dummy_job ||= new_dummy_job('staging')
+ end
+
+ def dummy_pipeline
+ @dummy_pipeline ||=
+ Ci::Pipeline.new(sha: project.repository.commit('master').sha)
+ end
+
+ def new_dummy_job(environment)
+ project.environments.find_or_create_by(name: environment)
+
+ Ci::Build.new(
+ project: project,
+ user: user,
+ environment: environment,
+ ref: 'master',
+ tag: false,
+ name: 'dummy',
+ pipeline: dummy_pipeline)
end
end