class Highway::Steps::Library::SlackStep
Public Class Methods
name()
click to toggle source
# File lib/highway/steps/library/slack.rb, line 17 def self.name "slack" end
parameters()
click to toggle source
# File lib/highway/steps/library/slack.rb, line 21 def self.parameters [ Parameters::Single.new( name: "avatar", required: false, type: Types::AnyOf.new( url: Types::Url.new(), emoji: Types::String.regex(/\:[a-z0-9_-]+\:/), ), ), Parameters::Single.new( name: "channel", required: true, type: Types::String.regex(/#[a-z0-9_-]+/) ), Parameters::Single.new( name: "username", required: false, type: Types::String.new(), default: "Highway", ), Parameters::Single.new( name: "webhook", required: true, type: Types::Url.new(), ), ] end
run(parameters:, context:, report:)
click to toggle source
# File lib/highway/steps/library/slack.rb, line 50 def self.run(parameters:, context:, report:) username = parameters["username"] webhook = parameters["webhook"].to_s avatar_emoji = parameters["avatar"][:value] if parameters["avatar"]&[:tag] == :emoji avatar_url = parameters["avatar"][:value].to_s if parameters["avatar"]&[:tag] == :url attachments = [ generate_build_attachments(context), generate_tests_attachments(context), generate_deployment_attachments(context), ] attachments = attachments.flatten.compact attachments.each { |attachment| attachment[:mrkdwn_in] = [:text, :fields] attachment[:fallback] ||= attachment.fetch(:fields, []).reduce([]) { |memo, field| memo + ["#{field[:title]}: #{field[:value]}."] }.join(" ") } attachments.each { |attachment| attachment[:fields].each { |field| field[:value] = Slack::Notifier::Util::LinkFormatter.format(field[:value]) } attachment[:fallback] = Slack::Notifier::Util::LinkFormatter.format(attachment[:fallback]) } notifier = Slack::Notifier.new(webhook) notifier.post({ username: username, icon_emoji: avatar_emoji, icon_url: avatar_url, attachments: attachments, }) context.interface.success("Successfully posted a report message on Slack.") end
Private Class Methods
generate_build_attachments(context)
click to toggle source
# File lib/highway/steps/library/slack.rb, line 90 def self.generate_build_attachments(context) # Generate main field containing information about build status # and its identifier. main_title = context.reports_any_failed? ? "Build failed" : "Build succeeded" if context.env.ci? if context.env.ci_build_number != nil if context.env.ci_build_url != nil main_value = "[#{context.env.ci_build_number}](#{context.env.ci_build_url})" else main_value = "#{context.env.ci_build_number}" end else main_value = "(unknown build)" end else main_value = "(local build)" end # Generate duration field, rounding and ceiling it to minutes, if # possible. duration_title = "Duration" if context.duration_so_far > 60 duration_value = "#{(context.duration_so_far.to_f / 60).ceil} minutes" else duration_value = "#{context.duration_so_far} seconds" end # Generate pull request field, containing number, title and a URL, # if possible. pr_title = "Pull Request" if context.env.ci_trigger == :pr && context.env.git_pr_number != nil if context.env.git_pr_url != nil if context.env.git_pr_title != nil pr_value = "[##{context.env.git_pr_number}: #{context.env.git_pr_title}](#{context.env.git_pr_url})" else pr_value = "[##{context.env.git_pr_number}](#{context.env.git_pr_url})" end else if context.env.git_pr_title != nil pr_value = "##{context.env.git_pr_number}: #{context.env.git_pr_title}" else pr_value = "##{context.env.git_pr_number}" end end end # Generate commit field, containing hash, message and a URL, if # possible. commit_title = "Commit" if context.env.git_commit_hash != nil if context.env.git_commit_message != nil commit_value = "#{context.env.git_commit_hash[0,7]}: #{context.env.git_commit_message}" else commit_value = "#{context.env.git_commit_hash}" end end # Infer the attachment color. attachment_color = context.reports_any_failed? ? "danger" : "good" # Assemble the attachment. attachment_fields = [] attachment_fields << {title: main_title, value: main_value, short: true} if main_value != nil attachment_fields << {title: duration_title, value: duration_value, short: true} if duration_value != nil attachment_fields << {title: pr_title, value: pr_value, short: false} if pr_value != nil attachment_fields << {title: commit_title, value: commit_value, short: false} if commit_value != nil { color: attachment_color, fields: attachment_fields, } end
generate_deployment_attachments(context)
click to toggle source
# File lib/highway/steps/library/slack.rb, line 310 def self.generate_deployment_attachments(context) # Skip if there are no deployment reports. reports = context.deployment_reports return nil if reports.empty? # Map reports into attachments. attachments = reports.map { |report| prepare_deployment_attachment(report[:deployment]) } attachments end
generate_tests_attachments(context)
click to toggle source
# File lib/highway/steps/library/slack.rb, line 175 def self.generate_tests_attachments(context) # Skip if there are no test reports. report = prepare_tests_report(context) return nil unless report != nil # Prepare variables. result = :error if !report[:errors].empty? result ||= :failure if !report[:failures].empty? result ||= :success errors = report[:errors] failures = report[:failures] count = report[:count] # Generate main field containing the information about the result and # counts of all, successful and failed tests. main_title = case result when :success then "Tests succeeded" when :failure, :error then "Tests failed" end main_value = "Executed #{count[:all]} tests: #{count[:succeeded]} succeeded, #{count[:failed]} failed." # Generate errors field containing first three error locations and # reasons. unless errors.empty? errors_title = "Compile errors" errors_messages = errors.first(3).map { |error| if error[:location] "```#{error[:location]}: #{error[:reason]}```" else "```#{error[:reason]}```" end } errors_value = errors_messages.join("\n") errors_value << "\nand #{errors.count - 3} more..." if errors.count > 3 end # Generate failures field containing first three failure locations and # reasons. unless failures.empty? failures_title = "Failing test cases" failures_messages = failures.first(3).map { |failure| "```#{failure[:location]}: #{failure[:reason]}```" } failures_value = failures_messages.join("\n") failures_value << "\nand #{failures.count - 3} more..." if failures.count > 3 end # Generate the fallback value. attachment_fallback = case result when :success then "Tests succeeded. #{main_value}" when :failure then "Tests failed. #{main_value}" when :error then "Tests failed. One or more compiler errors occured." end # Infer the attachment color. attachment_color = case result when :success then "good" when :failure, :error then "danger" end # Assemble the attachment. attachment_fields = [] attachment_fields << {title: main_title, value: main_value, short: false} if main_value != nil attachment_fields << {title: errors_title, value: errors_value, short: false} if errors_value != nil attachment_fields << {title: failures_title, value: failures_value, short: false} if failures_value != nil { color: attachment_color, fields: attachment_fields, fallback: attachment_fallback, } end
prepare_deployment_attachment(report)
click to toggle source
# File lib/highway/steps/library/slack.rb, line 327 def self.prepare_deployment_attachment(report) # Generate main field containing the information about deployment # result and information. main_title = "Deployment succeeded" package_comps = [] package_comps << report[:package][:name] package_comps << report[:package][:version] package_comps << "(#{report[:package][:build]})" if report[:package][:build] != nil package_value = package_comps.compact.join(" ").strip package_value = "(unknown package)" if package_value.empty? main_value = "Successfully deployed #{package_value} to #{report[:service]}." # Generate install button pointing to the installation page. install_title = "Install" install_url = report[:urls][:install] # Generate manage button pointing to the view page. view_title = "View" view_url = report[:urls][:view] # Generate the attachment fallback value and color. attachment_fallback = "Deployment succeeded. #{main_value}" attachment_color = "good" # Assemble the attachment. attachment_fields = [] attachment_fields << {title: main_title, value: main_value, short: false} if main_value != nil attachment_actions = [] attachment_actions << {type: "button", style: "primary", text: install_title, url: install_url} if install_url != nil attachment_actions << {type: "button", style: "default", text: view_title, url: view_url} if view_url != nil { color: attachment_color, fields: attachment_fields, actions: attachment_actions, fallback: attachment_fallback, } end
prepare_tests_report(context)
click to toggle source
# File lib/highway/steps/library/slack.rb, line 268 def self.prepare_tests_report(context) return nil if context.test_reports.empty? zero_report = { errors: [], failures: [], count: {all: 0, failed: 0, succeeded: 0} } merged_results = context.test_reports.map { |report| report[:result] } merged_report = context.test_reports.reduce(zero_report) { |memo, report| { errors: memo[:errors] + report[:test][:errors], failures: memo[:failures] + report[:test][:failures], count: { all: memo[:count][:all] + report[:test][:count][:all], failed: memo[:count][:failed] + report[:test][:count][:failed], succeeded: memo[:count][:succeeded] + report[:test][:count][:succeeded], } } } merged_report[:result] = merged_results.each_cons(2) { |lhs, rhs| if lhs == :error || rhs == :error :error elsif lhs == :failure || rhs == :failure :failure elsif lhs == :succeess && rhs == :success :success else :failure end } merged_report end