Files
backend_v2/scripts/push-build.sh

122 lines
5.0 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# 本地构建 + 上传 + 远程发布(前后端都走预构建,服务器不编译)
#
# SERVER=user@server ./scripts/push-build.sh
# SERVER=user@server REMOTE_DIR=/opt/fashion WEB_DIR=../test ./scripts/push-build.sh
#
# 流程:
# 1. 建 SSH 隧道(本地 18091 → 服务器回环 18091):前端构建期靠它读线上 SSG 数据
# 2. 本机 npm run build → 静态页内容与线上数据一致,且不占服务器资源
# 3. 本机交叉编译 linux/amd64 → 产出 server-linux-amd64
# 4. 上传 dist/ 与二进制
# 5. 远程 ./deploy.sh all --prebuilt → 服务器只打镜像 + 蓝绿切换
set -euo pipefail
cd "$(dirname "$0")/.." # 后端仓根
SERVER="${SERVER:-}"
if [ -z "$SERVER" ]; then
echo "用法: SERVER=user@host ./scripts/push-build.sh"
echo ""
echo "可选环境变量:"
echo " REMOTE_DIR 服务器上的项目根(默认 /opt/fashion)"
echo " WEB_DIR 本地前端仓(默认 ../test)"
echo " SSH_OPTS 额外 ssh 参数(默认 -o ConnectTimeout=10)"
exit 1
fi
REMOTE_DIR="${REMOTE_DIR:-/opt/fashion}"
REMOTE_BACKEND="${REMOTE_BACKEND:-${REMOTE_DIR}/backend_v2}"
REMOTE_FRONTEND="${REMOTE_FRONTEND:-${REMOTE_DIR}/frontend_v2}"
WEB_DIR="${WEB_DIR:-../frontend_v2}"
SSH_OPTS="${SSH_OPTS:--o ConnectTimeout=10}"
TUNNEL_PORT="${TUNNEL_PORT:-18091}"
# 本机也放一份 .env(复制服务器那份即可),用于取 SSG_TOKEN 等构建期密钥
SSG_TOKEN="${SSG_TOKEN:-}"
if [ -f .env ]; then
# shellcheck disable=SC1091
set -a; . ./.env; set +a
fi
# Git Bash 的 $HOME 常是 /home/<user>,而 Windows 上生成的密钥在 C:\Users\<user>\.ssh 下。
# 这里自动兜底,避免在 Git Bash 里 ssh 找不到私钥而报 publickey denied。
if [ -z "${SSH_KEY:-}" ]; then
# Windows 用户目录优先:Git Bash 的 $HOME 下可能还躺着一把无关的旧钥匙
for cand in "/c/Users/${USERNAME:-}/.ssh/id_ed25519" "${USERPROFILE:-}/.ssh/id_ed25519" "$HOME/.ssh/id_ed25519"; do
if [ -n "$cand" ] && [ -f "$cand" ]; then
SSH_KEY="$cand"
break
fi
done
fi
if [ -n "${SSH_KEY:-}" ]; then
SSH_OPTS="$SSH_OPTS -i $SSH_KEY"
echo " 使用私钥:$SSH_KEY"
fi
TUNNEL_PID=""
cleanup() { [ -n "$TUNNEL_PID" ] && kill "$TUNNEL_PID" 2>/dev/null || true; }
trap cleanup EXIT
echo "==> 0/5 检查 SSH 免密登录"
# 隧道是后台起的(ssh -N ... &),一旦需要交互输密码就会静默卡住,所以必须免密。
if ! ssh $SSH_OPTS -o BatchMode=yes "$SERVER" true 2>/dev/null; then
echo "!! 无法免密登录 $SERVER"
echo ""
echo " Windows(PowerShell):"
echo " ssh-keygen -t ed25519 -C deploy@local"
echo " type \$env:USERPROFILE\\.ssh\\id_ed25519.pub | ssh $SERVER \"mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys\""
echo ""
echo " Linux / macOS / WSL:"
echo " ssh-keygen -t ed25519 -C deploy@local && ssh-copy-id $SERVER"
echo ""
echo " 配好后用这条确认:ssh $SERVER true && echo ok"
exit 1
fi
echo " 通过"
# 服务器若开了 SSG_TOKEN,构建期必须带同一个值。自动从服务器 .env 取,避免本机再维护一份密钥。
if [ -z "${SSG_TOKEN:-}" ]; then
SSG_TOKEN="$(ssh $SSH_OPTS -o BatchMode=yes "$SERVER" \
"grep -m1 '^SSG_TOKEN=' '${REMOTE_BACKEND}/.env' 2>/dev/null | cut -d= -f2-" 2>/dev/null || true)"
if [ -n "$SSG_TOKEN" ]; then
echo " 已从服务器读取 SSG_TOKEN(${#SSG_TOKEN} 字符)"
else
echo " 服务器未设置 SSG_TOKEN,构建期不带 token"
fi
fi
echo "==> 1/5 建立 SSH 隧道(本地 ${TUNNEL_PORT} → ${SERVER}:127.0.0.1:18091)"
ssh -N $SSH_OPTS -o ExitOnForwardFailure=yes \
-L "${TUNNEL_PORT}:127.0.0.1:18091" "$SERVER" &
TUNNEL_PID=$!
for i in $(seq 1 15); do
if (echo > "/dev/tcp/127.0.0.1/${TUNNEL_PORT}") >/dev/null 2>&1; then
break
fi
if [ "$i" -eq 15 ]; then
echo "!! 隧道 15 秒内没建起来(检查 SSH 连通性、服务器上 proxy 是否在跑)"
exit 1
fi
sleep 1
done
echo "==> 2/5 构建前端(构建期数据来自线上)"
(cd "$WEB_DIR" && BASE_API_SSG="http://127.0.0.1:${TUNNEL_PORT}" SSG_TOKEN="$SSG_TOKEN" npm run build)
[ -f "$WEB_DIR/dist/server/entry.mjs" ] || { echo "!! 前端产物缺失:$WEB_DIR/dist/server/entry.mjs"; exit 1; }
echo "==> 3/5 交叉编译后端(linux/amd64)"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags "-s -w" -o server-linux-amd64 ./cmd/server
echo "==> 4/5 上传产物到 ${SERVER}:${REMOTE_DIR}"
ssh $SSH_OPTS "$SERVER" "mkdir -p '${REMOTE_BACKEND}' '${REMOTE_FRONTEND}'"
tar -C "$WEB_DIR" -czf - dist | ssh $SSH_OPTS "$SERVER" "tar -xzf - -C '${REMOTE_FRONTEND}'"
scp $SSH_OPTS server-linux-amd64 "${SERVER}:${REMOTE_BACKEND}/server-linux-amd64"
echo "==> 5/5 远程发布(预构建 + 蓝绿切换)"
RELEASE="$(date +%Y%m%d-%H%M%S)-$(git rev-parse --short HEAD 2>/dev/null || echo nogit)"
ssh $SSH_OPTS "$SERVER" "cd '${REMOTE_BACKEND}' && RELEASE='${RELEASE}' ./deploy.sh all --prebuilt"
echo "完成:$RELEASE"