@cloudglab/zentao-cli 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/MCP_ZENTAO_REBUILD_PLAN.md +505 -0
  3. package/README.md +319 -0
  4. package/dist/api/bug.d.ts +32 -0
  5. package/dist/api/bug.js +85 -0
  6. package/dist/api/bug.js.map +1 -0
  7. package/dist/api/build.d.ts +31 -0
  8. package/dist/api/build.js +21 -0
  9. package/dist/api/build.js.map +1 -0
  10. package/dist/api/comment.d.ts +20 -0
  11. package/dist/api/comment.js +47 -0
  12. package/dist/api/comment.js.map +1 -0
  13. package/dist/api/development-context.d.ts +14 -0
  14. package/dist/api/development-context.js +35 -0
  15. package/dist/api/development-context.js.map +1 -0
  16. package/dist/api/execution.d.ts +46 -0
  17. package/dist/api/execution.js +47 -0
  18. package/dist/api/execution.js.map +1 -0
  19. package/dist/api/index.d.ts +43 -0
  20. package/dist/api/index.js +46 -0
  21. package/dist/api/index.js.map +1 -0
  22. package/dist/api/plan.d.ts +18 -0
  23. package/dist/api/plan.js +33 -0
  24. package/dist/api/plan.js.map +1 -0
  25. package/dist/api/product.d.ts +7 -0
  26. package/dist/api/product.js +14 -0
  27. package/dist/api/product.js.map +1 -0
  28. package/dist/api/program.d.ts +7 -0
  29. package/dist/api/program.js +14 -0
  30. package/dist/api/program.js.map +1 -0
  31. package/dist/api/project.d.ts +8 -0
  32. package/dist/api/project.js +15 -0
  33. package/dist/api/project.js.map +1 -0
  34. package/dist/api/relation.d.ts +17 -0
  35. package/dist/api/relation.js +66 -0
  36. package/dist/api/relation.js.map +1 -0
  37. package/dist/api/release.d.ts +6 -0
  38. package/dist/api/release.js +11 -0
  39. package/dist/api/release.js.map +1 -0
  40. package/dist/api/search.d.ts +17 -0
  41. package/dist/api/search.js +168 -0
  42. package/dist/api/search.js.map +1 -0
  43. package/dist/api/statistics.d.ts +13 -0
  44. package/dist/api/statistics.js +67 -0
  45. package/dist/api/statistics.js.map +1 -0
  46. package/dist/api/story.d.ts +14 -0
  47. package/dist/api/story.js +23 -0
  48. package/dist/api/story.js.map +1 -0
  49. package/dist/api/task.d.ts +17 -0
  50. package/dist/api/task.js +37 -0
  51. package/dist/api/task.js.map +1 -0
  52. package/dist/api/testcase.d.ts +51 -0
  53. package/dist/api/testcase.js +31 -0
  54. package/dist/api/testcase.js.map +1 -0
  55. package/dist/api/testtask.d.ts +41 -0
  56. package/dist/api/testtask.js +34 -0
  57. package/dist/api/testtask.js.map +1 -0
  58. package/dist/api/user.d.ts +6 -0
  59. package/dist/api/user.js +9 -0
  60. package/dist/api/user.js.map +1 -0
  61. package/dist/bin/zentao-dev.d.ts +2 -0
  62. package/dist/bin/zentao-dev.js +8 -0
  63. package/dist/bin/zentao-dev.js.map +1 -0
  64. package/dist/bin/zentao-pm.d.ts +2 -0
  65. package/dist/bin/zentao-pm.js +8 -0
  66. package/dist/bin/zentao-pm.js.map +1 -0
  67. package/dist/bin/zentao-qa.d.ts +2 -0
  68. package/dist/bin/zentao-qa.js +8 -0
  69. package/dist/bin/zentao-qa.js.map +1 -0
  70. package/dist/bin/zentao.d.ts +2 -0
  71. package/dist/bin/zentao.js +8 -0
  72. package/dist/bin/zentao.js.map +1 -0
  73. package/dist/cli.d.ts +1 -0
  74. package/dist/cli.js +74 -0
  75. package/dist/cli.js.map +1 -0
  76. package/dist/core/api-provider.d.ts +3 -0
  77. package/dist/core/api-provider.js +17 -0
  78. package/dist/core/api-provider.js.map +1 -0
  79. package/dist/core/auth.d.ts +13 -0
  80. package/dist/core/auth.js +90 -0
  81. package/dist/core/auth.js.map +1 -0
  82. package/dist/core/cli-registry.d.ts +18 -0
  83. package/dist/core/cli-registry.js +128 -0
  84. package/dist/core/cli-registry.js.map +1 -0
  85. package/dist/core/config.d.ts +7 -0
  86. package/dist/core/config.js +58 -0
  87. package/dist/core/config.js.map +1 -0
  88. package/dist/core/http.d.ts +12 -0
  89. package/dist/core/http.js +50 -0
  90. package/dist/core/http.js.map +1 -0
  91. package/dist/core/list-result.d.ts +14 -0
  92. package/dist/core/list-result.js +59 -0
  93. package/dist/core/list-result.js.map +1 -0
  94. package/dist/core/pagination.d.ts +9 -0
  95. package/dist/core/pagination.js +12 -0
  96. package/dist/core/pagination.js.map +1 -0
  97. package/dist/core/roles.d.ts +4 -0
  98. package/dist/core/roles.js +13 -0
  99. package/dist/core/roles.js.map +1 -0
  100. package/dist/core/tool-registry.d.ts +3 -0
  101. package/dist/core/tool-registry.js +77 -0
  102. package/dist/core/tool-registry.js.map +1 -0
  103. package/dist/core/write-guard.d.ts +25 -0
  104. package/dist/core/write-guard.js +53 -0
  105. package/dist/core/write-guard.js.map +1 -0
  106. package/dist/index.d.ts +3 -0
  107. package/dist/index.js +3 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/tools/bug.d.ts +2 -0
  110. package/dist/tools/bug.js +41 -0
  111. package/dist/tools/bug.js.map +1 -0
  112. package/dist/tools/build.d.ts +2 -0
  113. package/dist/tools/build.js +8 -0
  114. package/dist/tools/build.js.map +1 -0
  115. package/dist/tools/comment.d.ts +2 -0
  116. package/dist/tools/comment.js +23 -0
  117. package/dist/tools/comment.js.map +1 -0
  118. package/dist/tools/context.d.ts +2 -0
  119. package/dist/tools/context.js +11 -0
  120. package/dist/tools/context.js.map +1 -0
  121. package/dist/tools/execution.d.ts +2 -0
  122. package/dist/tools/execution.js +21 -0
  123. package/dist/tools/execution.js.map +1 -0
  124. package/dist/tools/init.d.ts +2 -0
  125. package/dist/tools/init.js +28 -0
  126. package/dist/tools/init.js.map +1 -0
  127. package/dist/tools/phase3a.d.ts +4 -0
  128. package/dist/tools/phase3a.js +123 -0
  129. package/dist/tools/phase3a.js.map +1 -0
  130. package/dist/tools/phase3b.d.ts +5 -0
  131. package/dist/tools/phase3b.js +161 -0
  132. package/dist/tools/phase3b.js.map +1 -0
  133. package/dist/tools/plan.d.ts +2 -0
  134. package/dist/tools/plan.js +14 -0
  135. package/dist/tools/plan.js.map +1 -0
  136. package/dist/tools/product.d.ts +2 -0
  137. package/dist/tools/product.js +10 -0
  138. package/dist/tools/product.js.map +1 -0
  139. package/dist/tools/profile.d.ts +2 -0
  140. package/dist/tools/profile.js +6 -0
  141. package/dist/tools/profile.js.map +1 -0
  142. package/dist/tools/program.d.ts +2 -0
  143. package/dist/tools/program.js +8 -0
  144. package/dist/tools/program.js.map +1 -0
  145. package/dist/tools/project.d.ts +2 -0
  146. package/dist/tools/project.js +13 -0
  147. package/dist/tools/project.js.map +1 -0
  148. package/dist/tools/relation.d.ts +2 -0
  149. package/dist/tools/relation.js +13 -0
  150. package/dist/tools/relation.js.map +1 -0
  151. package/dist/tools/release.d.ts +2 -0
  152. package/dist/tools/release.js +7 -0
  153. package/dist/tools/release.js.map +1 -0
  154. package/dist/tools/search.d.ts +2 -0
  155. package/dist/tools/search.js +18 -0
  156. package/dist/tools/search.js.map +1 -0
  157. package/dist/tools/shared.d.ts +2 -0
  158. package/dist/tools/shared.js +11 -0
  159. package/dist/tools/shared.js.map +1 -0
  160. package/dist/tools/statistics.d.ts +2 -0
  161. package/dist/tools/statistics.js +10 -0
  162. package/dist/tools/statistics.js.map +1 -0
  163. package/dist/tools/story.d.ts +2 -0
  164. package/dist/tools/story.js +14 -0
  165. package/dist/tools/story.js.map +1 -0
  166. package/dist/tools/task.d.ts +2 -0
  167. package/dist/tools/task.js +48 -0
  168. package/dist/tools/task.js.map +1 -0
  169. package/dist/tools/testcase.d.ts +2 -0
  170. package/dist/tools/testcase.js +16 -0
  171. package/dist/tools/testcase.js.map +1 -0
  172. package/dist/tools/testtask.d.ts +2 -0
  173. package/dist/tools/testtask.js +14 -0
  174. package/dist/tools/testtask.js.map +1 -0
  175. package/dist/types/common.d.ts +15 -0
  176. package/dist/types/common.js +2 -0
  177. package/dist/types/common.js.map +1 -0
  178. package/dist/types/zentao.d.ts +42 -0
  179. package/dist/types/zentao.js +2 -0
  180. package/dist/types/zentao.js.map +1 -0
  181. package/dist/utils/json.d.ts +2 -0
  182. package/dist/utils/json.js +27 -0
  183. package/dist/utils/json.js.map +1 -0
  184. package/dist/version.d.ts +1 -0
  185. package/dist/version.js +2 -0
  186. package/dist/version.js.map +1 -0
  187. package/package.json +48 -0
