#!/usr/bin/python3 # # git-changelog - Output a rpm changelog # # Copyright (C) 2009 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # # Author: David Cantrell # Author: Brian C. Lane import os import re import subprocess import sys import textwrap from argparse import ArgumentParser class ChangeLog: def __init__(self, tag): self.tag = tag self.ignore = None def _getCommitDetail(self, commit, field, long=False): proc = subprocess.Popen(['git', 'log', '-1', "--pretty=format:%s" % field, commit], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() ret = proc[0].decode("utf8").strip("\n").split('\n') if long: return ret if len(ret) == 1 and ret[0].find('@') != -1: ret = ret[0].split('@')[0] elif len(ret) == 1: ret = ret[0] else: ret = filter(lambda x: x != '', ret) return ret def getBugs(self, msg): """Get the Resolves/Related bugs from the commit. Bug in first line is considered Resolves """ bugs = [] if not msg: return [] # summary line format is ^.*#([0-9]+).* # Make sure the bz# isn't likely to be a github issue for line in msg: m = re.match(r"^(Resolves|Related|Conflicts):\ +(rhbz#|RHEL-)(\d+)", line) if m and m.group(1) and m.group(2) and m.group(3): bugs.append((m.group(1), m.group(2), m.group(3))) else: # Assume summary line references are still rhbz# only m = re.match(r"^.*#(\d+).*", line) if m and m.group(1) and int(m.group(1)) > 100000: bugs.append(("Resolves", "rhbz#", m.group(1))) return bugs def getLog(self): rev_range = "%s.." % (self.tag) proc = subprocess.Popen(['git', 'log', '--pretty=oneline', rev_range], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() lines = filter(lambda x: x.find('l10n: ') != 41 and \ x.find('Merge commit') != 41 and \ x.find('Merge branch') != 41, proc[0].decode("utf8").strip('\n').split('\n')) if self.ignore and self.ignore != '': for commit in self.ignore.split(','): lines = filter(lambda x: not x.startswith(commit), lines) log = [] for line in lines: fields = line.split(' ') commit = fields[0] summary = self._getCommitDetail(commit, "%s") long = self._getCommitDetail(commit, "%b", True) author = self._getCommitDetail(commit, "%aE") msg = ["%s (%s)" % (summary.strip(), author)] for r, kind, bz in self.getBugs(long): msg.append("%s: %s%s" % (r, kind, bz)) log.append(msg) return log def formatLog(self): s = "" for msg in self.getLog(): sublines = textwrap.wrap(msg[0], 77) s = s + "- %s\n" % sublines[0] for line in sublines[1:] + msg[1:]: s = s + " %s\n" % line return s def main(): parser = ArgumentParser(description="Generate changelog entries from git commits") parser.add_argument("-t", "--tag", dest="tag", help="Last tag, changelog is commits after this tag") args = parser.parse_args() cl = ChangeLog(args.tag) print(cl.formatLog()) if __name__ == "__main__": main()