Files
yawn/server/deploy-docker.sh
2026-08-22 07:09:49 +00:00

85 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
repository="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
expected_repository="$HOME/yawn"
state_directory="$HOME/.local/state/yawn"
deployed_revision_file="$state_directory/deployed-revision"
compose=(docker compose --project-name yawn --project-directory "$repository" --file "$repository/compose.yaml")
if [[ "$repository" != "$expected_repository" ]]; then
printf 'Expected the repository at %s, found %s\n' "$expected_repository" "$repository" >&2
exit 1
fi
for command in git docker flock; do
if ! command -v "$command" >/dev/null 2>&1; then
printf 'Missing required command: %s\n' "$command" >&2
exit 1
fi
done
if ! docker compose version >/dev/null 2>&1; then
printf 'Docker Compose v2 is required.\n' >&2
exit 1
fi
mkdir -p "$state_directory"
exec 9>"$state_directory/deploy.lock"
if ! flock -n 9; then
printf 'Another Yawn deployment is already running.\n'
exit 0
fi
cd "$repository"
if [[ "$(git branch --show-current)" != "main" ]]; then
printf 'Deployments must run from the main branch.\n' >&2
exit 1
fi
if [[ -n "$(git status --porcelain --untracked-files=normal)" ]]; then
printf 'Refusing to deploy a checkout with local changes.\n' >&2
exit 1
fi
printf 'Updating main...\n'
git fetch origin main
fetched="$(git rev-parse FETCH_HEAD)"
git merge --ff-only "$fetched"
if [[ "$(git rev-parse HEAD)" != "$fetched" ]]; then
printf 'HEAD does not match origin/main after updating.\n' >&2
exit 1
fi
printf 'Building the production image...\n'
"${compose[@]}" build --pull yawn
"${compose[@]}" up -d --remove-orphans yawn
container="$("${compose[@]}" ps -q yawn)"
if [[ -z "$container" ]]; then
printf 'Docker Compose did not create the Yawn container.\n' >&2
exit 1
fi
printf 'Waiting for Yawn to become healthy...\n'
for _ in {1..60}; do
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container")"
case "$status" in
healthy)
temporary_revision="$(mktemp "$state_directory/deployed-revision.XXXXXX")"
git rev-parse HEAD >"$temporary_revision"
mv -f -- "$temporary_revision" "$deployed_revision_file"
printf 'The Yawn container is healthy.\n'
exit 0
;;
unhealthy | exited | dead)
"${compose[@]}" logs --tail 50 yawn >&2
exit 1
;;
esac
sleep 2
done
printf 'Yawn did not become healthy before the timeout.\n' >&2
"${compose[@]}" logs --tail 50 yawn >&2
exit 1