-
Notifications
You must be signed in to change notification settings - Fork 1
/
deploy.functions
294 lines (232 loc) · 9.06 KB
/
deploy.functions
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
# This file is part of shellfire heroku. It is subject to the licence terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/shellfire-dev/heroku/master/COPYRIGHT. No part of shellfire heroku, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
# Copyright © 2015 The developers of shellfire heroku. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/shellfire-dev/heroku/master/COPYRIGHT.
core_dependency_requires '*' git cut
core_usesIn git
heroku_deploy_findBuildPackUrl()
{
local submoduleName="$heroku_configurationFolderName"/"$heroku_buildpacksFolderName"/"$heroku_moduleName"
local backpackUrl="$(git config --file "$heroku_repositoryPath"/.gitmodules --get "submodule.${submoduleName}.url")"
local backpackRevision="$(git_inRepository "$heroku_repositoryPath" git submodule status "$submoduleName" | cut -c2-41)"
heroku_buildpackUrl="${backpackUrl}#${backpackRevision}"
}
core_usesIn heroku toolbelt
core_dependency_requires '*' heroku
heroku_deploy_createApp()
{
if ! core_path_isReadableAndSearchableAndWritableFolderPath "$heroku_repositoryPath"/.git; then
core_exitError $core_commandLine_exitCode_CANTCREAT "The .git folder in '$heroku_repositoryPath' is not writable; it needs to be when creating an app"
fi
heroku_toolbelt_inRepository true true create "$heroku_appName" --stack "$heroku_stack" --region "$heroku_region" --remote "$heroku_remote" --buildpack "$heroku_buildpackUrl"
}
core_usesIn git
heroku_deploy_createAppIfNecessary()
{
if git_hasRemote "$heroku_repositoryPath" "$heroku_remote"; then
heroku_deploy_changeBuildpackUrlIfDifferent
heroku_deploy_changeAppNameIfDifferent
heroku_deploy_changeStackIfDifferent
heroku_deploy_warnIfRegionIsDifferent
else
heroku_deploy_createApp
fi
}
core_usesIn heroku toolbelt
core_dependency_requires '*' tail head
heroku_deploy_changeBuildpackUrlIfDifferent()
{
heroku_toolbelt_inRepository true false buildpacks
local existingBuildpackUrl="$(tail -n +2 "$_heroku_toolbelt_standardOutputFilePath" | head -n 1)"
if [ "$existingBuildpackUrl" != "$heroku_buildpackUrl" ]; then
heroku_toolbelt_inRepository true true buildpacks:set "$heroku_buildpackUrl"
fi
}
core_usesIn heroku toolbelt
core_dependency_requires '*' head cut
heroku_deploy_changeAppNameIfDifferent()
{
heroku_toolbelt_inRepository true false info
local existingAppName="$(head -n 1 "$_heroku_toolbelt_standardOutputFilePath" | cut -c5-)"
if [ "$existingAppName" != "$heroku_appName" ]; then
heroku_toolbelt_inRepository true true apps:rename "$heroku_appName"
fi
}
core_usesIn heroku toolbelt
core_dependency_requires '*' awk
heroku_deploy_changeStackIfDifferent()
{
heroku_toolbelt_inRepository true false info
local existingStack="$(awk '$1 ~/^Stack:$/ {print $2}' "$_heroku_toolbelt_standardOutputFilePath")"
if [ "$existingStack" != "$heroku_stack" ]; then
heroku_toolbelt_inRepository true true stack:set "$heroku_stack"
fi
}
core_usesIn heroku toolbelt
core_dependency_requires '*' awk
heroku_deploy_warnIfRegionIsDifferent()
{
heroku_toolbelt_inRepository true false info
local existingRegion="$(awk '$1 ~/^Region:$/ {print $2}' "$_heroku_toolbelt_standardOutputFilePath")"
if [ "$existingRegion" != "$heroku_region" ]; then
core_message WARN "Can not change region to '$heroku_region'. The app is currently running on the '$existingRegion' region; changing it is manual. See https://devcenter.heroku.com/articles/app-migration"
fi
}
core_usesIn heroku toolbelt
heroku_deploy_maintenanceModeEnable()
{
heroku_toolbelt_inRepository true true maintenance:on
}
core_usesIn heroku toolbelt
heroku_deploy_maintenanceModeDisable()
{
heroku_toolbelt_inRepository true true maintenance:off
}
heroku_deploy_setPreboot()
{
local action
if core_variable_isTrue "$heroku_preboot"; then
action=enable
else
action=disable
fi
# Parsing the command line output of shellfire heroku features is just TOO painful, so we deliberately invoke errors
heroku_toolbelt_inRepository false false features:"$action" preboot 2>/dev/null
}
core_dependency_requires '*' sort comm
heroku_deploy_setDomains()
{
local TMP_FILE
core_temporaryFiles_newFileToRemoveOnExit
local existingDomainsFilePath="$TMP_FILE"
core_temporaryFiles_newFileToRemoveOnExit
local sortedUniqueExistingDomainsFilePath="$TMP_FILE"
core_temporaryFiles_newFileToRemoveOnExit
local newDomainsFilePath="$TMP_FILE"
core_temporaryFiles_newFileToRemoveOnExit
local sortedUniqueNewDomainsFilePath="$TMP_FILE"
core_temporaryFiles_newFileToRemoveOnExit
local domainsToDeleteFilePath="$TMP_FILE"
core_temporaryFiles_newFileToRemoveOnExit
local domainsToAddFilePath="$TMP_FILE"
# Logic based on format here (and experimentation): https://devcenter.heroku.com/articles/custom-domains#view-existing-domains
heroku_toolbelt_inRepository true false domains
{
local startProcessing=false
local checkFirstProcessingLineForHerokuCruftIfNoDomains=false
local line
while IFS= read -r line
do
if [ "$line" = "=== $heroku_appName Custom Domains" ]; then
startProcessing=true
ignoreLines=2
elif $startProcessing; then
if [ $ignoreLines -ne 0 ]; then
ignoreLines=$((ignoreLines - 1))
continue
fi
# lack of quotes deliberate
IFS=' ' set -- $line
local domainName="$1"
local dnsTarget="$2"
printf '%s\n' "$domainName"
fi
done <"$_heroku_toolbelt_standardOutputFilePath"
} >"$existingDomainsFilePath"
sort -u "$existingDomainsFilePath" >"$sortedUniqueExistingDomainsFilePath"
_heroku_deploy_setDomains_callback()
{
local domainName="$core_variable_array_element"
printf '%s\n' "$domainName"
}
configure_iterateOverArrayWithDefaultsIfEmpty heroku domains _heroku_deploy_setDomains_callback >"$newDomainsFilePath"
sort -u "$newDomainsFilePath" >"$sortedUniqueNewDomainsFilePath"
local domainName
comm -23 "$sortedUniqueExistingDomainsFilePath" "$sortedUniqueNewDomainsFilePath" >"$domainsToDeleteFilePath"
while IFS="$(printf '\t')" read -r domainName
do
heroku_toolbelt_inRepository true true domains:remove "$domainName"
done <"$domainsToDeleteFilePath"
comm -13 "$sortedUniqueExistingDomainsFilePath" "$sortedUniqueNewDomainsFilePath" >"$domainsToAddFilePath"
while IFS="$(printf '\t')" read -r domainName
do
heroku_toolbelt_inRepository true true domains:add "$domainName"
done <"$domainsToAddFilePath"
}
# This is a bit nasty: https://devcenter.heroku.com/articles/ssl-endpoint
heroku_deploy_setSsl()
{
# Really only needs to be done once
heroku_toolbelt_inRepository true true addons:create ssl:endpoint
# We ought to keep the .csr, too
# .crt needs to include the certificate chain; need not include the public key (that makes it .pem)
heroku_toolbelt_inRepository true true certs:add server.crt server.key
}
core_usesIn heroku toolbelt
core_dependency_requires '*' cat
heroku_deploy_setEnvironmentVariables()
{
# Not a perfect system, as there are other env variables that might not be in source control (for good reasons)
# Designed to support, say, the Ant buildpack: https://github.com/dennisg/heroku-buildpack-ant
# Strips any trailing line feeds, sadly
heroku_environmentVariablesConfigurationFolderPath="$heroku_configurationFolderPath"/"$heroku_environmentVariablesConfigurationFolderName"
if ! core_path_isReadableAndSearchableAndWritableFolderPath "$heroku_environmentVariablesConfigurationFolderPath"; then
return 0
fi
local environmentVariables
local environmentVariables_initialised
core_variable_array_initialise environmentVariables
pushd "$heroku_environmentVariablesConfigurationFolderPath"
local environmentVariableFile
set +f
for environmentVariableFile in *
do
set -f
if ! core_path_isReadableFilePath "$environmentVariableFile"; then
continue
fi
case "$environmentVariableFile" in
.*)
# Ignore .gitignore, etc files
continue
;;
esac
core_variable_array_append environmentVariables "$environmentVariableFile"="$(cat "$environmentVariableFile")"
# We can unset any key, it needn't exist, but getting a list of keys without a silly message is hard
done
set -f
popd
_heroku_deploy_setEnvironmentVariables_callback()
{
if [ $# -eq 0 ]; then
return 0
fi
heroku_toolbelt_inRepository true true config:set "$@"
}
core_variable_array_passToFunctionAsArguments environmentVariables _heroku_deploy_setEnvironmentVariables_callback
}
_heroku_deploy_push_git()
{
git_push "$heroku_repositoryPath" "$heroku_remote" "$heroku_refspec":master 2>&1
}
_heroku_deploy_push_messageLine()
{
local line
while IFS= read -r line
do
core_message NOTICE "push: $line"
done
if [ -n "$line" ]; then
core_message NOTICE "push: $line"
fi
}
core_usesIn core pipefail
core_usesIn git
heroku_deploy_push()
{
set +e
core_pipefail_execute _heroku_deploy_push_git \| _heroku_deploy_push_messageLine
local exitCode=$?
set -e
if [ $exitCode -ne 0 ]; then
core_exitError $core_commandLine_exitCode_PROTOCOL "Deployment failure"
fi
}