-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathbuild_autoincrement_release.sh
executable file
·214 lines (189 loc) · 7.06 KB
/
build_autoincrement_release.sh
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
#!/usr/bin/env bash
# a global hash map holding commit hash to pr link (derived from ref names) pairs
declare -A hash2namesref=( ["k1"]="v1")
# populate global hash map hash2namesref with
# key value pairs as <commit hash> to <hueristically derived pr link>
# which are derived from git log --pretty=format:'%H %d' output
get_hash2pr_map() {
commit_hash_refnames_regex="^([a-f0-9]{40})[[:blank:]]*(.*)"
refnames_pr_id_regex="^\(.*/pr/([0-9]+).*\)"
GIT_LOG_LHASH2REFNAMES="$(mktemp /tmp/$(basename $0).h2refnames.XXXXXX)"
git log --pretty=format:'%H %d' ${COMMIT_RANGE} > ${GIT_LOG_LHASH2REFNAMES}
while read -r line || [ -n "$line" ]; do
line=$(echo "$line" | xargs)
if [[ $line =~ $commit_hash_refnames_regex ]];
then
hash=${BASH_REMATCH[1]}
nmref=${BASH_REMATCH[2]}
pr_link=""
# echo "MATCH: " "hash=" "$hash" "nmref=" "$nmref"
if [[ $nmref =~ $refnames_pr_id_regex ]];
then
pr_link="(#${BASH_REMATCH[1]})"
# echo "PR LINK:" "$pr_link"
fi
hash2namesref["$hash"]="$pr_link"
else
echo "Warning: malformed git log record skipped, expecting <commit hash> [<ref names>]"
echo "Record=" "$line"
fi
done < "${GIT_LOG_LHASH2REFNAMES}"
}
# return release history string with '\n' delimited
generate_release_history() {
commit_hash_subj_regex="^([a-f0-9]{40})[[:blank:]]+(.+)(\(\#[0-9]+\))?"
GIT_LOG_LHASH2SUBJ="$(mktemp /tmp/$(basename $0).h2subj.XXXXXX)"
git log --pretty=format:'%H %s' ${COMMIT_RANGE} > ${GIT_LOG_LHASH2SUBJ}
rel_hist=""
while read -r line || [ -n "$line" ]; do
line=$(echo "$line" | xargs)
if [[ $line =~ $commit_hash_subj_regex ]];
then
hash=${BASH_REMATCH[1]}
subj=${BASH_REMATCH[2]}
pr_link=${BASH_REMATCH[3]}
release_entry="- ${subj}"
if [ -z "${pr_link}" ];
then
pr_link="${hash2namesref[$hash]}"
release_entry="- ${subj} ${pr_link}"
fi
rel_hist="${rel_hist}\n${release_entry}"
else
echo "Warning: malformed git log record skipped, expecting <commit hash> <subject title> [<pr link>]"
echo "Record=" "$line"
fi
done < "${GIT_LOG_LHASH2SUBJ}"
echo "${rel_hist}"
}
# args:
# $1 - ${NEW_RELEASE_TAG}
# $2 - ${NEW_RELEASE_DATE}
# $3 - ${NEW_RELEASE_HISTORY}
write_release_note() {
GITHUB_RELEASE_PAYLOAD="$(mktemp /tmp/$(basename $0).releasePayload.XXXXXX)"
echo "{" > "${GITHUB_RELEASE_PAYLOAD}"
echo '"tag_name":' "\"$1\"," >> "${GITHUB_RELEASE_PAYLOAD}"
echo '"name":' "\"$1\"," >> "${GITHUB_RELEASE_PAYLOAD}"
echo '"body":' "\"$1 - $2\n================\n$3\"," >> "${GITHUB_RELEASE_PAYLOAD}"
echo '"draft": false,' >> "${GITHUB_RELEASE_PAYLOAD}"
echo '"prerelease": false' >> "${GITHUB_RELEASE_PAYLOAD}"
echo "}" >> "${GITHUB_RELEASE_PAYLOAD}"
}
# helper to show usage
usage() {
echo "Usage:"
echo "build_autoincrement_release.sh [<commit range>]"
echo ""
echo "Example 1: build a release since last release tag"
echo "build_autoincrement_release.sh"
echo ""
echo "Example 2: build a release between 2 commits or 2 tags - for testing usually"
echo "below command builds r93 with pull requests between r91 and r92:"
echo "build_autoincrement_release.sh 'r91..r92'"
}
set -eo pipefail
commit_range_regex="[a-z0-9]{1,40}\.\.[a-z0-9]{1,40}"
COMMIT_RANGE=""
# Parse command line option
if [ $# -eq 0 ];
then
echo "Build auto increment release..."
else
if [[ $1 =~ $commit_range_regex ]];
then
COMMIT_RANGE="$1"
else
usage
exit
fi
fi
# Detect if running from a fork
#
GITHUB_REPO="$(git ls-remote --get-url | grep -o '[^:/]\{1,\}/bluebutton-web-server')"
# Test running from root of repository
#
if [[ ! -f "LICENSE" ]]; then
echo "Please run script from the root of repository: ./ops/build_autoincrement_release.sh"
exit 1
fi
# Test running from master branch
#
if [[ "$(git branch --show-current)" != "master" ]]; then
echo "Please run script from the master branch of repository: git checkout master"
exit 1
fi
# Test GitHub access token
#
if [[ -z "${GITHUB_ACCESS_TOKEN}" ]]; then
echo "Please set your GitHub access token: export GITHUB_ACCESS_TOKEN=\"XXXSAMPLETOKENVALUEXXX\""
exit 1
fi
if [[ ! "$(curl -s -H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${GITHUB_ACCESS_TOKEN}" \
"https://api.github.com/user" | grep login)" ]]; then
echo "Please check your token, GitHub API did not detect an authenticated user!"
exit 1
fi
# Test GitHub and local tags are in sync
#
git pull --quiet --all --tags
LOCAL_TAGS="$(git tag | sort -u -V)"
REMOTE_TAGS="$(git ls-remote --quiet --tags | grep -o 'r[0-9]\{1,\}[-hotfix]*' | sort -u -V)"
if [[ "${LOCAL_TAGS}" != "${REMOTE_TAGS}" ]]; then
echo "Please reconcile your local repository tags, they do not match tags on the remote repository!"
exit 1
fi
# Determine if new release tag is needed
#
PREV_RELEASE_TAG="$(git describe --tags --abbrev=0)"
NEW_RELEASE_TAG="r$((${PREV_RELEASE_TAG:1} + 1))"
NEW_RELEASE_DATE="$(date +%Y-%m-%d)"
# if no commit range from command line then default to last release to HEAD
if [ -z "${COMMIT_RANGE}" ];
then
COMMIT_RANGE="${PREV_RELEASE_TAG}..HEAD"
fi
# NEW_RELEASE_HISTORY="$(git log --pretty=format:'- %s %d' ${PREV_RELEASE_TAG}..HEAD)"
# generate hash map of <commit hash> to <pr link>
get_hash2pr_map
NEW_RELEASE_HISTORY=$(generate_release_history)
if [[ -z "${NEW_RELEASE_HISTORY}" ]]; then
echo "No commits detected since previous release, no need for a new release, exiting."
rm "/tmp/$(basename $0)"*
exit 0
fi
# Create and push new release tag
#
echo "Pushing new tag"
git tag -a -s -m "Blue Button API release $NEW_RELEASE_TAG" "$NEW_RELEASE_TAG"
git push --tags
# Create GitHub release template
#
write_release_note "${NEW_RELEASE_TAG}" "${NEW_RELEASE_DATE}" "${NEW_RELEASE_HISTORY}"
# Create GitHub release via API request
#
GITHUB_RELEASE_STATUS="$(mktemp /tmp/$(basename $0).releaseStatus.XXXXXX)"
curl -s -X POST -H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${GITHUB_ACCESS_TOKEN}" \
"https://api.github.com/repos/${GITHUB_REPO}/releases" \
--data-binary "@${GITHUB_RELEASE_PAYLOAD}" > "${GITHUB_RELEASE_STATUS}"
# Verify GitHub release
if grep -q "\"tag_name\": \"${NEW_RELEASE_TAG}\"" "${GITHUB_RELEASE_STATUS}"
then
echo "Release created successfully: https://github.com/${GITHUB_REPO}/releases/tag/${NEW_RELEASE_TAG}"
rm "/tmp/$(basename $0)"*
exit 0
else
echo "Error during release creation, dumping debug output!"
echo "Release JSON payload:"
cat "${GITHUB_RELEASE_PAYLOAD}"
echo "Release API status:"
cat "${GITHUB_RELEASE_STATUS}"
echo "Rolling back pushed tag"
git push -d origin "$NEW_RELEASE_TAG"
echo "Deleting local tag"
git tag -d "$NEW_RELEASE_TAG"
rm "/tmp/$(basename $0)"*
exit 1
fi