-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrelease.sh
More file actions
385 lines (324 loc) · 10.6 KB
/
release.sh
File metadata and controls
385 lines (324 loc) · 10.6 KB
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
#!/bin/bash
NOW="$(date +'%B %d, %Y')"
# ANSI/VT100 colours
YELLOW='\033[1;33m'
LIGHTYELLOW='\033[0;33m'
RED='\033[0;31m'
LIGHTRED='\033[1;31m'
GREEN='\033[0;32m'
LIGHTGREEN='\033[1;32m'
BLUE='\033[0;34m'
LIGHTBLUE='\033[1;34m'
PURPLE='\033[0;35m'
LIGHTPURPLE='\033[1;35m'
CYAN='\033[0;36m'
LIGHTCYAN='\033[1;36m'
WHITE='\033[1;37m'
LIGHTGRAY='\033[0;37m'
DARKGRAY='\033[1;30m'
BOLD="\033[1m"
INVERT="\033[7m"
RESET='\033[0m'
# Default options
FLAG_JSON="false"
FLAG_PUSH="false"
I_OK="✅"
I_STOP="🚫"
I_ERROR="❌"
I_END="👋🏻"
S_NORM="${WHITE}"
S_LIGHT="${LIGHTGRAY}"
S_NOTICE="${GREEN}"
S_QUESTION="${YELLOW}"
S_WARN="${LIGHTRED}"
S_ERROR="${RED}"
V_SUGGEST="0.1.2-rc5" # This is suggested in case VERSION file or user supplied version via -v is missing
V_MAJOR="" # 0
V_MINOR="" # 1
V_PATCH="" # 2
V_BUILD_TYPE="" # rc
V_BUILD_COUNTER="" # 5
V_NAME=""
V_CODE=""
SCRIPT_VER="1.0"
GIT_MSG="Release: "
REL_NOTE=""
REL_PREFIX="release/"
PUSH_DEST="origin"
# Show credits & help
usage() {
echo -e "$GREEN" \
"\n █▄▄ █░█ █▀▄▀█ █▀█ ▄▄ █░█ █▀▀ █▀█ █▀ █ █▀█ █▄░█ " \
"\n █▄█ █▄█ █░▀░█ █▀▀ ░░ ▀▄▀ ██▄ █▀▄ ▄█ █ █▄█ █░▀█ " \
"\n\t\t\t\t\t$LIGHTGRAY v${SCRIPT_VER}"
echo -e " ${S_NORM}${BOLD}Usage:${RESET}" \
"\n $0 [-v <version number>] [-m <release message>] [-n] [-p] [-h]" 1>&2
echo -e "\n ${S_NORM}${BOLD}Options:${RESET}"
echo -e " $S_WARN-v$S_NORM <version number>\tSpecify a manual version number"
echo -e " $S_WARN-m$S_NORM <release message>\tCustom release message."
echo -e " $S_WARN-p$S_NORM \t\t\tPush commits to ORIGIN. "
echo -e " $S_WARN-n$S_NORM \t\t\tDon't perform a commit automatically. " \
"\n\t\t\t* You may want to do that manually after checking everything, for example."
echo -e " $S_WARN-b$S_NORM \t\t\tDon't create automatic \`release-<version>\` branch"
echo -e " $S_WARN-h$S_NORM \t\t\tShow this help message. "
echo -e "\n ${S_NORM}${BOLD}Original author: $S_LIGHT https://github.com/jv-t/bump-version $RESET"
echo -e "\n ${S_NORM}${BOLD}Changes by: $S_LIGHT https://github.com/d4rken $RESET\n"
}
# If there are no commits in repo, quit, because you can't tag with zero commits.
check-commits-exist() {
git rev-parse HEAD &>/dev/null
if [ ! "$?" -eq 0 ]; then
echo -e "\n${I_STOP} ${S_ERROR}Your current branch doesn't have any commits yet. Can't tag without at least one commit." >&2
echo
exit 1
fi
}
exit_abnormal() {
echo -e " ${S_LIGHT}––––––"
usage # Show help
exit 1
}
# Process script options
process-arguments() {
local OPTIONS OPTIND OPTARG
# Get positional parameters
JSON_FILES=()
while getopts ":v:p:m:hbn" OPTIONS; do # Note: Adding the first : before the flags takes control of flags and prevents default error msgs.
case "$OPTIONS" in
h)
# Show help
exit_abnormal
;;
v)
# User has supplied a version number
V_USR_SUPPLIED=$OPTARG
;;
m)
REL_NOTE=$OPTARG
# Custom release note
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Release note:" ${S_NORM}"'"$REL_NOTE"'"
;;
p)
FLAG_PUSH=true
PUSH_DEST=${OPTARG} # Replace default with user input
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Pushing to <${S_NORM}${PUSH_DEST}${S_LIGHT}>, as the last action in this script."
;;
n)
FLAG_NOCOMMIT=true
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Disable commit after tagging."
;;
b)
FLAG_NOBRANCH=true
echo -e "\n${S_LIGHT}Option set: ${S_NOTICE}Disable committing to new branch."
;;
\?)
echo -e "\n${I_ERROR}${S_ERROR} Invalid option: ${S_WARN}-$OPTARG" >&2
echo
exit_abnormal
;;
:)
echo -e "\n${I_ERROR}${S_ERROR} Option ${S_WARN}-$OPTARG ${S_ERROR}requires an argument." >&2
echo
exit_abnormal
;;
esac
done
}
# Suggests version from VERSION file, or grabs from user supplied -v <version>.
# If none is set, suggest default from options.
process-version() {
V_RAW=""
V_FILE_REGEX='^([0-9]+\.[0-9]+\.[0-9]+-[a-zA-Z]+[0-9]+) ([0-9]+)$'
V_FILE_RAW="$(cat VERSION)"
if [ -f VERSION ] && [ -s VERSION ] && [[ $V_FILE_RAW =~ $V_FILE_REGEX ]]; then
V_PREV="${BASH_REMATCH[1]}"
V_SUGGEST=$V_PREV
echo -e "\n${S_NOTICE}Current version from <${S_NORM}VERSION${S_NOTICE}> file: ${S_NORM}$V_PREV"
else
echo -ne "\n${S_WARN}The [${S_NORM}VERSION${S_WARN}] "
if [ ! -f VERSION ]; then
echo "VERSION file was not found."
elif [ ! -s VERSION ]; then
echo "VERSION file is empty."
else
echo "could not be parsed."
fi
fi
# If a version number is supplied by the user with [-v <version number>], then use it
if [ -n "$V_USR_SUPPLIED" ]; then
echo -e "\n${S_NOTICE}You selected version using [-v]:" "${S_WARN}${V_USR_SUPPLIED}"
V_RAW="${V_USR_SUPPLIED}"
else
echo -ne "\n${S_QUESTION}Enter a new version number [${S_NORM}$V_SUGGEST${S_QUESTION}]: "
echo -ne "$S_WARN"
read -r V_RAW
fi
if [ -z "$V_RAW" ]; then
V_RAW=$V_PREV
fi
if [ -z "$V_RAW" ]; then
echo -e "\n${I_STOP} ${S_ERROR}Error: No version was supplied (no file, no CLI)\n"
exit_abnormal
fi
SEMVER_REGEX='^([0-9]+)\.([0-9]+)\.([0-9]+)-([a-zA-Z]+)([0-9]+)$'
echo -e "\n${S_NOTICE}Parsing ${V_RAW}"
if [[ $V_RAW =~ $SEMVER_REGEX ]]; then
echo -e "\n${I_OK} ${S_NOTICE} Successfully parsed ${V_RAW} to ${BASH_REMATCH[0]}"
V_MAJOR="${BASH_REMATCH[1]}"
echo "V_MAJOR=$V_MAJOR"
V_MINOR="${BASH_REMATCH[2]}"
echo "V_MINOR=$V_MINOR"
V_PATCH="${BASH_REMATCH[3]}"
echo "V_PATCH=$V_PATCH"
V_BUILD_TYPE="${BASH_REMATCH[4]}"
echo "V_BUILD_TYPE=$V_BUILD_TYPE"
V_BUILD_COUNTER="${BASH_REMATCH[5]}"
echo "V_BUILD_COUNTER=$V_BUILD_COUNTER"
else
echo -e "\n${I_STOP} ${S_ERROR}Error: Failed to parse $V_RAW\n"
exit_abnormal
fi
if [ -z "$V_USR_SUPPLIED" ]; then
if [ "$V_BUILD_COUNTER" -eq "$V_BUILD_COUNTER" ] 2>/dev/null; then # discard stderr (2) output to black hole (suppress it)
V_BUILD_COUNTER=$((V_BUILD_COUNTER + 1)) # Increment
fi
fi
V_NAME="$V_MAJOR.$V_MINOR.$V_PATCH-$V_BUILD_TYPE$V_BUILD_COUNTER"
V_CODE=$((V_MAJOR * 10000000 + V_MINOR * 100000 + V_PATCH * 1000 + V_BUILD_COUNTER * 10))
echo -e "${S_NOTICE}Setting version to [${S_NORM}${V_NAME} (${V_CODE})${S_NOTICE}] ...."
}
# Only tag if tag doesn't already exist
check-tag-exists() {
TAG_CHECK_EXISTS=$(git tag -l v"$V_NAME")
if [ -n "$TAG_CHECK_EXISTS" ]; then
echo -e "\n${I_STOP} ${S_ERROR}Error: A release with that tag version number already exists!\n"
exit 0
fi
}
{
create-tag() {
if [ -z "$2" ]; then
# Default release note
git tag -a "v$1" -m "Tag version $1."
else
# Custom release note
git tag -a "v$1" -m "$2"
fi
echo -e "\n${I_OK} ${S_NOTICE}Added GIT tag"
}
PROPS_FILE_NAME="version.properties"
echo -e "\n${S_NOTICE}Parsing ${PROPS_FILE_NAME}:\n"
V_MAJOR_REGEX='^([a-zA-Z\.]+major)=([0-9]+)$'
V_MINOR_REGEX='^([a-zA-Z\.]+minor)=([0-9]+)$'
V_PATCH_REGEX='^([a-zA-Z\.]+patch)=([0-9]+)$'
V_BUILD_REGEX='^([a-zA-Z\.]+build)=([0-9]+)$'
PROPS_FILE_NEW=""
LAST_LINE=$(wc -l <$PROPS_FILE_NAME)
CURRENT_LINE=0
while read -r line; do
CURRENT_LINE=$((CURRENT_LINE + 1))
if [[ $line =~ $V_MAJOR_REGEX ]]; then
updated="${BASH_REMATCH[1]}=${V_MAJOR}"
echo "Found major, replacing: $line -> $updated"
PROPS_FILE_NEW+=$updated
elif [[ $line =~ $V_MINOR_REGEX ]]; then
updated="${BASH_REMATCH[1]}=${V_MINOR}"
echo "Found minor, replacing: $line -> $updated"
PROPS_FILE_NEW+=$updated
elif [[ $line =~ $V_PATCH_REGEX ]]; then
updated="${BASH_REMATCH[1]}=${V_PATCH}"
echo "Found patch, replacing: $line -> $updated"
PROPS_FILE_NEW+=$updated
elif [[ $line =~ $V_BUILD_REGEX ]]; then
updated="${BASH_REMATCH[1]}=${V_BUILD_COUNTER}"
echo "Found build, replacing: $line -> $updated"
PROPS_FILE_NEW+=$updated
else
PROPS_FILE_NEW+="$line"
fi
if [[ $CURRENT_LINE -ne $LAST_LINE ]]; then
PROPS_FILE_NEW+="\n"
fi
done <"$PROPS_FILE_NAME"
echo -e "$PROPS_FILE_NEW" >"$PROPS_FILE_NAME"
git add "$PROPS_FILE_NAME"
echo -e "\n${I_OK} ${S_NOTICE}Updated [${S_NORM}${PROPS_FILE_NAME}${S_NOTICE}] file"
}
{
[ -f VERSION ] && ACTION_MSG="Updated" || ACTION_MSG="Created"
echo "${V_NAME} ${V_CODE}" >VERSION # Create file
echo -e "\n${I_OK} ${S_NOTICE}${ACTION_MSG} [${S_NORM}VERSION${S_NOTICE}] file"
# Stage file for commit
git add VERSION
}
{
[ "$FLAG_NOBRANCH" = true ] && return
BRANCH_MSG=$(git rev-parse --verify "${REL_PREFIX}${V_NAME}" 2>&1)
if [ "$?" -eq 0 ]; then
echo -e "\n${I_STOP} ${S_ERROR}Error: Branch <${S_NORM}${REL_PREFIX}${V_NAME}${S_ERROR}> already exists!\n"
exit 1
fi
}
{
[ "$FLAG_NOBRANCH" = true ] && return
echo -e "\n${S_NOTICE}Creating new release branch..."
BRANCH_MSG=$(git branch "${REL_PREFIX}${V_NAME}" 2>&1)
if [ ! "$?" -eq 0 ]; then
echo -e "\n${I_STOP} ${S_ERROR}Error\n$BRANCH_MSG\n"
exit 1
else
BRANCH_MSG=$(git checkout "${REL_PREFIX}${V_NAME}" 2>&1)
echo -e "\n${I_OK} ${S_NOTICE}${BRANCH_MSG}"
fi
}
{
[ "$FLAG_NOCOMMIT" = true ] && return
echo -e "\n${S_NOTICE}Committing..."
COMMIT_MSG=$(git commit -m "${GIT_MSG}" 2>&1)
if [ ! "$?" -eq 0 ]; then
echo -e "\n${I_STOP} ${S_ERROR}Error\n$COMMIT_MSG\n"
exit 1
else
echo -e "\n${I_OK} ${S_NOTICE}$COMMIT_MSG"
fi
}
{
[ "$FLAG_NOCOMMIT" = true ] && return
if [ "$FLAG_PUSH" = true ]; then
CONFIRM="Y"
else
echo -ne "\n${S_QUESTION}Push tags to <${S_NORM}${PUSH_DEST}${S_QUESTION}>? [${S_NORM}N/y${S_QUESTION}]: "
read CONFIRM
fi
case "$CONFIRM" in
[yY][eE][sS] | [yY])
echo -e "\n${S_NOTICE}Pushing files + tags to <${S_NORM}${PUSH_DEST}${S_NOTICE}>..."
PUSH_MSG=$(git push "${PUSH_DEST}" v"$V_NAME" 2>&1) # Push new tag
PUSH_MSG+="\n"
PUSH_MSG+=$(git push 2>&1) # Push new tag
if [ ! "$?" -eq 0 ]; then
echo -e "\n${I_STOP} ${S_WARN}Warning\n$PUSH_MSG"
# exit 1
else
echo -e "\n${I_OK} ${S_NOTICE}$PUSH_MSG"
fi
;;
esac
}
#### Initiate Script ###########################
check-commits-exist
process-arguments "$@"
process-version
GIT_MSG+="${V_NAME}"
check-branch-exist
check-tag-exists
echo -e "\n${S_LIGHT}––––––"
do-version-properties
do-versionfile
do-branch
do-commit
create-tag "${V_NAME}" "${REL_NOTE}"
do-push
echo -e "\n${S_LIGHT}––––––"
echo -e "\n${I_OK} ${S_NOTICE}"Bumped $([ -n "${V_PREV}" ] && echo "${V_PREV} –>" || echo "to ") "$V_NAME"
echo -e "\n${GREEN}Done ${I_END}\n"