-
Notifications
You must be signed in to change notification settings - Fork 55
/
gitlog2changelog.py
executable file
·151 lines (137 loc) · 5.62 KB
/
gitlog2changelog.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python3
# Copyright 2008 Marcus D. Hanwell <[email protected]>
# Minor changes for NUT by Charles Lepple
# Distributed under the terms of the GNU General Public License v2 or later
#
# Updates by Treece Burgess in October of 2024:
# Add --start_commit and --fout command line arguments
# Update the re.search conditional check to actually check against a valid return value
# Correctly account for the final entry of the git log summary
import string, re, os
from textwrap import TextWrapper
import sys, argparse
def cmd_line_interface():
"""Setup for the command line interface..
:return: The argparse.Namespace object.
"""
parser = argparse.ArgumentParser()
parser.add_argument("--starting_commit", required = True,
help = "Commit hash for the starting point of the desired range (non-inclusive).")
parser.add_argument("--fout", required = True,
help = "Name to give output file. E.g. ChangeLogP800.txt")
return parser.parse_args()
if __name__ == "__main__":
# Collect the command line arguments
args = cmd_line_interface()
# Range of specific commits that we want to create a change log for
rev_range = '%s..HEAD' % args.starting_commit
# Execute git log with the desired command line options.
# This is implemented using subprocess.Popen
fin = os.popen('git log --summary --stat --no-merges --date=short %s' % rev_range, 'r', buffering = -1)
# Needed to properly parse final entry
lines = fin.readlines()
last_line = lines[-1]
# Create a ChangeLog file in the current directory.
fout = open(args.fout, 'w')
# Set up the loop variables in order to locate the blocks we want
authorFound = False
dateFound = False
messageFound = False
filesFound = False
message = ""
messageNL = False
files = ""
prevAuthorLine = ""
wrapper = TextWrapper(initial_indent="\t", subsequent_indent="\t ")
# The main part of the loop
for line in lines:
# The commit line marks the start of a new commit object.
if line.startswith('commit'):
# Start all over again...
authorFound = False
dateFound = False
messageFound = False
messageNL = False
message = ""
filesFound = False
files = ""
continue
# Match the author line and extract the part we want
elif 'Author:' in line:
authorList = re.split(': ', line, 1)
author = authorList[1]
author = author[0:len(author)-1]
authorFound = True
# Match the date line
elif 'Date:' in line:
dateList = re.split(': ', line, 1)
date = dateList[1]
date = date[0:len(date)-1]
dateFound = True
# The Fossil-IDs are ignored:
elif line.startswith(' Fossil-ID:') or line.startswith(' [[SVN:'):
continue
# The svn-id lines are ignored
elif ' git-svn-id:' in line:
continue
# The sign off line is ignored too
elif 'Signed-off-by' in line:
continue
# Extract the actual commit message for this commit
elif authorFound & dateFound & messageFound == False:
# Find the commit message if we can
if len(line) == 1:
if messageNL:
messageFound = True
else:
messageNL = True
elif len(line) == 4:
messageFound = True
else:
if len(message) == 0:
message = message + line.strip()
else:
message = message + " " + line.strip()
# If this line is hit all of the files have been stored for this commit
elif re.search('files? changed', line) != None:
filesFound = True
# We only want to continue if it is not the last line;
# continuing on the last line would skip the final entry
if line is not last_line:
continue
# Collect the files for this commit. FIXME: Still need to add +/- to files
elif authorFound & dateFound & messageFound:
fileList = re.split(' \| ', line, 2)
if len(fileList) > 1:
if len(files) > 0:
files = files + ", " + fileList[0].strip()
else:
files = fileList[0].strip()
# All of the parts of the commit have been found - write out the entry
if authorFound & dateFound & messageFound & filesFound:
# First the author line, only outputted if it is the first for that
# author on this day
authorLine = date + " " + author
if len(prevAuthorLine) == 0:
fout.write(authorLine + "\n\n")
elif authorLine == prevAuthorLine:
pass
else:
fout.write("\n" + authorLine + "\n\n")
# Assemble the actual commit message line(s) and limit the line length
# to 80 characters.
commitLine = "* " + files + ": " + message
# Write out the commit line
fout.write(wrapper.fill(commitLine) + "\n")
#Now reset all the variables ready for a new commit block.
authorFound = False
dateFound = False
messageFound = False
messageNL = False
message = ""
filesFound = False
files = ""
prevAuthorLine = authorLine
# Close the input and output lines now that we are finished.
fin.close()
fout.close()