#!/usr/bin/env bash # vps-manager 本地一键部署(零 SSH) # # 流程: # 1. 检查工作区干净 → git push 到 Gitea # 2. 轮询 cc1 的 /health(含 commit 字段)直到线上版本追平本地 HEAD # (cc1 上 vps-manager-update.timer 每 1 分钟自动拉取并重启) # 3. 验证核心 API 全部 200 # # 可配置项(环境变量): # DEPLOY_HEALTH_URL 健康检查地址(默认 Tailscale HTTPS 域名) # DEPLOY_TIMEOUT 等待超时秒数(默认 720;首次使用含旧 5 分钟 timer 周期余量) # GIT_BRANCH 推送分支(默认 main) # # 用法:./deploy/deploy.sh set -euo pipefail HEALTH_URL="${DEPLOY_HEALTH_URL:-https://dify.taile5765c.ts.net/health}" TIMEOUT="${DEPLOY_TIMEOUT:-720}" BRANCH="${GIT_BRANCH:-main}" POLL_INTERVAL=15 cd "$(dirname "$0")/.." echo "==> [1/3] 推送代码" if [ -n "$(git status --porcelain)" ]; then echo "⚠️ 存在未提交变更,请先 commit:" git status --short exit 1 fi git push origin "$BRANCH" LOCAL=$(git rev-parse HEAD) # /health 返回 7 位短哈希,比对统一用短哈希 LOCAL_SHORT=$(git rev-parse --short=7 HEAD) echo " 本地版本 ${LOCAL:0:8} 已推送,等待 cc1 自动更新…" echo "==> [2/3] 等待 cc1 更新(轮询 ${HEALTH_URL})" fetch_remote_commit() { curl -s --max-time 10 "$HEALTH_URL" \ | python3 -c "import json,sys; print(json.load(sys.stdin).get('commit',''))" 2>/dev/null || echo "" } deadline=$(( $(date +%s) + TIMEOUT )) REMOTE="" while [ "$(date +%s)" -lt "$deadline" ]; do REMOTE=$(fetch_remote_commit) if [ "$REMOTE" = "$LOCAL_SHORT" ]; then echo " ✅ cc1 已更新至 ${LOCAL:0:8}" break fi echo " 线上 ${REMOTE:0:8} | 目标 ${LOCAL:0:8},${POLL_INTERVAL}s 后重试…" sleep "$POLL_INTERVAL" done if [ "$REMOTE" != "$LOCAL_SHORT" ]; then echo "❌ 部署超时(${TIMEOUT}s 内 cc1 未更新至 ${LOCAL:0:8},当前线上 ${REMOTE:0:8})" echo " 排查:ssh cc1 'journalctl -u vps-manager-update.service -n 30'" exit 1 fi echo "==> [3/3] 验证核心 API" BASE="${HEALTH_URL%/health}" FAILED=0 for path in /api/assets /api/accounts /api/providers /api/stats/overview; do code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$BASE$path" || echo "000") if [ "$code" = "200" ]; then echo " ✓ $path -> $code" else echo " ❌ $path -> $code" FAILED=1 fi done if [ "$FAILED" -ne 0 ]; then echo "❌ 部署后验证失败,请检查 cc1 服务日志" exit 1 fi echo "🎉 部署完成:${LOCAL:0:8} 已在 cc1 生效并通过验证"