#!/usr/bin/env bash # Meant to run via the HOST's system crontab on each environment's box (not # inside a container) — Gitea lives on a separate machine, so rather than # exposing an inbound webhook receiver on staging/production, each box just # polls its branch and redeploys when it moves. Silent when there's nothing # new, so it's safe to run every couple of minutes from cron. # # Example crontab line (staging box): # */2 * * * * /srv/bookstore/deploy/poll-deploy.sh staging >> /var/log/bookstore-deploy.log 2>&1 set -euo pipefail ENVIRONMENT="${1:?Usage: poll-deploy.sh }" REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO_ROOT" # A deploy (docker compose up --build + full WP/plugin install) can run # longer than the cron interval on modest hardware, and the git # checkout/reset below writes directly onto the live working tree that's # bind-mounted into the running containers — a second poll firing mid-deploy # would race the first one's file writes. Non-blocking: if one's already # running, this run just skips (the next poll picks up wherever HEAD ends up), # rather than queuing up concurrent deploys. LOCK_FILE="${REPO_ROOT}/.poll-deploy-${ENVIRONMENT}.lock" exec 200>"$LOCK_FILE" if ! flock -n 200; then echo "$(date -Is) deploy already in progress for ${ENVIRONMENT}, skipping this poll" exit 0 fi case "$ENVIRONMENT" in staging) BRANCH=staging ;; production) BRANCH=main ;; *) echo "environment must be 'staging' or 'production'" >&2; exit 1 ;; esac BEFORE="$(git rev-parse HEAD)" git fetch origin "$BRANCH" --quiet AFTER="$(git rev-parse "origin/${BRANCH}")" if [[ "$BEFORE" == "$AFTER" ]]; then exit 0 fi echo "$(date -Is) deploying ${ENVIRONMENT} (${BRANCH}): ${BEFORE:0:7} -> ${AFTER:0:7}" git checkout -f "$BRANCH" git reset --hard "origin/${BRANCH}" "$REPO_ROOT/deploy/deploy.sh" "$ENVIRONMENT"