File size: 7,968 Bytes
6b0231d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#! /usr/bin/env bash

# Copyright 2020, Mark Callow
# SPDX-License-Identifier: Apache-2.0

# Generate release notes from git log.
#
# mkrelnotes [-b] [-c] [-d] [-e] [-l] [-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 -e is specified changes to `external` packages will be included in the
# release notes.
#
# If -l is specified changes to the load test apps will be included in the
# release notes.
#
# 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 --netrc https://api.github.com/repos/KhronosGroup/KTX-Software/commits/$hash 2>/dev/null)"
    author="$(echo $cmtjson | jq -r -e '.author.login')"
  else
    prjson="$(curl --netrc 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.
         -e  Include changes to `external` packages.
         -i  Interactively select the changes to include.
         -l  Include changes to load test apps. Ignored if -t specified.
         -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 ;;
    -e) includeExternal="true"; shift ;;
    -i) interactive="true"; shift;;
    -l) includeLoadtests="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

# Change to the project root
cd $(dirname $0)/$depth

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

lib=$(log libktx lib)
tools=$(log Tools tools)
js_binding=$(log "JS Bindings" interface/js_binding)
java_binding=$(log "Java Bindings" interface/java_binding)
python_binding=$(log "Python Bindings" interface/python_binding)

if [ -n "$includeBuildSystem" ]; then
   build=$(log "Build Scripts and CMake files" scripts $(find . \( -path ./build -o -path ./.git -o -path ./external -o -path ./other_include \) -prune -false -o -name CMakeLists.txt -o -name '*.cmake'))
fi
if [ -n "$includeExternal" ]; then
   external=$(log "External Package Dependencies" external)
fi
if [ -n "$includeTests" ]; then
  tests=$(log "Tests" tests)
elif [ -n "$includeLoadtests" ]; then
  loadtests=$(log "Load test apps" tests/loadtests)
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

$js_binding

$java_binding

$python_binding

$external

$tests

$loadtests

$build
EOF

if [ -f $SAVED_RELNOTES_FILE ]; then
  awk '! /Release Notes/ && ! /======/ && ! /<!-- Copyright/ && ! /<!-- SPDX/ {print}' $SAVED_RELNOTES_FILE >> $RELNOTES_FILE
  rm $SAVED_RELNOTES_FILE
fi