18F/identity-idp

View on GitHub
scripts/notify-slack

Summary

Maintainability
Test Coverage
#!/usr/bin/env ruby
# frozen_string_literal: true
 
require 'json'
require 'net/http'
require 'optparse'
 
# Posts a message to Slack via webhook
class NotifySlack
def run(argv:, stdin:, stdout:)
channel = nil
username = nil
text = nil
webhook = nil
icon = ':login-gov:'
raise_on_failure = false
 
program_name = File.basename($PROGRAM_NAME)
 
parser = OptionParser.new do |opts|
opts.banner = <<~STR
#{program_name} [options]
 
Usage:
 
* Using arguments
 
#{program_name} --text "my *message*" \\
--channel "#some-channel" \\
--webhook https://example.com/webhook
 
* Passing text over STDIN
 
echo "my *message*" | #{program_name} --text - \\
--channel "#some-channel" \\
--webhook https://example.com/webhook
 
Options:
STR
 
opts.on('--channel CHANNEL', 'which channel to notify') do |channel_v|
channel = channel_v
end
 
opts.on('--webhook WEBHOOK', 'Slack webhook URL') do |webhook_v|
webhook = webhook_v
end
 
opts.on('--username USERNAME', 'which username to notify as') do |username_v|
username = username_v
end
 
opts.on('--text TEXT', 'text of notification, pass - to read from STDIN') do |text_v|
if text_v == '-'
if stdin.tty?
stdout.print 'please enter text of message: '
text = stdin.gets
else
text = stdin.read
end
else
text = text_v
end
end
 
opts.on('--icon ICON', 'slack emoji to use as icon (optional)') do |icon_v|
icon = icon_v
end
 
opts.on('--[no-]raise', <<~EOS) do |raise_v|
raise errors/exit uncleanly if the webhook fails. defaults to not raising
EOS
raise_on_failure = raise_v
end
 
opts.on('--help') do
puts opts
exit 0
end
end
 
parser.parse!(argv)
 
if !channel || !username || !text || !webhook
stdout.puts parser
exit 1
end
 
notify(
webhook: webhook,
channel: channel,
username: username,
text: text,
icon: format_icon(icon),
)
stdout.puts 'OK'
rescue Net::HTTPClientException => err
stdout.puts "#{program_name} HTTP ERROR: #{err.response.code}"
raise err if raise_on_failure
rescue => err
stdout.puts "#{program_name} ERROR: #{err.message}"
raise err if raise_on_failure
end
 
# @raise [Net::HTTPClientException] throws an error for non-successful response
# @return [Net::HTTPResponse]
def notify(webhook:, channel:, username:, text:, icon:)
url = URI(webhook)
 
req = Net::HTTP::Post.new(url)
req.form_data = {
'payload' => {
channel: channel,
username: username,
text: text,
icon_emoji: icon,
}.to_json,
}
 
Net::HTTP.start(
url.hostname,
url.port,
use_ssl: url.scheme == 'https',
open_timeout: 1,
read_timeout: 1,
write_timeout: 1,
ssl_timeout: 1,
) do |http|
http.request(req)
end.value
end
 
def format_icon(icon)
if icon.start_with?(':') && icon.end_with?(':')
icon
else
":#{icon}:"
end
end
end
 
if $PROGRAM_NAME == __FILE__
NotifySlack.new.run(argv: ARGV, stdin: STDIN, stdout: STDOUT)
end