Closed shedd closed 9 years ago
+1
+1
+1
same here
+1
+1
Yes, please integrate slack notifications!
+1
I got tired of waiting for a response, so I created my own coveralls:
Gemfile
gem 'simplecov', '~> 0.9.1', require: false, group: :test
.simplecov
require 'simplecov'
require 'json'
class SimpleCov::Formatter::SlackFormatter
ERROR_THRESHOLD = 50.0
WARNING_THRESHOLD = 90.0
LINE_NUMBER_WIDTH = 5
def format(result)
payload = slack_payload(result)
notify_slack(payload)
puts 'Coverage reported to Slack'
end
private
def local_filepath(filepath)
filepath.to_s.gsub(Rails.root.to_s, '')
end
def notify_slack(payload)
uri = URI.parse(slack_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data(payload: payload.to_json)
response = http.request(request)
rescue SocketError => e
puts "#{ e.message } or slack may be down"
end
def slack_url
domain = "#{ ENV['SLACK_TEAM'] }.slack.com"
url = "https://#{ domain }/services/hooks/incoming-webhook"
params = "token=#{ ENV['SLACK_TOKEN'] }"
"#{ url }?#{ params }"
end
def slack_payload(simple_cov_result)
covered_percent = simple_cov_result.covered_percent.round(2)
covered_lines = simple_cov_result.covered_lines
total_lines = simple_cov_result.total_lines
{
channel: ENV['SLACK_CHANNEL'],
username: 'Simplecov',
icon_emoji: ':mag:',
text: "#{ covered_lines }/#{ total_lines } lines (#{ covered_percent }%)",
attachments: slack_attachments(simple_cov_result)
}
end
def slack_attachments(simple_cov_result)
attachments = []
simple_cov_result.files.each do |file|
attachments << slack_attachment(file) if file.covered_percent < 100
end
attachments
end
def slack_attachment(simple_cov_file_result)
covered_percent = simple_cov_file_result.covered_percent.round(2)
covered_lines = simple_cov_file_result.covered_lines.count
total_lines = simple_cov_file_result.lines_of_code
missed_lines = simple_cov_file_result.missed_lines.map do |missed_line|
"#{ line_number(missed_line.line_number) }.#{ missed_line.source }"
end
{
color: color_for_covered_percent(covered_percent),
mrkdwn_in: ['fields'],
fields: [
{
title: 'File path',
value: local_filepath(simple_cov_file_result.filename),
short: false
},
{
title: 'Covered percent',
value: "#{ covered_percent }%",
short: true
},
{
title: 'Covered lines',
value: "#{ covered_lines }/#{ total_lines }",
short: true
},
{
title: 'Missed lines',
value: "```\n#{ missed_lines.join('') }\n```",
short: false
},
]
}
end
def line_number(line_number)
"#{ ' ' * (LINE_NUMBER_WIDTH - line_number.to_s.length)}#{ line_number }"
end
def color_for_covered_percent(covered_percent)
if covered_percent > ERROR_THRESHOLD
covered_percent > WARNING_THRESHOLD ? 'good' : 'warning'
else
'danger'
end
end
end
%w{ SLACK_TEAM SLACK_TOKEN SLACK_CHANNEL }.each do |env|
raise "Please provide #{ env } environment variable" unless ENV[env]
end
SimpleCov.start 'rails'
SimpleCov.formatter = SimpleCov::Formatter::SlackFormatter
At the beginning of your test_helper.rb or spec_helper
require 'simplecov' if ENV['TEST_COVERAGE']
In your CI service (travis-ci, codeship):
TEST_COVERAGE=true bundle exec rake test
or
TEST_COVERAGE=true bundle exec rspec
Results look like these:
Hope you like it!
@fertapric really cool!
Thanks @nickel
Cool @fertapric !
Thanks @spejman
Creates a badge and uploads it to S3 so you can integrate it on your README
...
class SimpleCov::Formatter::SlackFormatter
...
end
class SimpleCov::Formatter::BadgeFormatter
BRIGHT_GREEN_THRESHOLD = 100.0
GREEN_THRESHOLD = 90.0
YELLOW_GREEN_THRESHOLD = 80.0
YELLOW_THRESHOLD = 70.0
ORANGE_THRESHOLD = 60.0
def format(simple_cov_result)
covered_percent = simple_cov_result.covered_percent.round(2)
badge = svg_for_covered_percent(covered_percent)
upload_badge_to_s3(badge)
puts 'Coverage badge uploaded to AWS S3'
end
private
def svg_for_covered_percent(covered_percent)
color = get_color_from_covered_percent(covered_percent)
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"128\" height=\"20\">
<linearGradient id=\"a\" x2=\"0\" y2=\"100%\">
<stop offset=\"0\" stop-color=\"#bbb\" stop-opacity=\".1\"/>
<stop offset=\"1\" stop-opacity=\".1\"/>
</linearGradient>
<rect rx=\"3\" width=\"128\" height=\"20\" fill=\"#555\"/>
<rect rx=\"3\" x=\"63\" width=\"65\" height=\"20\" fill=\"#{ color }\"/>
<path fill=\"#{ color }\" d=\"M63 0h4v20h-4z\"/>
<rect rx=\"3\" width=\"128\" height=\"20\" fill=\"url(#a)\"/>
<g fill=\"#fff\" text-anchor=\"middle\" font-family=\"DejaVu Sans,Verdana,Geneva,sans-serif\" font-size=\"11\">
<text x=\"32.5\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">coverage</text>
<text x=\"32.5\" y=\"14\">coverage</text>
<text x=\"94.5\" y=\"15\" fill=\"#010101\" fill-opacity=\".3\">#{ covered_percent } %</text>
<text x=\"94.5\" y=\"14\">#{ covered_percent } %</text>
</g>
</svg>"
end
def get_color_from_covered_percent(covered_percent)
color = '#9f9f9f'
if covered_percent >= BRIGHT_GREEN_THRESHOLD
color = '#4c1'
elsif covered_percent >= GREEN_THRESHOLD
color = '#97ca00'
elsif covered_percent >= YELLOW_GREEN_THRESHOLD
color = '#a4a61d'
elsif covered_percent >= YELLOW_THRESHOLD
color = '#dfb317'
elsif covered_percent >= ORANGE_THRESHOLD
color = '#fe7d37'
else
color = '#e05d44'
end
color
end
def upload_badge_to_s3(badge)
options = {
acl: :public_read,
content_type: 'image/svg+xml',
cache_control: 'no-cache, no-store, must-revalidate',
expires: Time.now.gmtime.strftime('%a, %d %b %Y %H:%M:%S GMT')
}
s3_badge.write(badge, options)
end
def s3_badge
app_bucket.objects['monitoring/coverage/app.svg']
end
def app_bucket
s3_client.buckets['app']
end
def s3_client
@s3_client ||= AWS::S3.new(
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
)
end
end
%w{
SLACK_TEAM
SLACK_TOKEN
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
}.each do |env|
raise "Please provide #{ env } environment variable" unless ENV[env]
end
SimpleCov.start 'rails'
SimpleCov.formatters = [
SimpleCov::Formatter::SlackFormatter,
SimpleCov::Formatter::BadgeFormatter
]
And the results look like:
I'm using the flat version, feel free to get your own version at http://shields.io/
Hope you like it!
Any chance this will be baked into Coveralls itself?
+1
Hi everyone, Slack is now an officially supported notification!
Thank you for your patience. Cheers!
Good job!!! :+1:
:+1: Thanks!
@nickmerwin Getting an error when I try testing to the Slack-provided webhook: Error: wrong number of arguments (1 for 0)
Same here: Error: wrong number of arguments (1 for 0)
.
Also, for the notification boxes, it's unclear whether you mean coverage changes by a certain percent, or above/below a certain percent. I'm guessing the latter.…
@iwasrobbed same here, Error: wrong number of arguments (1 for 0)
@nickmerwin Same issue as others.
Error: wrong number of arguments (1 for 0)
+1
I tried to configure a webhook for https://slack.com using their webhook integration instructions, but it's returning a 500 server error.
Slack is great - would love to see it supported for notifications.