forked from plotly/dash-sample-apps
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deploy
executable file
·217 lines (181 loc) · 6.85 KB
/
deploy
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
#!/usr/bin/env bash
[[ -n "$TRACE" ]] && set -x
set -eo pipefail
readonly SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
readonly APPS_DIR_RELATIVE="${APPS_DIR_RELATIVE:-/apps}"
readonly APPS_DIR="${APPS_DIR:-${SOURCE_DIR}${APPS_DIR_RELATIVE}}"
readonly DASH_ENTERPRISE_URL="${DASH_ENTERPRISE_URL:-https://dash-playground.plotly.host}"
readonly CREATE_APP="${CREATE_APP:-false}"
readonly ALLOW_DASHR="${ALLOW_DASHR:-false}"
log-header() {
declare desc="Log header formatter";
echo "====> $*"
}
log-info() {
declare desc="Log info formatter";
echo " $*"
}
log-warn() {
declare desc="Log warn formatter";
echo " ? $*" 1>&2
}
log-fail() {
declare desc="Log fail formatter";
echo " ! $*" 1>&2
exit 1
}
log-exit() {
declare desc="Log exit formatter";
echo " ! $*" 1>&2
exit 0
}
fn-check-env() {
declare APP="$1"
if grep -Fxq "$APP" "$SOURCE_DIR/.deployignore"; then
log-exit "App $APP is in the .deployignore file, skipping deploy"
fi
if ! command -v "dds-client" >/dev/null; then
log-fail "dds-client binary not found"
fi
if [[ -z "$DASH_ENTERPRISE_API_KEY" ]]; then
log-fail "DASH_ENTERPRISE_API_KEY is not defined"
fi
if [[ -z "$DASH_ENTERPRISE_USERNAME" ]]; then
log-fail "DASH_ENTERPRISE_USERNAME is not defined"
fi
if [[ -z "$DASH_ENTERPRISE_URL" ]]; then
log-fail "DASH_ENTERPRISE_URL is not defined"
fi
if [[ -z "$CIRCLE_SHA1" ]]; then
log-fail "CIRCLE_SHA1 is not defined"
fi
}
main() {
declare APP="$1"
local app_dir="$APPS_DIR/$APP"
local remote_url="$DASH_ENTERPRISE_URL/GIT/$APP"
local is_dashr=false
local tmp_shallow_clone="$(mktemp -d -t apps-XXXXXXXXXX)"
local tmp_full_clone="$(mktemp -d -t apps-XXXXXXXXXX)"
local app_created=false
local force_push=true
local push_code=false
local exit_code remote_sha
trap "rm -rf '$tmp_shallow_clone' '$tmp_full_clone' >/dev/null" RETURN INT TERM EXIT
fn-check-env "$APP"
if [[ -z "$APP" ]]; then
log-fail "No app name specified"
fi
if [[ ! -d "$app_dir" ]]; then
log-fail "Invalid app name: $APP"
fi
if [[ "$APP" =~ "dashr" ]]; then
is_dashr=true
if [[ "$ALLOW_DASHR" != "true" ]]; then
log-exit "App $APP is a dashr app, skipping deploy"
fi
fi
if [[ ! -d "$app_dir/assets" ]]; then
log-warn "App $APP is missing the assets directory. Make sure to create one if you use asset files."
fi
log-header "Deploying $APP"
log-info "dashr: ${is_dashr}"
if [[ "$is_dashr" == "false" ]] && [[ "$CREATE_DBS" == "true" ]]; then
local celery_version="$(cat "$app_dir/requirements.txt" | grep -E "^celery=")"
local redis_version="$(cat "$app_dir/requirements.txt" | grep -E "^redis=")"
log-info "dash python version: $(cat "$app_dir/requirements.txt" | grep -E "^dash=")"
[[ -n "$celery_version" ]] && log-info "celery python version: $(cat "$app_dir/requirements.txt" | grep -E "^celery")"
[[ -n "$redis_version" ]] && log-info "redis python version: $(cat "$app_dir/requirements.txt" | grep -E "^redis")"
[[ -n "$sqlalchemy_version" ]] && log-info "sqlalchemy python version: $(cat "$app_dir/requirements.txt" | grep -E "^sqlalchemy")"
[[ -n "$flask_sqlalchemy_version" ]] && log-info "flask-sqlalchemy python version: $(cat "$app_dir/requirements.txt" | grep -E "^flask-sqlalchemy")"
if [[ -n "$sqlalchemy_version" ]] || [[ -n "$flask_sqlalchemy_version" ]]; then
if ! dds-client postgres:exists --name "$APP"; then
log-info "postgres not found, creating"
dds-client postgres:create --name "$APP"
dds-client postgres:link --name "$APP" --app "$APP"
fi
fi
if [[ -n "$celery_version" ]] || [[ -n "$redis_version" ]]; then
if ! dds-client redis:exists --name "$APP"; then
log-info "redis not found, creating"
dds-client redis:create --name "$APP"
dds-client redis:link --name "$APP" --app "$APP"
fi
fi
fi
if ! dds-client apps:exists --name "$APP" >/dev/null 2>&1; then
log-info "exists: false"
if [[ "$CREATE_APP" == "true" ]]; then
log-warn "$APP not found, creating"
dds-client apps:create --name "$APP"
app_created=true
else
log-exit "Deploy failed because there is no such app on Dash Gallery: $APP. Please use the web interface to create an app with this name"
fi
else
log-info "exists: true"
fi
# Disable sslverification
git config --global http.sslVerify false
if ! git clone --depth 1 "$remote_url" "$tmp_shallow_clone" 2>/dev/null && [[ "$app_created" != "true" ]]; then
log-fail "Unable to clone repository"
fi
remote_sha=$(git -C "$tmp_shallow_clone" log --pretty=format:"%h" 2>/dev/null || true)
log-info "remote-sha: $remote_sha"
if [[ -z "$remote_sha" ]]; then
log-header "Initializing repository"
git -C "$tmp_full_clone" init -q
git -C "$tmp_full_clone" remote rm origin 2>/dev/null || true
git -C "$tmp_full_clone" remote add origin "$remote_url"
elif git show "$remote_sha" >/dev/null 2>&1; then
log-header "Existing repository uses old monorepo, recreating"
git -C "$tmp_full_clone" init -q
git -C "$tmp_full_clone" remote rm origin 2>/dev/null || true
git -C "$tmp_full_clone" remote add origin "$remote_url"
force_push=true
else
if ! git clone "$remote_url" "$tmp_full_clone" 2>/dev/null; then
log-fail "Unable to clone repository"
fi
fi
log-header "Ensuring code is up to date"
log-info "Copying updated app source"
pushd "$tmp_full_clone" >/dev/null
find -not -path "./.git/*" -not -name ".git" -delete 2> /dev/null
popd >/dev/null
pushd "$app_dir" >/dev/null
cp -Rfp * "$tmp_full_clone"
[[ -f .buildpacks ]] && cp -fp .buildpacks "$tmp_full_clone/.buildpacks"
[[ -f .gitignore ]] && cp -fp .gitignore "$tmp_full_clone/.gitignore"
popd >/dev/null
if [[ "$is_dashr" == false ]]; then
log-info "Python app detected, injecting common python-specific files"
cp -p -n "$SOURCE_DIR/app.json" "$tmp_full_clone/app.json"
cp -p "$SOURCE_DIR/predeploy.py" "$tmp_full_clone/predeploy.py"
test -f "$tmp_full_clone/runtime.txt" || test -f "$SOURCE_DIR/runtime.txt" || cp -p "$SOURCE_DIR/runtime.txt" "$tmp_full_clone/runtime.txt"
fi
set +e
git -C "$tmp_full_clone" status | grep -Eo "working (directory|tree) clean" &> /dev/null
exit_code="$?"
set -e
if [[ "$exit_code" -ne 0 ]]; then
pushd "$tmp_full_clone" >/dev/null
push_code=true
git add .
git commit -qm "Deployed commit: $CIRCLE_SHA1"
popd >/dev/null
fi
if [[ "$push_code" != "true" ]]; then
log-header "🤜 App not updated, skipping deploy"
log-info "Check app out at $DASH_ENTERPRISE_URL/$APP/"
return 0
fi
if [[ "$force_push" == "true" ]]; then
log-header "Deploying via force push"
git -C "$tmp_full_clone" push --force origin master
else
log-header "Deploying"
git -C "$tmp_full_clone" push origin master
fi
}
main "$@"