Skip to content

Instantly share code, notes, and snippets.

@choffmeister
Last active August 29, 2015 14:23
Show Gist options
  • Save choffmeister/69e8befa70d567fc1f02 to your computer and use it in GitHub Desktop.
Save choffmeister/69e8befa70d567fc1f02 to your computer and use it in GitHub Desktop.
#!/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
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
print
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment