Last active
August 29, 2015 14:23
-
-
Save choffmeister/69e8befa70d567fc1f02 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import subprocess | |
import os | |
import re | |
import sys | |
import itertools | |
sprint_regex = '^sprint\-(\d+)?$' | |
semver_regex = '^v(\d+)\.(\d+)\.(\d+)(\-(.*))?$' | |
include_regex='\.(css|dust|html|js|json|less|md|conf|css|gradle|html|java|js|json|md|properties|raml|sh|sql|txt|xml|xsd|yml)$' | |
exclude_regex='vendor|JMeter|dist|static' | |
def toint(strOrNone): | |
if strOrNone: | |
return int(strOrNone) | |
else: | |
return None | |
def run(cmd, cwd = None, stdout = subprocess.PIPE): | |
p = subprocess.Popen(cmd, cwd = cwd, env = os.environ, stdout = stdout, stderr = subprocess.PIPE) | |
stdout, err = p.communicate() | |
if p.wait() != 0: raise Exception(err) | |
return stdout | |
def git_tags(): | |
return run(['git', 'tag']).splitlines() | |
def git_commits(ref_old, ref_new): | |
commits_raw = run(['git', 'log', '%s..%s' % (ref_old, ref_new), '--no-merges', '--pretty=%B|<|>|']).split('|<|>|')[:-1] | |
commits = filter(lambda c: c != None, map(lambda c: parse_commit(c), commits_raw)) | |
return commits | |
def git_changes_stats(ref_old, ref_new): | |
global include_regex | |
global exclude_regex | |
lines = run(['git', 'diff', '%s..%s' % (ref_old, ref_new), '--numstat', '-w']).splitlines() | |
all = filter(lambda c: c != None, map(parse_change, lines)) | |
filtered_1 = filter(lambda c: re.search(include_regex, c['file']) != None, all) | |
filtered_2 = filter(lambda c: re.search(exclude_regex, c['file']) is None, filtered_1) | |
return filtered_2 | |
def git_changes(ref_old, ref_new): | |
global include_regex | |
global exclude_regex | |
lines = run(['git', 'log', '%s..%s' % (ref_old, ref_new), '--pretty=tformat:', '--numstat', '-w']).splitlines() | |
all = filter(lambda c: c != None, map(parse_change, lines)) | |
filtered_1 = filter(lambda c: re.search(include_regex, c['file']) != None, all) | |
filtered_2 = filter(lambda c: re.search(exclude_regex, c['file']) is None, filtered_1) | |
return filtered_2 | |
def tags_filter(t): | |
global sprint_regex | |
global semver_regex | |
return re.search(sprint_regex, t) or re.search(semver_regex, t) | |
def tags_sort(a, b): | |
global sprint_regex | |
global semver_regex | |
sprint_a = re.match(sprint_regex, a) | |
sprint_b = re.match(sprint_regex, b) | |
semver_a = re.match(semver_regex, a) | |
semver_b = re.match(semver_regex, b) | |
if sprint_a and semver_b: | |
return -1 | |
elif sprint_b and semver_a: | |
return 1 | |
elif sprint_a and sprint_b: | |
va = toint(sprint_a.group(1)) | |
vb = toint(sprint_b.group(1)) | |
return cmp(va, vb) | |
else: | |
va = [toint(semver_a.group(1)), toint(semver_a.group(2)), toint(semver_a.group(3))] | |
vb = [toint(semver_b.group(1)), toint(semver_b.group(2)), toint(semver_b.group(3))] | |
if cmp(va, vb) != 0: | |
return cmp(va, vb) | |
else: | |
return -cmp(semver_a.group(5), semver_b.group(5)) | |
def parse_change(raw_line): | |
match = re.match('^(\d+)\s+(\d+)\s(.*)$', raw_line) | |
if match: | |
return { | |
'file': match.group(3).strip(), | |
'added': int(match.group(1)), | |
'removed': int(match.group(2)) | |
} | |
else: | |
return None | |
def parse_commit(raw_body): | |
subject = re.match('^([^\(]+)\(([^\)]+)\):(.*)$', raw_body.strip().splitlines()[0].strip()) | |
jira_ids = re.findall('UNITY\-\d+', raw_body) | |
if subject: | |
return { | |
'raw_body': raw_body.strip(), | |
'type': subject.group(1).strip(), | |
'scope': subject.group(2).strip(), | |
'subject': subject.group(3).strip(), | |
'jira_ids': jira_ids | |
} | |
else: | |
return None | |
tags = ['HEAD'] + list(reversed(sorted(filter(tags_filter, git_tags()), cmp = tags_sort))) | |
print '# Changelog\n' | |
for ref_new, ref_old in zip(tags[:-1], tags[1:]): | |
print '## %s\n' % ref_new | |
changes = git_changes(ref_old, ref_new) | |
commits = git_commits(ref_old, ref_new) | |
for type, g1 in itertools.groupby(sorted(commits, key = lambda c: c['type']), lambda c: c['type']): | |
print '### %s\n' % type | |
for commit in g1: | |
jira_ids_md = map(lambda j: '[[%s]](https://epages.atlassian.net/browse/%s)' % (j, j), commit['jira_ids']) | |
print '* (%s) %s %s' % (commit['scope'], commit['subject'], ', '.join(jira_ids_md)) | |
print '# Metrics\n' | |
for ref_new, ref_old in zip(tags[:-1], tags[1:]): | |
print '## %s\n' % ref_new | |
changes_stats = git_changes_stats(ref_old, ref_new) | |
added = reduce(lambda s, c: s + c['added'], changes_stats, 0) | |
removed = reduce(lambda s, c: s + c['removed'], changes_stats, 0) | |
print '* Added %d' % added | |
print '* Removed %d' % removed | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment