caterium.ru and app.caterium.ru are separate Timeweb sites with separate document roots. The apex domain's root is reserved for an unrelated future site, so auto-detection must never be able to land there. Drop the generic $HOME/public_html and unverified app.caterium.ru/public_html guesses in favor of the confirmed real path ($HOME/caterium-app/public_html), and require CATERIUM_WEB_ROOT explicitly in the documented cron command. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
110 lines
3.0 KiB
Bash
110 lines
3.0 KiB
Bash
#!/bin/sh
|
|
set -eu
|
|
|
|
REPO_URL="${CATERIUM_REPO_URL:-git@github.com:pavlov346346-source/caterium-app.git}"
|
|
BRANCH="${CATERIUM_BRANCH:-production}"
|
|
STATE_DIR="${CATERIUM_STATE_DIR:-$HOME/.caterium-deploy}"
|
|
REPO_DIR="${CATERIUM_REPO_DIR:-$STATE_DIR/repo}"
|
|
BACKUP_DIR="${CATERIUM_BACKUP_DIR:-$STATE_DIR/backups}"
|
|
LOCK_DIR="$STATE_DIR/lock"
|
|
|
|
log() {
|
|
printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
}
|
|
|
|
fail() {
|
|
log "ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
find_web_root() {
|
|
if [ -n "${CATERIUM_WEB_ROOT:-}" ]; then
|
|
printf '%s\n' "$CATERIUM_WEB_ROOT"
|
|
return 0
|
|
fi
|
|
|
|
for candidate in \
|
|
"$HOME/caterium-app/public_html"
|
|
do
|
|
if [ -d "$candidate" ] && [ -f "$candidate/index.html" ]; then
|
|
printf '%s\n' "$candidate"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
command -v git >/dev/null 2>&1 || fail "git is not available"
|
|
command -v rsync >/dev/null 2>&1 || fail "rsync is not available"
|
|
command -v tar >/dev/null 2>&1 || fail "tar is not available"
|
|
|
|
mkdir -p "$STATE_DIR" "$BACKUP_DIR"
|
|
|
|
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
|
|
if [ -f "$LOCK_DIR/pid" ]; then
|
|
old_pid=$(cat "$LOCK_DIR/pid" 2>/dev/null || true)
|
|
if [ -n "$old_pid" ] && kill -0 "$old_pid" 2>/dev/null; then
|
|
log "Another deployment is running; skip"
|
|
exit 0
|
|
fi
|
|
fi
|
|
rm -rf "$LOCK_DIR"
|
|
mkdir "$LOCK_DIR" 2>/dev/null || {
|
|
log "Could not acquire deployment lock; skip"
|
|
exit 0
|
|
}
|
|
fi
|
|
printf '%s\n' "$$" > "$LOCK_DIR/pid"
|
|
cleanup_lock() {
|
|
rm -rf "$LOCK_DIR"
|
|
}
|
|
trap cleanup_lock 0 HUP INT TERM
|
|
|
|
WEB_ROOT=$(find_web_root) || fail "web root not found; set CATERIUM_WEB_ROOT"
|
|
[ -d "$WEB_ROOT" ] || fail "web root does not exist: $WEB_ROOT"
|
|
|
|
if [ ! -d "$REPO_DIR/.git" ]; then
|
|
log "Initial clone of $BRANCH"
|
|
rm -rf "$REPO_DIR"
|
|
git clone --quiet --single-branch --branch "$BRANCH" "$REPO_URL" "$REPO_DIR" \
|
|
|| fail "initial Git clone failed; verify GitHub SSH key access"
|
|
fi
|
|
|
|
cd "$REPO_DIR"
|
|
log "Fetching $BRANCH"
|
|
git fetch --quiet origin "$BRANCH" || fail "git fetch failed"
|
|
NEW_SHA=$(git rev-parse FETCH_HEAD)
|
|
OLD_SHA=$(cat "$WEB_ROOT/.caterium-release" 2>/dev/null || true)
|
|
|
|
if [ "$NEW_SHA" = "$OLD_SHA" ]; then
|
|
log "Already current: $NEW_SHA"
|
|
exit 0
|
|
fi
|
|
|
|
git reset --quiet --hard "$NEW_SHA" || fail "could not switch deploy checkout"
|
|
[ -s "$REPO_DIR/public/index.html" ] || fail "release validation failed: public/index.html is missing or empty"
|
|
|
|
STAMP=$(date '+%Y%m%d-%H%M%S')
|
|
BACKUP_FILE="$BACKUP_DIR/${STAMP}-${OLD_SHA:-pre-marker}.tgz"
|
|
log "Backing up current site"
|
|
tar -czf "$BACKUP_FILE" -C "$WEB_ROOT" . || fail "backup failed; live files left unchanged"
|
|
|
|
log "Deploying $NEW_SHA to $WEB_ROOT"
|
|
rsync -a --delete-delay \
|
|
--exclude '.well-known/' \
|
|
--exclude '.caterium-release' \
|
|
"$REPO_DIR/public/" "$WEB_ROOT/" \
|
|
|| fail "rsync failed"
|
|
|
|
printf '%s\n' "$NEW_SHA" > "$WEB_ROOT/.caterium-release"
|
|
|
|
# Keep only the four newest rollback archives.
|
|
set +e
|
|
ls -1t "$BACKUP_DIR"/*.tgz 2>/dev/null | awk 'NR > 4' | while IFS= read -r old_backup; do
|
|
rm -f "$old_backup"
|
|
done
|
|
set -e
|
|
|
|
log "Deployment complete: $NEW_SHA"
|