package/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # @cloudglab/zentao-cli
2
+
3
+ 基于 TypeScript 重建的禅道命令行工具,优先适配当前禅道 `18.5` 的 REST v1 API。
4
+
5
+ ![zentao-cli hero](./assets/readme/zentao-cli-hero.png)
6
+
7
+ > 把任务、Bug、需求、测试、计划、构建、发布这些禅道操作,直接接进本地 `zentao` 命令,给命令行、脚本和 skill 调用。
8
+
9
+ ## 亮点
10
+
11
+ - `60` 个 CLI 命令,覆盖任务、Bug、需求、执行、测试、计划、构建、发布、搜索等核心场景
12
+ - `4` 个内置角色:`Dev / QA / PM / Full`
13
+ - 基于 TypeScript 重建,优先适配禅道 `18.5` REST v1 API
14
+ - 发布产物运行时目标:`Node.js >= 16`
15
+ - 默认写保护,写操作需要显式开启并确认,更适合接入智能体和自动化流程
16
+
17
+ ## 快速开始
18
+
19
+ 环境要求:`Node.js >= 16`
20
+
21
+ ### 安装
22
+
23
+ ```bash
24
+ # 运行时要求:Node.js >= 16
25
+
26
+ # 直接运行
27
+ npx -y @cloudglab/zentao-cli@latest
28
+
29
+ # 全局安装
30
+ npm i -g @cloudglab/zentao-cli@latest
31
+ ```
32
+
33
+ ### 配置
34
+
35
+ ```bash
36
+ export ZENTAO_URL="https://your-zentao.example.com"
37
+ export ZENTAO_USERNAME="your-account"
38
+ export ZENTAO_PASSWORD="your-password"
39
+ export ZENTAO_API_VERSION="v1"
40
+
41
+ # 可选:非标准部署时指定完整 API 基础地址
42
+ # export ZENTAO_API_BASE_URL="https://your-zentao.example.com/custom/api.php/v1"
43
+ ```
44
+
45
+ ### 运行
46
+
47
+ ```bash
48
+ # 查看帮助 / 版本
49
+ zentao help
50
+ zentao --version
51
+
52
+ # 默认 full 角色
53
+ zentao list
54
+ zentao getMyTasks --status all --limit 20
55
+
56
+ # 按角色启动
57
+ zentao --role dev getMyTasks --status all
58
+ zentao --role qa getMyBugs --limit 50
59
+ zentao --role pm getProducts
60
+
61
+ # 也可以直接用 npx
62
+ npx -y @cloudglab/zentao-cli@latest --role qa getMyBugs --limit 50
63
+ ```
64
+
65
+ ## 使用方式
66
+
67
+ ### CLI
68
+
69
+ 适合手动查数据、排查问题、批量执行脚本。
70
+
71
+ 常见场景:
72
+ - 查我的任务 / Bug / 统计
73
+ - 查询需求、执行、计划、构建、发布
74
+ - 创建或更新任务、测试用例、测试单
75
+ - 做任务流转、Bug 处理、批量排期、回填工时、同步状态
76
+ - 通过 `Dev / QA / PM / Full` 角色入口提供差异化能力
77
+
78
+ ### 智能体 / Skill 接入建议
79
+
80
+ 推荐顺序:
81
+
82
+ 1. 先检查本机有没有 `zentao`
83
+ 2. 没有就安装:`npm i -g @cloudglab/zentao-cli@latest`
84
+ 3. skill 内优先调用本地 `zentao`
85
+ 4. 只在不能安装时,才退回 `npx -y @cloudglab/zentao-cli@latest`
86
+
87
+ 常用检查命令:
88
+
89
+ ```bash
90
+ command -v zentao
91
+ zentao --version
92
+ ```
93
+
94
+ skill / 自动化里推荐直接执行:
95
+
96
+ ```bash
97
+ zentao --role qa getMyBugs --limit 50
98
+ zentao getProductBugs --productId 123 --status all --limit 100
99
+ ```
100
+
101
+ ### Skill
102
+
103
+ 适合把当前能力包装成可复用的 AI Skill,对外推广更友好。
104
+
105
+ 相关文档:
106
+ - `skills/zentao-cli/reference/overview.md`
107
+ - `skills/zentao-cli/reference/install.md`
108
+
109
+ 安装 skill 时,统一走:
110
+
111
+ ```bash
112
+ npx skills add @cloudglab/zentao-cli -g
113
+ ```
114
+
115
+ skill 内部入口建议:
116
+
117
+ - 优先:`zentao`
118
+ - 或按角色:`zentao --role qa`
119
+ - 无本地安装时兜底:`npx -y @cloudglab/zentao-cli@latest`
120
+
121
+ 适合场景:
122
+ - 给团队成员提供统一入口
123
+ - 给非开发用户提供更低门槛的禅道操作方式
124
+ - 做内部推广和标准化接入
125
+
126
+ ## 当前 MVP 能力
127
+
128
+ - token 登录:仅在明确鉴权失败时才从明文密码回退到 MD5
129
+ - 登录错误分类:区分账号密码错误、token 接口不存在、网络失败、服务端异常
130
+ - 自动清洗 PHP warning + JSON 混合响应
131
+ - `getMyTasks`
132
+ - `getTaskDetail`
133
+ - `getBugDetail`
134
+ - `getStoryDetail`
135
+ - `getExecutionDetail`
136
+ - `getExecutionBugs`
137
+ - `getMyBugs`
138
+ - `getProductBugs`
139
+ - `getComments`
140
+ - 写操作 preview:`updateTask`、`finishTask`、`resolveBug`、`addComment`
141
+ - `getMyProfile`
142
+ - `getMyTaskStatistics`
143
+ - `getMyBugStatistics`
144
+ - `getStoryRelatedBugs`
145
+ - `getBugRelatedStory`
146
+ - `getDevelopmentContext`
147
+ - `getProducts` / `getProductDetail`
148
+ - `getProjects` / `getProjectDetail`
149
+ - `getProjectExecutions` / `getExecutionBuilds`
150
+ - `getProductStories`
151
+ - `getProductTestCases` / `getTestCaseDetail`
152
+ - `getTestTasks` / `getTestTaskDetail`
153
+ - `getPrograms` / `getProgramDetail`
154
+ - `getProductPlans` / `getPlanDetail`
155
+ - `getProjectBuilds` / `getBuildDetail`
156
+ - `getProjectReleases`
157
+ - `searchStories`
158
+ - `searchStoriesByProductName`
159
+ - `updateStory` / `changeStory`(默认 preview)
160
+ - `createTaskFromStory` / `createTaskFromBug`(默认 preview)
161
+ - `linkStoriesToPlan` / `unlinkStoriesFromPlan`(默认 preview)
162
+ - `linkBugsToPlan` / `unlinkBugsFromPlan`(默认 preview)
163
+ - `updateExecution` / `startExecution` / `closeExecution` / `suspendExecution` / `activateExecution` / `putoffExecution`(默认 preview)
164
+ - `createBuild` / `updateBuild`(默认 preview)
165
+ - `createTestCase` / `updateTestCase`(默认 preview)
166
+ - `createTestTask` / `updateTestTask`(默认 preview)
167
+
168
+ `updateExecution` 按禅道 18.5 REST v1 文档/源码需要保留/传入:
169
+
170
+ - `project`
171
+ - `name`
172
+ - `code`
173
+ - `begin`
174
+ - `end`
175
+
176
+ 注意:`updateExecution` 在禅道 18.5 且后台启用代号时存在服务端源码问题:`api/v1/entries/execution.php` 中 `$fields .= 'code'` 缺少前置逗号,导致请求体里的 `code` 不会进入服务端 `$_POST`,服务端会误报 `『迭代代号』不能为空。`。客户端无法稳定绕过;工具仍保留,但调用时会直接返回该诊断错误,不做真实写入。
177
+
178
+ `createBuild` 当前按禅道 18.5 实机/参考包契约使用 `POST /projects/{project}/builds`,通常需要提供:
179
+
180
+ - `project`
181
+ - `execution`
182
+ - `product`
183
+ - `name`
184
+ - `builder`
185
+
186
+ 补充说明:
187
+
188
+ - `createTaskFromStory` / `createTaskFromBug` 在当前实例上实机验证发现通常需要额外提供:
189
+ - `assignedTo`
190
+ - `estStarted`
191
+ - `deadline`
192
+ - `createTaskFromBug` 当前只保证:
193
+ - 基于 Bug 预填任务内容并尝试创建任务
194
+ - 不保证创建后自动建立 Bug 关联
195
+ - 角色工具过滤:`full` / `dev` / `qa` / `pm`
196
+ - 写操作保护 helper:默认禁用写操作,后续写工具必须配合 `ZENTAO_ENABLE_WRITE=true` 和 `confirm: true`;已知 18.5 不支持或服务端有缺陷的写工具会保留入口,但调用时直接返回明确诊断错误。
197
+ - Phase 3B 写工具(execution / build / testcase / testtask)默认同样返回 preview,真实执行仍需 `ZENTAO_ENABLE_WRITE=true` + `confirm=true`:
198
+ - execution:`updateExecution` / `startExecution` / `closeExecution` / `suspendExecution` / `activateExecution` / `putoffExecution`
199
+ - build:`createBuild` / `updateBuild`
200
+ - testcase:`createTestCase` / `updateTestCase`
201
+ - testtask:`createTestTask` / `updateTestTask`
202
+ - 角色权限:
203
+ - `full` 拥有 `execution-write` + `build-write` + `testcase-write` + `testtask-write`
204
+ - `dev` 拥有 `execution-write` + `build-write`
205
+ - `pm` 仅拥有 `execution-write`
206
+ - `qa` 拥有 `testcase-write` + `testtask-write`
207
+ - `createTestCase` / `updateTestCase` 当前按禅道 18.5 REST v1 契约:
208
+ - 创建路径:`POST /products/{productId}/testcases`
209
+ - 更新路径:`PUT /testcases/{testCaseId}`
210
+ - `steps` 数组每项形如 `{ desc, expect, type? }`,`type` 支持 `step` / `item` / `group`,默认 `step`
211
+ - `module` / `story` 允许传 `0` 表示无模块 / 无关联需求
212
+ - `project` / `execution` / `keywords` 不是禅道 18.5 REST v1 用例创建/更新 entry 接收字段,传入会被服务端忽略;18.5 v1 创建的是产品用例,不会直接绑定项目/执行。
213
+ - `createTestTask` 当前按禅道 18.5 REST v1 契约:
214
+ - 创建路径:`POST /projects/{project}/testtasks`
215
+ - 创建必填:`project` / `productID` / `name` / `build` / `begin` / `end`,`begin` / `end` 格式 `YYYY-MM-DD`
216
+ - 创建请求体实际使用 `product` 字段,工具入参保留 `productID` 并在 API 层映射
217
+ - `build` 兼容数字 ID 和字符串 ID
218
+ - `createTestTask` 当前实例真实写验证通过
219
+ - `updateTestTask`:禅道 18.5 v1 `api/v1/entries/testtask.php` 只有 `get/delete`,没有 `put` 更新入口。工具仍保留,但调用时会直接返回该诊断错误,不做真实写入。
220
+ - `linkBugsToPlan` 已按 18.5 源码修正为 `POST /productplans/{planId}/linkbugs`。
221
+ - `finishTask` 已按 18.5 源码改为 `POST /tasks/{taskId}/finish`,需要 `currentConsumed` / `realStarted` / `finishedDate`。
222
+ - `addComment`:禅道 18.5 v1 没有 `comment/comments` entry,当前只支持 `getComments` 从对象详情 actions 回退读取;`addComment` 工具仍保留,但调用时会直接返回该诊断错误。
223
+ - token 失效后自动重试一次
224
+ - 可选 `ZENTAO_API_BASE_URL`:用于非标准 `/zentao/api.php/v1` 部署
225
+
226
+ ## 配置
227
+
228
+ 说明:
229
+
230
+ - `getMyBugs` 当前默认语义是“跨所有产品指派给我的 Bug”;传 `productId` 时收窄到指定产品。
231
+ - `getMyBugStatistics` 默认统计跨所有产品指派给我的 Bug;传 `productId` 时收窄到指定产品。
232
+ - `getComments` 在禅道 18.5 上会 fallback 到对象详情里的 `actions`,返回结果会明确标注 `source: "actions-fallback"`。
233
+ - `updateTask` / `finishTask` 不会默认修改 `assignedTo`,只有显式传入才会更新指派人。
234
+
235
+ 支持环境变量:
236
+
237
+ ```bash
238
+ export ZENTAO_URL="https://zentao.cloudglab.cn"
239
+ export ZENTAO_USERNAME="your-account"
240
+ export ZENTAO_PASSWORD="your-password"
241
+ export ZENTAO_API_VERSION="v1"
242
+ # 可选:非标准部署时直接指定完整 API 基础地址
243
+ # export ZENTAO_API_BASE_URL="https://zentao.cloudglab.cn/custom/api.php/v1"
244
+ ```
245
+
246
+ 注意:`ZENTAO_URL` 传根域名即可,不要带 `/zentao`。
247
+
248
+ `initZentao` 现在默认只校验并在当前进程内生效,不会自动把密码写入 `~/.zentao/config.json`。
249
+ 只有显式传 `save: true` 才会落盘。
250
+
251
+ ## 开发
252
+
253
+ ```bash
254
+ pnpm install
255
+ pnpm typecheck
256
+ pnpm build
257
+ ```
258
+
259
+ ## 发布链路
260
+
261
+ 已内置 GitHub Actions:当你 push 形如 `v*` 的 tag 时,会自动:
262
+
263
+ 1. 安装依赖
264
+ 2. 执行 `pnpm typecheck`
265
+ 3. 执行 `pnpm build`
266
+ 4. 发布 npm 包到 registry
267
+ 5. 自动创建对应 GitHub Release
268
+
269
+ 工作流文件:
270
+
271
+ - `.github/workflows/publish.yml`
272
+
273
+ ### 使用前准备
274
+
275
+ 1. 先把代码推到 GitHub 仓库
276
+ 2. 在 npm 上为 `@cloudglab/zentao-cli` 配置 GitHub Actions trusted publisher,绑定仓库 `cloudglab/zentao-cli`
277
+ 3. 确保 `package.json` 中的 `version` 与你要打的 tag 一致
278
+
279
+ ### 发版方式
280
+
281
+ 例如当前 `package.json` 版本是 `0.1.0`,则发版命令:
282
+
283
+ ```bash
284
+ git tag v0.1.0
285
+ git push origin v0.1.0
286
+ ```
287
+
288
+ 工作流会校验:
289
+
290
+ - tag `v0.1.0` 是否与 `package.json` 中的 `0.1.0` 一致
291
+
292
+ 如果不一致,Action 会直接失败,避免把错误版本发布到 npm。
293
+
294
+ ### 推荐顺序
295
+
296
+ ```bash
297
+ # 1. 修改 package.json version
298
+ # 2. 提交代码
299
+ # 3. 推送分支
300
+ # 4. 打 tag
301
+ git tag v0.1.0
302
+ git push origin main
303
+ git push origin v0.1.0
304
+ ```
305
+
306
+ ### 当前还未自动完成的部分
307
+
308
+ 下面这些仍需要你首次手动完成一次:
309
+
310
+ - 初始化本地 git 仓库
311
+ - 首次 commit
312
+ - 创建 GitHub 仓库并 push 上去
313
+ - 在 npm 包侧完成 trusted publisher 绑定
314
+
315
+ ## 启动
316
+
317
+ ```bash
318
+ pnpm dev
319
+ ```
@@ -0,0 +1,32 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ import { type PaginationInput } from '../core/pagination.js';
3
+ import type { ZentaoBug } from '../types/zentao.js';
4
+ export interface BugListParams extends PaginationInput {
5
+ productId: number;
6
+ status?: string;
7
+ branch?: string;
8
+ order?: string;
9
+ }
10
+ export interface ResolveBugInput {
11
+ resolution: 'fixed' | 'bydesign' | 'duplicate' | 'external' | 'notrepro' | 'postponed' | 'willnotfix';
12
+ resolvedBuild?: string;
13
+ resolvedDate?: string;
14
+ assignedTo?: string;
15
+ comment?: string;
16
+ duplicateBug?: number;
17
+ }
18
+ export interface MyBugListParams extends PaginationInput {
19
+ productId?: number;
20
+ branch?: string;
21
+ order?: string;
22
+ }
23
+ export declare class BugApi {
24
+ private readonly http;
25
+ constructor(http: ZentaoHttpClient);
26
+ getMyBugs(params?: MyBugListParams): Promise<unknown>;
27
+ getProductBugs(params: BugListParams): Promise<unknown>;
28
+ getBugDetail(bugId: number): Promise<ZentaoBug>;
29
+ resolveBug(bugId: number, input: ResolveBugInput): Promise<unknown>;
30
+ private getAllMyBugsInProduct;
31
+ private sortBugs;
32
+ }
@@ -0,0 +1,85 @@
1
+ import { toClientPaginatedListResult, toServerListResult } from '../core/list-result.js';
2
+ import { normalizePagination } from '../core/pagination.js';
3
+ export class BugApi {
4
+ constructor(http) {
5
+ this.http = http;
6
+ }
7
+ async getMyBugs(params = {}) {
8
+ if (params.productId) {
9
+ return this.getProductBugs({ ...params, productId: params.productId, status: 'assigntome' });
10
+ }
11
+ const response = await this.http.request('GET', '/products');
12
+ const productsResult = toServerListResult(response, ['products']);
13
+ const products = productsResult.items;
14
+ const allBugs = [];
15
+ for (const product of products) {
16
+ const productId = product.id;
17
+ if (!productId)
18
+ continue;
19
+ const bugs = await this.getAllMyBugsInProduct({
20
+ productId,
21
+ branch: params.branch,
22
+ order: params.order,
23
+ });
24
+ allBugs.push(...bugs.map((bug) => ({
25
+ ...bug,
26
+ product: bug.product ?? productId,
27
+ productName: bug.productName ?? product.name,
28
+ })));
29
+ }
30
+ const sorted = this.sortBugs(allBugs, params.order);
31
+ const paginated = toClientPaginatedListResult({ bugs: sorted }, ['bugs'], params);
32
+ return {
33
+ ...paginated,
34
+ scope: 'global-assigntome',
35
+ scannedProducts: products.length,
36
+ };
37
+ }
38
+ async getProductBugs(params) {
39
+ const pagination = normalizePagination(params);
40
+ const response = await this.http.request('GET', `/products/${params.productId}/bugs`, {
41
+ params: {
42
+ ...pagination,
43
+ branch: params.branch ?? 'all',
44
+ order: params.order ?? 'id_desc',
45
+ status: params.status === 'all' ? undefined : params.status,
46
+ },
47
+ });
48
+ return toServerListResult(response, ['bugs'], params);
49
+ }
50
+ async getBugDetail(bugId) {
51
+ return this.http.request('GET', `/bugs/${bugId}`);
52
+ }
53
+ async resolveBug(bugId, input) {
54
+ const payload = { ...input };
55
+ if (payload.resolution === 'fixed' && !payload.resolvedBuild)
56
+ payload.resolvedBuild = 'trunk';
57
+ if (payload.resolution === 'duplicate' && !payload.duplicateBug) {
58
+ throw new Error('resolution=duplicate 时必须提供 duplicateBug');
59
+ }
60
+ return this.http.request('POST', `/bugs/${bugId}/resolve`, { data: payload });
61
+ }
62
+ async getAllMyBugsInProduct(params) {
63
+ const limit = 100;
64
+ const firstPage = await this.getProductBugs({ ...params, status: 'assigntome', page: 1, limit });
65
+ const bugs = [...firstPage.items];
66
+ const total = firstPage.total ?? bugs.length;
67
+ const totalPages = Math.ceil(total / limit);
68
+ for (let page = 2; page <= totalPages; page += 1) {
69
+ const response = await this.getProductBugs({ ...params, status: 'assigntome', page, limit });
70
+ bugs.push(...response.items);
71
+ }
72
+ return bugs;
73
+ }
74
+ sortBugs(bugs, order) {
75
+ const normalizedOrder = (order ?? 'id_desc').toLowerCase();
76
+ const sorted = [...bugs];
77
+ if (normalizedOrder === 'id_asc') {
78
+ sorted.sort((a, b) => a.id - b.id);
79
+ return sorted;
80
+ }
81
+ sorted.sort((a, b) => b.id - a.id);
82
+ return sorted;
83
+ }
84
+ }
85
+ //# sourceMappingURL=bug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug.js","sourceRoot":"","sources":["../../src/api/bug.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ export interface CreateBuildInput {
3
+ project: number;
4
+ execution: number;
5
+ product: number;
6
+ branch?: number;
7
+ name: string;
8
+ builder: string;
9
+ date?: string;
10
+ desc?: string;
11
+ scmPath?: string;
12
+ filePath?: string;
13
+ }
14
+ export interface UpdateBuildInput {
15
+ execution?: number;
16
+ product?: number;
17
+ name?: string;
18
+ builder?: string;
19
+ date?: string;
20
+ desc?: string;
21
+ scmPath?: string;
22
+ filePath?: string;
23
+ }
24
+ export declare class BuildApi {
25
+ private readonly http;
26
+ constructor(http: ZentaoHttpClient);
27
+ getProjectBuilds(projectId: number): Promise<unknown>;
28
+ getBuildDetail(buildId: number): Promise<unknown>;
29
+ createBuild(payload: CreateBuildInput): Promise<unknown>;
30
+ updateBuild(buildId: number, update: UpdateBuildInput): Promise<unknown>;
31
+ }
@@ -0,0 +1,21 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ export class BuildApi {
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ async getProjectBuilds(projectId) {
7
+ const response = await this.http.request('GET', `/projects/${projectId}/builds`);
8
+ return toServerListResult(response, ['builds']);
9
+ }
10
+ async getBuildDetail(buildId) {
11
+ return this.http.request('GET', `/builds/${buildId}`);
12
+ }
13
+ async createBuild(payload) {
14
+ const { project, ...build } = payload;
15
+ return this.http.request('POST', `/projects/${project}/builds`, { data: build });
16
+ }
17
+ async updateBuild(buildId, update) {
18
+ return this.http.request('PUT', `/builds/${buildId}`, { data: update });
19
+ }
20
+ }
21
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/api/build.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AA0B5D,MAAM,OAAO,QAAQ;IACnB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,SAAS,SAAS,CAAC,CAAC;QACjF,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAe;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;QACtC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,MAAwB;QACzD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1E,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ export type CommentObjectType = 'task' | 'bug' | 'story' | 'product' | 'project' | 'execution' | string;
3
+ export interface AddCommentInput {
4
+ objectType: CommentObjectType;
5
+ objectID: number;
6
+ comment: string;
7
+ }
8
+ export interface CommentsFallbackResult {
9
+ source: 'actions-fallback';
10
+ note: string;
11
+ actions: unknown;
12
+ }
13
+ export declare class CommentApi {
14
+ private readonly http;
15
+ constructor(http: ZentaoHttpClient);
16
+ getComments(objectType: CommentObjectType, objectID: number): Promise<unknown>;
17
+ addComment(input: AddCommentInput): Promise<unknown>;
18
+ private getActionsFromObjectDetail;
19
+ private getObjectEndpoint;
20
+ }
@@ -0,0 +1,47 @@
1
+ export class CommentApi {
2
+ constructor(http) {
3
+ this.http = http;
4
+ }
5
+ async getComments(objectType, objectID) {
6
+ try {
7
+ return await this.http.request('GET', `/comments/${objectType}/${objectID}`);
8
+ }
9
+ catch (error) {
10
+ if (error instanceof Error && error.message.includes('404')) {
11
+ return this.getActionsFromObjectDetail(objectType, objectID);
12
+ }
13
+ throw error;
14
+ }
15
+ }
16
+ async addComment(input) {
17
+ return this.http.request('POST', '/comment', { data: input });
18
+ }
19
+ async getActionsFromObjectDetail(objectType, objectID) {
20
+ const endpoint = this.getObjectEndpoint(objectType, objectID);
21
+ const detail = await this.http.request('GET', endpoint);
22
+ return {
23
+ source: 'actions-fallback',
24
+ note: '当前禅道版本不支持 /comments/{objectType}/{objectID},这里返回对象详情中的 actions,其中包含评论以及状态变更等操作记录。',
25
+ actions: detail.actions ?? [],
26
+ };
27
+ }
28
+ getObjectEndpoint(objectType, objectID) {
29
+ switch (objectType) {
30
+ case 'task':
31
+ return `/tasks/${objectID}`;
32
+ case 'bug':
33
+ return `/bugs/${objectID}`;
34
+ case 'story':
35
+ return `/stories/${objectID}`;
36
+ case 'product':
37
+ return `/products/${objectID}`;
38
+ case 'project':
39
+ return `/projects/${objectID}`;
40
+ case 'execution':
41
+ return `/executions/${objectID}`;
42
+ default:
43
+ throw new Error(`不支持从详情回退获取评论: ${objectType}`);
44
+ }
45
+ }
46
+ }
47
+ //# sourceMappingURL=comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/api/comment.ts"],"names":[],"mappings":"AAgBA,MAAM,OAAO,UAAU;IACrB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,WAAW,CAAC,UAA6B,EAAE,QAAgB;QAC/D,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,UAAU,IAAI,QAAQ,EAAE,CAAC,CAAC;QAC/E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5D,OAAO,IAAI,CAAC,0BAA0B,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC/D,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAsB;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,0BAA0B,CAAC,UAA6B,EAAE,QAAgB;QACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAA0B,KAAK,EAAE,QAAQ,CAAC,CAAC;QACjF,OAAO;YACL,MAAM,EAAE,kBAAkB;YAC1B,IAAI,EAAE,mFAAmF;YACzF,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;SAC9B,CAAC;IACJ,CAAC;IAEO,iBAAiB,CAAC,UAA6B,EAAE,QAAgB;QACvE,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,MAAM;gBACT,OAAO,UAAU,QAAQ,EAAE,CAAC;YAC9B,KAAK,KAAK;gBACR,OAAO,SAAS,QAAQ,EAAE,CAAC;YAC7B,KAAK,OAAO;gBACV,OAAO,YAAY,QAAQ,EAAE,CAAC;YAChC,KAAK,SAAS;gBACZ,OAAO,aAAa,QAAQ,EAAE,CAAC;YACjC,KAAK,SAAS;gBACZ,OAAO,aAAa,QAAQ,EAAE,CAAC;YACjC,KAAK,WAAW;gBACd,OAAO,eAAe,QAAQ,EAAE,CAAC;YACnC;gBACE,MAAM,IAAI,KAAK,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import type { BugApi } from './bug.js';
2
+ import type { RelationApi } from './relation.js';
3
+ import type { StoryApi } from './story.js';
4
+ export declare class DevelopmentContextApi {
5
+ private readonly bugApi;
6
+ private readonly storyApi;
7
+ private readonly relationApi;
8
+ constructor(bugApi: BugApi, storyApi: StoryApi, relationApi: RelationApi);
9
+ getDevelopmentContext(input: {
10
+ entityType: 'story' | 'bug';
11
+ entityId: number;
12
+ productId?: number;
13
+ }): Promise<unknown>;
14
+ }
@@ -0,0 +1,35 @@
1
+ export class DevelopmentContextApi {
2
+ constructor(bugApi, storyApi, relationApi) {
3
+ this.bugApi = bugApi;
4
+ this.storyApi = storyApi;
5
+ this.relationApi = relationApi;
6
+ }
7
+ async getDevelopmentContext(input) {
8
+ if (input.entityType === 'story') {
9
+ const story = await this.storyApi.getStoryDetail(input.entityId);
10
+ const relatedBugs = await this.relationApi.getStoryRelatedBugs(input.entityId, input.productId);
11
+ const testCases = Array.isArray(story.cases) ? story.cases : [];
12
+ return {
13
+ entityType: 'story',
14
+ story,
15
+ relatedBugs,
16
+ testCases,
17
+ summary: {
18
+ relatedBugsCount: relatedBugs.bugs.length,
19
+ testCasesCount: testCases.length,
20
+ },
21
+ };
22
+ }
23
+ const bug = await this.bugApi.getBugDetail(input.entityId);
24
+ const relatedStory = await this.relationApi.getBugRelatedStory(input.entityId);
25
+ return {
26
+ entityType: 'bug',
27
+ bug,
28
+ relatedStory,
29
+ summary: {
30
+ hasRelatedStory: relatedStory !== null,
31
+ },
32
+ };
33
+ }
34
+ }
35
+ //# sourceMappingURL=development-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"development-context.js","sourceRoot":"","sources":["../../src/api/development-context.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,qBAAqB;IAChC,YACmB,MAAc,EACd,QAAkB,EAClB,WAAwB;QAFxB,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAU;QAClB,gBAAW,GAAX,WAAW,CAAa;IACxC,CAAC;IAEJ,KAAK,CAAC,qBAAqB,CAAC,KAA4E;QACtG,IAAI,KAAK,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACjE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,mBAAmB,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YAChG,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YAEhE,OAAO;gBACL,UAAU,EAAE,OAAO;gBACnB,KAAK;gBACL,WAAW;gBACX,SAAS;gBACT,OAAO,EAAE;oBACP,gBAAgB,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM;oBACzC,cAAc,EAAE,SAAS,CAAC,MAAM;iBACjC;aACF,CAAC;QACJ,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3D,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE/E,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,GAAG;YACH,YAAY;YACZ,OAAO,EAAE;gBACP,eAAe,EAAE,YAAY,KAAK,IAAI;aACvC;SACF,CAAC;IACJ,CAAC;CACF"}