forked from KhronosGroup/KTX-Software
-
Notifications
You must be signed in to change notification settings - Fork 4
/
mkrelnotes
executable file
·252 lines (219 loc) · 7.04 KB
/
mkrelnotes
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#! /bin/bash
# Copyright 2020, Mark Callow
# SPDX-License-Identifier: Apache-2.0
# Generate release notes from git log.
#
# mkrelnotes [-b] [-c] [-d] [-p <preface> [-t] <previous release tag> <release name>
#
# <previous release tag> is the name of the tag identifying the previous
# release. <this release> is the name to be given to the tag for the upcoming
# release. N.B. this tag cannot be created until after ther release notes
# have been generated and checked in. The release notes will include changes
# in the two-dot commit range <previous release tag>..HEAD.
#
# <preface> is inserted between the title and the detailed change list
# that is extracted with git log. It should be used to summarize
# new features and known issues using level 3 (###) headings for those
# sections.
#
# If -b is specified build system changes will be included in the
# release # notes.
#
# If -c is specified any previous $RELNOTES_FILE will be appended, with the
# title lines stripped, to the release notes generated here, thus enabling
# cumulative release notes. Otherwise any previous $RELNOTES_FILE file is
# replaced.
#
# If -d is specified details of the changes will be included, otherwise only
# the summary is shown.
#
# If -i is specified the release notes will be built interactively. That is,
# for each change the user will be asked if it should be included.
#
# If -t is specified changes to the tests will be included in the release notes
# otherwise they are omitted.
# Depth of this script relative to the project root
depth=.
RELNOTES_FILE="RELEASE_NOTES.md"
# The author name in a commit message comes from whatever the user
# has set as user.name in their git config. It usually has no relation
# to their GitHub username so putting an @ before it has no meaning.
#
SUMMARY_FORMAT_W_AUTH="* %s (%h) (%an)"
SUMMARY_FORMAT="* %s (%h)"
function commit_summary() {
local hash=$1
local summary
local prjson
pr=$(git log --oneline -n 1 $hash | grep -o -E "\(#[0-9]+\)" | grep -o -E "[0-9]+")
# Even in PR's the commit has the full name of the user as known to GitHub,
# not their GitHub username. We want to use the GitHub username so there will
# be a link back to the person. We can retrieve this by requesting detailed info
# from GitHub via HTTPS.
summary=$(git log --pretty="$SUMMARY_FORMAT" -n 1 $hash)
if [ -z "$pr" ]; then
cmtjson="$(curl -n https://api.github.com/repos/KhronosGroup/KTX-Software/commits/$hash 2>/dev/null)"
author="$(echo $cmtjson | jq -r -e '.author.login')"
else
prjson="$(curl -n https://api.github.com/repos/KhronosGroup/KTX-Software/pulls/$pr 2>/dev/null)"
author="$(echo $prjson | jq -r -e '.user.login')"
fi
summary+=" (@$author)"
# \_ avoids confusion with _ for italics.
echo "$summary" | sed -e 's/_/\\_/g'
if [ -n "$includeDetails" ]; then
body="$(git log --pretty="%b" -n 1 $hash | sed -E 's/^(.+)/ \1/')"
if [ -n "$body" ]; then
echo ""
# Remove CR which some multi-line commit bodies contain for unknown reasons.
echo "$body" | tr -d \\r | sed -e 's/_/\\_/g'
fi
fi
}
function revisions_in () {
local range=$1; shift
git rev-list $range $*
}
function log() {
local part=$1; shift
local log
for rev in $(revisions_in "$range" $*); do
if [ -n "$interactive" ]; then
git log -1 $rev > /dev/tty
processed=0
while [ $processed -eq 0 ]; do
echo "Include this change? [d,i,s,?] ?" > /dev/tty
read -n 1 opt
echo "" > /dev/tty
case $opt in
d)
git show --pretty=oneline $rev > /dev/tty
;;
[is])
processed=1
;;
?)
echo "d - show diff of this commit" > /dev/tty
echo "i - include this commit." > /dev/tty
echo "s - skip this commit." > /dev/tty
echo "? - display this help message." > /dev/tty
;;
*)
echo "Unknown option: $opt. Try again." > /dev/tty
;;
esac
done
case $opt in
i)
log+="$(commit_summary $rev)"
;;
esac
else
log+="$(commit_summary $rev)"
fi
# For reasons I do not understand I have been completely unable to prevent
# trailing newlines from being removed from the output of commit_summary
# so resorting to ANSI-C quoting to insert some new lines between summaries.
log+=$'\n\n'
done
if [ -n "$log" ]; then
echo "### $part"
echo
echo "$log"
echo
fi
}
function usage() {
cat << EOU
Usage: $0 [-b] [-c] [-d] [-i] [-p <preface>] [-t] <previous release tag> <release name>"
Options:
-b Include build system changes
-c Make cumulative release notes
-d Include details of changes. If absent only the summary is shown.
-i Interactively select the changes to include.
-p <preface>
Include the file <preface> before the list of changes.
-t Include test changes.
EOU
}
while true; do
case $1 in
-b) includeBuildSystem="true"; shift ;;
-c) cumulative="true"; shift;;
-d) includeDetails="true"; shift ;;
-i) interactive="true"; shift;;
-p) preface=$2; shift 2 ;;
-t) includeTests="true"; shift ;;
-*) usage; exit 1 ;;
*) break ;;
esac
done
if [ $# -ne 2 ]; then
echo "$0: Need previous release tag and this release name, e.g. 'v4.0.0 v4.0.1'."
exit 1
else
range=$1..
lastrel=$1
thisrel=$2
fi
#if [ $# -ne 1 ]; then
# echo '$0: Need a two-dot revision range, e.g, `v4.0.0..v4.0.1`.'
# exit 1
#else
# range=$1
# if ! [[ $range =~ ([[:alnum:][:punct:]]+)\.\.([[:alnum:]][[:alnum:][:punct:]]*)? ]]; then
# echo "$0: <revision range> is not a two-dot range."
# exit 1
# else
# lastrel=${BASH_REMATCH[1]}
# thisrel=${BASH_REMATCH[2]}
# if [ -z "$lastrel" ]; then
# lastrel=HEAD
# fi
# fi
#fi
SAVED_RELNOTES_FILE="${RELNOTES_FILE%.md}-$lastrel.md"
# Save or remove old relnotes.
if [ -f $RELNOTES_FILE ]; then
if [ -z "$cumulative" ]; then
rm $RELNOTES_FILE;
else
mv $RELNOTES_FILE $SAVED_RELNOTES_FILE
fi
fi
# Read preface file before cd.
if [ -n "$preface" ]; then
PREFACE=$(cat $preface)
fi
# Change to the directory where the script is.
cd $(dirname $0)
# Change to project root.
pushd $depth > /dev/null
lib=$(log libktx lib)
tools=$(log Tools tools)
if [ -n "$includeTests" ]; then
tests=$(log "Tests" tests)
fi
js_binding=$(log "JS Wrappers" interface/js_binding)
if [ -n "$includeBuildSystem" ]; then
cmake=$(log "Build System" $(find . \( -path ./build -o -path ./.git -o -path ./other_include \) -prune -false -o -name CMakeLists.txt -o -name '*.cmake'))
fi
cat > $RELNOTES_FILE <<- EOF
$(date '+<!-- Copyright %Y, The Khronos Group Inc. -->')
<!-- SPDX-License-Identifier: Apache-2.0 -->
Release Notes
=============
## Version ${thisrel#v}
$PREFACE
### Changes since $lastrel (by part)
$lib
$tools
$tests
$js_binding
$cmake
EOF
popd > /dev/null
if [ -f $SAVED_RELNOTES_FILE ]; then
awk '! /Release Notes/ && ! /======/ && ! /<!-- Copyright/ && ! /<!-- SPDX/ {print}' $SAVED_RELNOTES_FILE >> $RELNOTES_FILE
rm $SAVED_RELNOTES_FILE
fi