lib/slackistrano/capistrano.rb in slackistrano-2.0.0 vs lib/slackistrano/capistrano.rb in slackistrano-2.0.1

- old
+ new

@@ -1,50 +1,166 @@ require 'net/http' require 'json' +require 'forwardable' load File.expand_path("../tasks/slack.rake", __FILE__) module Slackistrano + class Capistrano - # - # - # - def self.post(team: nil, token: nil, webhook: nil, via_slackbot: false, payload: {}) - if via_slackbot - post_as_slackbot(team: team, token: token, webhook: webhook, payload: payload) - else - post_as_webhook(team: team, token: token, webhook: webhook, payload: payload) + extend Forwardable + def_delegators :env, :fetch, :run_locally + + # + # + # + def initialize(env) + @env = env end - rescue => e - error("[slackistrano] Error notifying Slack!") - error("[slackistrano] Error: #{e.inspect}") - end - # - # - # - def self.post_as_slackbot(team: nil, token: nil, webhook: nil, payload: {}) - uri = URI(URI.encode("https://#{team}.slack.com/services/hooks/slackbot?token=#{token}&channel=#{payload[:channel]}")) + # + # + # + def run(action) + should_run = fetch("slack_run".to_sym) + should_run &&= fetch("slack_run_#{action}".to_sym) + return unless should_run - text = payload[:attachments].collect { |a| a[:text] }.join("\n") + _self = self + run_locally { _self.post(action, self) } - Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| - http.request_post uri, text end - end - # - # - # - def self.post_as_webhook(team: nil, token: nil, webhook: nil, payload: {}) - params = {'payload' => payload.to_json} + # + # + # + def post(action, backend) + team = fetch(:slack_team) + token = fetch(:slack_token) + webhook = fetch(:slack_webhook) + via_slackbot = fetch(:slack_via_slackbot) - if webhook.nil? - webhook = "https://#{team}.slack.com/services/hooks/incoming-webhook" - params.merge!('token' => token) + channels = fetch(:slack_channel) + channel_action = "slack_channel_#{action}".to_sym + channels = fetch(channel_action) if fetch(channel_action) + channels = Array(channels) + if via_slackbot == false && channels.empty? + channels = [nil] # default webhook channel + end + + payload = { + username: fetch(:slack_username), + icon_url: fetch(:slack_icon_url), + icon_emoji: fetch(:slack_icon_emoji), + } + + payload[:attachments] = case action + when :updated + make_attachments(action, color: 'good') + when :reverted + make_attachments(action, color: '#4CBDEC') + when :failed + make_attachments(action, color: 'danger') + else + make_attachments(action) + end + + channels.each do |channel| + payload[:channel] = channel + + # This is a nasty hack, but until Capistrano provides an official way to determine if + # --dry-run was passed this is the only option. + # See https://github.com/capistrano/capistrano/issues/1462 + if ::Capistrano::Configuration.env.send(:config)[:sshkit_backend] == SSHKit::Backend::Printer + backend.info("[slackistrano] Slackistrano Dry Run:") + backend.info("[slackistrano] Team: #{team}") + backend.info("[slackistrano] Webhook: #{webhook}") + backend.info("[slackistrano] Via Slackbot: #{via_slackbot}") + backend.info("[slackistrano] Payload: #{payload.to_json}") + + # Post to the channel. + else + + begin + response = post_to_slack(team: team, + token: token, + webhook: webhook, + via_slackbot: via_slackbot, + payload: payload) + + rescue => e + backend.warn("[slackistrano] Error notifying Slack!") + backend.warn("[slackistrano] Error: #{e.inspect}") + end + + if response.code !~ /^2/ + warn("[slackistrano] Slack API Failure!") + warn("[slackistrano] URI: #{response.uri}") + warn("[slackistrano] Code: #{response.code}") + warn("[slackistrano] Message: #{response.message}") + warn("[slackistrano] Body: #{response.body}") if response.message != response.body && response.body !~ /<html/ + end + end + end + end - uri = URI(webhook) - Net::HTTP.post_form(uri, params) - end + # + # + # + def make_attachments(action, options={}) + attachments = options.merge({ + title: fetch(:"slack_title_#{action}"), + pretext: fetch(:"slack_pretext_#{action}"), + text: fetch(:"slack_msg_#{action}"), + fields: fetch(:"slack_fields_#{action}"), + fallback: fetch(:"slack_fallback_#{action}"), + mrkdwn_in: [:text, :pretext] + }).reject{|k, v| v.nil? } + [attachments] + end + private :make_attachments + # + # + # + def post_to_slack(via_slackbot: nil, team: nil, token: nil, webhook: nil, payload: {}) + if via_slackbot + post_as_slackbot(team: team, token: token, webhook: webhook, payload: payload) + else + post_as_webhook(team: team, token: token, webhook: webhook, payload: payload) + end + end + private :post_to_slack + + # + # + # + def post_as_slackbot(team: nil, token: nil, webhook: nil, payload: {}) + uri = URI(URI.encode("https://#{team}.slack.com/services/hooks/slackbot?token=#{token}&channel=#{payload[:channel]}")) + + text = payload[:attachments].collect { |a| a[:text] }.join("\n") + + Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| + http.request_post uri, text + end + end + private :post_as_slackbot + + # + # + # + def post_as_webhook(team: nil, token: nil, webhook: nil, payload: {}) + params = {'payload' => payload.to_json} + + if webhook.nil? + webhook = "https://#{team}.slack.com/services/hooks/incoming-webhook" + params.merge!('token' => token) + end + + uri = URI(webhook) + Net::HTTP.post_form(uri, params) + end + private :post_as_webhook + + end end