-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathdeploy.sh
184 lines (131 loc) · 6.46 KB
/
deploy.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
artifacts_path=$1
base_directory=$2
php_executable=$3
# Replace the tilde with the path to the home directory.
if [[ "$base_directory" =~ ^~ ]]; then
base_directory="$HOME${base_directory:1}"
fi
releases_directory="$base_directory/releases"
current_directory_path="$base_directory/current"
lock_directory_path="$base_directory/deployment-currently-running"
# If this project was previously deployed with Deployer then the storage directory and .env file are
# in the "shared" directory.
if [[ -d "$base_directory/shared/storage" ]] && [[ -f "$base_directory/shared/.env" ]]; then
real_storage_directory_path="$base_directory/shared/storage"
real_env_file_path="$base_directory/shared/.env"
else
real_storage_directory_path="$base_directory/storage"
real_env_file_path="$base_directory/.env"
fi
is_first_deployment=$([[ -h "$current_directory_path" ]] && echo false || echo true)
has_created_lock_directory=false
release_directory_created=false
release_activated=false
use_datetime_release_directory_name=false
# By default we use an incrementing id for release directory names. Laravel Envoyer uses datetime names
# instead. If we detect that Envoyer was previously used to deploy this project then we will also use
# datetime names to keep things consistent.
if [[ -h "$current_directory_path" ]] && [[ "$(realpath "$current_directory_path")" =~ /20[0-9]{12}$ ]]; then
use_datetime_release_directory_name=true
fi
run_hook () {
hook_file_name=$1
hook_parameters=("${@:2}")
hook_entry_directory=$(pwd)
# Run the hook, and pass down every argument except the first one (the first one is the name of the hook).
tar -xf "$artifacts_path" "{SCRIPTS_DIR}/hooks/$hook_file_name" -O | bash -se -- "$php_executable" "${hook_parameters[@]}"
# Make sure the hook didn't change the directory.
cd "$hook_entry_directory" || exit 1
}
on_exit() {
script_status_code=$?
if [[ -f "$artifacts_path" ]]; then
echo "Deleting downloaded artifacts."
rm "$artifacts_path"
fi
if [[ "$release_directory_created" == true && "$release_activated" == false ]]; then
echo "Deleting new but unactivated release directory \"$new_release_directory\"."
rm -rf "$new_release_directory"
fi
if [[ "$release_activated" == true ]] && [[ "$script_status_code" -ne 0 ]]; then
echo "{STYLE_WARNING}The new release has been activated!{STYLE_RESET}"
fi
if [[ "$has_created_lock_directory" == true ]]; then
rmdir "$lock_directory_path"
fi
# Exit this trap with the original status code.
exit "$script_status_code"
}
# This "trap" command will call the "on_exit" function when we exit this script.
trap on_exit INT EXIT TERM
mkdir -p "$releases_directory"
# Here we check if the "$releases_directory" is set correctly. Later on in the script we delete old
# release directories. We don't want to risk deleting something important.
#
# Most deployment scripts including this one use numeric names for release directories. If any directories
# inside "$releases_directory" does not have a numeric name then we are probably in the wrong place.
for release_directory_path in "$releases_directory/"*/ ; do
if [[ -e "$release_directory_path" ]] && ! [[ $release_directory_path =~ /[0-9]+/$ ]] ; then
echo -e "{STYLE_ERROR}The name of existing release directory \"$release_directory_path\" is not fully numeric, this should never happen.{STYLE_RESET}"
exit 1
fi
done
if [[ -d "$lock_directory_path" ]]; then
echo -e "{STYLE_ERROR}The directory \"$lock_directory_path\" exists, this means another deployment is currently running.{STYLE_RESET}"
exit 1
fi
if [[ ! -x "$(command -v "$php_executable")" ]]; then
echo -e "{STYLE_ERROR}The PHP executable is set to \"$php_executable\", but that file either does not exist or is not executable.{STYLE_RESET}"
exit 1
elif [[ "$php_executable" != "php" ]]; then
echo "Using \"$php_executable\" to run PHP."
fi
# Create a lock file to ensure we can't run multiple deployments at the same time. (https://mywiki.wooledge.org/BashFAQ/045)
mkdir "$lock_directory_path"
has_created_lock_directory=true
if [[ "$use_datetime_release_directory_name" == true ]]; then
new_release_directory="$releases_directory/$(date +"%Y%m%d%H%M%S")"
else
current_release_id=$(ls "$releases_directory" | sort --numeric-sort | tail -n1) || 0;
new_release_directory="$releases_directory/$((current_release_id + 1))"
fi
echo "Creating directory \"$new_release_directory\" for the new release."
mkdir "$new_release_directory"
release_directory_created=true
echo "Creating a symlink to the storage directory."
if [[ ! -d "$real_storage_directory_path" ]]; then
mkdir -p "$real_storage_directory_path/"{app/public,framework/{cache/data,sessions,testing,views},logs};
fi
ln -nsfr "$real_storage_directory_path" "$new_release_directory/storage"
if [[ ! -s "$real_env_file_path" ]]; then
touch "$real_env_file_path"
echo -e "{STYLE_ERROR}Your \"$real_env_file_path\" file is empty. Run the deployment again after you've filled it in.{STYLE_RESET}"
exit 1
fi
echo "Creating a symlink to the .env file."
ln -nsfr "$real_env_file_path" "$new_release_directory/.env"
echo "Extracting deployment artifacts."
cd "$new_release_directory" || exit 1
tar --extract --file="$artifacts_path"
if ! [[ $("$php_executable" artisan tinker --help) =~ "--execute" ]]; then
echo -e "{STYLE_ERROR}Laravel Tinker is not installed or you are using an outdated version. Laravel Tinker version ^2.0 is required.{STYLE_RESET}"
exit 1
fi
run_hook "set-file-permissions.sh" "$new_release_directory"
run_hook "before-activation.sh" "$base_directory" "$artifacts_path"
if [[ -h "$current_directory_path" ]]; then
previous_release_directory_path=$(realpath "$current_directory_path")
fi
echo "Activating the new release."
# We symlink our new release to the "current" directory. This activates the new release.
ln -nsfr "$new_release_directory" "$current_directory_path"
release_activated=true
if [[ "$is_first_deployment" == false ]]; then
run_hook "flush-opcache.sh" "$current_directory_path" "$previous_release_directory_path"
fi
run_hook "after-activation.sh" "$base_directory" "$artifacts_path"
# Keep only the 3 newest release directories.
for old_release_directory in $(ls "$releases_directory" | sort --numeric-sort --reverse | tail -n+4) ; do
echo "Deleting old release directory \"$releases_directory/$old_release_directory\"."
rm -rf "${releases_directory:?}/$old_release_directory"
done