#!/bin/bash ############################################################################### # 本地回滚脚本 # 在本地运行,通过 SSH 连接服务器并执行回滚 ############################################################################### set -e # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # 获取脚本所在目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" ############################################################################### # 函数:打印带颜色的消息 ############################################################################### log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warning() { echo -e "${YELLOW}[⚠]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } ############################################################################### # 函数:加载配置文件 ############################################################################### load_config() { if [ ! -f "$PROJECT_ROOT/.env.deploy" ]; then log_error "配置文件不存在: $PROJECT_ROOT/.env.deploy" echo "" echo "请先运行以下命令进行配置:" echo " npm run deploy:setup" exit 1 fi source "$PROJECT_ROOT/.env.deploy" if [ -z "$SERVER_HOST" ] || [ -z "$SERVER_USER" ]; then log_error "配置不完整,请检查 .env.deploy 文件" exit 1 fi log_success "配置加载完成" } ############################################################################### # 函数:列出可回滚的版本 ############################################################################### list_backup_versions() { echo "" echo "正在获取可用的备份版本..." echo "" local ssh_options="" if [ -n "$SSH_KEY_PATH" ]; then ssh_options="-i $SSH_KEY_PATH" fi if [ -n "$SERVER_PORT" ]; then ssh_options="$ssh_options -p $SERVER_PORT" fi # 上传回滚脚本 scp $ssh_options -q \ "$SCRIPT_DIR/rollback-on-server.sh" \ "$SERVER_USER@$SERVER_HOST":/tmp/ || { log_error "上传回滚脚本失败" exit 1 } # 执行列表命令 local env_vars="PRODUCTION_PATH=$PRODUCTION_PATH BACKUP_DIR=$BACKUP_DIR" ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "$env_vars bash /tmp/rollback-on-server.sh list" } ############################################################################### # 函数:执行回滚 ############################################################################### execute_rollback() { local version_index="${1:-1}" echo "" echo "╔════════════════════════════════════════════════════════════════╗" echo "║ 版本回滚工具 ║" echo "╚════════════════════════════════════════════════════════════════╝" echo "" # 列出可用版本 list_backup_versions # 询问确认 echo "" read -p "确认回滚到版本 #$version_index? (yes/no): " -r echo "" if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then log_info "回滚已取消" exit 0 fi # SSH 选项 local ssh_options="" if [ -n "$SSH_KEY_PATH" ]; then ssh_options="-i $SSH_KEY_PATH" fi if [ -n "$SERVER_PORT" ]; then ssh_options="$ssh_options -p $SERVER_PORT" fi log_info "正在执行回滚..." echo "" # 执行回滚命令 local env_vars="PRODUCTION_PATH=$PRODUCTION_PATH BACKUP_DIR=$BACKUP_DIR" local rollback_output=$(ssh $ssh_options "$SERVER_USER@$SERVER_HOST" \ "$env_vars bash /tmp/rollback-on-server.sh rollback $version_index" 2>&1) if echo "$rollback_output" | grep -q "ROLLBACK_SUCCESS=true"; then # 提取回滚版本 local rollback_version=$(echo "$rollback_output" | grep "ROLLBACK_VERSION=" | cut -d= -f2) # 发送通知 if [ "$ENABLE_WECHAT_NOTIFY" = "true" ]; then bash "$SCRIPT_DIR/notify-wechat.sh" rollback \ "$rollback_version" \ "$USER" || { log_warning "企业微信通知发送失败" } fi # 显示结果 echo "" echo "╔════════════════════════════════════════════════════════════════╗" echo "║ 🎉 回滚成功! ║" echo "╚════════════════════════════════════════════════════════════════╝" echo "" echo -e "${BOLD}回滚信息:${NC}" echo " 目标版本: $rollback_version" echo " 回滚时间: $(date '+%Y-%m-%d %H:%M:%S')" echo "" echo -e "${BOLD}访问地址:${NC}" echo " https://valuefrontier.cn" echo "" echo "════════════════════════════════════════════════════════════════" echo "" log_success "回滚完成" else log_error "回滚失败" echo "$rollback_output" exit 1 fi # 清理临时文件 ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "rm -f /tmp/rollback-on-server.sh" > /dev/null 2>&1 || true } ############################################################################### # 主函数 ############################################################################### main() { local action="${1:-rollback}" local version_index="${2:-1}" # 加载配置 load_config case "$action" in list) list_backup_versions ;; rollback|*) execute_rollback "$version_index" ;; esac } # 错误处理 trap 'log_error "回滚过程中发生错误"; exit 1' ERR # 执行主函数 main "$@"