Browse Source
Since the `CHANGELOG.md` file is a major source for merge conflicts I decided to build a tiny tool that generates the entries for the changelog automatically from the commit messages.travis-debug
Christian Decker
5 years ago
committed by
Rusty Russell
3 changed files with 186 additions and 3 deletions
@ -0,0 +1,143 @@ |
|||
#!/usr/bin/env python3 |
|||
from collections import namedtuple |
|||
import re |
|||
import sys |
|||
import shlex |
|||
import subprocess |
|||
import requests |
|||
from mako.template import Template |
|||
import argparse |
|||
from datetime import datetime |
|||
|
|||
# What sections do we support in the changelog: |
|||
sections = [ |
|||
'added', |
|||
'changed', |
|||
'deprecated', |
|||
'fixed', |
|||
'removed', |
|||
'security', |
|||
] |
|||
|
|||
repo = 'ElementsProject/lightning' |
|||
|
|||
Entry = namedtuple("Entry", ["commit", "pullreq", "content", "section"]) |
|||
|
|||
|
|||
def git(cmd): |
|||
cmd = shlex.split(cmd) |
|||
out = subprocess.check_output(['git'] + cmd) |
|||
return out.decode('UTF-8') |
|||
|
|||
|
|||
def get_commit_range(): |
|||
"""Find a commit range that we should collect the CHANGELOG for. |
|||
""" |
|||
description = git("describe") |
|||
version = description.split('-')[0] |
|||
return "{version}..master".format(version=version) |
|||
|
|||
|
|||
def get_log_entries(commitrange): |
|||
commit = None |
|||
logs = git("log {commitrange}".format(commitrange=commitrange)) |
|||
entries = [] |
|||
|
|||
for l in logs.split('\n'): |
|||
m = re.match(r'^commit ([A-Fa-f0-9]{40})$', l) |
|||
if m: |
|||
commit = m.group(1) |
|||
|
|||
m = re.match( |
|||
r'^\s+Changelog-({}): (.*)$'.format("|".join(sections)), l) |
|||
if not m: |
|||
continue |
|||
|
|||
# Now try to resolve the pull request that originated this commit: |
|||
headers = { |
|||
'Accept': 'application/vnd.github.groot-preview+json', |
|||
} |
|||
|
|||
url = 'https://api.github.com/repos/{repo}/commits/{commit}/pulls'.format(repo=repo, commit=commit) |
|||
content = requests.get(url, headers=headers).json() |
|||
if len(content): |
|||
pullreq = content[0]['number'] |
|||
else: |
|||
pullreq = None |
|||
|
|||
e = Entry(commit, pullreq, m.group(2), m.group(1)) |
|||
entries.append(e) |
|||
|
|||
return entries |
|||
|
|||
|
|||
def group(entries): |
|||
groups = {s: [] for s in sections} |
|||
for e in entries: |
|||
groups[e.section].append(e) |
|||
return groups |
|||
|
|||
|
|||
def commit_date(commitsha): |
|||
"""Get the date of the specified commit. |
|||
""" |
|||
line = git("show -s --format=%ci") |
|||
dt = datetime.strptime(line.strip(), '%Y-%m-%d %H:%M:%S %z') |
|||
return dt |
|||
|
|||
|
|||
template = Template("""<%def name="group(entries)"> |
|||
% for e in entries: |
|||
- ${e.content} ([${e.pullreq}](https://github.com/ElementsProject/lightning/pull/${e.pullreq})) |
|||
% endfor |
|||
</%def> |
|||
<!-- |
|||
TODO: Insert version codename, and username of the contributor that named the release. |
|||
--> |
|||
|
|||
${h2} [${version}] - ${date.strftime("%Y-%m-%d")}: "CODENAME" |
|||
|
|||
This release named by @USERNAME. |
|||
|
|||
${h3} Added |
|||
${group(groups['added']) | trim} |
|||
${h3} Changed |
|||
${group(groups['changed']) | trim} |
|||
${h3} Deprecated |
|||
|
|||
Note: You should always set `allow-deprecated-apis=false` to test for changes. |
|||
${group(groups['deprecated']) | trim} |
|||
${h3} Removed |
|||
${group(groups['removed']) | trim} |
|||
${h3} Fixed |
|||
${group(groups['fixed']) | trim} |
|||
${h3} Security |
|||
${group(groups['security']) | trim}""") |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
parser = argparse.ArgumentParser( |
|||
description='Generate a changelog summary for a given commit range' |
|||
) |
|||
parser.add_argument('commitrange', type=str, nargs='?', |
|||
help='Range of commits to consider (format: <from_commit>..<to_commit>', |
|||
default=get_commit_range()) |
|||
|
|||
args = parser.parse_args() |
|||
|
|||
if '..' not in args.commitrange: |
|||
print("Commit range must include '..' to separate 'from_commit' and 'to_commit'") |
|||
sys.exit(1) |
|||
|
|||
fromcommit, tocommit = args.commitrange.split('..') |
|||
entries = get_log_entries(args.commitrange) |
|||
groups = group(entries) |
|||
date = commit_date(tocommit) |
|||
|
|||
print(template.render( |
|||
groups=groups, |
|||
h2='##', |
|||
h3='###', |
|||
version=tocommit, |
|||
date=date, |
|||
)) |
Loading…
Reference in new issue