lib/release_tools/slack/coordinated_pipeline_notification.rb (136 lines of code) (raw):
# frozen_string_literal: true
require 'release_tools/time_util'
module ReleaseTools
module Slack
class CoordinatedPipelineNotification
include ::SemanticLogger::Loggable
include ReleaseTools::TimeUtil
include Utilities
# deploy_version - Deployer package
# pipeline - GitLab response pipeline object
# environment - gstg-ref, gstg-cny, gstg, gprd-cny, gprd
def initialize(deploy_version:, pipeline:, environment:)
@deploy_version = deploy_version
@pipeline = pipeline
@environment = environment
end
def execute
logger.info('Sending slack notification', deploy_version: deploy_version, environment: environment, deployer_url: deployer_url)
response = send_notification
return response unless send_diffs_notification?
send_threaded_diffs_notification(response['ts'])
end
private
attr_reader :deploy_version, :pipeline, :environment
def deployer_url
pipeline&.web_url
end
def send_notification
params = {
channel: slack_channel[:id],
message: fallback_text,
blocks: slack_block
}
if thread_to_started_notification?
params[:additional_options] = {
thread_ts: started_notification_message['ts'],
reply_broadcast: true
}
end
ReleaseTools::Slack::Message.post(**params)
end
def slack_channel
if environment == 'gstg-ref'
{ id: Slack::STAGING_REF_DEPLOYMENT, name: Slack::STAGING_REF_DEPLOYMENT_NAME }
else
{ id: Slack::ANNOUNCEMENTS, name: Slack::ANNOUNCEMENTS_NAME }
end
end
def thread_to_started_notification?
# Thread "success" or "failed" notifications to the started notification.
deployer_status != DEPLOYER_STATUS_STARTED && started_notification_message
end
def fallback_text
"#{environment} #{deployer_status} #{deploy_version}"
end
def slack_block
[
{
type: 'section',
text: ReleaseTools::Slack::Webhook.mrkdwn(section_block)
},
{
type: 'context',
elements: context_elements
}
]
end
def section_block
[].tap do |text|
text << environment_icon
text << status_icon
text << release_managers_mention if mention_release_managers?
text << "*#{environment}*"
text << deployer_status_link
text << "`#{deploy_version}`"
end.join(' ')
end
def deployer_status_link
if pipeline
"<#{deployer_url}|#{deployer_status}>"
else
"Downstream pipeline couldn't be found, check if `#{bridge_job_name}` job in <#{ENV.fetch('CI_PIPELINE_URL', nil)}|coordinated pipeline> has started."
end
end
def bridge_job_name
"deploy:#{environment}"
end
def context_elements
[].tap do |elements|
elements << clock_context_element
elements << { type: 'mrkdwn', text: ":sentry: #{new_sentry_link}" }
elements << { type: 'mrkdwn', text: ":timer_clock: #{wall_duration}" } if finished_or_failed?
end
end
def new_sentry_link
version = ReleaseTools::AutoDeploy::Version.new(deploy_version)
"<https://new-sentry.gitlab.net/gitlab/gitlabcom/releases/#{version.rails_sha}/|View Sentry>"
end
def wall_duration
duration(current_time - start_time).first
end
def start_time
Time.parse(pipeline.created_at)
end
def finished_or_failed?
[DEPLOYER_STATUS_SUCCESS, DEPLOYER_STATUS_FAILED].include?(deployer_status)
end
def send_diffs_notification?
deployer_status == DEPLOYER_STATUS_STARTED
end
def send_threaded_diffs_notification(thread_ts)
args = {
deploy_version: deploy_version,
environment: environment,
thread_ts: thread_ts,
channel: slack_channel[:id]
}
ReleaseTools::Slack::CoordinatedPipelineDiffsNotification.new(**args).execute
end
def started_notification_message
return @started_notification_message if @started_notification_message
results = ReleaseTools::Slack::Search.query(
"#{environment} #{DEPLOYER_STATUS_STARTED} #{deploy_version}",
channel: slack_channel[:name]
)
deployment_started_notification_regex = /\*#{environment}\* <[^|]+\|#{DEPLOYER_STATUS_STARTED}> `#{deploy_version}`$/
@started_notification_message =
results
.detect do |m|
m.dig('blocks', 0, 'text', 'text') =~ deployment_started_notification_regex
end
if @started_notification_message
logger.info('Found deployment started notification', slack_msg: @started_notification_message['permalink'], deploy_version: deploy_version, environment: environment, deployer_url: deployer_url)
else
logger.warn('Could not find deployment started notification', deploy_version: deploy_version, environment: environment, deployer_url: deployer_url)
end
@started_notification_message
end
end
end
end