hookehuyr

feat(deploy): 添加多环境部署系统

- 新增 deploy/ 目录,包含部署脚本和配置
- 支持 dev、oa、behalo 三个环境
- 支持单环境和批量部署
- 添加交互确认和进度提示
- 更新 package.json 部署脚本命令

影响文件:
- deploy/config.sh
- deploy/deploy.sh
- deploy/README.md
- package.json
# H5 项目多环境部署方案
## 概述
本部署方案支持将 H5 项目一键部署到一个或多个环境,适用于前端开发团队的日常发布流程。
### 特性
-**多环境支持**:dev、oa、behalo 三个环境
-**批量部署**:一次部署到多个环境
-**交互确认**:部署前需确认,防止误操作
-**自动归档**:自动打包构建产物
-**进度提示**:清晰的部署进度和结果反馈
## 快速开始
### 环境要求
- Node.js 18.19.1(项目使用 `.nvm` 管理)
- pnpm
- SSH 访问权限(配置 `ipadbiz-inner` 别名)
### 部署命令
```bash
# 单环境部署
pnpm deploy:dev # 部署到开发环境
pnpm deploy:oa # 部署到 OA 环境
pnpm deploy:behalo # 部署到 Behalo 环境
# 或者使用脚本直接调用
./deploy/deploy.sh dev
./deploy/deploy.sh oa
./deploy/deploy.sh behalo
# 多环境部署
./deploy/deploy.sh dev oa # 部署到开发和 OA 环境
./deploy/deploy.sh dev oa behalo # 部署到所有环境
```
## 环境说明
| 环境名称 | 服务器路径 | 访问地址 | 说明 |
| ---------- | ------------------ | ----------------------- | ----------- |
| **dev** | `/opt/space-dev/f` | http://oa-dev.onwall.cn | 开发环境 |
| **oa** | `/opt/oa/f` | http://oa.onwall.cn | OA 环境 |
| **behalo** | `/opt/behalo/f` | http://behalo.onwall.cn | Behalo 环境 |
## 部署流程
```
1. 检查环境
2. 确认部署环境(交互式)
3. 执行构建 (pnpm build)
4. 创建归档 (mlaj.tar.gz)
5. 上传归档到服务器
6. 远程解压部署
7. 清理归档文件
8. 显示访问地址
```
## 文件结构
```
deploy/
├── README.md # 本文档
├── config.sh # 环境配置文件
└── deploy.sh # 主部署脚本
```
### config.sh
环境配置文件,定义了每个环境的:
- 服务器信息(SSH 别名)
- 远程部署路径
- 构建命令和产物目录
- 备份配置
- 健康检查配置(预留)
- 通知配置(预留)
**配置结构**
```bash
# 每个环境对应一个配置函数
deploy_config_dev() {
export PROJECT_NAME="mlaj"
export SERVER_HOST="ipadbiz-inner"
export REMOTE_DEPLOY_DIR="/opt/space-dev/f"
export BUILD_DIR="dist"
export BUILD_COMMAND="pnpm build"
# ...
}
```
### deploy.sh
主部署脚本,负责:
1. 检查必需命令(pnpm、ssh、scp、tar)
2. 解析环境参数
3. 加载对应环境配置
4. 执行构建
5. 创建并上传归档
6. 远程解压部署
7. 输出部署结果
## 添加新环境
1.`config.sh` 中添加配置函数:
```bash
deploy_config_newenv() {
export PROJECT_NAME="mlaj"
export SERVER_HOST="your-ssh-alias"
export REMOTE_DEPLOY_DIR="/path/to/deploy"
export BUILD_DIR="dist"
export BUILD_COMMAND="pnpm build"
# ...其他配置
}
```
2.`config.sh``load_env_config()` 函数中添加:
```bash
load_env_config() {
case "$1" in
# ...现有环境
newenv)
deploy_config_newenv
;;
# ...
esac
}
```
3.`deploy.sh` 的提示信息中添加新环境名称
## 常见问题
### Q: SSH 连接失败?
确保已配置 SSH 别名 `ipadbiz-inner`,在 `~/.ssh/config` 中:
```
Host ipadbiz-inner
HostName your-server-ip
User your-username
Port 22
IdentityFile ~/.ssh/your-key
```
### Q: 构建失败?
检查 Node.js 版本是否为 18.19.1:
```bash
nvm use 18.19.1
```
### Q: 权限不足?
确保脚本有执行权限:
```bash
chmod +x deploy/deploy.sh
chmod +x deploy/config.sh
```
## 注意事项
1. **部署前确认**:脚本会在部署前要求确认,请仔细核对环境
2. **构建时间**:首次构建可能需要较长时间,请耐心等待
3. **网络稳定**:部署过程中请保持网络稳定
4. **环境隔离**:不同环境的配置相互独立,互不影响
---
**维护者**: 前端开发团队
**最后更新**: 2026-02-23
#!/bin/bash
# ============================================================================
# H5 项目多环境部署配置
# ============================================================================
#
# 说明:
# - 每个环境对应一个配置段
# - 部署时通过环境名称加载对应配置
# - 支持命令行参数覆盖配置
#
# 使用方法:
# source deploy/config.sh
# ./deploy/deploy.sh <env1> [env2] ...
#
# 环境命名建议:
# - dev: 开发环境
# - test: 测试环境
# - staging: 预发布环境
# - prod: 生产环境
# ============================================================================
# ============================================================================
# 环境配置段
# ============================================================================
# ----- 开发环境配置 -----
deploy_config_dev() {
# 项目名称(用于标识)
export PROJECT_NAME="mlaj"
# 服务器配置 - 使用 SSH alias
export SERVER_HOST="ipadbiz-inner"
export SERVER_USER="" # SSH alias 已配置用户
export SERVER_PORT="" # SSH alias 已配置端口
# 远程路径配置
export REMOTE_BASE_DIR="/opt/space-dev/f" # 远程基础目录
export REMOTE_DEPLOY_DIR="${REMOTE_BASE_DIR}" # 部署目录
# 本地路径配置
export BUILD_DIR="dist" # 构建产物目录
export BUILD_ARCHIVE="${PROJECT_NAME}.tar.gz" # 归档文件名(固定名称)
# 构建命令
export BUILD_COMMAND="pnpm build"
# 备份配置(保留备份数量,0=不备份)
export BACKUP_ENABLED="false"
export BACKUP_MAX_COUNT="0"
# 部署后操作
export DEPLOY_CLEANUP="true" # 是否清理部署归档
export RESTART_SERVER="false" # 是否重启服务器
# 健康检查配置
export HEALTH_CHECK_ENABLED="false" # 是否启用健康检查
export HEALTH_CHECK_URL="" # 健康检查 URL
export HEALTH_CHECK_TIMEOUT="10" # 健康检查超时(秒)
# 通知配置
export NOTIFY_ENABLED="false" # 是否发送通知
export NOTIFY_WEBHOOK="" # 通知 Webhook URL
}
# ----- OA 服务器配置(已有 oa_upload )-----
deploy_config_oa() {
export PROJECT_NAME="mlaj"
# 服务器配置 - 使用 SSH alias
export SERVER_HOST="ipadbiz-inner"
export SERVER_USER="" # SSH alias 已配置用户
export SERVER_PORT="" # SSH alias 已配置端口
# 远程路径配置
export REMOTE_BASE_DIR="/opt/oa/f" # 远程基础目录
export REMOTE_DEPLOY_DIR="${REMOTE_BASE_DIR}" # 部署目录
# 本地路径配置
export BUILD_DIR="dist" # 构建产物目录
export BUILD_ARCHIVE="${PROJECT_NAME}.tar.gz" # 归档文件名(固定名称)
# 构建命令
export BUILD_COMMAND="pnpm build"
# 备份配置(保留备份数量,0=不备份)
export BACKUP_ENABLED="false"
export BACKUP_MAX_COUNT="0"
# 部署后操作
export DEPLOY_CLEANUP="true" # 是否清理部署归档
export RESTART_SERVER="false" # 是否重启服务器
# 健康检查配置
export HEALTH_CHECK_ENABLED="false" # 是否启用健康检查
export HEALTH_CHECK_URL="" # 健康检查 URL
export HEALTH_CHECK_TIMEOUT="10" # 健康检查超时(秒)
# 通知配置
export NOTIFY_ENABLED="false" # 是否发送通知
export NOTIFY_WEBHOOK="" # 通知 Webhook URL
}
# ----- Behalo 服务器配置(已有 behalo_upload)-----
deploy_config_behalo() {
export PROJECT_NAME="mlaj"
# 服务器配置 - 使用 SSH alias
export SERVER_HOST="ipadbiz-inner"
export SERVER_USER="" # SSH alias 已配置用户
export SERVER_PORT="" # SSH alias 已配置端口
# 远程路径配置
export REMOTE_BASE_DIR="/opt/behalo/f" # 远程基础目录
export REMOTE_DEPLOY_DIR="${REMOTE_BASE_DIR}" # 部署目录
# 本地路径配置
export BUILD_DIR="dist" # 构建产物目录
export BUILD_ARCHIVE="${PROJECT_NAME}.tar.gz" # 归档文件名(固定名称)
# 构建命令
export BUILD_COMMAND="pnpm build"
# 备份配置(保留备份数量,0=不备份)
export BACKUP_ENABLED="false"
export BACKUP_MAX_COUNT="0"
# 部署后操作
export DEPLOY_CLEANUP="true" # 是否清理部署归档
export RESTART_SERVER="false" # 是否重启服务器
# 健康检查配置
export HEALTH_CHECK_ENABLED="false" # 是否启用健康检查
export HEALTH_CHECK_URL="" # 健康检查 URL
export HEALTH_CHECK_TIMEOUT="10" # 健康检查超时(秒)
# 通知配置
export NOTIFY_ENABLED="false" # 是否发送通知
export NOTIFY_WEBHOOK="" # 通知 Webhook URL
}
# ============================================================================
# 辅助函数
# ============================================================================
# 打印带颜色的消息
log_info() {
echo -e "\033[0;32m[INFO]\033[0m $@"
}
log_success() {
echo -e "\033[0;32m[SUCCESS]\033[0m $@"
}
log_warning() {
echo -e "\033[0;33m[WARNING]\033[0m $@"
}
log_error() {
echo -e "\033[0;31m[ERROR]\033[0m $@"
}
# 打印分隔线
print_separator() {
echo "================================================================================"
}
# 加载环境配置
# 参数: $1 - 环境名称
load_env_config() {
local env_name="$1"
case "$env_name" in
dev)
deploy_config_dev
;;
oa)
deploy_config_oa
;;
behalo)
deploy_config_behalo
;;
*)
log_error "未知环境: $env_name"
log_info "可用环境: dev, oa, behalo"
exit 1
;;
esac
}
# ============================================================================
# 验证配置
# ============================================================================
validate_config() {
log_info "验证配置..."
# 检查必需变量
required_vars=(
"PROJECT_NAME"
"SERVER_HOST"
"SERVER_USER"
"REMOTE_DEPLOY_DIR"
"BUILD_DIR"
"BUILD_ARCHIVE"
)
for var in "${required_vars[@]}"; do
if [ -z "${!var}" ]; then
log_error "缺少必需配置: $var"
exit 1
fi
done
# 检查本地构建目录
if [ ! -d "$BUILD_DIR" ]; then
log_error "构建目录不存在: $BUILD_DIR"
log_info "请先运行: $BUILD_COMMAND"
exit 1
fi
log_success "配置验证通过"
}
# 导出主函数供 deploy.sh 使用
export load_env_config
export validate_config
#!/bin/bash
# ============================================================================
# H5 项目多环境部署脚本
# ============================================================================
#
# 说明:支持一次部署到一个或多个环境
# 使用方法:./deploy.sh <env1> [env2] [env3] ...
#
# 示例:
# ./deploy.sh dev # 部署到开发环境
# ./deploy.sh test prod # 部署到测试和生产环境
# ./deploy.sh dev test prod # 部署到开发、测试和生产环境
#
# ============================================================================
set -e # 遇到错误立即退出
# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
# 加载配置文件
source "${SCRIPT_DIR}/config.sh"
# ============================================================================
# 辅助函数
# ============================================================================
# 显示分隔线
print_separator() {
echo "================================================================================"
}
# 检查必需的命令
check_commands() {
local required_cmds=("pnpm" "ssh" "scp" "tar" "rm")
for cmd in "${required_cmds[@]}"; do
if ! command -v "$cmd" &> /dev/null; then
log_error "缺少必需命令: $cmd"
log_info "请先安装缺失的工具"
exit 1
fi
done
}
# 检查本地构建产物
check_build() {
if [ ! -d "$BUILD_DIR" ]; then
log_error "构建目录不存在: $BUILD_DIR"
log_info "请先运行: $BUILD_COMMAND"
exit 1
fi
}
# 执行构建
do_build() {
log_info "开始构建项目..."
cd "$PROJECT_DIR"
$BUILD_COMMAND
if [ $? -ne 0 ]; then
log_error "构建失败"
exit 1
fi
log_success "构建完成"
cd "$SCRIPT_DIR"
}
# 创建归档
create_archive() {
local archive_name="$BUILD_ARCHIVE"
log_info "创建部署归档: $archive_name"
cd "$PROJECT_DIR"
tar -czf "$archive_name" "$BUILD_DIR"
if [ $? -ne 0 ]; then
log_error "创建归档失败"
exit 1
fi
log_success "归档创建完成: $archive_name"
cd "$SCRIPT_DIR"
}
# 上传归档
upload_archive() {
local archive_name="$1"
log_info "上传归档到服务器..."
scp -P "$SERVER_PORT" "$archive_name" \
"${SERVER_USER}@${SERVER_HOST}:/tmp/"
if [ $? -ne 0 ]; then
log_error "上传失败"
exit 1
fi
log_success "归档上传完成"
}
# 执行远程部署
do_deploy() {
local archive_name="$1"
local remote_archive_path="/tmp/${archive_name}"
local remote_deploy_dir="$REMOTE_DEPLOY_DIR"
log_info "开始远程部署..."
ssh -p "$SERVER_PORT" "${SERVER_USER}@${SERVER_HOST}" << EOF
set -e
# 进入部署目录
cd "\$remote_deploy_dir" || mkdir -p "\$remote_deploy_dir"
# 备份当前版本(如果启用)
if [ "\$BACKUP_ENABLED" = "true" ]; then
echo "[INFO] 备份当前版本..."
if [ -d "\$remote_deploy_dir" ]; then
# 查找现有的备份目录
BACKUP_DIR="\${remote_deploy_dir}_backup_\$(date +%Y%m%d_%H%M%S)"
mkdir -p "\$BACKUP_DIR"
# 备份当前版本
cp -r "\$remote_deploy_dir/"* "\$BACKUP_DIR/" 2>/dev/null || true
echo "[SUCCESS] 备份完成: \$BACKUP_DIR"
# 清理旧备份(保留指定数量)
if [ "\$BACKUP_MAX_COUNT" -gt 0 ]; then
echo "[INFO] 清理旧备份(保留 \$BACKUP_MAX_COUNT 个)..."
ls -td "\${remote_deploy_dir}_backup_" | sort -r | tail -n +\`"\$BACKUP_MAX_COUNT\" | xargs rm -rf
fi
fi
fi
# 解压新版本
echo "[INFO] 解压新版本..."
tar -xzf "\$remote_archive_path" -C "\$remote_deploy_dir"
# 清理归档文件
rm -f "\$remote_archive_path"
echo "[SUCCESS] 部署完成"
EOF
if [ $? -ne 0 ]; then
log_error "远程部署失败"
exit 1
fi
log_success "远程部署完成"
}
# 部署到单个环境
deploy_to_env() {
local env_name="$1"
log_info "=========================================="
log_info "开始部署到环境: $env_name"
log_info "=========================================="
# 加载环境配置
load_env_config "$env_name"
# 执行构建
do_build
# 创建归档
create_archive "$BUILD_ARCHIVE"
# 上传归档
upload_archive "$BUILD_ARCHIVE"
# 执行远程部署
do_deploy "$BUILD_ARCHIVE"
log_success "环境 [$env_name] 部署完成"
}
# ============================================================================
# 主流程
# ============================================================================
# 检查命令
check_commands
# 检查是否提供了环境参数
if [ $# -eq 0 ]; then
log_error "使用方法: $0 <env1> [env2] [env3] ..."
log_info "可用环境: dev, oa, behalo"
exit 1
fi
# 显示将要部署的环境
log_info "将要部署到以下环境:"
for env in "$@"; do
echo " - $env"
done
print_separator
# 确认部署
read -p "确认部署以上环境?(y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
log_warning "已取消部署"
exit 0
fi
print_separator
# 逐个部署环境
for env in "$@"; do
deploy_to_env "$env"
print_separator
done
# 最终总结
log_success "所有环境部署完成!"
print_separator
log_info "部署摘要:"
for env in "$@"; do
echo " ✓ $env"
done
print_separator
log_info "访问地址:"
for env in "$@"; do
case "$env" in
dev)
echo " - 开发环境: http://oa-dev.onwall.cn"
;;
oa)
echo " - OA环境: http://oa.onwall.cn"
;;
behalo)
echo " - Behalo环境: http://behalo.onwall.cn"
;;
esac
done
print_separator
log_success "部署流程全部结束!"
......@@ -32,6 +32,10 @@
"dev_upload": "npm run build_tar && npm run scp-dev && npm run dec-dev && npm run remove_tar",
"behalo_upload": "npm run build_tar && npm run scp-behalo && npm run dec-behalo && npm run remove_tar",
"oa_upload": "npm run build_tar && npm run scp-oa && npm run dec-oa && npm run remove_tar",
"deploy": "./deploy/deploy.sh",
"deploy:dev": "./deploy/deploy.sh dev",
"deploy:oa": "./deploy/deploy.sh oa",
"deploy:behalo": "./deploy/deploy.sh behalo",
"api:generate": "node .claude/custom_skills/api-generator/scripts/generateApiFromOpenAPI.cjs",
"api:diff": "node .claude/custom_skills/api-generator/scripts/apiDiff.cjs",
"prepare": "husky"
......