$npx -y skills add TestAny-io/testany-agent-skills --skill testany-import-gitTestany Git 导入:把 Git 仓库里的测试脚本批量注册成 Testany platform cases,并持续同步、切 commit、演化 binding、配 webhook
| 1 | # Testany Git Import |
| 2 | |
| 3 | 把一个 Git 仓库里的测试脚本批量注册成 Testany platform cases,并在后续以 sync / switch / relation 的方式保持与仓库同步。 |
| 4 | |
| 5 | 用户输入: $ARGUMENTS |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## 核心概念 |
| 10 | |
| 11 | | 对象 | 说明 | |
| 12 | |------|------| |
| 13 | | **Connection** | 一次 OAuth 授权后得到的 Git 平台身份(当前支持 GitHub)。GitHub 连接下有若干 `installation_bindings`,每个绑定代表一个 GitHub App 安装(owner/org + 可访问 repo 范围)。`installation_id` 是后续浏览仓库的必填入参 | |
| 14 | | **Import History** | 一次导入配置:绑定到某个 connection、某个 repo、某个 ref,决定了"这些文件 ↔ 这些 case"的映射 | |
| 15 | | **File Binding** | import history 下"一个文件 ↔ 一个 case"的绑定记录,是 Testany 上那批 case 的真源 | |
| 16 | | **Sync Record** | 一次同步动作的审计记录(per-file 成功/失败/跳过) | |
| 17 | |
| 18 | ### import_mode(枚举值必须严格匹配) |
| 19 | |
| 20 | **本质差别:后端 auto-diff vs 用户手动选** —— 不是"仓库内容多少是测试"之类的场景判断。 |
| 21 | |
| 22 | - `managed_import`:镜像仓库、自动 diff。`confirm_git_sync` 触发一次 mirror→binding 的增量落地;新增文件还可以另走 addFiles,上游被删走 sourceDeleted 两阶段确认 |
| 23 | - `sync_link`:显式管理 binding 集。**current phase 下 `confirm_git_sync` 不可用**,binding 集演化统一走 addFiles(新增文件)和 sourceDeleted(上游删除)两条关系流。`preview_git_sync` 在这里仅用于查看"已绑定文件相对 last_synced_commit 的变化" |
| 24 | |
| 25 | 选择建议:想省心 + 信任仓库当 source-of-truth → `managed_import`;想精细控制每次哪些文件入 binding 集 → `sync_link`。不要基于"仓库是否纯测试"这类理由推断。 |
| 26 | |
| 27 | ### sync_mode(枚举值必须严格匹配) |
| 28 | |
| 29 | - `latest`:跟随 `tracked_branch` 的 HEAD,每次 sync 自动前进 |
| 30 | - `pinned_commit`:钉在某个 commit;要前进必须走 switchCommit |
| 31 | |
| 32 | --- |
| 33 | |
| 34 | ## 操作速查 |
| 35 | |
| 36 | | 意图 | 工具链 | |
| 37 | |------|--------| |
| 38 | | 看我有哪些 Git 连接 | `testany_list_git_connections` | |
| 39 | | 新建 GitHub 连接 | `testany_initiate_git_oauth` → 用户浏览器完成 → 轮询 list | |
| 40 | | Access token 快过期 / 已过期但 refresh_token 还在 | `testany_refresh_git_connection_scope`(server-to-server,无需浏览器) | |
| 41 | | Refresh_token 也挂了 / 用户主动断连 / 换账号 | `testany_reauthorize_git_connection`(返回 `authorize_url`,需用户浏览器完成) | |
| 42 | | 连接侧 repo 选择 / scope 变更 | `testany_refresh_git_connection_scope`(同入口;它既刷 token 又校对 scope) | |
| 43 | | 删连接 | `testany_disconnect_git_connection` | |
| 44 | | 列可访问仓库 | `testany_list_git_repositories`(必填 `installation_id`) | |
| 45 | | 选分支 / commit | `testany_list_git_branches` / `testany_list_git_commits` | |
| 46 | | 看仓库目录 / 预览文件 | `testany_browse_git_tree` / `testany_preview_git_file` | |
| 47 | | 列 / 查 / 删 import | `testany_list_git_imports` / `testany_get_git_import` / `testany_delete_git_import` | |
| 48 | | 新建导入 | `testany_create_git_import` | |
| 49 | | 看 / 清 bindings | `testany_list_git_import_file_bindings` / `testany_delete_git_import_file_bindings` | |
| 50 | | 周期同步(**managed_import 专属**) | `testany_preview_git_sync` → `testany_confirm_git_sync`(sync_link 在 current phase **不支持** confirm_sync;改走 addFiles/sourceDeleted) | |
| 51 | | 重放失败 sync(sync_link 专属) | `testany_retry_git_sync({sync_record_id})` | |
| 52 | | 切 commit(要求 sync_mode=pinned_commit) | `testany_preview_git_switch_commit` → `testany_confirm_git_switch_commit` | |
| 53 | | 解除 pinned、回 latest(要求 sync_mode=pinned_commit) | `testany_preview_git_switch_mode` → `testany_confirm_git_switch_mode` | |
| 54 | | 审计同步历史 | `testany_list_git_sync_records` → `testany_get_git_sync_record` | |
| 55 | | 加新文件(managed_import 与 sync_link 均可) | `testany_get_git_add_files_summary` → `_list_git_add_files_candidates` → `_confirm_git_add_files` | |
| 56 | | 标记源删除(managed_import 与 sync_link 均可) | `testany_get_git_source_deleted_summary` → `_list_..._candidates` → `_confirm_git_source_deleted` | |
| 57 | | Webhook 读 / 开关 / 轮换 | `testany_get_git_webhook_config` / `_update_git_webhook_config` / `_disable_git_webhook` / `_regenerate_git_webhook_secret` | |
| 58 | |
| 59 | --- |
| 60 | |
| 61 | ## Phase 1:连接 Git 平台 |
| 62 | |
| 63 | 1. `testany_list_git_connections`,找目标平台的连接 |
| 64 | 2. 如果**没有连接** → `testany_initiate_git_oauth({platform: "github"})` 拿 `authorize_url`,交给用户浏览器完成 GitHub App 安装授权(agent 不能替点击;明确告知"完成后回来说一声"),然后轮询 `testany_list_git_connections` 到新连接出现 |
| 65 | 3. 如果**有连接**,做**健康检查**(详见 [connection-health.md](./references/connection-health.md)): |
| 66 | - **配置层**:`status == "connected_scope_ready"` 才是健康 ⚠️ 不是字面 `"ready"` |
| 67 | - **凭证层**:`token_expires_at` 必须 > `now + 60s`;否则先调 `testany_refresh_git_connection_scope` 做 server-to-server 刷新(不打扰用户) |
| 68 | - 看各 `installation_bindings[i].scope_verified_at` 是否太旧(>24h 可选刷) |
| 69 | 4. 健康后,从 `connection.installation_bindings[]` 挑目标 `installation_id` |
| 70 | |
| 71 | **常见不健康状态 → 修复路径速查**(完整枚举见 `connection-health.md`): |
| 72 | |
| 73 | | `status` / 症状 | 处理 | |
| 74 | |---|---| |
| 75 | | `connected_scope_ready` 但 `token_expires_at` 过期或临近 | `refresh_connection_scope`(server-to-server) | |
| 76 | | `token_expired` | `reauthorize_git_connection` → 浏览器 | |
| 77 | | `permission_changed` | 先 `refresh_connection_scope`;失败再 `reauthorize` | |
| 78 | | `authorized_no_installation` | 用 `scope_management_entry_url` 让用户浏览器装 installation | |
| 79 | | `disconnected` | `initiate_git_oauth` 重新授权 | |
| 80 | |
| 81 | > **关键纪律**:不要只看 `status`。GitHub App access_token 默认 8h 过期,到期时 `status` 仍然是 `connected_scope_ready`(滞后指标),下次 GitHub-API 调用才会让后端把它翻到 `token_expired`。主动用 `token_expires_at` 判断能避免一次多余的失败重试。 |
| 82 | |
| 83 | --- |
| 84 | |
| 85 | ## Phase 2:选仓库与 ref |
| 86 | |
| 87 | 1. `testany_list_git_repositories({connection_id, installation_id, search?})` 选出 `owner/repo` + `repo_full_name` |
| 88 | 2. 再选参照系: |
| 89 | - `sync_mode=latest` → `testany_list_git_branches` 选 `tracked_branch` |
| 90 | - `sync_mode=pinned_commit` → 还要 `testany_list_git_commits` 选 |