class Fastlane::Actions::SlackAction::Runner

Public Class Methods

deep_merge(a, b) click to toggle source

Adapted from stackoverflow.com/a/30225093/158525

# File fastlane/lib/fastlane/actions/slack.rb, line 158
def self.deep_merge(a, b)
  merger = proc do |key, v1, v2|
    Hash === v1 && Hash === v2 ?
      v1.merge(v2, &merger) : Array === v1 && Array === v2 ?
                                v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2
  end
  a.merge(b, &merger)
end
generate_slack_attachments(options) click to toggle source
# File fastlane/lib/fastlane/actions/slack.rb, line 72
def self.generate_slack_attachments(options)
  color = (options[:success] ? 'good' : 'danger')
  should_add_payload = ->(payload_name) { options[:default_payloads].map(&:to_sym).include?(payload_name.to_sym) }

  slack_attachment = {
    fallback: options[:message],
    text: options[:message],
    pretext: options[:pretext],
    color: color,
    mrkdwn_in: ["pretext", "text", "fields", "message"],
    fields: []
  }

  # custom user payloads
  slack_attachment[:fields] += options[:payload].map do |k, v|
    {
      title: k.to_s,
      value: Fastlane::Notification::Slack::LinkConverter.convert(v.to_s),
      short: false
    }
  end

  # Add the lane to the Slack message
  # This might be nil, if slack is called as "one-off" action
  if should_add_payload[:lane] && Actions.lane_context[Actions::SharedValues::LANE_NAME]
    slack_attachment[:fields] << {
      title: 'Lane',
      value: Actions.lane_context[Actions::SharedValues::LANE_NAME],
      short: true
    }
  end

  # test_result
  if should_add_payload[:test_result]
    slack_attachment[:fields] << {
      title: 'Result',
      value: (options[:success] ? 'Success' : 'Error'),
      short: true
    }
  end

  # git branch
  if Actions.git_branch && should_add_payload[:git_branch]
    slack_attachment[:fields] << {
      title: 'Git Branch',
      value: Actions.git_branch,
      short: true
    }
  end

  # git_author
  if Actions.git_author_email && should_add_payload[:git_author]
    if FastlaneCore::Env.truthy?('FASTLANE_SLACK_HIDE_AUTHOR_ON_SUCCESS') && options[:success]
    # We only show the git author if the build failed
    else
      slack_attachment[:fields] << {
        title: 'Git Author',
        value: Actions.git_author_email,
        short: true
      }
    end
  end

  # last_git_commit
  if Actions.last_git_commit_message && should_add_payload[:last_git_commit]
    slack_attachment[:fields] << {
      title: 'Git Commit',
      value: Actions.last_git_commit_message,
      short: false
    }
  end

  # last_git_commit_hash
  if Actions.last_git_commit_hash(true) && should_add_payload[:last_git_commit_hash]
    slack_attachment[:fields] << {
      title: 'Git Commit Hash',
      value: Actions.last_git_commit_hash(short: true),
      short: false
    }
  end

  # merge additional properties
  deep_merge(slack_attachment, options[:attachment_properties])
end
new(slack_url) click to toggle source
# File fastlane/lib/fastlane/actions/slack.rb, line 10
def initialize(slack_url)
  @notifier = Fastlane::Notification::Slack.new(slack_url)
end
trim_message(message) click to toggle source

As there is a text limit in the notifications, we are usually interested in the last part of the message e.g. for tests

# File fastlane/lib/fastlane/actions/slack.rb, line 63
def self.trim_message(message)
  # We want the last 7000 characters, instead of the first 7000, as the error is at the bottom
  start_index = [message.length - 7000, 0].max
  message = message[start_index..-1]
  # We want line breaks to be shown on slack output so we replace
  # input non-interpreted line break with interpreted line break
  message.gsub('\n', "\n")
end

Public Instance Methods

post_message(channel:, username:, attachments:, link_names:, icon_url:, fail_on_error:) click to toggle source
# File fastlane/lib/fastlane/actions/slack.rb, line 41
def post_message(channel:, username:, attachments:, link_names:, icon_url:, fail_on_error:)
  @notifier.post_to_legacy_incoming_webhook(
    channel: channel,
    username: username,
    link_names: link_names,
    icon_url: icon_url,
    attachments: attachments
  )
  UI.success('Successfully sent Slack notification')
rescue => error
  UI.error("Exception: #{error}")
  message = "Error pushing Slack message, maybe the integration has no permission to post on this channel? Try removing the channel parameter in your Fastfile, this is usually caused by a misspelled or changed group/channel name or an expired SLACK_URL"
  if fail_on_error
    UI.user_error!(message)
  else
    UI.error(message)
  end
end
run(options) click to toggle source
# File fastlane/lib/fastlane/actions/slack.rb, line 14
def run(options)
  options[:message] = self.class.trim_message(options[:message].to_s || '')
  options[:message] = Fastlane::Notification::Slack::LinkConverter.convert(options[:message])

  options[:pretext] = options[:pretext].gsub('\n', "\n") unless options[:pretext].nil?

  if options[:channel].to_s.length > 0
    channel = options[:channel]
    channel = ('#' + options[:channel]) unless ['#', '@'].include?(channel[0]) # send message to channel by default
  end

  username = options[:use_webhook_configured_username_and_icon] ? nil : options[:username]

  slack_attachment = self.class.generate_slack_attachments(options)
  link_names = options[:link_names]
  icon_url = options[:use_webhook_configured_username_and_icon] ? nil : options[:icon_url]

  post_message(
    channel: channel,
    username: username,
    attachments: [slack_attachment],
    link_names: link_names,
    icon_url: icon_url,
    fail_on_error: options[:fail_on_error]
  )
end