Diff
1diff --git a/tools/changelog.sh b/tools/changelog.sh
2index ebdffba0a6b996408c52577f1bd03ee6bb0cd002..13cfb95304eb3f4568f48b42036dad8b2e53750c 100755
3--- a/tools/changelog.sh
4+++ b/tools/changelog.sh
5@@ -1,5 +1,8 @@
6 #!/usr/bin/env zsh
7
8+cd "$ZSH"
9+setopt extendedglob
10+
11 ##############################
12 # CHANGELOG SCRIPT CONSTANTS #
13 ##############################
14@@ -114,15 +117,8 @@ function parse-commit {
15 fi
16 }
17
18- # Ignore commit if it is a merge commit
19- if [[ $(command git show -s --format=%p $1 | wc -w) -gt 1 ]]; then
20- return
21- fi
22-
23 # Parse commit with hash $1
24- local hash="$1" subject body warning rhash
25- subject="$(command git show -s --format=%s $hash)"
26- body="$(command git show -s --format=%b $hash)"
27+ local hash="$1" subject="$2" body="$3" warning rhash
28
29 # Commits following Conventional Commits (https://www.conventionalcommits.org/)
30 # have the following format, where parts between [] are optional:
31@@ -384,7 +380,8 @@ function main {
32 # Commit classification arrays
33 local -A commits subjects scopes breaking reverts
34 local truncate=0 read_commits=0
35- local hash version tag
36+ local version tag
37+ local hash refs subject body
38
39 # Get the first version name:
40 # 1) try tag-like version, or
41@@ -396,17 +393,40 @@ function main {
42 || version=$(command git symbolic-ref --quiet --short $until 2>/dev/null) \
43 || version=$(command git rev-parse --short $until 2>/dev/null)
44
45- # Get commit list from $until commit until $since commit, or until root
46- # commit if $since is unset, in short hash form.
47- command git rev-list --abbrev-commit --abbrev=7 ${since:+$since..}$until | while read hash; do
48+ # Get commit list from $until commit until $since commit, or until root commit if $since is unset
49+ local range=${since:+$since..}$until
50+
51+ # Git log options
52+ # -z: commits are delimited by null bytes
53+ # --format: [7-char hash]<field sep>[ref names]<field sep>[subject]<field sep>[body]
54+ # --abbrev=7: force commit hashes to be 7 characters long
55+ # --no-merges: merge commits are omitted
56+ local SEP="0mZmAgIcSeP"
57+ local -a raw_commits
58+ raw_commits=(${(0)"$(command git log -z \
59+ --format="%h${SEP}%D${SEP}%s${SEP}%b" --abbrev=7 \
60+ --no-merges $range)"})
61+
62+ local raw_commit
63+ local -a raw_fields
64+ for raw_commit in $raw_commits; do
65 # Truncate list on versions with a lot of commits
66 if (( ++read_commits > 40 )); then
67 truncate=1
68 break
69 fi
70
71+ # Read the commit fields (@ is needed to keep empty values)
72+ raw_fields=("${(@ps:$SEP:)raw_commit}")
73+ hash="${raw_fields[1]}"
74+ refs="${raw_fields[2]}"
75+ subject="${raw_fields[3]}"
76+ body="${raw_fields[4]}"
77+
78 # If we find a new release (exact tag)
79- if tag=$(command git describe --exact-match --tags $hash 2>/dev/null); then
80+ if [[ "$refs" = *tag:\ * ]]; then
81+ # Parse tag name (needs: setopt extendedglob)
82+ tag="${${refs##*tag: }%%,# *}"
83 # Output previous release
84 display-release
85 # Reinitialize commit storage
86@@ -420,7 +440,7 @@ function main {
87 read_commits=1
88 fi
89
90- parse-commit "$hash"
91+ parse-commit "$hash" "$subject" "$body"
92 done
93
94 display-release
95@@ -431,8 +451,6 @@ function main {
96 fi
97 }
98
99-cd "$ZSH"
100-
101 # Use raw output if stdout is not a tty
102 if [[ ! -t 1 && -z "$3" ]]; then
103 main "$1" "$2" --raw