| #!/usr/bin/python |
| from optparse import OptionParser |
| import re |
| import subprocess |
| import sys |
| |
| """ |
| This script generates a release note from the output of git log |
| between the specified tags. |
| |
| Options: |
| --issues Show output the commits with issues associated with them. |
| --issue-numbers Show outputs issue numbers of the commits with issues |
| associated with them |
| |
| Arguments: |
| since -- tag name |
| until -- tag name |
| |
| Example Input: |
| |
| * <commit subject> |
| + |
| <commit message> |
| |
| Bug: issue 123 |
| Change-Id: <change id> |
| Signed-off-by: <name> |
| |
| Expected Output: |
| |
| * issue 123 <commit subject> |
| + |
| <commit message> |
| """ |
| |
| parser = OptionParser(usage='usage: %prog [options] <since> <until>') |
| |
| parser.add_option('-i', '--issues', action='store_true', |
| dest='issues_only', default=False, |
| help='only output the commits with issues association') |
| |
| parser.add_option('-n', '--issue-numbers', action='store_true', |
| dest='issue_numbers_only', default=False, |
| help='only outputs issue numbers of the commits with \ |
| issues association') |
| |
| (options, args) = parser.parse_args() |
| |
| if len(args) != 2: |
| parser.error("wrong number of arguments") |
| |
| issues_only = options.issues_only |
| issue_numbers_only = options.issue_numbers_only |
| |
| since_until = args[0] + '..' + args[1] |
| proc = subprocess.Popen(['git', 'log', '--reverse', '--no-merges', |
| since_until, "--format=* %s%n+%n%b"], |
| stdout=subprocess.PIPE, |
| stderr=subprocess.STDOUT,) |
| |
| stdout_value = proc.communicate()[0] |
| |
| subject = "" |
| message = [] |
| is_issue = False |
| |
| # regex pattern to match following cases such as Bug: 123, Issue Bug: 123, |
| # Bug: GERRIT-123, Bug: issue 123, Bug issue: 123, issue: 123, issue: bug 123 |
| p = re.compile('bug: GERRIT-|bug(:? issue)?:? |issue(:? bug)?:? ', |
| re.IGNORECASE) |
| |
| if issue_numbers_only: |
| for line in stdout_value.splitlines(True): |
| if p.match(line): |
| sys.stdout.write(p.sub('', line)) |
| else: |
| for line in stdout_value.splitlines(True): |
| # Move issue number to subject line |
| if p.match(line): |
| line = p.sub('issue ', line).replace('\n',' ') |
| subject = subject[:2] + line + subject[2:] |
| is_issue = True |
| elif line.startswith('* '): |
| # Write change log for a commit |
| if subject != "": |
| if (not issues_only or is_issue): |
| # Write subject |
| sys.stdout.write(subject) |
| # Write message lines |
| if message != []: |
| # Clear + from last line in commit message |
| message[-1] = '\n' |
| for m in message: |
| sys.stdout.write(m) |
| # Start new commit block |
| message = [] |
| subject = line |
| is_issue = False |
| # Remove commit footers |
| elif re.match(r'((\w+-)+\w+:)', line): |
| continue |
| # Don't add extra blank line if last one is already blank |
| elif line == '\n' and message and message[-1] != '+\n': |
| message.append('+\n') |
| elif line != '\n': |
| message.append(line) |