debian-mirror-gitlab/scripts/generate-failed-pipeline-slack-message.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

182 lines
4.6 KiB
Ruby
Raw Normal View History

2022-11-25 23:54:43 +05:30
#!/usr/bin/env ruby
# frozen_string_literal: true
2023-01-13 00:05:48 +05:30
require 'optparse'
require 'json'
2022-11-25 23:54:43 +05:30
2023-01-13 00:05:48 +05:30
require_relative 'api/pipeline_failed_jobs'
2022-11-25 23:54:43 +05:30
2023-01-13 00:05:48 +05:30
class GenerateFailedPipelineSlackMessage
DEFAULT_OPTIONS = {
failed_pipeline_slack_message_file: 'failed_pipeline_slack_message.json',
incident_json_file: 'incident.json'
}.freeze
2022-11-25 23:54:43 +05:30
2023-01-13 00:05:48 +05:30
def initialize(options)
@incident_json_file = options.delete(:incident_json_file)
2022-11-25 23:54:43 +05:30
end
2023-01-13 00:05:48 +05:30
def execute
{
2022-11-25 23:54:43 +05:30
channel: ENV['SLACK_CHANNEL'],
username: "Failed pipeline reporter",
icon_emoji: ":boom:",
text: "*#{title}*",
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: "*#{title}*"
2023-01-13 00:05:48 +05:30
},
accessory: {
type: "button",
text: {
type: "plain_text",
text: incident_button_text
},
url: incident_button_link
2022-11-25 23:54:43 +05:30
}
},
{
type: "section",
2023-01-13 00:05:48 +05:30
text: {
type: "mrkdwn",
text: "*Branch*: #{branch_link}"
}
2022-11-25 23:54:43 +05:30
},
{
type: "section",
2023-01-13 00:05:48 +05:30
text: {
type: "mrkdwn",
text: "*Commit*: #{commit_link}"
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: "*Triggered by* #{triggered_by_link} • *Source:* #{source} • *Duration:* #{pipeline_duration} minutes"
}
2022-11-25 23:54:43 +05:30
},
{
type: "section",
text: {
type: "mrkdwn",
text: "*Failed jobs (#{failed_jobs.size}):* #{failed_jobs_list}"
}
}
]
}
end
private
2023-01-13 00:05:48 +05:30
attr_reader :incident_json_file
def failed_jobs
@failed_jobs ||= PipelineFailedJobs.new(API::DEFAULT_OPTIONS.dup.merge(exclude_allowed_to_fail_jobs: true)).execute
end
2022-11-25 23:54:43 +05:30
def title
2023-01-13 00:05:48 +05:30
"#{project_link} pipeline #{pipeline_link} failed"
end
def incident_exist?
return @incident_exist if defined?(@incident_exist)
@incident_exist = File.exist?(incident_json_file)
end
def incident
return unless incident_exist?
@incident ||= JSON.parse(File.read(incident_json_file))
end
def incident_button_text
if incident_exist?
"View incident ##{incident['iid']}"
else
'Create incident'
end
end
def incident_button_link
if incident_exist?
incident['web_url']
else
2023-03-04 22:38:38 +05:30
"#{ENV['CI_SERVER_URL']}/#{ENV['BROKEN_BRANCH_INCIDENTS_PROJECT']}/-/issues/new?" \
2023-01-13 00:05:48 +05:30
"issuable_template=incident&issue%5Bissue_type%5D=incident"
end
2022-11-25 23:54:43 +05:30
end
def pipeline_link
"<#{ENV['CI_PIPELINE_URL']}|##{ENV['CI_PIPELINE_ID']}>"
end
def branch_link
"<#{ENV['CI_PROJECT_URL']}/-/commits/#{ENV['CI_COMMIT_REF_NAME']}|`#{ENV['CI_COMMIT_REF_NAME']}`>"
end
def pipeline_duration
((Time.now - Time.parse(ENV['CI_PIPELINE_CREATED_AT'])) / 60.to_f).round(2)
end
def commit_link
"<#{ENV['CI_PROJECT_URL']}/-/commit/#{ENV['CI_COMMIT_SHA']}|#{ENV['CI_COMMIT_TITLE']}>"
end
def source
2023-01-13 00:05:48 +05:30
"`#{ENV['CI_PIPELINE_SOURCE']}#{schedule_type}`"
end
def schedule_type
ENV['CI_PIPELINE_SOURCE'] == 'schedule' ? ": #{ENV['SCHEDULE_TYPE']}" : ''
2022-11-25 23:54:43 +05:30
end
def project_link
2023-01-13 00:05:48 +05:30
"<#{ENV['CI_PROJECT_URL']}|#{ENV['CI_PROJECT_PATH']}>"
2022-11-25 23:54:43 +05:30
end
def triggered_by_link
"<#{ENV['CI_SERVER_URL']}/#{ENV['GITLAB_USER_LOGIN']}|#{ENV['GITLAB_USER_NAME']}>"
end
def failed_jobs_list
failed_jobs.map { |job| "<#{job.web_url}|#{job.name}>" }.join(', ')
end
end
2023-01-13 00:05:48 +05:30
if $PROGRAM_NAME == __FILE__
options = GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS.dup
OptionParser.new do |opts|
opts.on("-i", "--incident-json-file file_path", String, "Path to a file where the incident JSON data "\
"can be found (defaults to "\
"`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:incident_json_file]}`)") do |value|
options[:incident_json_file] = value
end
opts.on("-f", "--failed-pipeline-slack-message-file file_path", String, "Path to a file where to save the Slack "\
"message (defaults to "\
"`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:failed_pipeline_slack_message_file]}`)") do |value|
options[:failed_pipeline_slack_message_file] = value
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end.parse!
failed_pipeline_slack_message_file = options.delete(:failed_pipeline_slack_message_file)
GenerateFailedPipelineSlackMessage.new(options).execute.tap do |message_payload|
if failed_pipeline_slack_message_file
File.write(failed_pipeline_slack_message_file, JSON.pretty_generate(message_payload))
end
end
end