gaoluyang
12 小时以前 062f5f120f24bee98849d7870b3a461970736404
宁夏-万通
1.发版配置文件修改
已添加1个文件
265 ■■■■■ 文件已修改
WTXC.sh 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
WTXC.sh
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,265 @@
#!/usr/bin/env bash
# ============================================================
# å®å¤ä¸‡é€šæ–°æ â€”— å‰ç«¯éƒ¨ç½²è„šæœ¬ï¼ˆmacOS / Linux ç‰ˆï¼‰
# å¯¹åº”仓库里的 WTXC.bat,只适用于本分支(万通新材)。
#
#   ./WTXC.sh                 # æž„建 + ä¸Šä¼  + è§£åŽ‹ï¼ˆç­‰ä»·äºŽ WTXC.bat)
#   ./WTXC.sh --dry-run       # åªæž„建和本地检查,不连服务器、不上传
#   ./WTXC.sh --skip-build    # ä¸æž„建,直接上传当前目录已有的 dist.zip
#
# æµç¨‹ä¸Ž WTXC.bat å®Œå…¨ä¸€è‡´ï¼špnpm build(带 VITE_COMPANY=WTXC)→ ç”Ÿæˆ dist.zip
#   â†’ scp ä¸Šä¼ åˆ° <远端目录>/.dist.zip.uploading â†’ æ ¡éªŒå¤§å° â†’ æ”¹å
#   â†’ unzip -t æ ¡éªŒ â†’ unzip -o è§£åŽ‹ â†’ åˆ é™¤è¿œç«¯ zip
#
# éƒ¨ç½²ç›®æ ‡ï¼šroot@42.63.71.140:/home/vue/dist
#
# çŽ¯å¢ƒå˜é‡è¦†ç›–ï¼šDEPLOY_PASSWORD、DEPLOY_HOST、DEPLOY_DIR、DEPLOY_PORT
#   ï¼ˆæ”¹å¯†ç æˆ–临时指到别的目录时用,避免把密码写进命令行历史)
#
# è¯´æ˜Žï¼šWTXC.bat èµ°çš„æ˜¯ bin\sshpass.exe(Windows ä¸“用)。macOS ä¸Šæ²¡æœ‰ sshpass
#   æ—¶æœ¬è„šæœ¬è‡ªåŠ¨æ”¹ç”¨ç³»ç»Ÿè‡ªå¸¦çš„ expect é€å¯†ç ï¼Œå› æ­¤æ— éœ€é¢å¤–安装;若已装
#   sshpass(brew install hudochenkov/sshpass/sshpass)则优先使用它。
# ============================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# ------------------------------------------------------------------
# 1. å‚数与目标配置(对应 WTXC.bat é¡¶éƒ¨çš„ Configuration æ®µï¼‰
# ------------------------------------------------------------------
SKIP_BUILD=0
DRY_RUN=0
for arg in "$@"; do
  case "$arg" in
    --skip-build) SKIP_BUILD=1 ;;
    --dry-run) DRY_RUN=1 ;;
    -h | --help)
      # æ‰“印文件头部的注释说明(第一行 shebang ä¹‹åŽåˆ° set ä¹‹å‰ï¼‰
      awk 'NR == 1 { next } /^set / { exit } { print }' "${BASH_SOURCE[0]}"
      exit 0
      ;;
    *)
      echo "[ERROR] æœªçŸ¥å‚数:${arg}(可用:--skip-build / --dry-run / -h)" >&2
      exit 1
      ;;
  esac
