-
Notifications
You must be signed in to change notification settings - Fork 9
/
changelog.py
executable file
·80 lines (62 loc) · 2.56 KB
/
changelog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env python
# Cheddar changelog generator
# (c) cheddar-lang 2016-
#
# Outputs data including name, hash, email & message
from subprocess import check_output
from collections import namedtuple, defaultdict
import re
import sys
import argparse
ITEM_LENGTH = 80
INDENT = ' - '
# Handle process arguments
parser = argparse.ArgumentParser()
parser.add_argument("logfile", help="file to write to, default stdout", nargs='?', type=argparse.FileType('w+'), default=sys.stdout)
parser.add_argument("--latest", help="only shows the latest changes", action="store_true")
args = parser.parse_args()
LOGFILE = args.logfile
# These do most of the heavy lifting
Commit = namedtuple('Commit', ['author', 'email', 'hash', 'change'])
def getlog(start, end):
rawdata = check_output(["git", "log", start + ".." + end, "--format=%cn%n%ce%n%h%n%s"]).decode("utf-8").splitlines()
ITEMS_PER_COMMIT = 4
return list(map(Commit, *[iter(rawdata)] * ITEMS_PER_COMMIT))
# Get all info we need
if args.latest:
tags = ["HEAD", check_output([ "git", "describe", "--tags", "--abbrev=0" ]).decode("utf-8").strip()]
else:
tags = check_output([ "git", "for-each-ref", "--sort=taggerdate", "--format", "%(tag)" ]).decode("utf-8").strip().splitlines()[::-1]
# parse commit format
commit_format = re.compile(r"^(.+?) \[(.+?)\]: (.+)")
# Start generating change log
# Writes to `CHANGELOG`
with LOGFILE as log:
# Generate changes
# This goes from old -> new
for i in range(len(tags) - 1):
former, latter = tags[i + 1], tags[i]
logItems = getlog(former, latter)
longestName = len(max(logItems, key=lambda s: len(s.author)).author)
log.write(
(former + " -> " + latter).center(ITEM_LENGTH, ' ') + '\n'
)
log.write( "=" * ITEM_LENGTH + '\n' )
# Now handle sorting of commits
commits = defaultdict(list)
for item in logItems:
res = re.match(commit_format, item.change)
if res == None:
commits['other'].append(item)
elif res.group(1) != 'version':
commits[res.group(1).lower().strip()].append(
item._replace(change='{}: {}'.format(res.group(2), res.group(3)))
)
for category, items in sorted(commits.items()):
log.write("{}:\n".format(category))
lastLogAuthor = ""
for logItem in items:
log.write(
INDENT + '{1} ({0.hash}) {0.change}\n'.format(logItem, logItem.author.ljust(longestName))
)
log.write('\n\n')