110 lines
3.2 KiB
Bash
110 lines
3.2 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
|
|
|
root=/opt/autolibrary
|
|
service=autolibrary-webserver.service
|
|
current=$root/current
|
|
sha=${RELEASE_SHA:?Missing RELEASE_SHA}
|
|
port=${AUTOLIBRARY_PORT:-3003}
|
|
[[ $sha =~ ^[0-9a-f]{40}$ && $(git rev-parse HEAD) == "$sha" ]]
|
|
[[ $port =~ ^[1-9][0-9]{0,4}$ && $port -le 65535 ]]
|
|
base_url=http://127.0.0.1:$port
|
|
|
|
healthy() {
|
|
local path
|
|
for path in / /api/health; do
|
|
[[ $(curl --silent --show-error --noproxy '*' --max-time 2 \
|
|
--output /dev/null --write-out '%{http_code}' "$base_url$path") == 200 ]] || return 1
|
|
done
|
|
}
|
|
|
|
wait_for_service() {
|
|
local attempt
|
|
for ((attempt = 0; attempt < 20; attempt++)); do
|
|
if systemctl is-active --quiet "$service" && healthy; then
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# Serialize releases, including manual reruns of the workflow.
|
|
exec 9>"$root/releases/.deploy.lock"
|
|
flock -x 9
|
|
remote_head=$(git ls-remote --exit-code origin refs/heads/main)
|
|
if [[ ${remote_head%%$'\t'*} != "$sha" ]]; then
|
|
echo "Skipping $sha because main has moved."
|
|
exit 0
|
|
fi
|
|
|
|
previous=
|
|
if [[ -L $current ]]; then
|
|
previous=$(readlink "$current")
|
|
[[ -d $current ]] || { echo "Broken release link: $current" >&2; exit 1; }
|
|
elif [[ -e $current ]]; then
|
|
echo "Expected a release symlink at $current" >&2
|
|
exit 1
|
|
fi
|
|
|
|
test -f "$root/shared/config.json"
|
|
sudo -n -l /usr/bin/systemctl restart "$service" >/dev/null
|
|
sudo -n -l /usr/bin/systemctl stop "$service" >/dev/null
|
|
|
|
release=$(mktemp -d "$root/releases/$sha.XXXXXXXX")
|
|
switch_dir=
|
|
finished=false
|
|
|
|
switch_to() {
|
|
ln -s -- "$1" "$switch_dir/current" &&
|
|
mv -Tf -- "$switch_dir/current" "$current"
|
|
}
|
|
|
|
cleanup() {
|
|
local status=$?
|
|
trap - EXIT
|
|
trap '' INT TERM
|
|
set +e
|
|
if ! $finished && [[ $(readlink "$current") == "$release" ]]; then
|
|
echo "Deployment failed. Restoring the previous service state." >&2
|
|
if [[ -n $previous ]]; then
|
|
rm -f -- "$switch_dir/current"
|
|
if ! switch_to "$previous" || ! sudo -n /usr/bin/systemctl restart "$service" ||
|
|
! wait_for_service; then
|
|
echo "Rollback failed. Check journalctl -u $service." >&2
|
|
status=1
|
|
fi
|
|
elif ! sudo -n /usr/bin/systemctl stop "$service" || ! rm -f -- "$current"; then
|
|
echo "Could not clean up the first deployment. Check $service and $current." >&2
|
|
status=1
|
|
fi
|
|
fi
|
|
if ! $finished && [[ $(readlink "$current") != "$release" ]]; then
|
|
rm -rf -- "$release"
|
|
fi
|
|
if [[ -n $switch_dir ]]; then
|
|
rm -rf -- "$switch_dir"
|
|
fi
|
|
exit "$status"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
switch_dir=$(mktemp -d "$root/.switch.XXXXXXXX")
|
|
install -m 0755 .deploy/webserver "$release/webserver"
|
|
install -d -m 0755 "$release/frontend" "$release/backend"
|
|
cp -r frontend/dist "$release/frontend/dist"
|
|
cp -r backend/templates "$release/backend/templates"
|
|
test -s "$release/frontend/dist/index.html"
|
|
test -s "$release/backend/templates/404.html"
|
|
ln -s "$root/shared/logs" "$release/logs"
|
|
chmod -R a+rX "$release"
|
|
|
|
switch_to "$release"
|
|
sudo -n /usr/bin/systemctl restart "$service"
|
|
wait_for_service
|
|
finished=true
|
|
echo "Deployed $sha to $release"
|