done
COMPANY="WTXC"
EXPECT_BRANCH="dev_宁夏_万通新材料"
REMOTE_USER="root"
REMOTE_HOST="42.63.71.140"
PORT="22"
PASSWORD="Nxwtxc123."
REMOTE_DIR="/home/vue/dist"
ZIP_FILE="dist.zip"
# å…è®¸ç”¨çŽ¯å¢ƒå˜é‡è¦†ç›–
REMOTE_HOST="${DEPLOY_HOST:-$REMOTE_HOST}"
REMOTE_DIR="${DEPLOY_DIR:-$REMOTE_DIR}"
PASSWORD="${DEPLOY_PASSWORD:-$PASSWORD}"
PORT="${DEPLOY_PORT:-$PORT}"
SSH_OPTS=(-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -o NumberOfPasswordPrompts=1)
# ------------------------------------------------------------------
# 2. å‰ç½®æ£€æŸ¥ï¼šåªèƒ½åœ¨æœ¬å®¢æˆ·åˆ†æ”¯ä¸Šæž„建部署
#    åŒ…里写死了万通的名称/Logo/接口地址,用别的分支构建会把别客户的前端传上来。
# ------------------------------------------------------------------
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo '')"
if [ -n "$CURRENT_BRANCH" ] && [ "$CURRENT_BRANCH" != "$EXPECT_BRANCH" ]; then
  if [ "${ALLOW_BRANCH_MISMATCH:-0}" != "1" ]; then
    echo "[ERROR] å½“前分支是 ${CURRENT_BRANCH},不是万通分支 ${EXPECT_BRANCH}。" >&2
    echo "        æœ¬è„šæœ¬ä¼šæŠŠæž„å»ºç»“æžœéƒ¨ç½²åˆ°ä¸‡é€šç”Ÿäº§æœåŠ¡å™¨ï¼Œè¯·å…ˆåˆ‡å›žä¸‡é€šåˆ†æ”¯ï¼š" >&2
    echo "        git checkout ${EXPECT_BRANCH}" >&2
    echo "        ç¡®å®žè¦åœ¨è¯¥åˆ†æ”¯ä¸Šéƒ¨ç½²æ—¶ï¼Œå¯åŠ  ALLOW_BRANCH_MISMATCH=1 è·³è¿‡æ­¤æ ¡éªŒã€‚" >&2
    exit 1
  fi
  echo "[WARN] åˆ†æ”¯ä¸æ˜¯ ${EXPECT_BRANCH}(当前 ${CURRENT_BRANCH}),按 ALLOW_BRANCH_MISMATCH=1 ç»§ç»­ã€‚" >&2
fi
echo
echo "============================================================"
echo "         Vue Dist Auto Deploy (万通新材 / macOS)"
echo "============================================================"
echo
echo "Company    : $COMPANY"
echo "Server     : $REMOTE_USER@$REMOTE_HOST:$PORT"
echo "Remote Dir : $REMOTE_DIR"
echo "Package    : $ZIP_FILE"
if [ -n "$(git status --porcelain 2>/dev/null || true)" ]; then
  echo "Git        : âš  å·¥ä½œåŒºæœ‰æœªæäº¤æ”¹åŠ¨ï¼ˆéƒ¨ç½²çš„æ˜¯å·¥ä½œåŒºå†…å®¹ï¼Œä¸æ˜¯æäº¤å†…å®¹ï¼‰"
else
  echo "Git        : ${CURRENT_BRANCH} @ $(git rev-parse --short HEAD 2>/dev/null || echo '-')"
fi
echo
# ------------------------------------------------------------------
# 3. ä¾èµ–检查(对应 WTXC.bat çš„ [1/7]~[3/7])
# ------------------------------------------------------------------
echo "[1/4] æ£€æŸ¥ pnpm / node ..."
command -v pnpm >/dev/null 2>&1 || {
  echo "[ERROR] æ‰¾ä¸åˆ° pnpm,请先 npm install -g pnpm" >&2
  exit 1
}
command -v node >/dev/null 2>&1 || {
  echo "[ERROR] æ‰¾ä¸åˆ° node" >&2
  exit 1
}
echo "      pnpm $(pnpm --version) / node $(node --version)"
if [ ! -d node_modules ]; then
  echo "[INFO] node_modules ä¸å­˜åœ¨ï¼Œæ‰§è¡Œ pnpm install ..."
  pnpm install
else
  echo "      node_modules å·²å­˜åœ¨"
fi
# ------------------------------------------------------------------
# 4. æž„建(对应 WTXC.bat çš„ [4/7])
#    æ³¨æ„ï¼šarchiver æ’件是在 closeBundle é‡Œå¼‚步写 dist.zip,
#    æ‰€ä»¥æž„建完要等它落地;同时先删掉旧 zip,避免把旧包当新包传上去。
#    é»˜è®¤æ¯æ¬¡é‡æ–°æž„建(WTXC.bat ä¹Ÿæ˜¯å¦‚此),只有显式 --skip-build æ‰å¤ç”¨æ—§åŒ…。
# ------------------------------------------------------------------
if [ "$SKIP_BUILD" -eq 0 ]; then
  echo
  echo "[2/4] æž„建中(VITE_COMPANY=${COMPANY},pnpm run build)..."
  rm -f "$ZIP_FILE"
  VITE_COMPANY="$COMPANY" pnpm run build
  for _ in $(seq 1 30); do
    [ -f "$ZIP_FILE" ] && break
    sleep 1
  done
