diff --git a/AGENTS.md b/AGENTS.md index 98b8bec0..d22b97bc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -64,6 +64,7 @@ ## 8. 构建与生产部署 +- 发布脚本会拒绝覆盖“不在本次版本里”的线上提交(防止互相冲掉已上线的改动)。热修复必须基于线上当前版本构建,发布后立即合入 `main`;遇到拦截先 `git fetch` 并合入最新 `main` 或线上热修复分支,不得随手加 `-AllowRollback`(`--allow-rollback`),撤回线上发布需负责人明确决定。 - 普通代码发布由任务 Codex 在完成验证与合并后直接执行,不要求用户再次说“部署、上线”;用户明确要求仅本地开发、仅审查或暂不上线时遵循其范围。正式发布只使用已合并的最新 `main`。 - Windows 开发机统一使用 `scripts/deploy-from-workstation.ps1`,macOS 开发机使用 `bash scripts/deploy-from-mac.sh`;两者流程一致(本机构建前端与镜像、迁移拦截、增量推送服务器本机 Registry、激活与健康检查、双版本保留)。服务器只运行开发机已构建的 `caiwu_akaunting:` 镜像,禁止在服务器执行 Composer、npm 或 Docker 构建。 - 新人只需表达部署需求;Codex 使用默认生产入口运行脚本。首次通过本机窗口提供一次服务器密码后,加密保存在本人电脑供后续自动使用,不要求新人准备私钥、执行命令或每次重输密码。已有私钥认证仍兼容。 diff --git a/scripts/deploy-from-mac.sh b/scripts/deploy-from-mac.sh index bc546618..9d9c37bb 100755 --- a/scripts/deploy-from-mac.sh +++ b/scripts/deploy-from-mac.sh @@ -17,6 +17,7 @@ # --configure-dingtalk-callback # --allow-non-main 允许非 main 分支(测试用) # --allow-migrations 允许执行待办数据库迁移(需先按 AGENTS.md 核对) +# --allow-rollback 允许覆盖不在本次版本里的线上提交(仅负责人决定撤回时使用) # --skip-regctl 跳过 regctl,直接用 docker 直传镜像 # --keep-images <数量> 默认 2 # --app-version <版本> 默认 3.1.15 @@ -45,6 +46,7 @@ bootstrap_server=0 configure_dingtalk_callback=0 allow_non_main=0 allow_migrations=0 +allow_rollback=0 skip_regctl=0 app_version='3.1.15' # 国内网络访问 GitHub 受限时,composer 的 GitHub dist 会失败;默认走腾讯云镜像。 @@ -71,6 +73,7 @@ while [ "$#" -gt 0 ]; do --configure-dingtalk-callback) configure_dingtalk_callback=1 ;; --allow-non-main) allow_non_main=1 ;; --allow-migrations) allow_migrations=1 ;; + --allow-rollback) allow_rollback=1 ;; --skip-regctl) skip_regctl=1 ;; -h|--help) sed -n '2,20p' "$0"; exit 0 ;; *) echo "未知参数:$1" >&2; exit 2 ;; @@ -505,7 +508,23 @@ if [ -n "$previous_sha" ]; then if git cat-file -e "${previous_sha}^{commit}" 2>/dev/null; then previous_sha_exists=1 else - previous_sha_exists=0 + # 线上可能是别人刚发的热修复分支,先拉取再判断。 + git fetch origin --quiet 2>/dev/null || true + if git cat-file -e "${previous_sha}^{commit}" 2>/dev/null; then + previous_sha_exists=1 + else + previous_sha_exists=0 + fi + fi + + # 防覆盖:线上当前版本必须包含在本次要发布的版本里,否则会撤掉别人已上线的改动。 + if [ "$allow_rollback" -eq 0 ]; then + if [ "$previous_sha_exists" -eq 0 ]; then + fail "线上当前版本 ${previous_sha} 在本地和 origin 都找不到(可能是未推送的分支),发布会把它覆盖。请让发布人先推送并合并进 main;确需撤回时显式添加 --allow-rollback。" + fi + if ! git merge-base --is-ancestor "$previous_sha" "$deploy_sha"; then + fail "线上当前版本($(git log -1 --format='%h %an %ad %s' --date=format:'%m-%d %H:%M' "$previous_sha"))不在本次发布的版本里,继续发布会把它及之后别人上线的改动撤掉。请先 git fetch 并把最新 main(或线上热修复分支)合入当前分支后重试;确需撤回时显式添加 --allow-rollback。" + fi fi if [ "$previous_sha_exists" -eq 0 ] && [ "$allow_migrations" -eq 0 ]; then diff --git a/scripts/deploy-from-workstation.ps1 b/scripts/deploy-from-workstation.ps1 index 631d51ae..83682387 100644 --- a/scripts/deploy-from-workstation.ps1 +++ b/scripts/deploy-from-workstation.ps1 @@ -22,6 +22,8 @@ param( [switch]$ConfigureDingTalkCallback, [switch]$AllowNonMain, [switch]$AllowMigrations, + # 仅在负责人明确决定撤回线上某次发布时使用;默认禁止覆盖不在本次版本里的线上提交。 + [switch]$AllowRollback, [switch]$SkipRegctl ) @@ -426,6 +428,25 @@ try { $previousShaExists = $LASTEXITCODE -eq 0 } + if ($previousSha -and -not $previousShaExists) { + # 线上可能是别人刚发的热修复分支,先拉取再判断,避免误判。 + git fetch origin --quiet 2>$null + git cat-file -e "${previousSha}^{commit}" 2>$null + $previousShaExists = $LASTEXITCODE -eq 0 + } + + # 防覆盖:线上当前版本必须包含在本次要发布的版本里,否则发布会把别人已上线的改动撤掉。 + if ($previousSha -and -not $AllowRollback) { + if (-not $previousShaExists) { + throw "线上当前版本 $previousSha 在本地和 origin 都找不到(可能是未推送的分支),发布会把它覆盖。请让发布人先推送并合并进 main;确需撤回时显式添加 -AllowRollback。服务器未发生任何变更。" + } + git merge-base --is-ancestor $previousSha $deploySha 2>$null + if ($LASTEXITCODE -ne 0) { + $previousInfo = (git log -1 --format='%h %an %ad %s' --date=format:'%m-%d %H:%M' $previousSha) -join '' + throw "线上当前版本($previousInfo)不在本次发布的版本里,继续发布会把它及之后别人上线的改动撤掉。请先 git fetch 并把最新 main(或线上热修复分支)合入当前分支后重试;确需撤回时显式添加 -AllowRollback。服务器未发生任何变更。" + } + } + if ($previousSha -and -not $previousShaExists -and -not $AllowMigrations) { throw "本地缺少服务器当前提交 $previousSha,无法安全比较数据库迁移。请先 git fetch 并核对全部待执行迁移,按 AGENTS.md 完成备份后使用 -AllowMigrations。" }