---
name: deploy-test
description: >-
  部署 / 发布到测试环境。触发场景包括但不限于：
  「部署测试环境」「部署test」「部署测试」「部署到测试」「部署到test」「发布测试」「发布test」「发布到测试」「发布到test」「上线测试」「上线test」「测试环境部署」「测试环境发布」「测试环境上线」「部署测试服」「发布测试服」「上线测试服」「推到测试」「推到test」「推测试」「推test」。
  「帮我部署」「帮我发布」「帮我上线」「部署一下」「发布一下」「上线一下」「部署吧」「发布吧」「上线吧」「部署了」「发布了」「上线了」「搞部署」「做部署」「弄部署」。
  「打测试」「打test」「打一下测试」「打个测试包」「打包测试」「打包到测试」「发版测试」「发版到测试」。
  「部署」「发布」「上线」单独说且上下文在讨论测试环境时也应触发。
  自动完成：记录当前分支→提交并推送当前分支→合并到test→推送→部署→发版→切回原分支。
---

# 部署测试环境

⚠️ **本 Skill 已触发。第一句话必须输出：「🔧 已触发 `deploy-test`，按流程部署测试环境...」然后严格按照以下步骤执行，不得跳过。**

将当前功能分支部署到测试环境，完成后自动切回原分支。

## 🚨 铁律（违反即错误）

- ⚠️ 部署测试环境**唯一正确流程**：当前功能分支 → 提交并推送当前分支 → 合并到 test → 推送 test → 触发部署 → 切回原分支。
- ⚠️ **绝对禁止**跳过合并步骤、直接在功能分支上部署、或往 test 分支直接提交代码。
- ⚠️ 每一步必须执行完毕并确认成功后才能进入下一步，不可并行或跳过。

## 核心流程

### 1. 记录当前分支

```bash
ORIGINAL_BRANCH=$(git branch --show-current)
echo "当前分支: $ORIGINAL_BRANCH"
```

### 2. 提交当前分支并推送远程

⚠️ 合并前必须确保当前分支所有改动已提交并推送，避免遗漏代码。

```bash
git add -A
git commit -m "..."  # 使用有意义的提交信息
git push origin "$ORIGINAL_BRANCH"
```

⚠️ **若本次改动经过循环 review（`loop-review` 修复过代码），必须确认所有 review 修复已同步到当前功能分支（PR 对应分支）并推送远程，再进行 test 合并。** 核对方式：

```bash
# 确认本地功能分支与远程已同步（本地无未推送提交）
# 先 fetch 让 origin/<分支> 引用最新，再用「分支的 upstream..HEAD」精确列举未推送提交
# ⚠️ 分支可能从未推送过（远程不存在该 ref），git fetch origin "$X" 会报 "couldn't find remote ref"；
#    用 2>/dev/null || true 容忍该失败，否则在 set -e 环境下会直接中断、后面的「远程分支不存在」兜底逻辑根本执行不到
git fetch origin "$ORIGINAL_BRANCH" 2>/dev/null || true
git status
# 无 upstream 时 @{u} 会报错，先检测：有 upstream 用 @{u} 精确差集；
# 无 upstream 时先确认远程分支是否存在（git log origin/X..HEAD 对不存在的引用会直接 fatal），
# 不存在 = 新分支从未推送。⚠️ 此时不能用 git log HEAD（会把 main 全部历史也算进来，输出上千行淹没真正关心的提交），
#    要相对默认分支（origin/main）取差集，只列出本分支相对默认分支的新增提交
DEFAULT_BRANCH=$(git remote show origin | grep 'HEAD branch' | cut -d: -f2 | tr -d ' ')
if git rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1; then
  UNPUSHED=$(git log "@{u}"..HEAD --oneline)
elif git rev-parse --verify "origin/$ORIGINAL_BRANCH" >/dev/null 2>&1; then
  UNPUSHED=$(git log "origin/$ORIGINAL_BRANCH"..HEAD --oneline)
elif git rev-parse --verify "origin/$DEFAULT_BRANCH" >/dev/null 2>&1; then
  UNPUSHED=$(git log "origin/$DEFAULT_BRANCH"..HEAD --oneline)
else
  UNPUSHED=$(git log HEAD --oneline)
fi
[ -z "$UNPUSHED" ] && echo "✅ 无未推送提交" || { echo "⚠️ 存在未推送提交："; echo "$UNPUSHED"; }
```

⚠️ 用 `git log @{u}..HEAD`（当前分支与其 upstream 的差集）而不是 `git log origin/"$ORIGINAL_BRANCH".."$ORIGINAL_BRANCH"`：后者在本地分支尚未 fetch 到最新 origin 时会把已推送过的提交误报为「未推送」，导致误判；且若分支创建时 track 的不是同名远程分支，`origin/X` 引用可能缺失。`@{u}` 始终指向当前分支真正跟踪的远程引用，语义更准确。⚠️ 但 `@{u}` 仅在分支设置了 upstream（`git push -u`）时可用；功能分支若用 `git push origin <branch>` 推送则无 upstream，`@{u}` 会直接报错，因此上面先用 `git rev-parse --abbrev-ref "@{u}"` 检测。无 upstream 时还要先确认远程分支存在——`git log origin/X..HEAD` 对**不存在的引用会直接 fatal**（而不是返回空），因此用 `git rev-parse --verify "origin/X"` 探测；远程分支不存在即新分支从未推送，此时全部本地提交都算「未推送」。

- ⚠️ 若 review 修复还没合进当前功能分支 → 先把修复 commit 到功能分支再推送，禁止带着"修复只在 test 分支"的状态去部署。
- ⚠️ feature 分支与 test 分支两条线必须保持同步：**所有 review 修复代码必须先落 feature 分支（PR 分支），再合并到 test**，缺一不可。

### 3. test 分支检查

如果 `test` 分支不存在，从主分支创建：

```bash
git fetch origin
if ! git show-ref --verify --quiet refs/heads/test; then
  MAIN=$(git remote show origin | grep 'HEAD branch' | cut -d: -f2 | tr -d ' ')
  git checkout -b test "origin/${MAIN:-main}"
  git push origin test
fi
```

### 4. 合并当前分支到 test

⚠️ 合并发生冲突时，以当前功能分支的内容为准（`-X theirs`）。因为当前分支的代码是刚改的最新版本，test 分支上的旧版本直接覆盖即可。

```bash
git checkout test
git pull origin test
git merge "$ORIGINAL_BRANCH" -X theirs
```

### 5. 推送 test 分支

```bash
git push origin test
```

### 6. 部署 test 分支

按项目自己的部署方式执行（Cloud Run / 容器 / npm publish 等）。

### 7. 发新版本

按项目发版规则执行（如 `./release.sh`）。

### 8. 切回原功能分支

```bash
git checkout "$ORIGINAL_BRANCH"
```

## 重要规则

- ⚠️ 推送 test 后必须立即执行 `git push origin test`
- ⚠️ 部署完成后必须立即切回原功能分支
- ⚠️ 部署必须自包含：migration、配置变更、依赖检查全部脚本化自动执行，禁止部署后人工补操作（自包含铁律见 AGENTS.base.md「⚠️ 可部署性自包含铁律」章节，写代码之前就要考虑）
- ⚠️ 合并到 test 发生冲突时，必须用 `-X theirs`（以当前功能分支为准），因为当前分支是最新代码，test 旧版本直接覆盖即可。
- 禁止直接往 test 分支提交代码
- 敏感信息（密钥、Token）必须从 Nacos 配置中心拉取，不得写死
