Commit de530d4e authored by Etienne Baqué's avatar Etienne Baqué

Merge branch '264393-add-event-timestamp-to-deployments-webhooks' into 'master'

Add event timestamp to deployments webhooks

See merge request gitlab-org/gitlab!60518
parents 876a10fd 5b266be8
...@@ -87,7 +87,7 @@ class Deployment < ApplicationRecord ...@@ -87,7 +87,7 @@ class Deployment < ApplicationRecord
after_transition any => :running do |deployment| after_transition any => :running do |deployment|
deployment.run_after_commit do deployment.run_after_commit do
Deployments::ExecuteHooksWorker.perform_async(id) Deployments::HooksWorker.perform_async(deployment_id: id, status_changed_at: Time.current)
end end
end end
...@@ -100,7 +100,7 @@ class Deployment < ApplicationRecord ...@@ -100,7 +100,7 @@ class Deployment < ApplicationRecord
after_transition any => FINISHED_STATUSES do |deployment| after_transition any => FINISHED_STATUSES do |deployment|
deployment.run_after_commit do deployment.run_after_commit do
Deployments::ExecuteHooksWorker.perform_async(id) Deployments::HooksWorker.perform_async(deployment_id: id, status_changed_at: Time.current)
end end
end end
...@@ -182,8 +182,8 @@ class Deployment < ApplicationRecord ...@@ -182,8 +182,8 @@ class Deployment < ApplicationRecord
Commit.truncate_sha(sha) Commit.truncate_sha(sha)
end end
def execute_hooks def execute_hooks(status_changed_at)
deployment_data = Gitlab::DataBuilder::Deployment.build(self) deployment_data = Gitlab::DataBuilder::Deployment.build(self, status_changed_at)
project.execute_hooks(deployment_data, :deployment_hooks) project.execute_hooks(deployment_data, :deployment_hooks)
project.execute_services(deployment_data, :deployment_hooks) project.execute_services(deployment_data, :deployment_hooks)
end end
......
...@@ -63,7 +63,7 @@ module Integrations ...@@ -63,7 +63,7 @@ module Integrations
return { error: s_('TestHooks|Ensure the project has deployments.') } unless deployment.present? return { error: s_('TestHooks|Ensure the project has deployments.') } unless deployment.present?
Gitlab::DataBuilder::Deployment.build(deployment) Gitlab::DataBuilder::Deployment.build(deployment, Time.current)
end end
def releases_events_data def releases_events_data
......
...@@ -642,6 +642,15 @@ ...@@ -642,6 +642,15 @@
:weight: 3 :weight: 3
:idempotent: :idempotent:
:tags: [] :tags: []
- :name: deployment:deployments_hooks
:worker_name: Deployments::HooksWorker
:feature_category: :continuous_delivery
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
:idempotent:
:tags: []
- :name: deployment:deployments_link_merge_request - :name: deployment:deployments_link_merge_request
:worker_name: Deployments::LinkMergeRequestWorker :worker_name: Deployments::LinkMergeRequestWorker
:feature_category: :continuous_delivery :feature_category: :continuous_delivery
......
# frozen_string_literal: true # frozen_string_literal: true
module Deployments module Deployments
# TODO: remove in https://gitlab.com/gitlab-org/gitlab/-/issues/329360
class ExecuteHooksWorker # rubocop:disable Scalability/IdempotentWorker class ExecuteHooksWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker include ApplicationWorker
...@@ -10,7 +11,7 @@ module Deployments ...@@ -10,7 +11,7 @@ module Deployments
def perform(deployment_id) def perform(deployment_id)
if (deploy = Deployment.find_by_id(deployment_id)) if (deploy = Deployment.find_by_id(deployment_id))
deploy.execute_hooks deploy.execute_hooks(Time.current)
end end
end end
end end
......
...@@ -13,7 +13,7 @@ module Deployments ...@@ -13,7 +13,7 @@ module Deployments
def perform(deployment_id) def perform(deployment_id)
if (deploy = Deployment.find_by_id(deployment_id)) if (deploy = Deployment.find_by_id(deployment_id))
LinkMergeRequestsService.new(deploy).execute LinkMergeRequestsService.new(deploy).execute
deploy.execute_hooks deploy.execute_hooks(Time.current)
end end
end end
end end
......
# frozen_string_literal: true
module Deployments
class HooksWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
queue_namespace :deployment
feature_category :continuous_delivery
def perform(params = {})
params = params.with_indifferent_access
if (deploy = Deployment.find_by_id(params[:deployment_id]))
deploy.execute_hooks(params[:status_changed_at].to_time)
end
end
end
end
---
title: Add status_changed_at to deployments webhooks
merge_request: 60518
author:
type: added
...@@ -1368,6 +1368,7 @@ X-Gitlab-Event: Deployment Hook ...@@ -1368,6 +1368,7 @@ X-Gitlab-Event: Deployment Hook
{ {
"object_kind": "deployment", "object_kind": "deployment",
"status": "success", "status": "success",
"status_changed_at":"2021-04-28 21:50:00 +0200",
"deployable_id": 796, "deployable_id": 796,
"deployable_url": "http://10.126.0.2:3000/root/test-deployment-webhooks/-/jobs/796", "deployable_url": "http://10.126.0.2:3000/root/test-deployment-webhooks/-/jobs/796",
"environment": "staging", "environment": "staging",
......
...@@ -36,7 +36,7 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do ...@@ -36,7 +36,7 @@ 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::LinkMergeRequestWorker).to receive(:perform_async) allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async) allow(Deployments::HooksWorker).to receive(:perform_async)
subject subject
expect(ci_build.failed?).to be_truthy expect(ci_build.failed?).to be_truthy
......
...@@ -5,7 +5,7 @@ module Gitlab ...@@ -5,7 +5,7 @@ module Gitlab
module Deployment module Deployment
extend self extend self
def build(deployment) def build(deployment, status_changed_at)
# Deployments will not have a deployable when created using the API. # Deployments will not have a deployable when created using the API.
deployable_url = deployable_url =
if deployment.deployable if deployment.deployable
...@@ -15,6 +15,7 @@ module Gitlab ...@@ -15,6 +15,7 @@ module Gitlab
{ {
object_kind: 'deployment', object_kind: 'deployment',
status: deployment.status, status: deployment.status,
status_changed_at: status_changed_at,
deployable_id: deployment.deployable_id, deployable_id: deployment.deployable_id,
deployable_url: deployable_url, deployable_url: deployable_url,
environment: deployment.environment.name, environment: deployment.environment.name,
......
...@@ -7,7 +7,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do ...@@ -7,7 +7,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
it 'returns the object kind for a deployment' do it 'returns the object kind for a deployment' do
deployment = build(:deployment, deployable: nil, environment: create(:environment)) deployment = build(:deployment, deployable: nil, environment: create(:environment))
data = described_class.build(deployment) data = described_class.build(deployment, Time.current)
expect(data[:object_kind]).to eq('deployment') expect(data[:object_kind]).to eq('deployment')
end end
...@@ -21,10 +21,12 @@ RSpec.describe Gitlab::DataBuilder::Deployment do ...@@ -21,10 +21,12 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
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.deployed_by) 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)
status_changed_at = Time.current
data = described_class.build(deployment) data = described_class.build(deployment, status_changed_at)
expect(data[:status]).to eq('failed') expect(data[:status]).to eq('failed')
expect(data[:status_changed_at]).to eq(status_changed_at)
expect(data[:deployable_id]).to eq(deployable.id) expect(data[:deployable_id]).to eq(deployable.id)
expect(data[:deployable_url]).to eq(expected_deployable_url) expect(data[:deployable_url]).to eq(expected_deployable_url)
expect(data[:environment]).to eq("somewhere") expect(data[:environment]).to eq("somewhere")
...@@ -38,7 +40,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do ...@@ -38,7 +40,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
it 'does not include the deployable URL when there is no deployable' do it 'does not include the deployable URL when there is no deployable' do
deployment = create(:deployment, status: :failed, deployable: nil) deployment = create(:deployment, status: :failed, deployable: nil)
data = described_class.build(deployment) data = described_class.build(deployment, Time.current)
expect(data[:deployable_url]).to be_nil expect(data[:deployable_url]).to be_nil
end end
......
...@@ -1205,7 +1205,7 @@ RSpec.describe Ci::Build do ...@@ -1205,7 +1205,7 @@ RSpec.describe Ci::Build do
before do before do
allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async) allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async) allow(Deployments::HooksWorker).to receive(:perform_async)
end end
it 'has deployments record with created status' do it 'has deployments record with created status' do
...@@ -1241,7 +1241,7 @@ RSpec.describe Ci::Build do ...@@ -1241,7 +1241,7 @@ RSpec.describe Ci::Build do
before do before do
allow(Deployments::UpdateEnvironmentWorker).to receive(:perform_async) allow(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async) allow(Deployments::HooksWorker).to receive(:perform_async)
end end
it_behaves_like 'avoid deadlock' it_behaves_like 'avoid deadlock'
......
...@@ -107,11 +107,13 @@ RSpec.describe Deployment do ...@@ -107,11 +107,13 @@ RSpec.describe Deployment do
end end
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do it 'executes Deployments::HooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker) freeze_time do
.to receive(:perform_async).with(deployment.id) expect(Deployments::HooksWorker)
.to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
deployment.run! deployment.run!
end
end end
it 'executes Deployments::DropOlderDeploymentsWorker asynchronously' do it 'executes Deployments::DropOlderDeploymentsWorker asynchronously' do
...@@ -141,11 +143,13 @@ RSpec.describe Deployment do ...@@ -141,11 +143,13 @@ RSpec.describe Deployment do
deployment.succeed! deployment.succeed!
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do it 'executes Deployments::HooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker) freeze_time do
.to receive(:perform_async).with(deployment.id) expect(Deployments::HooksWorker)
.to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
deployment.succeed! deployment.succeed!
end
end end
end end
...@@ -168,11 +172,13 @@ RSpec.describe Deployment do ...@@ -168,11 +172,13 @@ RSpec.describe Deployment do
deployment.drop! deployment.drop!
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do it 'executes Deployments::HooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker) freeze_time do
.to receive(:perform_async).with(deployment.id) expect(Deployments::HooksWorker)
.to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
deployment.drop! deployment.drop!
end
end end
end end
...@@ -195,11 +201,13 @@ RSpec.describe Deployment do ...@@ -195,11 +201,13 @@ RSpec.describe Deployment do
deployment.cancel! deployment.cancel!
end end
it 'executes Deployments::ExecuteHooksWorker asynchronously' do it 'executes Deployments::HooksWorker asynchronously' do
expect(Deployments::ExecuteHooksWorker) freeze_time do
.to receive(:perform_async).with(deployment.id) expect(Deployments::HooksWorker)
.to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
deployment.cancel! deployment.cancel!
end
end end
end end
...@@ -220,11 +228,13 @@ RSpec.describe Deployment do ...@@ -220,11 +228,13 @@ RSpec.describe Deployment do
deployment.skip! deployment.skip!
end end
it 'does not execute Deployments::ExecuteHooksWorker' do it 'does not execute Deployments::HooksWorker' do
expect(Deployments::ExecuteHooksWorker) freeze_time do
.not_to receive(:perform_async).with(deployment.id) expect(Deployments::HooksWorker)
.not_to receive(:perform_async).with(deployment_id: deployment.id, status_changed_at: Time.current)
deployment.skip! deployment.skip!
end
end end
end end
...@@ -714,7 +724,7 @@ RSpec.describe Deployment do ...@@ -714,7 +724,7 @@ RSpec.describe Deployment do
it 'schedules workers when finishing a deploy' do it 'schedules workers when finishing a deploy' do
expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).to receive(:perform_async) expect(Deployments::HooksWorker).to receive(:perform_async)
deploy.update_status('success') deploy.update_status('success')
end end
......
...@@ -9,7 +9,7 @@ RSpec.describe ChatMessage::DeploymentMessage do ...@@ -9,7 +9,7 @@ RSpec.describe ChatMessage::DeploymentMessage do
project = create(:project, :repository) project = create(:project, :repository)
commit = project.commit('HEAD') commit = project.commit('HEAD')
deployment = create(:deployment, status: :success, environment: environment, project: project, sha: commit.sha) deployment = create(:deployment, status: :success, environment: environment, project: project, sha: commit.sha)
data = Gitlab::DataBuilder::Deployment.build(deployment) data = Gitlab::DataBuilder::Deployment.build(deployment, Time.current)
message = described_class.new(data) message = described_class.new(data)
...@@ -118,7 +118,7 @@ RSpec.describe ChatMessage::DeploymentMessage do ...@@ -118,7 +118,7 @@ RSpec.describe ChatMessage::DeploymentMessage do
job_url = Gitlab::Routing.url_helpers.project_job_url(project, ci_build) job_url = Gitlab::Routing.url_helpers.project_job_url(project, ci_build)
commit_url = Gitlab::UrlBuilder.build(deployment.commit) commit_url = Gitlab::UrlBuilder.build(deployment.commit)
user_url = Gitlab::Routing.url_helpers.user_url(user) user_url = Gitlab::Routing.url_helpers.user_url(user)
data = Gitlab::DataBuilder::Deployment.build(deployment) data = Gitlab::DataBuilder::Deployment.build(deployment, Time.current)
message = described_class.new(data) message = described_class.new(data)
......
...@@ -59,7 +59,7 @@ RSpec.describe SlackService do ...@@ -59,7 +59,7 @@ RSpec.describe SlackService do
context 'deployment notification' do context 'deployment notification' do
let_it_be(:deployment) { create(:deployment, user: user) } let_it_be(:deployment) { create(:deployment, user: user) }
let(:data) { Gitlab::DataBuilder::Deployment.build(deployment) } let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, Time.current) }
it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_deployment_notification' it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_deployment_notification'
end end
......
...@@ -21,7 +21,7 @@ RSpec.describe Deployments::CreateService do ...@@ -21,7 +21,7 @@ RSpec.describe Deployments::CreateService do
expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).to receive(:perform_async) expect(Deployments::HooksWorker).to receive(:perform_async)
expect(service.execute).to be_persisted expect(service.execute).to be_persisted
end end
...@@ -37,7 +37,7 @@ RSpec.describe Deployments::CreateService do ...@@ -37,7 +37,7 @@ RSpec.describe Deployments::CreateService do
expect(Deployments::UpdateEnvironmentWorker).not_to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).not_to receive(:perform_async)
expect(Deployments::LinkMergeRequestWorker).not_to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).not_to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).not_to receive(:perform_async) expect(Deployments::HooksWorker).not_to receive(:perform_async)
expect(service.execute).to be_persisted expect(service.execute).to be_persisted
end end
...@@ -57,7 +57,7 @@ RSpec.describe Deployments::CreateService do ...@@ -57,7 +57,7 @@ RSpec.describe Deployments::CreateService do
expect(Deployments::UpdateEnvironmentWorker).not_to receive(:perform_async) expect(Deployments::UpdateEnvironmentWorker).not_to receive(:perform_async)
expect(Deployments::LinkMergeRequestWorker).not_to receive(:perform_async) expect(Deployments::LinkMergeRequestWorker).not_to receive(:perform_async)
expect(Deployments::ExecuteHooksWorker).not_to receive(:perform_async) expect(Deployments::HooksWorker).not_to receive(:perform_async)
described_class.new(environment.reload, user, params).execute described_class.new(environment.reload, user, params).execute
end end
......
...@@ -33,7 +33,7 @@ RSpec.describe Deployments::UpdateEnvironmentService do ...@@ -33,7 +33,7 @@ RSpec.describe Deployments::UpdateEnvironmentService do
before do before do
allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async) allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
allow(Deployments::ExecuteHooksWorker).to receive(:perform_async) allow(Deployments::HooksWorker).to receive(:perform_async)
job.success! # Create/Succeed deployment job.success! # Create/Succeed deployment
end end
......
...@@ -201,7 +201,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name| ...@@ -201,7 +201,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do |service_name|
context 'deployment events' do context 'deployment events' do
let_it_be(:deployment) { create(:deployment) } let_it_be(:deployment) { create(:deployment) }
let(:data) { Gitlab::DataBuilder::Deployment.build(deployment) } let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, Time.current) }
it_behaves_like 'calls the service API with the event message', /Deploy to (.*?) created/ it_behaves_like 'calls the service API with the event message', /Deploy to (.*?) created/
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Deployments::HooksWorker 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: deployment.id, status_changed_at: Time.current)
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: deployment.id, status_changed_at: Time.current)
end
it 'does not execute if a deployment does not exist' do
expect(ProjectServiceWorker).not_to receive(:perform_async)
worker.perform(deployment_id: non_existing_record_id, status_changed_at: Time.current)
end
it 'execute webhooks' do
deployment = create(:deployment, :running)
project = deployment.project
web_hook = create(:project_hook, deployment_events: true, project: project)
status_changed_at = Time.current
expect_next_instance_of(WebHookService, web_hook, hash_including(status_changed_at: status_changed_at), "deployment_hooks") do |service|
expect(service).to receive(:async_execute)
end
worker.perform(deployment_id: deployment.id, status_changed_at: status_changed_at)
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