Skip to content

Instantly share code, notes, and snippets.

@lepture
Last active August 29, 2015 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lepture/8803b79f03bbaa898c63 to your computer and use it in GitHub Desktop.
Save lepture/8803b79f03bbaa898c63 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import os
import re
import sys
import json
import requests
def parse_junit(filepath):
with open(filepath) as f:
content = f.read()
pattern = re.compile('<testsuite .*?>')
text = pattern.findall(content)[0]
tests = int(re.findall(r'tests="(\d+)"', text)[0])
errors = int(re.findall(r'errors="(\d+)"', text)[0])
failures = int(re.findall(r'failures="(\d+)"', text)[0])
skips = int(re.findall(r'skips="(\d+)"', text)[0])
# name = re.findall(r'name="(\w+)"', text)[0]
# time = float(re.findall(r'time="([\d\.]+)"', text)[0])
if errors or failures:
color = 'danger'
fallback = 'failed with %d tests, %d errors and %d failures' % (
tests, errors, failures
)
pretext = 'Build failed'
else:
color = 'good'
fallback = 'build success with %d tests and %d skips' % (tests, skips)
pretext = 'Build succeeded'
return dict(
fallback=fallback,
pretext=pretext,
color=color,
fields=[
{'title': 'tests', 'value': str(tests), 'short': True},
{'title': 'errors', 'value': str(errors), 'short': True},
{'title': 'failures', 'value': str(failures), 'short': True},
{'title': 'skips', 'value': str(skips), 'short': True},
],
)
def parse_coverage(filepath):
with open(filepath) as f:
content = f.read()
pattern = re.compile('<coverage .*?>')
text = pattern.findall(content)[0]
branch = float(re.findall(r'branch-rate="([\d\.]+)"', text)[0])
line = float(re.findall(r'line-rate="([\d\.]+)"', text)[0])
if line < 0.5:
pretext = 'Coverage is bad'
color = 'danger'
elif line < 0.8:
pretext = 'Coverage is well'
color = 'warning'
else:
pretext = 'Coverage is good'
color = 'good'
line = '%d%%' % int(line * 100)
branch = '%d%%' % int(branch * 100)
return dict(
fallback='Line coverage: %s, branch coverage: %s' % (line, branch),
pretext=pretext,
color=color,
fields=[
{'title': 'line', 'value': line, 'short': True},
{'title': 'branch', 'value': branch, 'short': True},
],
)
def send_to_slack(channel, url, msg='', attachments=None):
username = os.getenv('SLACK_USERNAME', 'Python')
payload = {
"channel": channel,
"username": username,
"text": msg,
"icon_emoji": ":snake:"
}
if attachments:
payload['attachments'] = attachments
headers = {'Content-Type': 'application/json'}
try:
requests.post(
url,
data=json.dumps(payload),
headers=headers,
timeout=5,
)
except:
print("Fail to send to slack")
def circle_ci(pretext):
user = os.getenv('CIRCLE_PROJECT_USERNAME')
if not user:
return pretext
repo = os.getenv('CIRCLE_PROJECT_REPONAME')
num = os.getenv('CIRCLE_BUILD_NUM')
url = 'https://circleci.com/gh/%s/%s/%s' % (user, repo, num)
pretext = '%s for %s <%s|#%s>' % (pretext, repo, url, num)
compare = os.getenv('CIRCLE_COMPARE_URL')
if not compare:
return pretext
branch = os.getenv('CIRCLE_BRANCH')
sha = os.getenv('CIRCLE_SHA1')
return '%s on <%s|%s#%s>' % (pretext, compare, branch, sha)
def main(test_file=None, coverage_file=None, slack_channel=None):
attachments = []
if test_file and os.path.isfile(test_file):
rv = parse_junit(test_file)
rv['pretext'] = circle_ci(rv['pretext'])
attachments.append(rv)
if coverage_file is None:
coverage_file = 'coverage.xml'
if os.path.isfile(coverage_file):
rv = parse_coverage(coverage_file)
attachments.append(rv)
if not attachments:
msg = 'There is no tests and coverage'
else:
msg = ''
slack_url = os.getenv('SLACK_URL')
if slack_channel:
for chan in slack_channel.split():
send_to_slack(chan, slack_url, msg, attachments)
return
branch = os.getenv('CIRCLE_BRANCH')
if branch == 'master':
channel = os.getenv('SLACK_MASTER_CHANNEL')
for chan in channel.split():
send_to_slack(chan, slack_url, msg, attachments)
return
channel = os.getenv('SLACK_DEVELOP_CHANNEL')
for chan in channel.split():
send_to_slack(chan, slack_url, msg, attachments)
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit()
test_file = sys.argv[1]
if len(sys.argv) > 2:
coverage_file = sys.argv[2]
else:
coverage_file = None
if len(sys.argv) > 3:
slack_channel = sys.argv[3]
else:
slack_channel = None
main(test_file, coverage_file, slack_channel)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment