-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
ci.sh
192 lines (159 loc) · 6.06 KB
/
ci.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
#!/usr/bin/env bash
set -e
# set default compose file and a namespace for the compose project, can be overridden
COMPOSE_FILE_BASE=${COMPOSE_FILE:-"docker-compose.build.yml"}
COMPOSE_PROJECT_NAME_BASE=${COMPOSE_PROJECT_NAME:-"ci-$CI_PROJECT_ID-$CI_PIPELINE_ID"}
# parse command line options
POSITIONAL=()
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-c|--copy)
COPY="$2"
shift
shift
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done
set -- "${POSITIONAL[@]}"
# copy stuff from a container
function copy_from_container() {
if [ ! -z "$1" ]; then
CONTAINER_NAME=$(echo $1 | cut -d':' -f 1)
CONTAINER_PATH=$(echo $1 | cut -d':' -f 2)
CONTAINER_ID=$(docker-compose ps -q $CONTAINER_NAME)
docker cp $CONTAINER_ID:$CONTAINER_PATH .
fi
}
if [ $# -gt 0 ]; then
# ci init
# --------------------------------------------------------------------
# initializes the current job
# you can overwrite the default compose file by providing an argument.
if [ "$1" == "init" ]; then
shift
# set compose file based on the argument
if [ ! -z "$1" ]; then
COMPOSE_FILE_BASE="docker-compose.$1.yml"
shift
fi
# set the compose project name to allow concurrent jobs
echo "export COMPOSE_FILE=$COMPOSE_FILE_BASE"
echo "export COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME_BASE"
# set default image and tag names
if [ -z "$IMAGE" ]; then
echo "export IMAGE=$CI_REGISTRY/$CI_PROJECT_PATH"
fi
if [ -z "$TAG" ]; then
echo "export TAG=build-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHA"
fi
if [ ! -z "$REGISTRY_USER" ]; then
# if a user specifies a dedicated docker registry, log into it
docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY &>/dev/null
elif [ ! -z "$CI_BUILD_TOKEN" ]; then
# or fall back to gitlabs own registry
docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY &>/dev/null
fi
# ci run
# --------------------------------------------------------------------
# spins up containers and executes the code piped in from stdin.
# makes sure the containers will be shut down even something fails.
# to allow concurrency, pass a unique identifier as argument.
# to copy something from a running container use the copy option
elif [ "$1" == "run" ]; then
shift
# prefix the compose project name with the given argument
if [ ! -z "$1" ]; then
export COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME_BASE-$1
shift
fi
# start containers
docker-compose up -d --no-build --remove-orphans --quiet-pull
sleep 5
# run the code from stdin
# catch errors, stop containers and copy files from containers
{
bash -c "$(cat)"
} || {
copy_from_container "$COPY"
docker-compose down
exit 1
}
# stop containers and copy files from containers
copy_from_container "$COPY"
docker-compose down
# ci down
# --------------------------------------------------------------------
# stop containers, pass a unique identifier as argument to stop specific
# containers
elif [ "$1" == "down" ]; then
shift
if [ ! -z "$1" ]; then
export COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME_BASE-$1
shift
fi
docker-compose down
# ci ssh
# --------------------------------------------------------------------
# set ssh key stored in SSH_KEY and add SSH_FINGERPRINT to known_hosts
elif [ "$1" == "ssh" ]; then
shift
if [ -z "$SSH_KEY" ] || [ -z "$SSH_FINGERPRINT" ]; then
echo "ERROR! SSH_KEY or SSH_FINGERPRINT not set!"
exit 1
fi
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "$SSH_FINGERPRINT" > ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
echo "$SSH_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# ci secrets
# --------------------------------------------------------------------
# loop through the environment variables given by SECRET_ENV_VARS and save
# them to files, in order to used them with docker secrets
elif [ "$1" == "secrets" ]; then
# define secret env vars that will be hashed and saved to files in order
# to be used with docker secrets
SECRET_ENV_VARS=${SECRET_ENV_VARS:-"LARAVEL_ENV,MYSQL_ROOT_PASSWORD,MYSQL_DATABASE,MYSQL_USER,MYSQL_PASSWORD"}
IFS=',' ; for SECRET_ENV_VAR in `echo "$SECRET_ENV_VARS"`; do
# save to file
echo "${!SECRET_ENV_VAR}" > "$SECRET_ENV_VAR.txt"
# generate hash
SECRET_ENV_VAR_HASH=$(sha512sum "$SECRET_ENV_VAR.txt" | cut -c1-16)
# export hash of saved file as env variable
echo "export ${SECRET_ENV_VAR}_HASH=${SECRET_ENV_VAR_HASH}"
done
# ci wait-for
# --------------------------------------------------------------------
# wait until the given service is ready
elif [ "$1" == "wait-for" ]; then
shift
COUNTER=0
CONTAINER=$(docker-compose ps -q $1)
STATUS="starting"
while [ "$STATUS" != "healthy" ]; do
STATUS=$(docker inspect -f {{.State.Health.Status}} $CONTAINER)
STATE=$(docker inspect -f {{.State.Status}} $CONTAINER)
sleep 1
if [ "$STATE" == "exited" ]; then
docker start $CONTAINER
fi
((COUNTER=COUNTER+1))
if [ $COUNTER -gt 300 ]; then
echo "Timeout after waiting for 5 minutes…"
exit 1
fi
done
# ci git-user
# --------------------------------------------------------------------
# get the git user of the last commit
elif [ "$1" == "git-user" ]; then
shift
echo "$(git --no-pager show -s --format='%an' $(git log --format="%H" -n 1))"
fi
fi