Skip to content

Instantly share code, notes, and snippets.

@mspaulding06
Created April 23, 2013 22:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mspaulding06/5447788 to your computer and use it in GitHub Desktop.
Save mspaulding06/5447788 to your computer and use it in GitHub Desktop.
Simple way to create a clean changelog between two commits. Allows changelog filtering to only include commits containing a substring or regular expression.
#!/usr/bin/env python
import sys
import re
from optparse import OptionParser
from subprocess import Popen, PIPE
class GitChangelog(object):
def __init__(self, from_ref=None, to_ref='HEAD', log_filter=None):
self.from_ref = from_ref
self.to_ref = to_ref
self.log_filter = log_filter
def get_log(self):
raw_log = self._generate_log()
log_entries = self._parse_log(raw_log)
pretty_log = []
for author in sorted(log_entries.iterkeys()):
if log_entries[author]:
pretty_log.append("%s:" % author)
pretty_log += log_entries[author]
pretty_log.append("")
return "\n".join(pretty_log)
def _parse_log(self, raw_log):
log_entries = {}
log_lines = raw_log.splitlines()
current_author = None
for line in log_lines:
if re.search('^\w+', line):
current_author = re.search('^([\w\s-]+)\s', line).groups()[0]
log_entries[current_author] = []
else:
if current_author not in log_entries:
raise ValueError("author '%s' does not exist" % current_author)
if self.log_filter:
if re.search(self.log_filter, line):
log_entries[current_author].append(line)
else:
log_entries[current_author].append(line)
return log_entries
def _generate_log(self):
delta = None
if self.from_ref is None:
delta = self.to_ref
else:
delta = "%s..%s" % (self.from_ref, self.to_ref)
p = Popen(["git", "shortlog", delta], stdin=PIPE, stdout=PIPE)
raw_log = p.communicate()[0]
if p.returncode != 0:
raise Exception("Failed to execute git")
return raw_log
def _strip_line(self, data, length=80):
data = data.lstrip()
return (data[:length] + '..') if len(data) > length else data
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-f", "--from", dest="from_ref",
help="changelog starts at this reference")
parser.add_option("-t", "--to", dest="to_ref", default="HEAD",
help="changelog ends at this reference")
parser.add_option("-l", "--log-filter", dest="log_filter",
help="take changes that include this string")
(opts, args) = parser.parse_args()
changelog = GitChangelog(from_ref=opts.from_ref, to_ref=opts.to_ref,
log_filter=opts.log_filter)
sys.stdout.write(changelog.get_log())
sys.stdout.flush()
@mspaulding06
Copy link
Author

Example usage:

./gen-changelog.py -f 3.3-m5 -t 3.3-m6 -l EUCA-\\d+ > changelog.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment