Files
hospital_performance/spug/deploy.sh

316 lines
8.6 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Spug 自动发布脚本 - 全栈项目
# 用途:医院绩效考核系统自动化部署脚本
# 执行方式:在 Spug 的"执行任务"中调用此脚本
set -e
# ==================== 配置参数 ====================
# 这些参数可以在 Spug 中通过环境变量传入
# 如果 SPUG_DEPLOY_DIR 为空,则使用默认值
if [ -z "${SPUG_DEPLOY_DIR}" ]; then
PROJECT_DIR="/var/www/hospital-performance"
else
PROJECT_DIR="${SPUG_DEPLOY_DIR}"
fi
PROJECT_NAME="${SPUG_APP_NAME:-hospital-performance}"
BACKUP_DIR="${PROJECT_DIR}/backups"
FRONTEND_DIR="${PROJECT_DIR}/frontend"
BACKEND_DIR="${PROJECT_DIR}/backend"
# Git 配置Spug 会自动设置 SPUG_GIT_URL
if [ -n "${SPUG_GIT_URL}" ]; then
GIT_REPO="${SPUG_GIT_URL}"
elif [ -n "${SPUG_GIT_REPO}" ]; then
GIT_REPO="${SPUG_GIT_REPO}"
else
GIT_REPO="https://gitea.gentronhealth.com/chenqi/hospital_performance.git"
fi
GIT_BRANCH="${SPUG_GIT_BRANCH:-main}"
# Python 虚拟环境
VENV_DIR="${PROJECT_DIR}/venv"
PYTHON_VERSION="${PYTHON_VERSION:-python3.10}"
# Node.js 配置
NODE_VERSION="${NODE_VERSION:-18}"
# 服务配置
BACKEND_SERVICE="${BACKEND_SERVICE:-hospital-backend}"
BACKEND_PORT="${BACKEND_PORT:-8000}"
FRONTEND_SERVICE="${FRONTEND_SERVICE:-nginx}"
# 日志配置
if [ -z "${LOG_FILE}" ]; then
LOG_FILE="/var/log/spug/deploy.log"
# 确保日志目录存在
mkdir -p /var/log/spug 2>/dev/null || true
fi
DEPLOY_TIME=$(date +"%Y%m%d_%H%M%S")
# ==================== 工具函数 ====================
log() {
local level=$1
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[${timestamp}] [${level}] ${message}" | tee -a "${LOG_FILE}"
}
info() {
log "INFO" "$@"
}
error() {
log "ERROR" "$@"
}
success() {
log "SUCCESS" "$@"
}
check_command() {
if ! command -v $1 &> /dev/null; then
error "命令 $1 未安装,请先安装"
exit 1
fi
}
# ==================== 前置检查 ====================
pre_check() {
info "========== 开始前置检查 =========="
# 检查必要命令
check_command git
check_command python3
check_command node
check_command npm
# 检查部署目录
if [ ! -d "${PROJECT_DIR}" ]; then
info "创建部署目录:${PROJECT_DIR}"
mkdir -p "${PROJECT_DIR}"
fi
# 检查磁盘空间(如果目录存在)
if [ -d "${PROJECT_DIR}" ]; then
local available_space=$(df -P "${PROJECT_DIR}" 2>/dev/null | awk 'NR==2 {print $4}')
if [ -n "${available_space}" ] && [ "${available_space}" -lt 1048576 ]; then
error "磁盘空间不足 1GB当前可用${available_space}KB"
exit 1
fi
fi
info "✓ 前置检查通过"
}
# ==================== 代码更新 ====================
update_code() {
info "========== 更新代码 =========="
cd "${PROJECT_DIR}"
if [ ! -d ".git" ]; then
info "首次部署,克隆仓库..."
# 确保目录为空或不存在
if [ "$(ls -A ${PROJECT_DIR} 2>/dev/null)" ]; then
info "目录非空,先备份现有文件..."
mkdir -p "${PROJECT_DIR}/backup_$(date +%Y%m%d_%H%M%S)_non_git"
find "${PROJECT_DIR}" -maxdepth 1 -type f -o -type d ! -name '.' -exec mv {} "${PROJECT_DIR}/backup_$(date +%Y%m%d_%H%M%S)_non_git/" \; 2>/dev/null || true
fi
git clone "${GIT_REPO}" .
git checkout "${GIT_BRANCH}"
else
info "更新现有代码..."
git fetch origin "${GIT_BRANCH}"
git reset --hard "origin/${GIT_BRANCH}"
git clean -fd
fi
local commit_hash=$(git rev-parse --short HEAD)
local commit_msg=$(git log -1 --pretty=format:"%s")
info "✓ 代码更新完成,当前版本:${commit_hash} - ${commit_msg}"
}
# ==================== 备份旧版本 ====================
backup_old_version() {
info "========== 备份当前版本 =========="
mkdir -p "${BACKUP_DIR}"
local backup_name="backup_${DEPLOY_TIME}"
local backup_path="${BACKUP_DIR}/${backup_name}"
# 备份关键目录
if [ -d "${BACKEND_DIR}" ]; then
cp -r "${BACKEND_DIR}" "${backup_path}_backend"
info "✓ 后端代码已备份到:${backup_path}_backend"
fi
if [ -d "${FRONTEND_DIR}/dist" ]; then
cp -r "${FRONTEND_DIR}/dist" "${backup_path}_frontend_dist"
info "✓ 前端构建已备份到:${backup_path}_frontend_dist"
fi
# 清理 30 天前的备份
find "${BACKUP_DIR}" -type d -name "backup_*" -mtime +30 -exec rm -rf {} \; 2>/dev/null || true
info "✓ 备份完成(保留最近 30 天)"
}
# ==================== 后端部署 ====================
deploy_backend() {
info "========== 部署后端服务 =========="
cd "${BACKEND_DIR}"
# 创建虚拟环境
if [ ! -d "${VENV_DIR}" ]; then
info "创建 Python 虚拟环境..."
${PYTHON_VERSION} -m venv "${VENV_DIR}"
fi
# 激活虚拟环境
source "${VENV_DIR}/bin/activate"
# 升级 pip
pip install --upgrade pip -q
# 安装依赖
info "安装 Python 依赖..."
pip install -r requirements.txt -q
# 数据库迁移
if [ -f "alembic.ini" ]; then
info "执行数据库迁移..."
alembic upgrade head
fi
# 初始化数据(如果存在)
if [ -f "init_db.py" ]; then
info "初始化数据库..."
python init_db.py || true
fi
# 重启后端服务
if systemctl list-units --type=service --all | grep -q "${BACKEND_SERVICE}"; then
info "重启后端服务..."
systemctl restart "${BACKEND_SERVICE}"
sleep 2
# 检查服务状态
if systemctl is-active --quiet "${BACKEND_SERVICE}"; then
success "✓ 后端服务重启成功"
else
error "✗ 后端服务启动失败"
exit 1
fi
else
info "未找到 systemd 服务,跳过重启"
fi
deactivate
info "✓ 后端部署完成"
}
# ==================== 前端部署 ====================
deploy_frontend() {
info "========== 部署前端服务 =========="
cd "${FRONTEND_DIR}"
# 安装依赖
info "安装 Node.js 依赖..."
npm install --production
# 构建前端
info "构建前端项目..."
npm run build
# 检查构建结果
if [ -d "dist" ] && [ "$(ls -A dist)" ]; then
success "✓ 前端构建成功"
else
error "✗ 前端构建失败dist 目录为空"
exit 1
fi
# 如果使用 Nginx重新加载配置
if systemctl list-units --type=service --all | grep -q "${FRONTEND_SERVICE}"; then
info "重新加载 Nginx..."
systemctl reload "${FRONTEND_SERVICE}"
fi
info "✓ 前端部署完成"
}
# ==================== 健康检查 ====================
health_check() {
info "========== 执行健康检查 =========="
# 等待服务启动
sleep 5
# 检查后端 API
local backend_url="http://localhost:${BACKEND_PORT}/api/v1/health"
if curl -f -s "${backend_url}" > /dev/null; then
success "✓ 后端 API 健康检查通过"
else
error "✗ 后端 API 健康检查失败"
# 回滚逻辑(可选)
# rollback
exit 1
fi
# 检查前端
if [ -d "${FRONTEND_DIR}/dist/index.html" ]; then
success "✓ 前端文件存在"
else
error "✗ 前端文件缺失"
exit 1
fi
info "✓ 所有健康检查通过"
}
# ==================== 清理工作 ====================
cleanup() {
info "========== 清理临时文件 =========="
# 清理 npm 缓存
npm cache clean --force 2>/dev/null || true
# 清理 Python 缓存
find "${PROJECT_DIR}" -type d -name "__pycache__" -exec rm -rf {} \; 2>/dev/null || true
find "${PROJECT_DIR}" -type f -name "*.pyc" -delete 2>/dev/null || true
info "✓ 清理完成"
}
# ==================== 主流程 ====================
main() {
info "========================================"
info "Spug 自动发布开始"
info "项目名称:${PROJECT_NAME}"
info "部署目录:${PROJECT_DIR}"
info "Git 分支:${GIT_BRANCH}"
info "========================================"
# 执行部署流程
pre_check
update_code
backup_old_version
deploy_backend
deploy_frontend
health_check
cleanup
info "========================================"
success "🎉 部署成功完成!"
info "========================================"
}
# 执行主流程
main "$@"