else
  echo
  echo "[2/4] è·³è¿‡æž„建(--skip-build),复用已有的 ${ZIP_FILE}"
  echo "[WARN] è¯·ç¡®è®¤è¯¥åŒ…就是用 VITE_COMPANY=${COMPANY} æž„建的:" >&2
  echo "       åŒ…里已写死客户的名称/Logo/接口地址,用错包会把别客户的前端传到本服务器。" >&2
fi
if [ ! -f "$ZIP_FILE" ]; then
  echo "[ERROR] æž„建结束但没有生成 $ZIP_FILE" >&2
  exit 1
fi
ZIP_BYTES="$(wc -c < "$ZIP_FILE" | tr -d ' ')"
echo "[OK] æ‰“包完成:${ZIP_FILE}(${ZIP_BYTES} å­—节)"
if [ "$DRY_RUN" -eq 1 ]; then
  echo "[INFO] --dry-run:本地检查通过,未连服务器、未上传。"
  exit 0
fi
# ------------------------------------------------------------------
# 5. è¿œç«¯æ“ä½œï¼ˆå¯¹åº” WTXC.bat çš„ [6/7][7/7])
# ------------------------------------------------------------------
EXPECT_HELPER="$(mktemp -t wtxc-sshpass)"
cleanup() { rm -f "$EXPECT_HELPER"; }
trap cleanup EXIT
cat > "$EXPECT_HELPER" <<'EXPECT'
#!/usr/bin/expect -f
# ç”¨æ³•: sshpass-helper <password> <command...>
set timeout 3600
set pw  [lindex $argv 0]
set cmd [lrange $argv 1 end]
eval spawn -noecho $cmd
expect {
  -re "(?i)are you sure you want to continue connecting" { send "yes\r"; exp_continue }
  -re "(?i)password:"                                   { send "$pw\r"; exp_continue }
  -re "(?i)permission denied"                           { exit 5 }
  # è¶…时必须显式退出,否则 expect ä¼šæŒ‚在后面的 wait ä¸Šä¸è¿”回
  timeout                                               { puts stderr "SSH è¶…æ—¶"; exit 9 }
  eof
}
catch wait result
exit [lindex $result 3]
EXPECT
chmod +x "$EXPECT_HELPER"
HAS_SSHPASS=0
command -v sshpass >/dev/null 2>&1 && HAS_SSHPASS=1
if [ "$HAS_SSHPASS" -eq 0 ] && ! command -v expect >/dev/null 2>&1; then
  echo "[ERROR] æ—¢æ²¡æœ‰ sshpass ä¹Ÿæ²¡æœ‰ expect,无法在脚本里自动送密码。" >&2
  echo "        å¯æ‰§è¡Œï¼šbrew install hudochenkov/sshpass/sshpass,或手工 scp ä¸Šä¼ ã€‚" >&2
  exit 1
