games-development-ai/deploy/prepare-staging-rc.sh

161 lines
6.6 KiB
Bash
Executable File
Raw 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
# 在 mini-desktop 的全新目录准备一个 commit-pinned staging RC。
# 本脚本只克隆、构建和留证,不切换 current、不停止或启动任何服务。
set -euo pipefail
RC_COMMIT="${RC_COMMIT:-}"
RC_HOST="${RC_HOST:-root@100.64.0.7}"
RC_ROOT="${RC_ROOT:-/root/game-staging/releases}"
RC_REPO_URL="${RC_REPO_URL:-$(git remote get-url origin 2>/dev/null || true)}"
if [[ ! "$RC_COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
printf 'RC_COMMIT 必须是完整 40 位小写提交哈希。\n' >&2
exit 2
fi
if [ -z "$RC_REPO_URL" ]; then
printf '无法解析仓库地址,请显式设置 RC_REPO_URL。\n' >&2
exit 2
fi
printf '准备 staging RC:host=%s commit=%s\n' "$RC_HOST" "$RC_COMMIT"
printf '注意:只构建候选,不切流、不起服。\n'
# 参数经 bash 位置参数传入;远端脚本使用单引号 heredoc,避免本机提前展开。
ssh -o ProxyCommand=none "$RC_HOST" bash -s -- "$RC_COMMIT" "$RC_ROOT" "$RC_REPO_URL" <<'REMOTE_SCRIPT'
set -euo pipefail
commit="$1"
root="$2"
repo_url="$3"
release="$root/$commit"
evidence="$release/evidence"
status_file="$release/RC_STATUS"
if [ -e "$release" ]; then
printf '拒绝复用既有 RC 目录:%s\n' "$release" >&2
exit 3
fi
mkdir -p "$root"
umask 077
git clone --no-checkout "$repo_url" "$release"
printf 'preparing\n' >"$status_file"
on_error() {
code=$?
printf 'failed exit=%s at=%s\n' "$code" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$status_file"
printf 'RC 准备失败,现场保留用于排障:%s\n' "$release" >&2
exit "$code"
}
trap on_error ERR
cd "$release"
git fetch --no-tags origin "$commit"
git checkout --detach "$commit"
actual="$(git rev-parse HEAD)"
[ "$actual" = "$commit" ] || { printf '提交不一致:expected=%s actual=%s\n' "$commit" "$actual" >&2; exit 4; }
[ -z "$(git status --porcelain --untracked-files=no)" ] || { printf '新检出存在 tracked 脏改动,拒绝构建。\n' >&2; exit 4; }
mkdir -p "$evidence"
previous="none"
if [ -L "$root/active" ]; then
previous="$(readlink -f "$root/active" || true)"
[ -n "$previous" ] || previous="broken-active-symlink"
elif [ -L "$root/current" ]; then
# 兼容 active 指针启用前的旧部署;新激活脚本只维护 canonical active。
previous="$(readlink -f "$root/current" || true)"
[ -n "$previous" ] || previous="broken-current-symlink"
fi
printf '%s\n' "$previous" >"$evidence/rollback-target.txt"
# 配置只记录来源、文件哈希和键名,绝不复制或输出密钥值。
{
printf 'captured_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
printf 'rc_commit=%s\n' "$commit"
printf 'previous_release=%s\n' "$previous"
if [ -f /root/huijing-dev.env ]; then
printf 'huijing_dev_env_sha256=%s\n' "$(sha256sum /root/huijing-dev.env | awk '{print $1}')"
printf 'huijing_dev_env_keys='
awk -F= '/^[A-Za-z_][A-Za-z0-9_]*=/{print $1}' /root/huijing-dev.env | sort | paste -sd, -
else
printf 'huijing_dev_env=missing\n'
fi
printf 'backend_staging_yaml_sha256=%s\n' "$(sha256sum game-cloud/huijing-server/src/main/resources/application-staging.yaml | awk '{print $1}')"
printf 'studio_staging_env_sha256=%s\n' "$(sha256sum game-studio/.env.staging | awk '{print $1}')"
printf 'admin_stage_env_sha256=%s\n' "$(sha256sum game-admin/.env.stage | awk '{print $1}')"
} >"$evidence/config-snapshot.txt"
printf '[1/6] 构建 Java 后端(跳过全量后端测试)\n'
(cd game-cloud && mvn clean install -pl huijing-server -am -DskipTests)
printf '[2/6] 构建 game-studio staging\n'
(cd game-studio && npm ci && npm run build -- --mode staging)
printf '[3/6] 构建 game-admin stage\n'
corepack prepare pnpm@9.15.4 --activate
(cd game-admin && pnpm install --frozen-lockfile && pnpm build:stage)
printf '[4/6] 准备 commit 内独立 Python 虚拟环境\n'
UV_BIN="${UV_BIN:-/root/.local/bin/uv}"
[ -x "$UV_BIN" ] || { printf '缺少 uv:%s\n' "$UV_BIN" >&2; exit 5; }
(cd cheap-worker && "$UV_BIN" venv .venv && "$UV_BIN" pip install --python .venv/bin/python -r requirements.txt)
(cd tier2/gen-worker && "$UV_BIN" venv .venv && "$UV_BIN" pip install --python .venv/bin/python -r requirements.txt)
printf '[5/6] 运行发布工具回归测试\n'
release_tool_tests=(
deploy/tests/test-staging-rc.sh
deploy/tests/test-provision-dogfood-users.sh
deploy/tests/test-provision-dogfood-nacos-transaction.sh
deploy/tests/test-import-newapi-pool.sh
)
(
export PATH="$release/cheap-worker/.venv/bin:$PATH"
for test_script in "${release_tool_tests[@]}"; do
printf 'RUN %s\n' "$test_script"
bash "$test_script"
done
printf 'RUN game-runtime/tools/test_newapi_pool_provision.py\n'
python3 -m unittest game-runtime/tools/test_newapi_pool_provision.py
printf 'RELEASE_TOOL_TESTS_PASS shell=%s python=1\n' "${#release_tool_tests[@]}"
) >"$evidence/release-tool-tests.log" 2>&1
printf '[6/6] 记录制品与启动坐标\n'
{
printf 'backend_jar=%s/game-cloud/huijing-server/target/huijing-server.jar\n' "$release"
printf 'studio_dist=%s/game-studio/dist\n' "$release"
printf 'admin_dist=%s/game-admin/dist-stage\n' "$release"
printf 'cheap_agent_python=%s/cheap-worker/.venv/bin/python\n' "$release"
printf 'cheap_agent_entry=%s/cheap-worker/cheap_service_app.py\n' "$release"
printf 'cheap_worker_entry=%s/cheap-worker/worker_service.py\n' "$release"
printf 'tier2_python=%s/tier2/gen-worker/.venv/bin/python\n' "$release"
printf 'tier2_entry=%s/tier2/gen-worker/service/app.py\n' "$release"
} >"$evidence/artifact-paths.env"
{
sha256sum game-cloud/huijing-server/target/huijing-server.jar
find game-studio/dist game-admin/dist-stage -type f -print0 | sort -z | xargs -0 sha256sum
} >"$evidence/artifacts.sha256"
{
printf 'schema=staging-rc-prepare-verification/1\n'
printf 'rc_commit=%s\n' "$commit"
printf 'release_tool_shell_tests=PASS\n'
printf 'release_tool_shell_test_count=%s\n' "${#release_tool_tests[@]}"
printf 'newapi_pool_python_tests=PASS\n'
printf 'backend_build=PASS\n'
printf 'backend_tests=NOT_RUN\n'
printf 'backend_tests_reason=maven_build_used_DskipTests\n'
printf 'studio_build=PASS\n'
printf 'admin_build=PASS\n'
} >"$evidence/verification-summary.txt"
[ -z "$(git status --porcelain --untracked-files=no)" ] || { printf '构建修改了 tracked 文件,拒绝将其标为 ready。\n' >&2; exit 6; }
printf 'ready commit=%s built_at=%s\n' "$commit" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$status_file"
chmod -R go-rwx "$evidence" "$status_file"
trap - ERR
printf 'RC_PREPARE_PASS release=%s\n' "$release"
printf 'rollback_target=%s\n' "$previous"
printf '下一步由统一部署窗口读取 evidence/artifact-paths.env,探活通过后再原子切换 current。\n'
REMOTE_SCRIPT