Commit c2d78268 authored by Sashi's avatar Sashi Committed by Sashi Kumar

Execute project hooks and services when deployment starts

This commit changes the deployment hook feature to additionally
trigger an event when a deployment starts.
parent c260eed3
...@@ -24,7 +24,7 @@ module ServicesHelper ...@@ -24,7 +24,7 @@ module ServicesHelper
when "commit", "commit_events" when "commit", "commit_events"
s_("ProjectService|Event will be triggered when a commit is created/updated") s_("ProjectService|Event will be triggered when a commit is created/updated")
when "deployment" when "deployment"
s_("ProjectService|Event will be triggered when a deployment finishes") s_("ProjectService|Event will be triggered when a deployment starts or finishes")
when "alert" when "alert"
s_("ProjectService|Event will be triggered when a new, unique alert is recorded") s_("ProjectService|Event will be triggered when a new, unique alert is recorded")
end end
......
...@@ -46,6 +46,8 @@ class Deployment < ApplicationRecord ...@@ -46,6 +46,8 @@ class Deployment < ApplicationRecord
scope :older_than, -> (deployment) { where('id < ?', deployment.id) } scope :older_than, -> (deployment) { where('id < ?', deployment.id) }
scope :with_deployable, -> { includes(:deployable).where('deployable_id IS NOT NULL') } scope :with_deployable, -> { includes(:deployable).where('deployable_id IS NOT NULL') }
FINISHED_STATUSES = %i[success failed canceled].freeze
state_machine :status, initial: :created do state_machine :status, initial: :created do
event :run do event :run do
transition created: :running transition created: :running
...@@ -63,27 +65,41 @@ class Deployment < ApplicationRecord ...@@ -63,27 +65,41 @@ class Deployment < ApplicationRecord
transition any - [:canceled] => :canceled transition any - [:canceled] => :canceled
end end
before_transition any => [:success, :failed, :canceled] do |deployment| before_transition any => FINISHED_STATUSES do |deployment|
deployment.finished_at = Time.current deployment.finished_at = Time.current
end end
after_transition any => :success do |deployment| after_transition any => :running do |deployment|
next unless deployment.project.forward_deployment_enabled?
deployment.run_after_commit do deployment.run_after_commit do
Deployments::SuccessWorker.perform_async(id) Deployments::ForwardDeploymentWorker.perform_async(id)
end end
end end
after_transition any => [:success, :failed, :canceled] do |deployment| after_transition any => :running do |deployment|
deployment.run_after_commit do deployment.run_after_commit do
Deployments::FinishedWorker.perform_async(id) next unless Feature.enabled?(:ci_send_deployment_hook_when_start, deployment.project)
Deployments::ExecuteHooksWorker.perform_async(id)
end end
end end
after_transition any => :running do |deployment| after_transition any => :success do |deployment|
next unless deployment.project.forward_deployment_enabled? deployment.run_after_commit do
Deployments::UpdateEnvironmentWorker.perform_async(id)
end
end
after_transition any => FINISHED_STATUSES do |deployment|
deployment.run_after_commit do deployment.run_after_commit do
Deployments::ForwardDeploymentWorker.perform_async(id) Deployments::LinkMergeRequestWorker.perform_async(id)
end
end
after_transition any => FINISHED_STATUSES do |deployment|
deployment.run_after_commit do
Deployments::ExecuteHooksWorker.perform_async(id)
end end
end end
end end
...@@ -273,7 +289,7 @@ class Deployment < ApplicationRecord ...@@ -273,7 +289,7 @@ class Deployment < ApplicationRecord
SQL SQL
end end
# Changes the status of a deployment and triggers the correspinding state # Changes the status of a deployment and triggers the corresponding state
# machine events. # machine events.
def update_status(status) def update_status(status)
case status case status
......
...@@ -38,7 +38,11 @@ module ChatMessage ...@@ -38,7 +38,11 @@ module ChatMessage
private private
def message def message
"Deploy to #{environment} #{humanized_status}" if running?
"Starting deploy to #{environment}"
else
"Deploy to #{environment} #{humanized_status}"
end
end end
def color def color
...@@ -73,5 +77,9 @@ module ChatMessage ...@@ -73,5 +77,9 @@ module ChatMessage
def humanized_status def humanized_status
status == 'success' ? 'succeeded' : status status == 'success' ? 'succeeded' : status
end end
def running?
status == 'running'
end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
module Deployments module Deployments
class AfterCreateService class UpdateEnvironmentService
attr_reader :deployment attr_reader :deployment
attr_reader :deployable attr_reader :deployable
...@@ -64,4 +64,4 @@ module Deployments ...@@ -64,4 +64,4 @@ module Deployments
end end
end end
Deployments::AfterCreateService.prepend_if_ee('EE::Deployments::AfterCreateService') Deployments::UpdateEnvironmentService.prepend_if_ee('EE::Deployments::UpdateEnvironmentService')
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
= form.label :deployment_events, class: 'list-label form-check-label ml-1' do = form.label :deployment_events, class: 'list-label form-check-label ml-1' do
%strong= s_('Webhooks|Deployment events') %strong= s_('Webhooks|Deployment events')
%p.text-muted.ml-1 %p.text-muted.ml-1
= s_('Webhooks|This URL will be triggered when a deployment is finished/failed/canceled') = s_('Webhooks|This URL is triggered when a deployment starts, finishes, fails, or is canceled')
.form-group .form-group
= form.label :enable_ssl_verification, s_('Webhooks|SSL verification'), class: 'label-bold checkbox' = form.label :enable_ssl_verification, s_('Webhooks|SSL verification'), class: 'label-bold checkbox'
.form-check .form-check
......
...@@ -427,6 +427,14 @@ ...@@ -427,6 +427,14 @@
:weight: 1 :weight: 1
:idempotent: true :idempotent: true
:tags: [] :tags: []
- :name: deployment:deployments_execute_hooks
:feature_category: :continuous_delivery
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
:idempotent:
:tags: []
- :name: deployment:deployments_finished - :name: deployment:deployments_finished
:feature_category: :continuous_delivery :feature_category: :continuous_delivery
:has_external_dependencies: :has_external_dependencies:
...@@ -443,6 +451,14 @@ ...@@ -443,6 +451,14 @@
:weight: 3 :weight: 3
:idempotent: :idempotent:
:tags: [] :tags: []
- :name: deployment:deployments_link_merge_request
:feature_category: :continuous_delivery
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
:idempotent: true
:tags: []
- :name: deployment:deployments_success - :name: deployment:deployments_success
:feature_category: :continuous_delivery :feature_category: :continuous_delivery
:has_external_dependencies: :has_external_dependencies:
...@@ -451,6 +467,14 @@ ...@@ -451,6 +467,14 @@
:weight: 3 :weight: 3
:idempotent: :idempotent:
:tags: [] :tags: []
- :name: deployment:deployments_update_environment
:feature_category: :continuous_delivery
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 3
:idempotent: true
:tags: []
- :name: gcp_cluster:cluster_configure_istio - :name: gcp_cluster:cluster_configure_istio
:feature_category: :kubernetes_management :feature_category: :kubernetes_management
:has_external_dependencies: true :has_external_dependencies: true
......
# frozen_string_literal: true
module Deployments
class ExecuteHooksWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
queue_namespace :deployment
feature_category :continuous_delivery
worker_resource_boundary :cpu
def perform(deployment_id)
if (deploy = Deployment.find_by_id(deployment_id))
deploy.execute_hooks
end
end
end
end
# frozen_string_literal: true
module Deployments
class LinkMergeRequestWorker
include ApplicationWorker
queue_namespace :deployment
idempotent!
feature_category :continuous_delivery
worker_resource_boundary :cpu
def perform(deployment_id)
if (deploy = Deployment.find_by_id(deployment_id))
LinkMergeRequestsService.new(deploy).execute
end
end
end
end
...@@ -12,7 +12,7 @@ module Deployments ...@@ -12,7 +12,7 @@ module Deployments
Deployment.find_by_id(deployment_id).try do |deployment| Deployment.find_by_id(deployment_id).try do |deployment|
break unless deployment.success? break unless deployment.success?
Deployments::AfterCreateService.new(deployment).execute Deployments::UpdateEnvironmentService.new(deployment).execute
end end
end end
end end
......
# frozen_string_literal: true
module Deployments
class UpdateEnvironmentWorker
include ApplicationWorker
queue_namespace :deployment
idempotent!
feature_category :continuous_delivery
worker_resource_boundary :cpu
def perform(deployment_id)
Deployment.find_by_id(deployment_id).try do |deployment|
break unless deployment.success?
Deployments::UpdateEnvironmentService.new(deployment).execute
end
end
end
end
---
title: Send chat notification when deployment starts
merge_request: 41214
author: Sashi Kumar
type: added
---
name: ci_send_deployment_hook_when_start
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41214
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247137
group: group::progressive delivery
type: development
default_enabled: false
...@@ -1303,7 +1303,12 @@ Note that `commit.id` is the ID of the pipeline, not the ID of the commit. ...@@ -1303,7 +1303,12 @@ Note that `commit.id` is the ID of the pipeline, not the ID of the commit.
### Deployment events ### Deployment events
Triggered when deployment is finished/failed/canceled. Triggered when a deployment:
- Starts ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41214) in GitLab 13.5.)
- Succeeds
- Fails
- Is cancelled
**Request Header**: **Request Header**:
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module EE module EE
module Deployments module Deployments
module AfterCreateService module UpdateEnvironmentService
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
override :execute override :execute
......
...@@ -35,7 +35,8 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do ...@@ -35,7 +35,8 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do
context 'when user does not have access to the environment' do context 'when user does not have access to the environment' do
it 'fails the build' do it 'fails the build' do
allow(Deployments::FinishedWorker).to receive(:perform_async) allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
subject subject
expect(ci_build.failed?).to be_truthy expect(ci_build.failed?).to be_truthy
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Deployments::AfterCreateService do RSpec.describe Deployments::UpdateEnvironmentService do
include ::EE::GeoHelpers include ::EE::GeoHelpers
let(:primary) { create(:geo_node, :primary) } let(:primary) { create(:geo_node, :primary) }
......
...@@ -20,8 +20,8 @@ module Gitlab ...@@ -20,8 +20,8 @@ module Gitlab
environment: deployment.environment.name, environment: deployment.environment.name,
project: deployment.project.hook_attrs, project: deployment.project.hook_attrs,
short_sha: deployment.short_sha, short_sha: deployment.short_sha,
user: deployment.user.hook_attrs, user: deployment.deployed_by.hook_attrs,
user_url: Gitlab::UrlBuilder.build(deployment.user), user_url: Gitlab::UrlBuilder.build(deployment.deployed_by),
commit_url: Gitlab::UrlBuilder.build(deployment.commit), commit_url: Gitlab::UrlBuilder.build(deployment.commit),
commit_title: deployment.commit.title commit_title: deployment.commit.title
} }
......
...@@ -20015,7 +20015,7 @@ msgstr "" ...@@ -20015,7 +20015,7 @@ msgstr ""
msgid "ProjectService|Event will be triggered when a confidential issue is created/updated/closed" msgid "ProjectService|Event will be triggered when a confidential issue is created/updated/closed"
msgstr "" msgstr ""
msgid "ProjectService|Event will be triggered when a deployment finishes" msgid "ProjectService|Event will be triggered when a deployment starts or finishes"
msgstr "" msgstr ""
msgid "ProjectService|Event will be triggered when a merge request is created/updated/merged" msgid "ProjectService|Event will be triggered when a merge request is created/updated/merged"
...@@ -28851,13 +28851,13 @@ msgstr "" ...@@ -28851,13 +28851,13 @@ msgstr ""
msgid "Webhooks|Tag push events" msgid "Webhooks|Tag push events"
msgstr "" msgstr ""
msgid "Webhooks|This URL will be triggered by a push to the repository" msgid "Webhooks|This URL is triggered when a deployment starts, finishes, fails, or is canceled"
msgstr "" msgstr ""
msgid "Webhooks|This URL will be triggered when a confidential issue is created/updated/merged" msgid "Webhooks|This URL will be triggered by a push to the repository"
msgstr "" msgstr ""
msgid "Webhooks|This URL will be triggered when a deployment is finished/failed/canceled" msgid "Webhooks|This URL will be triggered when a confidential issue is created/updated/merged"
msgstr "" msgstr ""
msgid "Webhooks|This URL will be triggered when a merge request is created/updated/merged" msgid "Webhooks|This URL will be triggered when a merge request is created/updated/merged"
......
...@@ -19,7 +19,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do ...@@ -19,7 +19,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
deployment = create(:deployment, status: :failed, environment: environment, sha: commit.sha, project: project) deployment = create(:deployment, status: :failed, environment: environment, sha: commit.sha, project: project)
deployable = deployment.deployable deployable = deployment.deployable
expected_deployable_url = Gitlab::Routing.url_helpers.project_job_url(deployable.project, deployable) expected_deployable_url = Gitlab::Routing.url_helpers.project_job_url(deployable.project, deployable)
expected_user_url = Gitlab::Routing.url_helpers.user_url(deployment.user) expected_user_url = Gitlab::Routing.url_helpers.user_url(deployment.deployed_by)
expected_commit_url = Gitlab::UrlBuilder.build(commit) expected_commit_url = Gitlab::UrlBuilder.build(commit)
data = described_class.build(deployment) data = described_class.build(deployment)
...@@ -30,7 +30,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do ...@@ -30,7 +30,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
expect(data[:environment]).to eq("somewhere") expect(data[:environment]).to eq("somewhere")
expect(data[:project]).to eq(project.hook_attrs) expect(data[:project]).to eq(project.hook_attrs)
expect(data[:short_sha]).to eq(deployment.short_sha) expect(data[:short_sha]).to eq(deployment.short_sha)
expect(data[:user]).to eq(deployment.user.hook_attrs) expect(data[:user]).to eq(deployment.deployed_by.hook_attrs)
expect(data[:user_url]).to eq(expected_user_url) expect(data[:user_url]).to eq(expected_user_url)
expect(data[:commit_url]).to eq(expected_commit_url) expect(data[:commit_url]).to eq(expected_commit_url)
expect(data[:commit_title]).to eq(commit.title) expect(data[:commit_title]).to eq(commit.title)
......
...@@ -1109,7 +1109,8 @@ RSpec.describe Ci::Build do ...@@ -1109,7 +1109,8 @@ RSpec.describe Ci::Build do
let(:environment) { deployment.environment } let(:environment) { deployment.environment }
before do before do
allow(Deployments::FinishedWorker).to receive(:perform_async) allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
end end
it 'has deployments record with created status' do it 'has deployments record with created status' do
...@@ -1129,7 +1130,8 @@ RSpec.describe Ci::Build do ...@@ -1129,7 +1130,8 @@ RSpec.describe Ci::Build do
context 'when transits to success' do context 'when transits to success' do
before do before do
allow(Deployments::SuccessWorker).to receive(:perform_async) allow(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
build.success! build.success!
end end
......
...@@ -98,16 +98,36 @@ RSpec.describe Deployment do ...@@ -98,16 +98,36 @@ RSpec.describe Deployment do
context 'when deployment runs' do context 'when deployment runs' do
let(:deployment) { create(:deployment) } let(:deployment) { create(:deployment) }
before do
deployment.run!
end
it 'starts running' do it 'starts running' do
freeze_time do freeze_time do
deployment.run!
expect(deployment).to be_running expect(deployment).to be_running
expect(deployment.finished_at).to be_nil expect(deployment.finished_at).to be_nil
end end
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker)
.to receive(:perform_async).with(deployment.id)
deployment.run!
end
it 'does not execute Deployments::ExecuteHooksWorker when feature is disabled' do
stub_feature_flags(ci_send_deployment_hook_when_start: false)
expect(Deployments::ExecuteHooksWorker)
.not_to receive(:perform_async).with(deployment.id)
deployment.run!
end
it 'executes Deployments::ForwardDeploymentWorker asynchronously' do
expect(Deployments::ForwardDeploymentWorker)
.to receive(:perform_async).once.with(deployment.id)
deployment.run!
end
end end
context 'when deployment succeeded' do context 'when deployment succeeded' do
...@@ -122,15 +142,15 @@ RSpec.describe Deployment do ...@@ -122,15 +142,15 @@ RSpec.describe Deployment do
end end
end end
it 'executes Deployments::SuccessWorker asynchronously' do it 'executes Deployments::UpdateEnvironmentWorker asynchronously' do
expect(Deployments::SuccessWorker) expect(Deployments::UpdateEnvironmentWorker)
.to receive(:perform_async).with(deployment.id) .to receive(:perform_async).with(deployment.id)
deployment.succeed! deployment.succeed!
end end
it 'executes Deployments::FinishedWorker asynchronously' do it 'executes Deployments::ExecuteHooksWorker asynchronously' do
expect(Deployments::FinishedWorker) expect(Deployments::ExecuteHooksWorker)
.to receive(:perform_async).with(deployment.id) .to receive(:perform_async).with(deployment.id)
deployment.succeed! deployment.succeed!
...@@ -149,12 +169,19 @@ RSpec.describe Deployment do ...@@ -149,12 +169,19 @@ RSpec.describe Deployment do
end end
end end
it 'executes Deployments::FinishedWorker asynchronously' do it 'executes Deployments::LinkMergeRequestWorker asynchronously' do
expect(Deployments::FinishedWorker) expect(Deployments::LinkMergeRequestWorker)
.to receive(:perform_async).with(deployment.id) .to receive(:perform_async).with(deployment.id)
deployment.drop! deployment.drop!
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker)
.to receive(:perform_async).with(deployment.id)
deployment.drop!
end
end end
context 'when deployment was canceled' do context 'when deployment was canceled' do
...@@ -169,12 +196,19 @@ RSpec.describe Deployment do ...@@ -169,12 +196,19 @@ RSpec.describe Deployment do
end end
end end
it 'executes Deployments::FinishedWorker asynchronously' do it 'executes Deployments::LinkMergeRequestWorker asynchronously' do
expect(Deployments::FinishedWorker) expect(Deployments::LinkMergeRequestWorker)
.to receive(:perform_async).with(deployment.id) .to receive(:perform_async).with(deployment.id)
deployment.cancel! deployment.cancel!
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker)
.to receive(:perform_async).with(deployment.id)
deployment.cancel!
end
end end
end end
...@@ -580,9 +614,10 @@ RSpec.describe Deployment do ...@@ -580,9 +614,10 @@ RSpec.describe Deployment do
expect(deploy).to be_success expect(deploy).to be_success
end end
it 'schedules SuccessWorker and FinishedWorker when finishing a deploy' do it 'schedules workers when finishing a deploy' do
expect(Deployments::SuccessWorker).to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
expect(Deployments::FinishedWorker).to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).to receive(:perform_async)
deploy.update_status('success') deploy.update_status('success')
end end
......
...@@ -70,6 +70,17 @@ RSpec.describe ChatMessage::DeploymentMessage do ...@@ -70,6 +70,17 @@ RSpec.describe ChatMessage::DeploymentMessage do
expect(message.pretext).to eq('Deploy to staging unknown') expect(message.pretext).to eq('Deploy to staging unknown')
end end
it 'returns a message for a running deployment' do
data = {
status: 'running',
environment: 'production'
}
message = described_class.new(data)
expect(message.pretext).to eq('Starting deploy to production')
end
end end
describe '#attachments' do describe '#attachments' do
......
...@@ -19,8 +19,9 @@ RSpec.describe Deployments::CreateService do ...@@ -19,8 +19,9 @@ RSpec.describe Deployments::CreateService do
status: 'success' status: 'success'
) )
expect(Deployments::SuccessWorker).to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
expect(Deployments::FinishedWorker).to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).to receive(:perform_async)
expect(service.execute).to be_persisted expect(service.execute).to be_persisted
end end
...@@ -34,8 +35,9 @@ RSpec.describe Deployments::CreateService do ...@@ -34,8 +35,9 @@ RSpec.describe Deployments::CreateService do
tag: false tag: false
) )
expect(Deployments::SuccessWorker).not_to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).not_to receive(:perform_async)
expect(Deployments::FinishedWorker).not_to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).not_to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).not_to receive(:perform_async)
expect(service.execute).to be_persisted expect(service.execute).to be_persisted
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Deployments::AfterCreateService do RSpec.describe Deployments::UpdateEnvironmentService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:options) { { name: 'production' } } let(:options) { { name: 'production' } }
...@@ -31,7 +31,8 @@ RSpec.describe Deployments::AfterCreateService do ...@@ -31,7 +31,8 @@ RSpec.describe Deployments::AfterCreateService do
subject(:service) { described_class.new(deployment) } subject(:service) { described_class.new(deployment) }
before do before do
allow(Deployments::FinishedWorker).to receive(:perform_async) allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
job.success! # Create/Succeed deployment job.success! # Create/Succeed deployment
end end
...@@ -100,8 +101,8 @@ RSpec.describe Deployments::AfterCreateService do ...@@ -100,8 +101,8 @@ RSpec.describe Deployments::AfterCreateService do
end end
before do before do
environment.update(name: 'review-apps/master') environment.update!(name: 'review-apps/master')
job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME') job.update!(environment: 'review-apps/$CI_COMMIT_REF_NAME')
end end
it 'does not create a new environment' do it 'does not create a new environment' do
...@@ -241,7 +242,7 @@ RSpec.describe Deployments::AfterCreateService do ...@@ -241,7 +242,7 @@ RSpec.describe Deployments::AfterCreateService do
end end
it 'does not raise errors if the merge request does not have a metrics record' do it 'does not raise errors if the merge request does not have a metrics record' do
merge_request.metrics.destroy merge_request.metrics.destroy!
expect(merge_request.reload.metrics).to be_nil expect(merge_request.reload.metrics).to be_nil
expect { service.execute }.not_to raise_error expect { service.execute }.not_to raise_error
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Deployments::ExecuteHooksWorker do
let(:worker) { described_class.new }
describe '#perform' do
before do
allow(ProjectServiceWorker).to receive(:perform_async)
end
it 'executes project services for deployment_hooks' do
deployment = create(:deployment, :running)
project = deployment.project
service = create(:service, type: 'SlackService', project: project, deployment_events: true, active: true)
expect(ProjectServiceWorker).to receive(:perform_async).with(service.id, an_instance_of(Hash))
worker.perform(deployment.id)
end
it 'does not execute an inactive service' do
deployment = create(:deployment, :running)
project = deployment.project
create(:service, type: 'SlackService', project: project, deployment_events: true, active: false)
expect(ProjectServiceWorker).not_to receive(:perform_async)
worker.perform(deployment.id)
end
it 'does not execute if a deployment does not exist' do
expect(ProjectServiceWorker).not_to receive(:perform_async)
worker.perform(non_existing_record_id)
end
it 'execute webhooks' do
deployment = create(:deployment, :running)
project = deployment.project
web_hook = create(:project_hook, deployment_events: true, project: project)
expect_next_instance_of(WebHookService, web_hook, an_instance_of(Hash), "deployment_hooks") do |service|
expect(service).to receive(:async_execute)
end
worker.perform(deployment.id)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Deployments::LinkMergeRequestWorker do
subject(:worker) { described_class.new }
describe '#perform' do
it 'links merge requests to the deployment' do
deployment = create(:deployment)
service = instance_double(Deployments::LinkMergeRequestsService)
expect(Deployments::LinkMergeRequestsService)
.to receive(:new)
.with(deployment)
.and_return(service)
expect(service).to receive(:execute)
worker.perform(deployment.id)
end
it 'does not link merge requests when the deployment is not found' do
expect(Deployments::LinkMergeRequestsService).not_to receive(:new)
worker.perform(non_existing_record_id)
end
end
context 'idempotent' do
include_examples 'an idempotent worker' do
let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) }
let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
let(:job_args) { deployment.id }
it 'links merge requests to deployment' do
mr1 = create(
:merge_request,
:merged,
source_project: project,
target_project: project,
source_branch: 'source1',
target_branch: deployment.ref
)
mr2 = create(
:merge_request,
:merged,
source_project: project,
target_project: project,
source_branch: 'source2',
target_branch: deployment.ref
)
mr3 = create(
:merge_request,
:merged,
source_project: project,
target_project: project,
target_branch: 'foo'
)
subject
expect(deployment.merge_requests).to include(mr1, mr2)
expect(deployment.merge_requests).not_to include(mr3)
end
end
end
end
...@@ -8,8 +8,8 @@ RSpec.describe Deployments::SuccessWorker do ...@@ -8,8 +8,8 @@ RSpec.describe Deployments::SuccessWorker do
context 'when successful deployment' do context 'when successful deployment' do
let(:deployment) { create(:deployment, :success) } let(:deployment) { create(:deployment, :success) }
it 'executes Deployments::AfterCreateService' do it 'executes Deployments::UpdateEnvironmentService' do
expect(Deployments::AfterCreateService) expect(Deployments::UpdateEnvironmentService)
.to receive(:new).with(deployment).and_call_original .to receive(:new).with(deployment).and_call_original
subject subject
...@@ -19,8 +19,8 @@ RSpec.describe Deployments::SuccessWorker do ...@@ -19,8 +19,8 @@ RSpec.describe Deployments::SuccessWorker do
context 'when canceled deployment' do context 'when canceled deployment' do
let(:deployment) { create(:deployment, :canceled) } let(:deployment) { create(:deployment, :canceled) }
it 'does not execute Deployments::AfterCreateService' do it 'does not execute Deployments::UpdateEnvironmentService' do
expect(Deployments::AfterCreateService).not_to receive(:new) expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
subject subject
end end
...@@ -29,8 +29,8 @@ RSpec.describe Deployments::SuccessWorker do ...@@ -29,8 +29,8 @@ RSpec.describe Deployments::SuccessWorker do
context 'when deploy record does not exist' do context 'when deploy record does not exist' do
let(:deployment) { nil } let(:deployment) { nil }
it 'does not execute Deployments::AfterCreateService' do it 'does not execute Deployments::UpdateEnvironmentService' do
expect(Deployments::AfterCreateService).not_to receive(:new) expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
subject subject
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Deployments::UpdateEnvironmentWorker do
subject(:worker) { described_class.new }
context 'when successful deployment' do
let(:deployment) { create(:deployment, :success) }
it 'executes Deployments::UpdateEnvironmentService' do
service = instance_double(Deployments::UpdateEnvironmentService)
expect(Deployments::UpdateEnvironmentService)
.to receive(:new)
.with(deployment)
.and_return(service)
expect(service).to receive(:execute)
worker.perform(deployment.id)
end
end
context 'when canceled deployment' do
let(:deployment) { create(:deployment, :canceled) }
it 'does not execute Deployments::UpdateEnvironmentService' do
expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
worker.perform(deployment.id)
end
end
context 'when deploy record does not exist' do
it 'does not execute Deployments::UpdateEnvironmentService' do
expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
worker.perform(non_existing_record_id)
end
end
context 'idempotent' do
include_examples 'an idempotent worker' do
let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, name: 'production') }
let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
let(:job_args) { deployment.id }
before do
merge_request.metrics.update!(merged_at: 1.hour.ago)
end
it 'updates merge requests metrics' do
subject
expect(merge_request.reload.metrics.first_deployed_to_production_at)
.to be_like_time(deployment.finished_at)
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment