chore(deploy): add same-host staging stack next to production
dev deploys to /opt/dukang-staging (819x, *-test domains); main deploys to production. Staging uses full Mock with shared WeChat app ids. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+66
-21
@@ -1,9 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# 在服务器上执行:拉取后的常规发版(不覆盖 .env.production、默认不 seed)
|
||||
# 在服务器上执行:拉取后的常规发版(不覆盖 env 文件、默认不 seed)
|
||||
# 通过 DUKANG_DEPLOY_ENV=staging|production 区分同机双栈
|
||||
set -euo pipefail
|
||||
|
||||
APP_ROOT="${APP_ROOT:-/opt/dukang}"
|
||||
DUKANG_DEPLOY_ENV="${DUKANG_DEPLOY_ENV:-production}"
|
||||
case "$DUKANG_DEPLOY_ENV" in
|
||||
staging|stage|test) DUKANG_DEPLOY_ENV=staging ;;
|
||||
production|prod) DUKANG_DEPLOY_ENV=production ;;
|
||||
*)
|
||||
echo "错误: DUKANG_DEPLOY_ENV 须为 staging 或 production,当前=$DUKANG_DEPLOY_ENV" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$DUKANG_DEPLOY_ENV" == "staging" ]]; then
|
||||
APP_ROOT="${APP_ROOT:-/opt/dukang-staging}"
|
||||
ENV_FILE_NAME=".env.staging"
|
||||
ECOSYSTEM_FILE="ecosystem.staging.config.cjs"
|
||||
VITE_API_DEFAULT="https://api-test.dukanghaoke.com"
|
||||
API_PORT=8190
|
||||
USER_PORT=8191
|
||||
PORT_GREP='819[0-4]'
|
||||
PM2_API=dukang-stg-api
|
||||
PM2_USER=dukang-stg-h5-user
|
||||
PM2_SHOP=dukang-stg-h5-shop
|
||||
PM2_PARTNER=dukang-stg-h5-partner
|
||||
PM2_ADMIN=dukang-stg-admin-web
|
||||
else
|
||||
APP_ROOT="${APP_ROOT:-/opt/dukang}"
|
||||
ENV_FILE_NAME=".env.production"
|
||||
ECOSYSTEM_FILE="ecosystem.config.cjs"
|
||||
VITE_API_DEFAULT="https://api.dukanghaoke.com"
|
||||
API_PORT=8090
|
||||
USER_PORT=8091
|
||||
PORT_GREP='809[0-4]'
|
||||
PM2_API=dukang-api
|
||||
PM2_USER=dukang-h5-user
|
||||
PM2_SHOP=dukang-h5-shop
|
||||
PM2_PARTNER=dukang-h5-partner
|
||||
PM2_ADMIN=dukang-admin-web
|
||||
fi
|
||||
|
||||
DEPLOY_DIR="$APP_ROOT/deploy"
|
||||
export APP_ROOT
|
||||
export APP_ENV="$DUKANG_DEPLOY_ENV"
|
||||
export DUKANG_ENV_FILE="$ENV_FILE_NAME"
|
||||
|
||||
SKIP_BUILD=false
|
||||
SKIP_DB=false
|
||||
@@ -11,9 +52,11 @@ RUN_SEED=false
|
||||
DB_PUSH_ACCEPT_DATA_LOSS=false
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
cat <<EOF
|
||||
用法: remote-release.sh [选项]
|
||||
|
||||
环境: DUKANG_DEPLOY_ENV=${DUKANG_DEPLOY_ENV} APP_ROOT=${APP_ROOT} env=${ENV_FILE_NAME}
|
||||
|
||||
--skip-build 跳过 pnpm build(仅重启 PM2)
|
||||
--skip-db 跳过 Prisma generate / db push
|
||||
--seed 执行 prisma:seed(默认不执行)
|
||||
@@ -36,6 +79,8 @@ done
|
||||
|
||||
cd "$APP_ROOT"
|
||||
|
||||
echo "==> 发版环境: $DUKANG_DEPLOY_ENV ($APP_ROOT)"
|
||||
|
||||
echo "==> 1. 启用 pnpm"
|
||||
corepack enable 2>/dev/null || true
|
||||
corepack prepare pnpm@11.2.2 --activate 2>/dev/null || true
|
||||
@@ -47,15 +92,16 @@ export NODE_OPTIONS="${NODE_OPTIONS:---max-old-space-size=8192}"
|
||||
export TARO_H5_PUBLIC_PATH="${TARO_H5_PUBLIC_PATH:-/user/}"
|
||||
export TARO_H5_ROUTER_BASENAME="${TARO_H5_ROUTER_BASENAME:-/user}"
|
||||
# C 端 H5 编译期注入的 API origin(勿落到 localhost)
|
||||
export VITE_API_TARGET="${VITE_API_TARGET:-https://api.dukanghaoke.com}"
|
||||
export VITE_API_TARGET="${VITE_API_TARGET:-$VITE_API_DEFAULT}"
|
||||
export VITE_APP_ENV="$DUKANG_DEPLOY_ENV"
|
||||
pnpm approve-builds --all 2>/dev/null || true
|
||||
pnpm install --frozen-lockfile 2>/dev/null || pnpm install
|
||||
|
||||
if [[ "$SKIP_DB" == false ]]; then
|
||||
echo "==> 3. 数据库 schema 同步(构建前,读取 .env.production)"
|
||||
echo "==> 3. 数据库 schema 同步(构建前,读取 $ENV_FILE_NAME)"
|
||||
cd "$APP_ROOT/server/dukang-api"
|
||||
if [[ ! -f .env.production ]]; then
|
||||
echo "错误: 未找到 server/dukang-api/.env.production" >&2
|
||||
if [[ ! -f "$ENV_FILE_NAME" ]]; then
|
||||
echo "错误: 未找到 server/dukang-api/$ENV_FILE_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
node scripts/with-api-env.cjs pnpm prisma:generate
|
||||
@@ -94,31 +140,30 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "==> 5. 重启 PM2"
|
||||
if pm2 describe dukang-api &>/dev/null; then
|
||||
# delete+start 以确保 cwd 从 h5-user 切到 mini-user
|
||||
pm2 delete dukang-h5-user 2>/dev/null || true
|
||||
pm2 start "$DEPLOY_DIR/ecosystem.config.cjs" --only dukang-h5-user
|
||||
pm2 restart dukang-api dukang-h5-shop dukang-h5-partner dukang-admin-web 2>/dev/null \
|
||||
|| pm2 restart dukang-api dukang-h5-shop dukang-h5-partner
|
||||
echo "==> 5. 重启 PM2 ($ECOSYSTEM_FILE)"
|
||||
if pm2 describe "$PM2_API" &>/dev/null; then
|
||||
pm2 delete "$PM2_USER" 2>/dev/null || true
|
||||
pm2 start "$DEPLOY_DIR/$ECOSYSTEM_FILE" --only "$PM2_USER"
|
||||
pm2 restart "$PM2_API" "$PM2_SHOP" "$PM2_PARTNER" "$PM2_ADMIN" 2>/dev/null \
|
||||
|| pm2 restart "$PM2_API" "$PM2_SHOP" "$PM2_PARTNER"
|
||||
else
|
||||
pm2 start "$DEPLOY_DIR/ecosystem.config.cjs"
|
||||
pm2 start "$DEPLOY_DIR/$ECOSYSTEM_FILE"
|
||||
fi
|
||||
pm2 save
|
||||
|
||||
echo "==> 6. 健康检查"
|
||||
sleep 2
|
||||
pm2 list
|
||||
ss -tlnp | grep -E '809[0-4]' || true
|
||||
curl -sf -o /dev/null -w "mini-user(h5): %{http_code}\n" http://127.0.0.1:8091/ || echo "mini-user(h5): FAIL"
|
||||
curl -sf -o /dev/null -w "api: %{http_code}\n" http://127.0.0.1:8090/api/v1/health 2>/dev/null \
|
||||
|| curl -sf -o /dev/null -w "api: %{http_code}\n" http://127.0.0.1:8090/ \
|
||||
ss -tlnp | grep -E "$PORT_GREP" || true
|
||||
curl -sf -o /dev/null -w "mini-user(h5): %{http_code}\n" "http://127.0.0.1:${USER_PORT}/" || echo "mini-user(h5): FAIL"
|
||||
curl -sf -o /dev/null -w "api: %{http_code}\n" "http://127.0.0.1:${API_PORT}/api/v1/health" 2>/dev/null \
|
||||
|| curl -sf -o /dev/null -w "api: %{http_code}\n" "http://127.0.0.1:${API_PORT}/" \
|
||||
|| echo "api: FAIL"
|
||||
|
||||
echo "==> 7. 记录系统版本"
|
||||
cd "$APP_ROOT/server/dukang-api"
|
||||
APP_ROOT="$APP_ROOT" DEPLOY_TRIGGER="${DEPLOY_TRIGGER:-manual}" \
|
||||
APP_ROOT="$APP_ROOT" DEPLOY_TRIGGER="${DEPLOY_TRIGGER:-manual}" DUKANG_ENV_FILE="$ENV_FILE_NAME" \
|
||||
node scripts/with-api-env.cjs node scripts/record-system-version.cjs \
|
||||
|| echo "WARN: system_version 写入失败"
|
||||
|
||||
echo "==> 发版完成"
|
||||
echo "==> 发版完成 ($DUKANG_DEPLOY_ENV)"
|
||||
|
||||
Reference in New Issue
Block a user