Files

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"