-
Notifications
You must be signed in to change notification settings - Fork 0
/
releaser.sh
executable file
·336 lines (286 loc) · 7.84 KB
/
releaser.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
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
#!/usr/bin/env bash
#
# GIT releaser version 1.0.x
# Author: Guewen FAIVRE ([email protected])
#
# Utility to self-creating a project release
# The resulting directory hold the repository content at the given branch/revision
#
# Version history :
# - 1.0 : Initial public release
#
# This software is released under the terms of the GNU GPL version 2 and above
# Please read the license at http://www.gnu.org/copyleft/gpl.html
#
#=====================================================================================
# Handle errors properly
set -o errexit
# Get pipelines exit codes (The exit status of the last command that threw a non-zero exit code is returned.)
set -o pipefail
# Force declaration of ALL variables
set -o nounset
# Debug (commented by default)
#set -o xtrace
######################
# Variables #
######################
# Magic variables
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
__base="$(basename ${__file} .sh)"
__parent="$(cd "$(dirname "${__dir}")" && pwd)"
# Variables
VERSION="1.0"
APP_NAME=${APP_NAME:-deploy}
STRATEGY="clone"
readonly APPS_DIRNAME="${__dir}/apps"
readonly REPOSITORIES_CACHE_DIR=${APPS_DIRNAME}/.cached-copy
readonly RELEASE_PATH_DIR=${APPS_DIRNAME}
# GIT variables
REPOSITORY=""
BRANCH="master"
REVISION="HEAD"
SHALLOW_CLONE=false
#####################
# Utilities. #
#####################
function is_file_exists(){
local fexists="$1"
[[ -f "${fexists}" ]] && return 0 || return 1
}
function cleanup(){
local target="$1"
local verbose=${2:-false}
local args=""
args="-rf"
# Wondering why "" ? See https://stackoverflow.com/a/2953673
if [ "$verbose" = true ]
then
args="${args}v"
fi
$(find ${target} ! -path ${target} -print0 | xargs -I {} -0 rm ${args} "{}")
}
function display()
{
local message="$1"
printf "[\033[36mInfo\033[0m] \033[32m${message}\033[0m\n"
}
function display_error(){
local error_message="${1}"
printf "[\033[31mError\033[0m] \033[32m${error_message}\033[0m\n"
}
# Dump script usage syntax and options
function releaser_Usage(){
printf "[\033[36mUsage\033[0m]: \033[32m$0 [params] repository\033\n"
printf "\033[32mParams can be one or more of the following :\032\n"
printf "\033[36m --version | -v\033[0m : Print out version number and exit\n"
printf "\033[36m --name | -n\033[0m : Specify the name of the release and checkout folders\n"
printf "\033[36m --branch | -b\033[0m : Check out corresponding branch\n"
printf "\033[36m --strategy | -s\033[0m : Change the way we create the local repository (clone or mirror, default is clone)\n"
printf "\033[36m --revision | -r\033[0m : Specify a revision to release\n"
printf "\033[36m --shallow | -sh\033[0m : Create a shallow clone with a history truncated to the specified number of commits.\n"
}
function setup(){
# Creating workdir env
mkdir -p ${APPS_DIRNAME}/${APP_NAME}
mkdir -p ${REPOSITORIES_CACHE_DIR}/${APP_NAME}
mkdir -p ${RELEASE_PATH_DIR}/${APP_NAME}
}
function is_valid_hash(){
local commit_hash="${1}"
if [[ "${commit_hash}" =~ ^[0-9a-f]{40}$ ]]
then
return 0
else
return 1
fi
}
# Getting the actual commit id, in case we were passed a tag
# or partial sha or something - it will return the sha if you pass a sha, too
function get_revision(){
local revision=""
if (is_valid_hash ${REVISION})
then
echo ${REVISION}
return 0
fi
# Ok we propably got a branch / tag name, let's find the hash
revision=$(git ls-remote --quiet ${REPOSITORY} ${BRANCH})
revision=$(echo ${revision}|cut -d " " -f 1)
if (is_valid_hash ${revision})
then
echo ${revision}
return 0
else
return 1
fi
}
function mark(){
(echo ${REVISION} > ${RELEASE_PATH_DIR}/${APP_NAME}/REVISION)
}
# Sync an existing repository with remote.
function sync_repo(){
local revision="$1"
local destination="$2"
cd ${destination}
git fetch origin && git fetch --tags origin && git reset --hard ${revision}
git clean -d -x -f
}
# Checkout a repository branch to a given revision
function checkout(){
local args=""
local remote=${remote:-origin}
# Add an option for the branch name so :git_shallow_clone works with branches
if [ "${REVISION}" == "${BRANCH}" ]
then
args="${args} -b ${BRANCH}"
fi
if [ "${remote}" != "origin" ]
then
args="${args} -o ${remote}"
fi
if [ "${SHALLOW_CLONE}" != false ]
then
args="${args} --depth ${SHALLOW_CLONE}"
fi
$(git clone ${args} --no-single-branch ${REPOSITORY} ${REPOSITORIES_CACHE_DIR}/${APP_NAME})
}
# Clones a repository or update it
function clone (){
# Switch from mirror strategy let's clean up ?
if ( is_file_exists "${REPOSITORIES_CACHE_DIR}/${APP_NAME}/HEAD" )
then
display "Cleaning up mirror repository ..."
cleanup "${REPOSITORIES_CACHE_DIR}/${APP_NAME}" true
fi
# We are checking if repository is empty before cloning.
if [ "$(ls -A ${REPOSITORIES_CACHE_DIR}/${APP_NAME})" ];
then
display "Repository already exists, updating ..."
sync_repo ${REVISION} ${REPOSITORIES_CACHE_DIR}/${APP_NAME}
else
display "Repository does not exists ... cloning"
checkout
fi
}
# Set up a mirror of the source repository
function mirror_clone(){
if [ "${SHALLOW_CLONE}" = false ]
then
git clone --mirror ${REPOSITORY} ${REPOSITORIES_CACHE_DIR}/${APP_NAME}
else
git clone --mirror --depth ${SHALLOW_CLONE} --no-single-branch ${REPOSITORY} ${REPOSITORIES_CACHE_DIR}/${APP_NAME}
fi
}
function update_mirror(){
cd ${REPOSITORIES_CACHE_DIR}/${APP_NAME}
# Update the origin URL if necessary.
git remote set-url origin ${REPOSITORY}
# Note: Requires git version 1.9 or greater
if [ "${SHALLOW_CLONE}" = false ]
then
git remote update --prune
else
git fetch --depth ${SHALLOW_CLONE} origin ${BRANCH}
fi
}
# Update or create a mirror repository (bare).
function mirror(){
if ( is_file_exists "${REPOSITORIES_CACHE_DIR}//${APP_NAME}/HEAD" )
then
display "Mirror already exists (Updating from branch: ${BRANCH})"
update_mirror ${BRANCH}
else
echo "Mirror does not exists ... cloning"
cleanup "${REPOSITORIES_CACHE_DIR}/${APP_NAME}"
mirror_clone
fi
}
# Building the release
function do_release(){
REVISION=$(get_revision)
if [ -z ${REVISION} ]
then
display_error "Unable to find or resolve revision on repository '${REPOSITORY}'."
exit 1
fi
display "Running with ${STRATEGY} strategy"
cleanup ${RELEASE_PATH_DIR}/${APP_NAME}
if [ "${STRATEGY}" == "mirror" ]
then
mirror
elif [ "${STRATEGY}" == "clone" ]
then
clone
else
display "Unknown strategy ${STRATEGY}"
exit 1
fi
display "Preparing archive from ${BRANCH}:${REVISION}"
cd ${REPOSITORIES_CACHE_DIR}/${APP_NAME} && \
$(git archive ${REVISION} | tar -x -f - -C ${RELEASE_PATH_DIR}/${APP_NAME})
# We add a file with the hash of the current build release
mark ${REVISION}
}
###################
# Options #
###################
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-v|--version)
display "Git releaser version ${VERSION}"
shift 2
;;
-h | --help)
releaser_Usage
shift 2
;;
-n | --name)
APP_NAME=${2}
shift 2
;;
-s | --strategy)
STRATEGY=${2}
shift 2
;;
-r | --revision)
REVISION=${2}
shift 2
;;
-sh | --shallow)
SHALLOW_CLONE=${2}
shift 2
;;
-b | --branch)
if [ "${2:-}" = "" ]
then
display_error "You need to specified a branch name."
exit 1
else
BRANCH=${2}
fi
shift 2
;;
-*)
display_error "Unrecognized parameter ${1}"
exit 1
;;
*)
break
;;
esac
done
if [ $# -lt 1 ]
then
releaser_Usage
exit 1
else
REPOSITORY="${1}"
fi
setup
if (do_release)
then
display "Release build successfully"
fi