feat: 自动化部署代码初步提交
This commit is contained in:
392
scripts/deploy-from-local.sh
Executable file
392
scripts/deploy-from-local.sh
Executable file
@@ -0,0 +1,392 @@
|
||||
#!/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"; }
|
||||
log_step() { echo -e "${CYAN}${BOLD}[$1]${NC} $2"; }
|
||||
|
||||
###############################################################################
|
||||
# 函数:加载配置文件
|
||||
###############################################################################
|
||||
load_config() {
|
||||
if [ ! -f "$PROJECT_ROOT/.env.deploy" ]; then
|
||||
log_error "配置文件不存在: $PROJECT_ROOT/.env.deploy"
|
||||
echo ""
|
||||
echo "请先运行以下命令进行配置:"
|
||||
echo " npm run deploy:setup"
|
||||
echo ""
|
||||
echo "或者手动创建配置文件:"
|
||||
echo " cp .env.deploy.example .env.deploy"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 加载配置
|
||||
source "$PROJECT_ROOT/.env.deploy"
|
||||
|
||||
# 检查必需的配置项
|
||||
if [ -z "$SERVER_HOST" ] || [ -z "$SERVER_USER" ]; then
|
||||
log_error "配置不完整,请检查 .env.deploy 文件"
|
||||
echo "必需配置项:"
|
||||
echo " - SERVER_HOST: 服务器地址"
|
||||
echo " - SERVER_USER: SSH 用户名"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "配置加载完成"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:检查本地 Git 状态
|
||||
###############################################################################
|
||||
check_local_git() {
|
||||
log_step "1/8" "检查本地代码"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# 检查是否是 Git 仓库
|
||||
if [ ! -d ".git" ]; then
|
||||
log_error "当前目录不是 Git 仓库"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 获取当前分支
|
||||
local current_branch=$(git branch --show-current)
|
||||
log_info "当前分支: $current_branch"
|
||||
|
||||
# 检查是否有未提交的更改
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
log_warning "存在未提交的更改"
|
||||
echo ""
|
||||
git status --short
|
||||
echo ""
|
||||
read -p "是否继续部署? (y/n): " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "部署已取消"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# 获取最新提交信息
|
||||
COMMIT_HASH=$(git rev-parse --short HEAD)
|
||||
COMMIT_MESSAGE=$(git log -1 --pretty=%B | head -n 1)
|
||||
COMMIT_AUTHOR=$(git log -1 --pretty=%an)
|
||||
|
||||
log_info "最新提交: $COMMIT_HASH - $COMMIT_MESSAGE"
|
||||
log_info "提交作者: $COMMIT_AUTHOR"
|
||||
|
||||
log_success "本地代码检查完成"
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:显示部署预览
|
||||
###############################################################################
|
||||
show_deploy_preview() {
|
||||
log_step "2/8" "部署预览"
|
||||
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ 部署预览 ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo -e "${BOLD}项目信息:${NC}"
|
||||
echo " 项目名称: vf_react"
|
||||
echo " 部署环境: 生产环境"
|
||||
echo " 目标服务器: $SERVER_USER@$SERVER_HOST"
|
||||
echo ""
|
||||
echo -e "${BOLD}代码信息:${NC}"
|
||||
echo " 当前分支: $(git branch --show-current)"
|
||||
echo " 提交版本: $COMMIT_HASH"
|
||||
echo " 提交信息: $COMMIT_MESSAGE"
|
||||
echo " 提交作者: $COMMIT_AUTHOR"
|
||||
echo ""
|
||||
echo -e "${BOLD}部署路径:${NC}"
|
||||
echo " Git 仓库: $REMOTE_PROJECT_PATH"
|
||||
echo " 生产目录: $PRODUCTION_PATH"
|
||||
echo ""
|
||||
echo "════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# 询问是否继续
|
||||
read -p "确认部署到生产环境? (yes/no): " -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
|
||||
log_info "部署已取消"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:测试 SSH 连接
|
||||
###############################################################################
|
||||
test_ssh_connection() {
|
||||
log_step "3/8" "测试 SSH 连接"
|
||||
|
||||
local ssh_options="-o ConnectTimeout=${SSH_TIMEOUT:-30} -o BatchMode=yes"
|
||||
|
||||
if [ -n "$SSH_KEY_PATH" ]; then
|
||||
ssh_options="$ssh_options -i $SSH_KEY_PATH"
|
||||
fi
|
||||
|
||||
if [ -n "$SERVER_PORT" ]; then
|
||||
ssh_options="$ssh_options -p $SERVER_PORT"
|
||||
fi
|
||||
|
||||
# 测试连接
|
||||
if ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "echo 'SSH 连接成功'" > /dev/null 2>&1; then
|
||||
log_success "SSH 连接成功"
|
||||
else
|
||||
log_error "SSH 连接失败"
|
||||
echo ""
|
||||
echo "请检查:"
|
||||
echo " 1. 服务器地址是否正确: $SERVER_HOST"
|
||||
echo " 2. SSH 用户名是否正确: $SERVER_USER"
|
||||
echo " 3. SSH 密钥是否配置正确"
|
||||
echo " 4. 服务器端口是否正确: ${SERVER_PORT:-22}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:上传服务器端脚本
|
||||
###############################################################################
|
||||
upload_server_scripts() {
|
||||
log_step "4/8" "上传部署脚本"
|
||||
|
||||
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
|
||||
|
||||
# 创建远程脚本目录
|
||||
ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "mkdir -p /tmp/deploy-scripts" || {
|
||||
log_error "创建远程目录失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 上传脚本
|
||||
scp $ssh_options \
|
||||
"$SCRIPT_DIR/deploy-on-server.sh" \
|
||||
"$SCRIPT_DIR/rollback-on-server.sh" \
|
||||
"$SCRIPT_DIR/notify-wechat.sh" \
|
||||
"$SERVER_USER@$SERVER_HOST":/tmp/deploy-scripts/ > /dev/null 2>&1 || {
|
||||
log_error "上传脚本失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 设置执行权限
|
||||
ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "chmod +x /tmp/deploy-scripts/*.sh" || {
|
||||
log_error "设置脚本权限失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_success "部署脚本上传完成"
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:执行服务器端部署
|
||||
###############################################################################
|
||||
execute_remote_deployment() {
|
||||
log_step "5/8" "执行远程部署"
|
||||
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
|
||||
|
||||
# 构建环境变量
|
||||
local env_vars="REMOTE_PROJECT_PATH=$REMOTE_PROJECT_PATH "
|
||||
env_vars+="PRODUCTION_PATH=$PRODUCTION_PATH "
|
||||
env_vars+="BACKUP_DIR=$BACKUP_DIR "
|
||||
env_vars+="LOG_DIR=$LOG_DIR "
|
||||
env_vars+="DEPLOY_BRANCH=$DEPLOY_BRANCH "
|
||||
env_vars+="KEEP_BACKUPS=$KEEP_BACKUPS "
|
||||
env_vars+="RUN_NPM_INSTALL=$RUN_NPM_INSTALL"
|
||||
|
||||
# 记录开始时间
|
||||
DEPLOY_START_TIME=$(date +%s)
|
||||
|
||||
# 执行部署脚本
|
||||
ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "$env_vars bash /tmp/deploy-scripts/deploy-on-server.sh" || {
|
||||
log_error "远程部署失败"
|
||||
send_failure_notification "部署脚本执行失败"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 记录结束时间
|
||||
DEPLOY_END_TIME=$(date +%s)
|
||||
DEPLOY_DURATION=$((DEPLOY_END_TIME - DEPLOY_START_TIME))
|
||||
|
||||
echo ""
|
||||
log_success "远程部署完成"
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:发送成功通知
|
||||
###############################################################################
|
||||
send_success_notification() {
|
||||
log_step "6/8" "发送部署通知"
|
||||
|
||||
if [ "$ENABLE_WECHAT_NOTIFY" = "true" ]; then
|
||||
local minutes=$((DEPLOY_DURATION / 60))
|
||||
local seconds=$((DEPLOY_DURATION % 60))
|
||||
local duration="${minutes}分${seconds}秒"
|
||||
|
||||
bash "$SCRIPT_DIR/notify-wechat.sh" success \
|
||||
"$DEPLOY_BRANCH" \
|
||||
"$COMMIT_HASH" \
|
||||
"$COMMIT_MESSAGE" \
|
||||
"$duration" \
|
||||
"$USER" || {
|
||||
log_warning "企业微信通知发送失败"
|
||||
}
|
||||
else
|
||||
log_info "企业微信通知未启用"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:发送失败通知
|
||||
###############################################################################
|
||||
send_failure_notification() {
|
||||
local error_message="$1"
|
||||
|
||||
if [ "$ENABLE_WECHAT_NOTIFY" = "true" ]; then
|
||||
bash "$SCRIPT_DIR/notify-wechat.sh" failure \
|
||||
"$DEPLOY_BRANCH" \
|
||||
"$error_message" \
|
||||
"$USER" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:清理临时文件
|
||||
###############################################################################
|
||||
cleanup() {
|
||||
log_step "7/8" "清理临时文件"
|
||||
|
||||
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
|
||||
|
||||
ssh $ssh_options "$SERVER_USER@$SERVER_HOST" "rm -rf /tmp/deploy-scripts" > /dev/null 2>&1 || true
|
||||
|
||||
log_success "清理完成"
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 函数:显示部署结果
|
||||
###############################################################################
|
||||
show_deployment_result() {
|
||||
log_step "8/8" "部署完成"
|
||||
|
||||
local minutes=$((DEPLOY_DURATION / 60))
|
||||
local seconds=$((DEPLOY_DURATION % 60))
|
||||
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ 🎉 部署成功! ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo -e "${BOLD}部署信息:${NC}"
|
||||
echo " 版本: $COMMIT_HASH"
|
||||
echo " 分支: $DEPLOY_BRANCH"
|
||||
echo " 提交: $COMMIT_MESSAGE"
|
||||
echo " 作者: $COMMIT_AUTHOR"
|
||||
echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo " 耗时: ${minutes}分${seconds}秒"
|
||||
echo ""
|
||||
echo -e "${BOLD}访问地址:${NC}"
|
||||
echo " https://valuefrontier.cn"
|
||||
echo ""
|
||||
echo "════════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 主函数
|
||||
###############################################################################
|
||||
main() {
|
||||
echo ""
|
||||
echo "╔════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ VF React - 生产环境部署工具 ║"
|
||||
echo "╚════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# 加载配置
|
||||
load_config
|
||||
|
||||
# 检查本地 Git 状态
|
||||
check_local_git
|
||||
|
||||
# 显示部署预览
|
||||
show_deploy_preview
|
||||
|
||||
# 测试 SSH 连接
|
||||
test_ssh_connection
|
||||
|
||||
# 上传服务器端脚本
|
||||
upload_server_scripts
|
||||
|
||||
# 执行远程部署
|
||||
execute_remote_deployment
|
||||
|
||||
# 发送成功通知
|
||||
send_success_notification
|
||||
|
||||
# 清理临时文件
|
||||
cleanup
|
||||
|
||||
# 显示部署结果
|
||||
show_deployment_result
|
||||
}
|
||||
|
||||
# 错误处理
|
||||
trap 'log_error "部署过程中发生错误"; send_failure_notification "部署异常中断"; exit 1' ERR
|
||||
|
||||
# 执行主函数
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user