74 lines
3.0 KiB
Bash
Executable File
74 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
APP_DIR=/server/web_91dj/h5
|
|
APP_NAME=web_91dj_h5
|
|
ARCHIVE="$APP_DIR/web_91dj_h5.tar.gz"
|
|
CURRENT="$APP_DIR/next"
|
|
RELEASES="$APP_DIR/releases"
|
|
NODE=/root/.nvm/versions/node/v22.22.3/bin/node
|
|
PM2=/root/.nvm/versions/node/v22.22.3/bin/pm2
|
|
NPM=/usr/bin/npm
|
|
PORT=21021
|
|
export PATH=/root/.nvm/versions/node/v22.22.3/bin:$PATH
|
|
STAGING=''
|
|
PREVIOUS=''
|
|
ACTIVATED=0
|
|
WAS_RUNNING=0
|
|
|
|
fail() { echo "发布失败:$*" >&2; exit 1; }
|
|
cleanup() {
|
|
result=$?
|
|
trap - EXIT INT TERM
|
|
if [ "$result" -ne 0 ] && [ "$ACTIVATED" -eq 1 ]; then
|
|
echo '发布失败,正在恢复上一版本…' >&2
|
|
"$PM2" delete "$APP_NAME" >/dev/null 2>&1 || true
|
|
[ -d "$CURRENT" ] && mv "$CURRENT" "$RELEASES/failed.$(date +%Y%m%d%H%M%S)" || true
|
|
if [ -n "$PREVIOUS" ] && [ -d "$PREVIOUS" ]; then
|
|
mv "$PREVIOUS" "$CURRENT"
|
|
[ "$WAS_RUNNING" -eq 1 ] && "$PM2" start "$CURRENT/start.mjs" --name "$APP_NAME" --interpreter "$NODE" >/dev/null 2>&1 || true
|
|
fi
|
|
fi
|
|
[ -n "$STAGING" ] && [ -d "$STAGING" ] && rm -rf "$STAGING"
|
|
exit "$result"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
[ -s "$ARCHIVE" ] || fail "未找到运行包:$ARCHIVE"
|
|
for tool in tar "$NODE" "$NPM" "$PM2"; do command -v "$tool" >/dev/null 2>&1 || fail "缺少命令:$tool"; done
|
|
"$NODE" -e 'const [a,b]=process.versions.node.split(".").map(Number);process.exit(a>20||a===20&&b>=9?0:1)' || fail '需要 Node.js >=20.9'
|
|
mkdir -p "$RELEASES"
|
|
while IFS= read -r entry; do
|
|
case "$entry" in
|
|
/*|../*|*/../*|*/..|*\\*) fail "运行包含非法路径:$entry" ;;
|
|
esac
|
|
done < <(/bin/tar -tzf "$ARCHIVE")
|
|
STAGING=$(mktemp -d "$APP_DIR/.release.XXXXXX")
|
|
/bin/tar -xzf "$ARCHIVE" -C "$STAGING" --no-same-owner
|
|
for file in start.mjs server.js package.json package-lock.json scripts/next-env.mjs scripts/check-health.mjs .next-test/BUILD_ID config/test.env; do
|
|
[ -s "$STAGING/$file" ] || fail "运行包缺少:$file"
|
|
done
|
|
[ -d "$STAGING/.next-test/static" ] && [ -d "$STAGING/public" ] || fail '运行包缺少 Next 静态资源'
|
|
(cd "$STAGING" && "$NPM" ci --omit=dev --no-audit --no-fund)
|
|
(cd "$STAGING" && "$NODE" -e 'for (const n of ["next","react","react-dom"]) require.resolve(n)') >/dev/null 2>&1 || fail '运行依赖校验失败'
|
|
if [ -f "$CURRENT/config/test.local.env" ] && [ ! -L "$CURRENT/config/test.local.env" ]; then
|
|
mkdir -p "$STAGING/config"
|
|
cp "$CURRENT/config/test.local.env" "$STAGING/config/test.local.env"
|
|
chmod 600 "$STAGING/config/test.local.env"
|
|
fi
|
|
if "$PM2" jlist 2>/dev/null | grep -q "\"name\":\"$APP_NAME\""; then WAS_RUNNING=1; fi
|
|
"$PM2" delete "$APP_NAME" >/dev/null 2>&1 || true
|
|
if [ -d "$CURRENT" ]; then
|
|
PREVIOUS="$RELEASES/next.$(date +%Y%m%d%H%M%S)"
|
|
mv "$CURRENT" "$PREVIOUS"
|
|
fi
|
|
mv "$STAGING" "$CURRENT"; STAGING=''; ACTIVATED=1
|
|
"$PM2" start "$CURRENT/start.mjs" --name "$APP_NAME" --interpreter "$NODE"
|
|
"$NODE" "$CURRENT/scripts/check-health.mjs" "http://127.0.0.1:$PORT" test
|
|
"$PM2" save
|
|
timestamp=$(date +%Y%m%d%H%M%S)
|
|
mv "$ARCHIVE" "$RELEASES/web_91dj_h5.$timestamp.tar.gz"
|
|
echo "发布完成:$APP_NAME;上一版本:${PREVIOUS:-无}"
|