104 lines
2.7 KiB
Bash
Executable File
104 lines
2.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
# Pure production deploy:
|
|
# - Always uses remote branch as source of truth
|
|
# - Discards local changes on server
|
|
# - Non-interactive, fail-fast
|
|
|
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$PROJECT_ROOT"
|
|
|
|
BRANCH_INPUT="${1:-}"
|
|
REMOTE="${2:-origin}"
|
|
|
|
echo "==> [prod] Project: $PROJECT_ROOT"
|
|
echo "==> [prod] Remote: $REMOTE"
|
|
echo "==> [prod] Branch: ${BRANCH_INPUT:-<auto>}"
|
|
|
|
if [[ ! -d ".git" ]]; then
|
|
echo "Error: current directory is not a git repository."
|
|
exit 1
|
|
fi
|
|
|
|
if ! git remote get-url "$REMOTE" >/dev/null 2>&1; then
|
|
echo "Error: git remote '$REMOTE' does not exist."
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> [prod] Fetching latest code"
|
|
git fetch "$REMOTE" --prune
|
|
|
|
resolve_default_branch() {
|
|
local remote="$1"
|
|
local head_ref
|
|
head_ref="$(git symbolic-ref -q --short "refs/remotes/$remote/HEAD" 2>/dev/null || true)"
|
|
if [[ -n "$head_ref" ]]; then
|
|
echo "${head_ref#${remote}/}"
|
|
return 0
|
|
fi
|
|
head_ref="$(git remote show "$remote" 2>/dev/null | awk '/HEAD branch/ {print $NF; exit}')"
|
|
if [[ -n "$head_ref" ]]; then
|
|
echo "$head_ref"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
if [[ -n "$BRANCH_INPUT" ]]; then
|
|
BRANCH="$BRANCH_INPUT"
|
|
else
|
|
BRANCH="$(resolve_default_branch "$REMOTE" || true)"
|
|
if [[ -z "$BRANCH" ]]; then
|
|
BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
fi
|
|
if [[ -z "$BRANCH" || "$BRANCH" == "HEAD" ]]; then
|
|
echo "Error: could not determine deploy branch. Please pass one explicitly:"
|
|
echo " sh deploy.prod.sh <branch> [remote]"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo "==> [prod] Using branch: $BRANCH"
|
|
|
|
if ! git show-ref --verify --quiet "refs/remotes/$REMOTE/$BRANCH"; then
|
|
echo "Error: remote branch '$REMOTE/$BRANCH' not found."
|
|
exit 1
|
|
fi
|
|
|
|
PREV_COMMIT="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
|
|
echo "==> [prod] Current commit: $PREV_COMMIT"
|
|
|
|
echo "==> [prod] Force sync to $REMOTE/$BRANCH (discard local changes)"
|
|
git checkout -B "$BRANCH" "$REMOTE/$BRANCH"
|
|
git reset --hard "$REMOTE/$BRANCH"
|
|
git clean -fd
|
|
|
|
NEW_COMMIT="$(git rev-parse --short HEAD)"
|
|
echo "==> [prod] New commit: $NEW_COMMIT"
|
|
|
|
if [[ ! -f ".env" && -f ".env.example" ]]; then
|
|
cp ".env.example" ".env"
|
|
echo "==> [prod] Created .env from .env.example"
|
|
fi
|
|
|
|
if docker compose version >/dev/null 2>&1; then
|
|
COMPOSE_CMD="docker compose"
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
|
COMPOSE_CMD="docker-compose"
|
|
else
|
|
COMPOSE_CMD=""
|
|
fi
|
|
|
|
if [[ -n "$COMPOSE_CMD" ]]; then
|
|
echo "==> [prod] Restarting services with $COMPOSE_CMD"
|
|
$COMPOSE_CMD down
|
|
$COMPOSE_CMD up -d --build --remove-orphans
|
|
echo "==> [prod] Deploy success: http://localhost:18000"
|
|
exit 0
|
|
fi
|
|
|
|
echo "==> [prod] docker compose not found, fallback to ./start.sh"
|
|
chmod +x ./start.sh
|
|
./start.sh
|