vagrant/.ci/slack

177 lines
4.7 KiB
Ruby
Executable File

#!/usr/bin/env ruby
require "optparse"
require "net/https"
require "uri"
require "json"
OPTIONS = [:channel, :username, :icon, :state, :message,
:message_file, :file, :title, :tail, :webhook].freeze
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
opts.on("-c", "--channel CHAN", "Send to channel") do |c|
options[:channel] = c
end
opts.on("-u", "--username USER", "Send as username") do |u|
options[:username] = u
end
opts.on("-i", "--icon URL", "User icon image") do |i|
options[:icon] = i
end
opts.on("-s", "--state STATE", "Message state (success, warn, error, or color code)") do |s|
options[:state] = s
end
opts.on("-m", "--message MESSAGE", "Message to send") do |m|
options[:message] = m
end
opts.on("-M", "--message-file MESSAGE_FILE", "Use file contents as message") do |m|
options[:message_file] = m
end
opts.on("-f", "--file MESSAGE_FILE", "Send raw contents of file in message") do |f|
options[:file] = f
end
opts.on("-t", "--title TITLE", "Message title") do |t|
options[:title] = t
end
opts.on("-T", "--tail N", "Send last N lines of content from raw message file") do |t|
options[:tail] = t
end
opts.on("-w", "--webhook HOOK", "Slack webhook") do |w|
options[:webhook] = w
end
opts.on("-h", "--help", "Print help") do
puts opts
exit
end
end.parse!
OPTIONS.each do |key|
if !options.key?(key)
env_key = "SLACK_#{key.to_s.upcase}"
if ENV[env_key]
options[key] = ENV[env_key]
end
end
end
if !options[:webhook]
$stderr.puts "ERROR: Webhook is required!"
exit 1
end
if ENV["CIRCLECI"]
options[:icon] = "https://emoji.slack-edge.com/TF1GCKJNM/circleci/054b58d488e65138.png" unless options[:icon]
options[:username] = "circleci" unless options[:username]
options[:footer] = "CircleCI - <#{ENV["CIRCLE_BUILD_URL"]}|#{ENV["CIRCLE_PROJECT_USERNAME"]}/#{ENV["CIRCLE_PROJECT_REPONAME"]}>"
options[:footer_icon] = "https://emoji.slack-edge.com/TF1GCKJNM/circleci/054b58d488e65138.png"
end
if ENV["GITHUB_ACTIONS"]
options[:icon] = "https://ca.slack-edge.com/T024UT03C-WG8NDATGT-f82ae03b9fca-48" unless options[:icon]
options[:username] = "github" unless options[:username]
options[:footer] = "Actions - <https://github.com/#{ENV["GITHUB_REPOSITORY"]}/commit/#{ENV["GITHUB_SHA"]}/checks|#{ENV["GITHUB_REPOSITORY"]}>"
options[:footer_icon] = "https://ca.slack-edge.com/T024UT03C-WG8NDATGT-f82ae03b9fca-48"
end
options[:state] = "success" unless options[:state]
case options[:state]
when "success", "good"
options[:state] = "good"
when "warn", "warning"
options[:state] = "warning"
when "error", "danger"
options[:state] = "danger"
else
if !options[:state].start_with?("#")
$stderr.puts "ERROR: Invalid value for `state` (#{options[:state]})"
exit 1
end
end
msg = options[:message]
# NOTE: Message provided from CLI argument will end up with
# double escaped newlines so remove one
msg.gsub!("\\n", "\n") if msg
if options[:message_file]
if !File.exist?(options[:message_file])
$stderr.puts "ERROR: Message file does not exist `#{options[:message_file]}`"
exit 1
end
msg_c = File.read(options[:message_file])
msg = msg ? "#{msg}\n\n#{msg_c}" : msg_c
end
if options[:file]
if !File.exist?(options[:file])
$stderr.puts "ERROR: Message file does not exist `#{options[:file]}`"
exit 1
end
if (tail = options[:tail].to_i) > 0
content = ""
buffer = 0
File.open(options[:file], "r") do |f|
until (content.split("\n").size > tail) || buffer >= f.size
buffer += 1000
buffer = f.size if buffer > f.size
f.seek(f.size - buffer)
content = f.read
end
end
parts = content.split("\n")
if parts.size > tail
parts = parts.slice(-tail, tail)
end
fmsg = parts ? parts.join("\n") : ""
else
fmsg = File.read(options[:file])
end
fmsg = "```\n#{fmsg}\n```"
if msg
msg = msg << "\n\n" << fmsg
end
end
if msg.to_s.empty?
$stderr.puts "ERROR: No message content provided!"
exit 1
end
attach = {text: msg, fallback: msg, color: options[:state], mrkdn: true}
attach[:title] = options[:title] if options[:title]
attach[:footer] = options[:footer] if options[:footer]
attach[:footer_icon] = options[:footer_icon] if options[:footer_icon]
attach[:ts] = Time.now.to_i
payload = {}.tap do |pd|
pd[:username] = options.fetch(:username, "packet-exec")
pd[:channel] = options[:channel] if options[:channel]
pd[:icon_url] = options[:icon] if options[:icon]
pd[:attachments] = [attach]
end
result = Net::HTTP.post(URI(options[:webhook]), payload.to_json, "Content-Type" => "application/json")
if !result.code.start_with?("2")
$stderr.puts "Failed to send slack message"
exit 1
else
$stdout.puts "ok"
end