#!/bin/bash # ═══════════════════════════════════════════════════════════════════ # SciLit — 生产环境一键部署脚本 # ═══════════════════════════════════════════════════════════════════ # # 用法: # export SCILIT_HOST=your-server.com # ./deploy.sh # 部署到默认服务器 # ./deploy.sh --skip-tests # 跳过本地测试,直接部署 # ./deploy.sh --help # 查看全部选项 # # 前置条件: # - 本地: SSH 可连接到服务器(推荐用 ~/.ssh/config) # - 服务器: 已装 Docker + docker compose,已 clone 项目 # - 服务器: .env 文件已配置好 # - 代码仓库: 支持 Gitee / GitHub / 自建 Git(git pull 能工作即可) # # 远程仓库配置: # - 本地 git remote 指向 Gitee: # git remote add gitee https://gitee.com/你的用户名/scilit-oncology.git # # deploy.sh 会尝试 push 到 origin(可设为 Gitee) # - 服务器上 git remote 也指向 Gitee: # git remote set-url origin https://gitee.com/你的用户名/scilit-oncology.git # - 可选: GitHub 同时保留用作备份: # git remote add github https://github.com/你的用户名/scilit-oncology.git # ═══════════════════════════════════════════════════════════════════ set -euo pipefail # ── 默认配置 ───────────────────────────────────────────────────── # 改为你的服务器信息 SERVER_HOST="${SCILIT_HOST:-your-server.com}" SERVER_USER="${SCILIT_USER:-root}" SERVER_PATH="${SCILIT_PATH:-/root/scilit-oncology}" # 本地项目根目录 LOCAL_ROOT="$(cd "$(dirname "$0")" && pwd)" # ── 颜色 ───────────────────────────────────────────────────────── GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' # No Color info() { echo -e "${GREEN}[✓]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } error() { echo -e "${RED}[✗]${NC} $1"; exit 1; } # ── 参数解析 ───────────────────────────────────────────────────── SKIP_TESTS=false ENV_FILE="" while [[ $# -gt 0 ]]; do case "$1" in --skip-tests) SKIP_TESTS=true; shift ;; --env) ENV_FILE="$2"; shift 2 ;; --help) echo "用法: $0 [--skip-tests] [--env .env.prod]" echo "" echo " --skip-tests 跳过本地测试和 lint" echo " --env FILE 指定服务器上的 .env 文件路径(默认: {SERVER_PATH}/.env)" exit 0 ;; *) error "未知参数: $1,使用 --help 查看用法" ;; esac done # ── 第一步:本地检查 + 测试 ───────────────────────────────────── echo "════════════════════════════════════════════" echo " SciLit 部署" echo " 目标: ${SERVER_USER}@${SERVER_HOST}" echo "════════════════════════════════════════════" echo "" if [ "$SKIP_TESTS" = false ]; then echo "── 1/4 本地测试 ──" cd "$LOCAL_ROOT/backend" info "运行后端测试..." python -m pytest tests/ -v --no-cov --tb=short 2>&1 | tail -5 local EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ]; then error "后端测试失败(exit code $EXIT_CODE),中止部署。用 --skip-tests 跳过。" fi info "后端测试通过" cd "$LOCAL_ROOT/frontend" info "构建前端(验证)..." npm run build 2>&1 | tail -3 info "前端构建通过" cd "$LOCAL_ROOT" else echo "── 1/4 本地测试 ── 已跳过" fi # ── 第二步:推送代码 ───────────────────────────────────────────── echo "" echo "── 2/4 推送代码 ──" cd "$LOCAL_ROOT" if git status --porcelain | grep -q .; then warn "有未提交的改动,建议先提交再部署。继续?(y/N)" read -r yn if [ "$yn" != "y" ] && [ "$yn" != "Y" ]; then error "已取消" fi fi # 尝试推送到 GitHub(失败不阻塞) if git push origin main 2>&1; then info "GitHub push 成功" else warn "GitHub push 失败(网络问题),继续部署..." fi # ── 第三步:服务器拉取 + 构建 + 启动 ──────────────────────────── echo "" echo "── 3/4 服务器部署 ──" DEPLOY_CMD=$(cat << SSHCMD set -e cd ${SERVER_PATH} echo " 拉取代码..." git pull origin main 2>&1 || echo " [!] git pull 失败,继续用本地代码" echo " 构建并启动..." docker compose -f docker-compose.prod.yml build 2>&1 | tail -3 # 优雅重启(不中断现有连接) echo " 正在更新服务..." docker compose -f docker-compose.prod.yml up -d --no-deps --remove-orphans 2>&1 echo " 等待就绪..." sleep 5 curl -sf http://localhost:8000/health && echo " [✓] backend 健康检查通过" || echo " [!] backend 健康检查失败" curl -sf http://localhost:80 && echo " [✓] frontend 健康检查通过" || echo " [!] frontend 健康检查失败" echo " 清理旧镜像..." docker image prune -f 2>&1 | tail -1 SSHCMD ) ssh -o StrictHostKeyChecking=no "${SERVER_USER}@${SERVER_HOST}" bash <<< "$DEPLOY_CMD" info "服务器部署完成" # ── 第四步:日志 ───────────────────────────────────────────────── echo "" echo "── 4/4 查看日志 ──" echo "" echo " 实时日志: ssh ${SERVER_USER}@${SERVER_HOST} 'cd ${SERVER_PATH} && docker compose -f docker-compose.prod.yml logs -f'" echo " backend: ssh ${SERVER_USER}@${SERVER_HOST} 'cd ${SERVER_PATH} && docker compose -f docker-compose.prod.yml logs -f backend'" echo " 重新部署: cd $(pwd) && bash deploy.sh" echo "" info "部署完毕 🎉"