Skip to content

Commit 6b6917d

Browse files
committed
Add Python script for auto-generating changelogs from pull requests.
For more information, please see http://mattdeboard.net/2014/01/14/automatic-changelog-generation-with-git/.
1 parent 4144d93 commit 6b6917d

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

release.py

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
"""This script generates release notes for each merged pull request from
3+
git merge-commit messages.
4+
5+
Usage:
6+
7+
`python release.py <start_commit> <end_commit> [--output {file,stdout}]`
8+
9+
For example, if you wanted to find the diff between version 1.0 and 1.2,
10+
and write the output to the release notes file, you would type the
11+
following:
12+
13+
`python release.py 1.0 1.2 -o file`
14+
15+
"""
16+
import os.path as op
17+
import re
18+
import subprocess
19+
from collections import deque
20+
21+
22+
def commit_msgs(start_commit, end_commit):
23+
"""Run the git command that outputs the merge commits (both subject
24+
and body) to stdout, and return the output.
25+
26+
"""
27+
fmt_string = ("'%s%n* [#{pr_num}]"
28+
"(https://github.com/elixir-lang/emacs-elixir/pull/{pr_num}) - %b'")
29+
return subprocess.check_output([
30+
"git",
31+
"log",
32+
"--pretty=format:%s" % fmt_string,
33+
"--merges", "%s..%s" % (start_commit, end_commit)])
34+
35+
36+
def release_note_lines(msgs):
37+
"""Parse the lines from git output and format the strings using the
38+
pull request number.
39+
40+
"""
41+
ptn = r"Merge pull request #(\d+).*\n([^\n]*)'$"
42+
pairs = re.findall(ptn, msgs, re.MULTILINE)
43+
return deque(body.format(pr_num=pr_num) for pr_num, body in pairs)
44+
45+
46+
def release_header_line(version, release_date=None):
47+
release_date = release_date or datetime.date.today().strftime('%Y/%m/%d')
48+
return "## %s - %s" % (version, release_date)
49+
50+
51+
def prepend(filename, lines, release_header=False):
52+
"""Write `lines` (i.e. release notes) to file `filename`."""
53+
if op.exists(filename):
54+
with open(filename, 'r+') as f:
55+
first_line = f.read()
56+
f.seek(0, 0)
57+
f.write('\n\n'.join([lines, first_line]))
58+
else:
59+
with open(filename, 'w') as f:
60+
f.write(lines)
61+
f.write('\n')
62+
63+
64+
if __name__ == "__main__":
65+
import argparse
66+
import datetime
67+
68+
parser = argparse.ArgumentParser()
69+
parser.add_argument('start_commit', metavar='START_COMMIT_OR_TAG')
70+
parser.add_argument('end_commit', metavar='END_COMMIT_OR_TAG')
71+
parser.add_argument('--filepath', '-f',
72+
help="Absolute path to output file.")
73+
parser.add_argument('--tag', '-t', metavar='NEW_TAG')
74+
parser.add_argument(
75+
'--date', '-d', metavar='RELEASE_DATE',
76+
help="Date of release for listed patch notes. Use yyyy/mm/dd format.")
77+
args = parser.parse_args()
78+
start, end = args.start_commit, args.end_commit
79+
lines = release_note_lines(commit_msgs(start, end))
80+
81+
if args.tag:
82+
lines.appendleft(release_header_line(args.tag, args.date))
83+
84+
lines = '\n'.join(lines)
85+
86+
if args.filepath:
87+
filename = op.abspath(args.filepath)
88+
prepend(filename, lines)
89+
else:
90+
print lines

0 commit comments

Comments
 (0)