关于 prod-push
用于通过 DeepAPI 的 main 分支、CI 和 Vercel 流程发布生产环境变更的技能,面向发布操作人员;要求获得用户明确授权,并跟踪部署与健康检查。
主要功能
- 01仅推送至 main 的流程
- 02合并 worktree 变更的步骤
- 03跟踪 CI 与部署
- 04验证生产环境健康状态
- 05事故恢复指引
适用场景
- 01发布经授权的生产变更
- 02在主检出目录落地 worktree 提交
- 03排查 CI 或部署失败
- 04事故期间跟踪恢复提交
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ davidondrej/ skills --skill prod-push安装后在 Claude Code 中输入/prod-push确认已加载。
详细介绍
生产推送
仅在用户明确要求推送后才执行。绝不要自行推送。
此处的发布方式
- 直接推送到
main。不创建 PR,不使用旁支。 - GitHub Actions
CI(.github/workflows/ci.yml)始终报告必需的verify。代码会运行类型检查和 lint;仅在相关路径发生变化时才运行生成文件、浏览器、数据库和 Windows 检查。完整测试套件每晚运行。 - Vercel(项目
deep-api)负责生产构建,并为每次main推送构建,包括仅修改文档的提交(ADR 0161 移除了忽略构建规则;不要重新启用)。仅当verify通过时才会将其部署到 Production。生产环境由deepapi.co提供服务。 - 同一分支上的新 CI 运行会取消正在进行的运行(
cancel-in-progress: true)。
从工作树落地更改
Agent 在关联工作树中开发(cursor/*、agent/* 分支);以下流程不会在这些分支上运行。要发布工作树中的更改:
- 在工作树中:在自己的分支上提交所有更改。绝不要在工作树中提交到
main。 - 在主检出目录(
~/code/DeepAPI)中:工作区必须干净(git status --porcelain --untracked-files=no不输出任何内容)。如果工作区因不属于你的 WIP 而有未提交更改,请停止并告知用户——绝不要先将其暂存。 - 执行
git pull --rebase origin main,然后合入你自己的分支:git merge <branch>(可能会快进),或者在分支历史混乱时 cherry-pick 其提交。一次只合入一个分支——绝不要在一次操作中合入两个 Agent 分支。 - 在主检出目录中解决冲突,重新运行相关检查,然后从下方流程的第 2 步继续。
- 推送经验证已上线后,保留工作树和分支——是否删除始终由用户决定,而不是你。
流程
重复执行,直到确切的更改已上线。
# 0. Fail closed before touching Git. Ship only from the primary main checkout:
# linked worktrees use their own branch's hook and may carry stale safety code.
[ "$(git branch --show-current)" = "main" ] || { echo "prod-push: not on main" >&2; exit 1; }
git_dir=$(git rev-parse --path-format=absolute --git-dir)
git_common_dir=$(git rev-parse --path-format=absolute --git-common-dir)
[ "$git_dir" = "$git_common_dir" ] || { echo "prod-push: linked worktree pushes are forbidden" >&2; exit 1; }
if git config --local --get-regexp '^user\.(name|email)$' >/dev/null; then
echo "prod-push: unexpected local Git identity override" >&2
exit 1
fi
if [ "$(git config user.name)" != "David Ondrej" ] || [ "$(git config user.email)" != "<email-address>" ]; then
echo "prod-push: unexpected effective Git identity" >&2
exit 1
fi
# If an incident is active and you are not the named recovery owner, STOP.
# Follow docs/runbooks/incident-response.md if you are the owner.
npm run incident:status
# 1. commit ONLY your files. WIP belongs in worktrees, never parked in this
# primary checkout — it must be clean between pushes. Never `git add -A`,
# `git add .`, or `commit -a`. If a file you touched also carries someone
# else's unfinished edits, copy it aside (outside the repo), strip their
# part, commit yours — and restore the copy only AFTER the push, because
# step 2 requires a clean tree.
git add <your files> && git commit
[ "$(git log -1 --format='%an <%ae>')" = "David Ondrej <<email-address>>" ] || { echo "prod-push: unexpected commit author" >&2; exit 1; }
# 2. sync + push (other agents also commit to main)
# The pull requires a CLEAN tree. --autostash is BANNED here: replaying
# dirty edits onto fresh upstream commits creates UU conflicts and orphaned
# autostash entries (this bit us on 2026-07-25). If tracked dirt remains
# that is not yours, stop and tell the user — never stash around it.
[ -z "$(git status --porcelain --untracked-files=no)" ] || { echo "prod-push: tree not clean; commit yours or stop" >&2; exit 1; }
# The pre-push hook typechecks the EXACT pushed commit in a clean worktree.
# Incident recovery pushes still run the full suite. Never use `--no-verify`.
git pull --rebase origin main
git push origin main
if git config --local --get-regexp '^user\.(name|email)$' >/dev/null; then
echo "prod-push: push introduced a local Git identity override; stop" >&2
exit 1
fi
SHA=$(git rev-parse HEAD)
# 3. Find the CI run immediately, then let GitHub stream it to completion
RUN_ID=""
for attempt in 1 2 3 4 5 6; do
RUN_ID=$(gh run list --workflow=ci.yml --branch=main --limit=10 \
--json headSha,databaseId --jq ".[] | select(.headSha==\"$SHA\") | .databaseId")
[ -n "$RUN_ID" ] && break
sleep 5
done
[ -n "$RUN_ID" ] || { echo "prod-push: CI run not found" >&2; exit 1; }
gh run watch "$RUN_ID" --exit-status
# 4. CI green -> confirm Vercel promoted this exact commit.
# EVERY main push deploys (ADR 0161), docs-only commits included — always
# verify the deployment; never skip this on a "docs-only" judgment call.
gh api "repos/davidondrej/DeepAPI/commits/$SHA/status" \
--jq '{state, vercel_logs: [.statuses[] | select(.context=="Vercel") | .target_url][0]}'
DEP=$(gh api "repos/davidondrej/DeepAPI/deployments?sha=$SHA&environment=Production&per_page=1" --jq '.[0].id')
gh api "repos/davidondrej/DeepAPI/deployments/$DEP/statuses" --jq '.[0].state'
# If promotion is still pending, poll every 10 seconds.
# 5. confirm prod is serving
curl -sS -m 15 https://deepapi.co/v1/health
完成 = CI 通过、Production 部署成功,且对应 SHA 的 GET /v1/health 状态正常。然后向用户报告已发布的内容。
正在处理的事故通道
只有 npm run incident:status 指定的负责人可以使用此通道。不要混入无关工作。
# Exactly one minimal recovery commit. The hook verifies that exact commit.
DEEPAPI_INCIDENT_RECOVERY=1 DEEPAPI_INCIDENT_OWNER=<owner> git push origin main
SHA=$(git rev-parse HEAD)
使用常规流程跟踪该确切 SHA 的 CI、Production 部署和健康状态。在第一个 SHA 得出最终结果前,不要推送第二次恢复尝试。只有用户可以决定恢复已得到验证并解除冻结;使用运行手册中的解除命令,并且只提交 .github/incident-freeze.json。
故障模式
CI 失败——获取确切失败步骤和输出:
gh run view <databaseId> --log-failed
在本地复现(npm run verify,或仅运行失败的步骤,例如 npm run typecheck),修复问题、提交,然后重新开始流程。推送前日志是确切提交的权威记录;手动运行检查的是共享工作区,可能包含其他 Agent 的 WIP。新的推送会获得新的 $SHA——跟踪该 SHA。
- CI 通过,但 Vercel 状态为
failure——Vercel 构建本身出错。使用npm run build复现。如果问题出在 Vercel 端(环境变量、平台限制),请停止并向用户提供vercel_logs链接——Agent 有意不具备 Vercel CLI 或仪表板访问权限。 - CI
conclusion: cancelled——较新的推送取代了你的推送;你的提交不会自行部署。确认较新的 sha 包含你的更改(git merge-base --is-ancestor $SHA <newer-sha>),并改为跟踪该 sha。 - 事故期间 CI
conclusion: cancelled——停止。未经许可的较新推送进入了main;告知用户,并在采取其他恢复操作前指出其 SHA。 - 健康检查返回
{"ok":false}(HTTP 503)——迁移漂移:已部署代码依赖尚未应用到生产数据库的迁移。部署本身仍然成功。Agent 绝不能写入生产环境——告知用户需要应用哪个迁移,然后停止循环。 - 推送被拒绝(non-fast-forward)——期间有人推送了更改。执行
git pull --rebase origin main后再次推送。
硬性规则
- 未经用户明确同意,绝不推送。绝不强制推送。绝不推送旁支。
- 绝不绕过或弱化 CI 来让检查通过:不得删除或跳过测试,不得使用
--no-verify,不得在检查失败时绕过检查进行合并。 npm run smoke:prod仅限用户运行(会产生真实费用)。免费的生产环境检查是GET /v1/health。- 如果更改包含数据库迁移,用户会手动将其应用到生产环境——在他们完成操作前,健康检查预计会持续失败,并在报告中说明这一点。
评论
支持 Markdown