#!/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:-}" 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 [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