fi
# åœ¨è¿œç«¯æ‰§è¡Œå‘½ä»¤ï¼Œè¿”回其退出码;stdout ç”±è°ƒç”¨æ–¹æ•获(失败时输出打到 stderr)
remote_run() {
  local out rc=0
  if [ "$HAS_SSHPASS" -eq 1 ]; then
    out="$(SSHPASS="$PASSWORD" sshpass -e ssh -p "$PORT" "${SSH_OPTS[@]}" "$REMOTE_USER@$REMOTE_HOST" "$1" 2>&1)" || rc=$?
  else
    out="$("$EXPECT_HELPER" "$PASSWORD" ssh -p "$PORT" "${SSH_OPTS[@]}" "$REMOTE_USER@$REMOTE_HOST" "$1" 2>&1)" || rc=$?
  fi
  if [ "$rc" -ne 0 ]; then
    echo "[ERROR] è¿œç«¯å‘½ä»¤æ‰§è¡Œå¤±è´¥ï¼ˆexit $rc):$1" >&2
    [ -n "$out" ] && printf '%s\n' "$out" >&2
  fi
  printf '%s' "$out"
  return "$rc"
}
# ä¸Šä¼ ä¸€ä¸ªæ–‡ä»¶ï¼šremote_copy <本地文件> <远端绝对路径>(保留进度条)
remote_copy() {
  if [ "$HAS_SSHPASS" -eq 1 ]; then
    SSHPASS="$PASSWORD" sshpass -e scp -P "$PORT" "${SSH_OPTS[@]}" "$1" "$REMOTE_USER@$REMOTE_HOST:$2"
  else
    "$EXPECT_HELPER" "$PASSWORD" scp -P "$PORT" "${SSH_OPTS[@]}" "$1" "$REMOTE_USER@$REMOTE_HOST:$2"
  fi
}
echo
echo "[3/4] è¿žæŽ¥æœåС噍 ..."
remote_run "echo SSH_OK" >/dev/null
echo "[OK] SSH è¿žæŽ¥æˆåŠŸ"
remote_run "mkdir -p '$REMOTE_DIR'" >/dev/null
echo "[OK] è¿œç«¯ç›®å½•就绪"
REMOTE_TMP="$REMOTE_DIR/.dist.zip.uploading"
echo
echo "[4/4] ä¸Šä¼ å¹¶è§£åŽ‹ ..."
remote_run "rm -f '$REMOTE_TMP'" >/dev/null
remote_copy "$ZIP_FILE" "$REMOTE_TMP"
echo "[OK] ä¸Šä¼ å®Œæˆ"
# è¿œç«¯å‘½ä»¤çš„输出里会混有 expect å›žæ˜¾çš„密码提示,命令本身的 stdout æ€»åœ¨æœ€åŽï¼Œ
# å–最后一个字段即为所需数值(stat çš„ stderr ä¹Ÿä¼šèµ°åˆ°è¿™é‡Œï¼Œæ•…再做一次空值判断)。
REMOTE_BYTES="$(remote_run "stat -c %s '$REMOTE_TMP'" | tr -d '\r' | awk 'END { print $NF }')"
REMOTE_BYTES="$(printf '%s' "$REMOTE_BYTES" | tr -cd '0-9')"
if [ -z "$REMOTE_BYTES" ] || [ "$REMOTE_BYTES" != "$ZIP_BYTES" ]; then
  echo "[ERROR] è¿œç«¯æ–‡ä»¶å¤§å°($REMOTE_BYTES)与本地($ZIP_BYTES)不一致,已中止;远端临时文件保留在 $REMOTE_TMP" >&2
  exit 1
fi
echo "[OK] å¤§å°æ ¡éªŒä¸€è‡´ï¼ˆ$REMOTE_BYTES å­—节)"
remote_run "mv -f '$REMOTE_TMP' '$REMOTE_DIR/$ZIP_FILE'" >/dev/null
echo "[OK] åŒ…已就位"
remote_run "command -v unzip" >/dev/null || {
  echo "[ERROR] è¿œç«¯æ²¡æœ‰ unzip:CentOS ç”¨ yum install -y unzip / Ubuntu ç”¨ apt install -y unzip" >&2
  exit 1
}
remote_run "cd '$REMOTE_DIR' && unzip -tq '$ZIP_FILE'" >/dev/null
echo "[OK] è¿œç«¯ zip æ ¡éªŒé€šè¿‡"
remote_run "cd '$REMOTE_DIR' && unzip -oq '$ZIP_FILE'" >/dev/null
echo "[OK] è§£åŽ‹å®Œæˆ"
remote_run "rm -f '$REMOTE_DIR/$ZIP_FILE'" >/dev/null || echo "[WARN] è¿œç«¯ zip åˆ é™¤å¤±è´¥ï¼ˆä¸å½±å“ä½¿ç”¨ï¼‰"
echo
echo "============================================================"
echo "                 DEPLOY SUCCESS"
echo "============================================================"
echo "Company    : $COMPANY"
echo "Server     : $REMOTE_HOST:$PORT"
echo "Remote Dir : $REMOTE_DIR"
echo "Package    : ${ZIP_FILE}(${ZIP_BYTES} å­—节)"
echo "提示:前端是静态资源,浏览器 Ctrl/Cmd+Shift+R å¼ºåˆ·åŽå†éªŒè¯ã€‚"
echo