ai-engineering-init 1.10.0 → 1.11.0
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.
- package/.claude/agents/code-scanner.md +145 -0
- package/.claude/hooks/skill-forced-eval.js +2 -0
- package/.claude/skills/analyze-requirements/SKILL.md +112 -0
- package/.claude/skills/fix-bug/SKILL.md +166 -0
- package/.claude/skills/yunxiao-task-management/SKILL.md +170 -258
- package/.claude/skills/yunxiao-task-management/templates//346/217/220/346/265/213/345/215/225/346/250/241/346/235/277.html +17 -0
- package/.codex/skills/analyze-requirements/SKILL.md +112 -0
- package/.codex/skills/dev/SKILL.md +131 -476
- package/.codex/skills/fix-bug/SKILL.md +166 -0
- package/.codex/skills/next/SKILL.md +42 -186
- package/.codex/skills/progress/SKILL.md +76 -147
- package/.codex/skills/yunxiao-task-management/SKILL.md +170 -258
- package/.codex/skills/yunxiao-task-management/templates//346/217/220/346/265/213/345/215/225/346/250/241/346/235/277.html +17 -0
- package/.cursor/agents/code-scanner.md +145 -0
- package/.cursor/hooks/cursor-skill-eval.js +10 -0
- package/.cursor/rules/skill-activation.mdc +7 -0
- package/.cursor/skills/analyze-requirements/SKILL.md +112 -0
- package/.cursor/skills/fix-bug/SKILL.md +166 -0
- package/.cursor/skills/yunxiao-task-management/SKILL.md +170 -258
- package/.cursor/skills/yunxiao-task-management/templates//346/217/220/346/265/213/345/215/225/346/250/241/346/235/277.html +17 -0
- package/AGENTS.md +44 -21
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/skills/analyze-requirements/SKILL.md +112 -0
- package/src/skills/fix-bug/SKILL.md +166 -0
- package/src/skills/yunxiao-task-management/SKILL.md +170 -258
- package/src/skills/yunxiao-task-management/templates//346/217/220/346/265/213/345/215/225/346/250/241/346/235/277.html +17 -0
|
@@ -3,8 +3,16 @@ name: yunxiao-task-management
|
|
|
3
3
|
description: |
|
|
4
4
|
阿里云云效(Yunxiao)项目协作任务管理技能。通过云效 Open API 直接操作工作项:查询任务、修改状态、编辑描述、添加评论、记录工时、创建子任务、搜索项目等。
|
|
5
5
|
支持完整开发工作流:读取任务 → 查找父需求 → 读取需求详情 → 创建提测单 → 编辑提测单 → 转给测试。
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
支持智能提测单完善:自动从 git 获取分支/提交信息,从 pom.xml 读取版本号,查找用户任务并填充提测单模板。
|
|
7
|
+
|
|
8
|
+
触发场景:
|
|
9
|
+
- 查询/修改云效任务状态
|
|
10
|
+
- 完善提测单内容(自动收集 git 信息)
|
|
11
|
+
- 创建提测单子任务
|
|
12
|
+
- 查看个人待处理任务
|
|
13
|
+
- 读取需求详情
|
|
14
|
+
|
|
15
|
+
触发词:云效、任务管理、工作项、修改状态、提测、提测单、完善提测单、SARW、EZML、IXXP、云效任务
|
|
8
16
|
---
|
|
9
17
|
|
|
10
18
|
# 云效任务管理 Skill
|
|
@@ -21,7 +29,16 @@ YUNXIAO_ACCESS_TOKEN: 个人访问令牌
|
|
|
21
29
|
**已知用户信息**:
|
|
22
30
|
- 组织 ID: `61dbcd725356b19beeb1dc03`
|
|
23
31
|
- 用户: 徐嘉骏(ID: `66286d4b06679a65daed4d28`)
|
|
24
|
-
|
|
32
|
+
|
|
33
|
+
**已知项目缓存**(避免全量扫描):
|
|
34
|
+
|
|
35
|
+
| customCode | 项目名称 | 项目 ID |
|
|
36
|
+
|------------|---------|---------|
|
|
37
|
+
| SARW | - | `4574cb1c653fe873335b6c4716` |
|
|
38
|
+
| EZML | - | `6f99a4e627fa88d6f8cb541e6c` |
|
|
39
|
+
| IXXP | 广州小鹏汽车 | `d93e6ddf18c83254d0b8f27e7d` |
|
|
40
|
+
|
|
41
|
+
> 新发现的项目应追加到此表。搜索项目时**优先查缓存**,命中则跳过 API 搜索。
|
|
25
42
|
|
|
26
43
|
## API 基础信息
|
|
27
44
|
|
|
@@ -64,12 +81,14 @@ Body: {} 或 { keyword: "关键词" }
|
|
|
64
81
|
|
|
65
82
|
返回数组,每个项目包含 `id`、`name`、`customCode`(如 SARW、IXXP)。
|
|
66
83
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
84
|
+
**重要**:`keyword` 搜索按项目名称模糊匹配,**不支持按 customCode 搜索**。要找 customCode,需全量分页扫描匹配。
|
|
85
|
+
|
|
86
|
+
**优先使用缓存**:先查"已知项目缓存"表,命中则直接用 ID,无需调 API。
|
|
87
|
+
|
|
88
|
+
**按项目名称查找**(用户说"小鹏汽车"时):
|
|
89
|
+
1. 先查缓存表的项目名称列
|
|
90
|
+
2. 未命中则用 `keyword` 搜索:`{ keyword: "小鹏汽车" }`
|
|
91
|
+
3. 仍未找到则全量分页扫描(perPage=100,逐页匹配 name)
|
|
73
92
|
|
|
74
93
|
### 2. 搜索工作项
|
|
75
94
|
|
|
@@ -92,10 +111,11 @@ Body: {
|
|
|
92
111
|
- `subject`: 标题
|
|
93
112
|
- `status`: `{ name, id }` — 状态名和状态 ID
|
|
94
113
|
- `assignedTo`: `{ name, id }` — 负责人
|
|
114
|
+
- `parentId`: 父工作项 ID
|
|
95
115
|
|
|
96
|
-
#### conditions
|
|
116
|
+
#### conditions 高级过滤
|
|
97
117
|
|
|
98
|
-
|
|
118
|
+
`conditions` 是 **JSON 字符串**,格式:
|
|
99
119
|
|
|
100
120
|
```json
|
|
101
121
|
{
|
|
@@ -110,34 +130,12 @@ Body: {
|
|
|
110
130
|
{ "className": "user", "fieldIdentifier": "assignedTo", "format": "list", "operator": "CONTAINS", "toValue": null, "value": ["用户ID"] }
|
|
111
131
|
```
|
|
112
132
|
|
|
113
|
-
|
|
133
|
+
**排除已完成/已取消状态**:
|
|
114
134
|
```json
|
|
115
135
|
{ "className": "status", "fieldIdentifier": "status", "format": "list", "operator": "NOT_CONTAINS", "toValue": null, "value": ["100014", "141230"] }
|
|
116
136
|
```
|
|
117
137
|
|
|
118
|
-
> `
|
|
119
|
-
|
|
120
|
-
**按创建人过滤**:
|
|
121
|
-
```json
|
|
122
|
-
{ "className": "user", "fieldIdentifier": "creator", "format": "list", "operator": "CONTAINS", "toValue": null, "value": ["用户ID"] }
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**按优先级过滤**:
|
|
126
|
-
```json
|
|
127
|
-
{ "className": "option", "fieldIdentifier": "priority", "format": "list", "operator": "CONTAINS", "toValue": null, "value": ["优先级值"] }
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
**组合多个条件**(放在同一个数组内为 AND 关系):
|
|
131
|
-
```json
|
|
132
|
-
{
|
|
133
|
-
"conditionGroups": [[
|
|
134
|
-
{ "className": "user", "fieldIdentifier": "assignedTo", "format": "list", "operator": "CONTAINS", "toValue": null, "value": ["用户ID"] },
|
|
135
|
-
{ "className": "statusStage", "fieldIdentifier": "statusStage", "format": "list", "operator": "CONTAINS", "toValue": null, "value": ["TODO", "DOING"] }
|
|
136
|
-
]]
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
> **注意**:`conditions` 传给 API 时必须是 **JSON 字符串**(`JSON.stringify(obj)`),不是对象。
|
|
138
|
+
> `conditions` 传给 API 时必须是 **JSON 字符串**(`JSON.stringify(obj)`),不是对象。
|
|
141
139
|
|
|
142
140
|
### 3. 获取工作项详情
|
|
143
141
|
|
|
@@ -151,12 +149,9 @@ GET /oapi/v1/projex/organizations/{orgId}/workitems/{workitemId}
|
|
|
151
149
|
PUT /oapi/v1/projex/organizations/{orgId}/workitems/{workitemId}
|
|
152
150
|
```
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
```json
|
|
156
|
-
{ "status": "100011" }
|
|
157
|
-
```
|
|
152
|
+
可组合多个字段一次更新:`{ "description": "...", "status": "100011", "subject": "..." }`。成功返回 **HTTP 204**。
|
|
158
153
|
|
|
159
|
-
常见状态 ID
|
|
154
|
+
常见状态 ID(参考值,不同项目可能不同):
|
|
160
155
|
|
|
161
156
|
| 状态名 | 状态 ID |
|
|
162
157
|
|--------|---------|
|
|
@@ -166,25 +161,6 @@ PUT /oapi/v1/projex/organizations/{orgId}/workitems/{workitemId}
|
|
|
166
161
|
| 已完成 | 100014 |
|
|
167
162
|
| 已取消 | 141230 |
|
|
168
163
|
|
|
169
|
-
> 不同项目的状态 ID 可能不同!先从该项目的工作项中收集已有状态,再使用对应 ID。
|
|
170
|
-
|
|
171
|
-
**修改描述**:
|
|
172
|
-
```json
|
|
173
|
-
{ "description": "新的描述内容" }
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**修改标题**:
|
|
177
|
-
```json
|
|
178
|
-
{ "subject": "新标题" }
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
**修改负责人**:
|
|
182
|
-
```json
|
|
183
|
-
{ "assignedTo": "用户ID" }
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
可组合多个字段一次更新。成功返回 **HTTP 204**(无 body)。
|
|
187
|
-
|
|
188
164
|
### 5. 添加评论
|
|
189
165
|
|
|
190
166
|
```
|
|
@@ -192,13 +168,6 @@ POST /oapi/v1/projex/organizations/{orgId}/workitems/{workitemId}/comments
|
|
|
192
168
|
Body: { "content": "评论内容" }
|
|
193
169
|
```
|
|
194
170
|
|
|
195
|
-
返回 `{ id: "评论ID" }`。
|
|
196
|
-
|
|
197
|
-
**获取评论列表**:
|
|
198
|
-
```
|
|
199
|
-
GET /oapi/v1/projex/organizations/{orgId}/workitems/{workitemId}/comments?page=1&perPage=20
|
|
200
|
-
```
|
|
201
|
-
|
|
202
171
|
### 6. 创建子任务
|
|
203
172
|
|
|
204
173
|
```
|
|
@@ -208,13 +177,11 @@ Body: {
|
|
|
208
177
|
"subject": "子任务标题",
|
|
209
178
|
"workitemTypeId": "任务类型ID",
|
|
210
179
|
"assignedTo": "用户ID", // 必需!
|
|
211
|
-
"parentId": "父工作项ID",
|
|
180
|
+
"parentId": "父工作项ID",
|
|
212
181
|
"description": "描述(可选)"
|
|
213
182
|
}
|
|
214
183
|
```
|
|
215
184
|
|
|
216
|
-
> `assignedTo` 虽然看似可选,但 API 强制要求,缺少会报错。
|
|
217
|
-
|
|
218
185
|
**获取任务类型 ID**:
|
|
219
186
|
```
|
|
220
187
|
GET /oapi/v1/projex/organizations/{orgId}/projects/{projectId}/workitemTypes?category=Task
|
|
@@ -222,264 +189,209 @@ GET /oapi/v1/projex/organizations/{orgId}/projects/{projectId}/workitemTypes?cat
|
|
|
222
189
|
|
|
223
190
|
### 7. 工时管理
|
|
224
191
|
|
|
225
|
-
|
|
192
|
+
**预估工时**:`POST .../workitems/{id}/estimatedEfforts` Body: `{ "spentTime": 480, "owner": "用户ID" }`
|
|
193
|
+
**实际工时**:`POST .../workitems/{id}/effortRecords` Body: `{ "actualTime": 240, "gmtStart": ts, "gmtEnd": ts }`
|
|
226
194
|
|
|
227
|
-
|
|
228
|
-
```
|
|
229
|
-
GET /oapi/v1/projex/organizations/{orgId}/workitems/{workitemId}/estimatedEfforts
|
|
230
|
-
```
|
|
195
|
+
## 不支持的操作
|
|
231
196
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
"spentTime": 480, // 480分钟 = 8小时
|
|
237
|
-
"description": "预估工时描述",
|
|
238
|
-
"owner": "用户ID"
|
|
239
|
-
}
|
|
240
|
-
```
|
|
197
|
+
| 操作 | 原因 |
|
|
198
|
+
|------|------|
|
|
199
|
+
| 添加附件 | API 不支持(504 超时/415 错误) |
|
|
200
|
+
| 获取用户信息 | 需要「用户信息(读取)」权限,Token 不支持 |
|
|
241
201
|
|
|
242
|
-
|
|
202
|
+
---
|
|
243
203
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
204
|
+
## 提测单完善流程(核心场景)
|
|
205
|
+
|
|
206
|
+
当用户说"完善提测单"、"填写提测单"、"帮我提测"时触发。用户可能**不提供任务 ID**,只说项目名或需求描述。
|
|
207
|
+
|
|
208
|
+
### 流程概览
|
|
248
209
|
|
|
249
|
-
**创建**:
|
|
250
210
|
```
|
|
251
|
-
|
|
252
|
-
Body: {
|
|
253
|
-
"actualTime": 240, // 240分钟 = 4小时
|
|
254
|
-
"description": "实际工时描述",
|
|
255
|
-
"gmtStart": 1772800000000, // 开始时间(毫秒时间戳)
|
|
256
|
-
"gmtEnd": 1772803000000 // 结束时间(毫秒时间戳)
|
|
257
|
-
}
|
|
211
|
+
1. 定位任务 → 2. 收集 git 信息 → 3. 读取版本号 → 4. 加载模板 → 5. 填充并更新描述
|
|
258
212
|
```
|
|
259
213
|
|
|
260
|
-
###
|
|
214
|
+
### Step 1: 定位任务
|
|
261
215
|
|
|
262
|
-
|
|
216
|
+
**场景 A:用户提供了任务编号**(如 IXXP-122)
|
|
217
|
+
- 从编号前缀提取 customCode(IXXP)
|
|
218
|
+
- 查缓存表 → 命中则直接用项目 ID
|
|
219
|
+
- 未命中则全量分页扫描匹配 customCode
|
|
220
|
+
- 搜索项目 Task,找到 serialNumber 匹配的工作项
|
|
263
221
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
// POST projects:search with body: { conditions: memberConditions }
|
|
273
|
-
```
|
|
222
|
+
**场景 B:用户只说项目名称**(如"小鹏汽车")
|
|
223
|
+
- 用项目名称匹配缓存或 keyword 搜索
|
|
224
|
+
- 找到项目后,用 `assignedTo` conditions 过滤当前用户的任务
|
|
225
|
+
- 展示任务列表,让用户选择或自动匹配标题含"提测"的任务
|
|
226
|
+
|
|
227
|
+
**场景 C:用户只说"我的提测单"**
|
|
228
|
+
- 用已知项目缓存逐个搜索当前用户的任务
|
|
229
|
+
- 筛选标题含"提测"的任务
|
|
274
230
|
|
|
275
|
-
**第二步:服务端过滤任务** — 用 `assignedTo` + `status NOT_CONTAINS` 只返回自己未完成的任务:
|
|
276
231
|
```javascript
|
|
277
|
-
|
|
232
|
+
// 查找用户在指定项目中的任务
|
|
233
|
+
const conditions = JSON.stringify({
|
|
278
234
|
conditionGroups: [[
|
|
279
235
|
{ className: "user", fieldIdentifier: "assignedTo", format: "list", operator: "CONTAINS", toValue: null, value: [USER_ID] },
|
|
280
236
|
{ className: "status", fieldIdentifier: "status", format: "list", operator: "NOT_CONTAINS", toValue: null, value: ["100014", "141230"] }
|
|
281
237
|
]]
|
|
282
238
|
});
|
|
283
|
-
// POST workitems:search with
|
|
239
|
+
// POST workitems:search with { spaceId, category: "Task", conditions, page: 1, perPage: 200 }
|
|
284
240
|
```
|
|
285
241
|
|
|
286
|
-
|
|
287
|
-
```javascript
|
|
288
|
-
const batchSize = 15;
|
|
289
|
-
for (let i = 0; i < projects.length; i += batchSize) {
|
|
290
|
-
const batch = projects.slice(i, i + batchSize);
|
|
291
|
-
const results = await Promise.all(batch.map(p => searchWorkitems(p.id, taskConditions)));
|
|
292
|
-
myTasks.push(...results.flat());
|
|
293
|
-
}
|
|
294
|
-
```
|
|
242
|
+
### Step 2: 收集 git 信息
|
|
295
243
|
|
|
296
|
-
|
|
297
|
-
> 注意:`members` 项目过滤在实测中未生效(仍返回全量项目),建议直接扫描所有项目但用 batchSize=20 并发处理。
|
|
244
|
+
从当前工作目录的 git 仓库自动收集:
|
|
298
245
|
|
|
299
|
-
|
|
246
|
+
```bash
|
|
247
|
+
# 当前分支名(后端分支)
|
|
248
|
+
git branch --show-current
|
|
300
249
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
| 添加附件 | API 不支持(504 超时/415 不支持的类型),MCP 源码中无附件相关实现 |
|
|
304
|
-
| 获取用户信息 | `/oapi/v1/platform/user` 需要「用户信息(读取)」权限,项目 Token 不支持 |
|
|
250
|
+
# 最近的相关提交(用户可能指定 commit hash)
|
|
251
|
+
git log {commitHash} -1 --stat
|
|
305
252
|
|
|
306
|
-
|
|
253
|
+
# 提交所在分支
|
|
254
|
+
git branch --contains {commitHash}
|
|
255
|
+
```
|
|
307
256
|
|
|
308
|
-
|
|
257
|
+
**信息映射**:
|
|
258
|
+
- 后端分支 = `git branch --show-current` 或 `git branch --contains {hash}`
|
|
259
|
+
- 需求描述 = 用户提供 或 commit message
|
|
260
|
+
- 前端分支 / h5分支 = 用户提供,默认留空或 "无"
|
|
309
261
|
|
|
310
|
-
###
|
|
262
|
+
### Step 3: 读取版本号
|
|
311
263
|
|
|
312
|
-
|
|
313
|
-
|
|
264
|
+
从定制仓库的 pom.xml 读取 `parent.version`:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# 读取 pom.xml 的 parent version
|
|
268
|
+
grep -A1 '<artifactId>core-dependencies</artifactId>' pom.xml | grep '<version>'
|
|
314
269
|
```
|
|
315
270
|
|
|
316
|
-
### Step
|
|
271
|
+
### Step 4: 加载提测单模板
|
|
317
272
|
|
|
318
|
-
|
|
273
|
+
模板文件位置:`{skill目录}/templates/提测单模板.html`
|
|
319
274
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
275
|
+
读取模板文件,替换占位符:
|
|
276
|
+
- `{项目名称}` → 项目中文名(如"小鹏汽车总部")
|
|
277
|
+
- `{版本号}` → pom.xml parent version
|
|
278
|
+
- `{后端分支}` → git 分支名
|
|
279
|
+
- `{前端分支}` → 用户提供或 "无"
|
|
280
|
+
- `{h5分支}` → 用户提供或 "无"
|
|
281
|
+
- `{需求描述}` → 需求内容
|
|
282
|
+
- `{开发者ID}` → 当前用户 ID
|
|
283
|
+
- `{开发者名}` → 当前用户名
|
|
284
|
+
- `{自测说明}` → "已自测通过" 或用户提供
|
|
285
|
+
- `{测试用例}` → 根据需求自动生成或用户提供
|
|
286
|
+
- `{提测人ID}` → 当前用户 ID
|
|
287
|
+
- `{提测人}` → 当前用户名
|
|
288
|
+
- `{验收人}` → 用户指定(先在项目成员中搜索 ID,未找到则纯文本)
|
|
324
289
|
|
|
325
|
-
|
|
326
|
-
const task = items.find(i => i.serialNumber === "EZML-1878");
|
|
327
|
-
const parentDetail = await yunxiaoReq(`/oapi/v1/projex/organizations/${ORG}/workitems/${task.parentId}`);
|
|
328
|
-
// parentDetail.categoryId === "Req"
|
|
329
|
-
// parentDetail.serialNumber === "EZML-1877"
|
|
330
|
-
```
|
|
290
|
+
**@提及语法**:`<span data-type="mention" data-id="{用户ID}">@{用户名}</span>`
|
|
331
291
|
|
|
332
|
-
|
|
333
|
-
- `parentId`: 父工作项 ID(Task → Req 的关联)
|
|
334
|
-
- `categoryId`: 工作项类别(`Task` / `Req` / `Bug` / `Risk`)
|
|
335
|
-
- `workitemType`: `{ name, id }` — 如 `{ name: "产品类需求", id: "9uy29901re573f561d69jn40" }`
|
|
336
|
-
- `space`: `{ name, id }` — 所属项目
|
|
292
|
+
**搜索用户 ID**:从项目工作项的 `assignedTo` 和 `creator` 字段收集所有成员,匹配姓名。
|
|
337
293
|
|
|
338
|
-
### Step
|
|
294
|
+
### Step 5: 更新工作项描述
|
|
339
295
|
|
|
340
296
|
```javascript
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
//
|
|
346
|
-
const text = desc.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
297
|
+
await yunxiaoReq(`/oapi/v1/projex/organizations/${ORG}/workitems/${workitemId}`, {
|
|
298
|
+
method: "PUT",
|
|
299
|
+
body: { description: filledTemplate }
|
|
300
|
+
});
|
|
301
|
+
// 成功返回 204
|
|
347
302
|
```
|
|
348
303
|
|
|
349
|
-
|
|
304
|
+
### 完整示例
|
|
350
305
|
|
|
351
|
-
|
|
306
|
+
```
|
|
307
|
+
用户:完善 IXXP-122 提测单,提交是 45bdb2a 装修优化,前端分支 master,验收人卢佳南
|
|
308
|
+
```
|
|
352
309
|
|
|
353
|
-
|
|
310
|
+
执行步骤:
|
|
311
|
+
1. IXXP → 查缓存命中 → 项目 ID `d93e6ddf18c83254d0b8f27e7d`
|
|
312
|
+
2. 搜索 Task 找到 IXXP-122
|
|
313
|
+
3. `git log 45bdb2a -1 --stat` → 获取提交详情
|
|
314
|
+
4. `git branch --contains 45bdb2a` → 后端分支
|
|
315
|
+
5. 读取 pom.xml → 版本号
|
|
316
|
+
6. 加载模板,替换占位符
|
|
317
|
+
7. 在项目成员中搜索"卢佳南"(未找到则纯文本写入)
|
|
318
|
+
8. PUT 更新描述 → 204 成功
|
|
354
319
|
|
|
355
|
-
```javascript
|
|
356
|
-
// 搜索该项目所有 Task,筛选 parentId 匹配的
|
|
357
|
-
const allTasks = await searchWorkitems(projectId, "Task");
|
|
358
|
-
const siblings = allTasks.filter(t => t.parentId === parentReqId);
|
|
359
|
-
// 展示: serialNumber, subject, status.name, assignedTo.name
|
|
360
320
|
```
|
|
321
|
+
用户:帮我完善小鹏汽车项目的提测单
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
执行步骤:
|
|
325
|
+
1. "小鹏汽车" → 查缓存匹配 IXXP
|
|
326
|
+
2. 用 assignedTo 过滤当前用户的未完成任务
|
|
327
|
+
3. 筛选标题含"提测"的任务 → 展示列表让用户确认
|
|
328
|
+
4. 从 git 自动收集分支、提交信息
|
|
329
|
+
5. 读取版本号,加载模板,填充更新
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## 开发工作流(创建提测单)
|
|
361
334
|
|
|
362
|
-
|
|
335
|
+
当需要**新建**提测单(而非完善已有的),用户说"创建提测单"时触发。
|
|
363
336
|
|
|
364
|
-
|
|
337
|
+
### 流程
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
读取任务(Task) → 查找父需求(Req) → 创建提测单子任务 → 填充描述
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Step 1: 读取任务并找到父需求
|
|
365
344
|
|
|
366
345
|
```javascript
|
|
367
|
-
|
|
368
|
-
const
|
|
369
|
-
|
|
346
|
+
const task = items.find(i => i.serialNumber === "EZML-1878");
|
|
347
|
+
const parentDetail = await yunxiaoReq(`/oapi/v1/projex/organizations/${ORG}/workitems/${task.parentId}`);
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Step 2: 创建提测单子任务
|
|
370
351
|
|
|
371
|
-
|
|
352
|
+
```javascript
|
|
353
|
+
const types = await yunxiaoReq(`/oapi/v1/projex/organizations/${ORG}/projects/${projectId}/workitemTypes?category=Task`);
|
|
372
354
|
await yunxiaoReq(`/oapi/v1/projex/organizations/${ORG}/workitems`, {
|
|
373
355
|
method: "POST",
|
|
374
356
|
body: {
|
|
375
357
|
spaceId: projectId,
|
|
376
358
|
subject: "提测-需求标题摘要",
|
|
377
|
-
workitemTypeId:
|
|
378
|
-
assignedTo: "测试人员ID",
|
|
379
|
-
parentId: parentReqId,
|
|
380
|
-
description:
|
|
359
|
+
workitemTypeId: types[0].id,
|
|
360
|
+
assignedTo: "测试人员ID",
|
|
361
|
+
parentId: parentReqId,
|
|
362
|
+
description: filledTemplate // 同提测单完善流程 Step 4-5
|
|
381
363
|
}
|
|
382
364
|
});
|
|
383
365
|
```
|
|
384
366
|
|
|
385
|
-
### Step
|
|
386
|
-
|
|
387
|
-
根据团队实际使用的提测单格式(参考 SARW-117、SARW-28 等),提测单描述包含以下结构:
|
|
388
|
-
|
|
389
|
-
```html
|
|
390
|
-
<article class="4ever-article">
|
|
391
|
-
<p>项目名称:{项目名称}</p>
|
|
392
|
-
<p>项目版本:{版本号}</p>
|
|
393
|
-
<p>项目分支:后端分支:{后端分支} 前端分支:{前端分支} h5分支:{h5分支}</p>
|
|
394
|
-
<p>项目需求:</p>
|
|
395
|
-
<ol>
|
|
396
|
-
<li><div>{需求1描述} <span data-type="mention" data-id="{开发者ID}">@{开发者名}</span></div></li>
|
|
397
|
-
<li><div>{需求2描述} <span data-type="mention" data-id="{开发者ID}">@{开发者名}</span></div></li>
|
|
398
|
-
</ol>
|
|
399
|
-
<p>开发人员:</p>
|
|
400
|
-
<ul style="list-style-type:none">
|
|
401
|
-
<li><div><input type="checkbox" readonly=""> <span data-type="mention" data-id="{ID}">@{名字}</span></div></li>
|
|
402
|
-
</ul>
|
|
403
|
-
<p>自测:</p>
|
|
404
|
-
<p>{自测截图或说明}</p>
|
|
405
|
-
<p>AI扫描:</p>
|
|
406
|
-
<p>{AI扫描结果}</p>
|
|
407
|
-
<p>提测人&验收人</p>
|
|
408
|
-
<p><span data-type="mention" data-id="{提测人ID}">@{提测人}</span> <span data-type="mention" data-id="{验收人ID}">@{验收人}</span></p>
|
|
409
|
-
</article>
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
**@提及语法**:`<span data-type="mention" data-id="{用户ID}" data-login="{用户ID}">@{用户名}</span>`
|
|
413
|
-
|
|
414
|
-
### Step 6: 转给测试
|
|
415
|
-
|
|
416
|
-
创建提测单后,将对应的开发任务状态改为"已提测"(如果项目有此状态)或"开发完成":
|
|
367
|
+
### Step 3: 修改开发任务状态
|
|
417
368
|
|
|
418
369
|
```javascript
|
|
419
|
-
// 修改任务状态为开发完成
|
|
420
370
|
await yunxiaoReq(`/oapi/v1/projex/organizations/${ORG}/workitems/${taskId}`, {
|
|
421
371
|
method: "PUT",
|
|
422
372
|
body: { status: "100011" } // 开发完成
|
|
423
373
|
});
|
|
424
374
|
```
|
|
425
375
|
|
|
426
|
-
### 常用工作项类型 ID(按项目动态获取)
|
|
427
|
-
|
|
428
|
-
| 类别 | 类型名 | 用途 |
|
|
429
|
-
|------|--------|------|
|
|
430
|
-
| Task | 任务 | 开发任务、提测单 |
|
|
431
|
-
| Req | 产品类需求 | 产品需求(父级) |
|
|
432
|
-
| Req | 业务类需求 | 业务需求 |
|
|
433
|
-
| Req | 技术类需求 | 技术需求 |
|
|
434
|
-
| Bug | 缺陷 | Bug 单 |
|
|
435
|
-
|
|
436
|
-
> 每个项目的类型 ID 不同,通过 `GET /workitemTypes?category={类别}` 获取。
|
|
437
|
-
|
|
438
376
|
---
|
|
439
377
|
|
|
440
|
-
##
|
|
441
|
-
|
|
442
|
-
### 批量修改状态
|
|
443
|
-
|
|
444
|
-
```
|
|
445
|
-
用户:把 SARW-87、SARW-74 改为开发完成
|
|
446
|
-
```
|
|
378
|
+
## 跨项目搜索用户任务
|
|
447
379
|
|
|
448
|
-
|
|
449
|
-
2. 从项目已有工作项中收集状态 → 找到"开发完成"的 ID
|
|
450
|
-
3. 对每个工作项调用 PUT 更新状态
|
|
451
|
-
4. 逐个 GET 验证更新结果
|
|
380
|
+
云效 API 不支持全局搜索,需逐项目扫描。
|
|
452
381
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
### 读取任务需求并提测
|
|
464
|
-
|
|
465
|
-
```
|
|
466
|
-
用户:读取 EZML-1878,看看要做什么
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
1. 从 serialNumber 前缀找到项目(EZML → 搜索 customCode 匹配)
|
|
470
|
-
2. 搜索项目 Task,找到 EZML-1878
|
|
471
|
-
3. 通过 `parentId` 获取父需求(EZML-1877)详情
|
|
472
|
-
4. 解析父需求 HTML 描述,提取需求内容
|
|
473
|
-
5. 展示给用户
|
|
474
|
-
|
|
475
|
-
```
|
|
476
|
-
用户:创建提测单
|
|
382
|
+
```javascript
|
|
383
|
+
// 全量扫描所有项目(perPage=100,逐页)
|
|
384
|
+
// 对每个项目用 assignedTo + status NOT_CONTAINS 过滤
|
|
385
|
+
// 并发批处理(batchSize=20)
|
|
386
|
+
const batchSize = 20;
|
|
387
|
+
for (let i = 0; i < projects.length; i += batchSize) {
|
|
388
|
+
const batch = projects.slice(i, i + batchSize);
|
|
389
|
+
const results = await Promise.all(batch.map(p => searchWorkitems(p.id)));
|
|
390
|
+
myTasks.push(...results.flat());
|
|
391
|
+
}
|
|
477
392
|
```
|
|
478
393
|
|
|
479
|
-
|
|
480
|
-
2. 生成提测单描述(使用模板)
|
|
481
|
-
3. 创建子任务(parentId 指向父需求,assignedTo 指向测试人员)
|
|
482
|
-
4. 修改开发任务状态为"开发完成"
|
|
394
|
+
> `members` 项目过滤在实测中未生效,建议直接扫描所有项目。
|
|
483
395
|
|
|
484
396
|
## Token 权限要求
|
|
485
397
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<article class="4ever-article">
|
|
2
|
+
<p>项目名称:{项目名称}</p>
|
|
3
|
+
<p>项目版本:{版本号}</p>
|
|
4
|
+
<p>项目分支:后端分支:{后端分支} 前端分支:{前端分支} h5分支:{h5分支}</p>
|
|
5
|
+
<p>项目需求:</p>
|
|
6
|
+
<ol>
|
|
7
|
+
<li><div>{需求描述} <span data-type="mention" data-id="{开发者ID}">@{开发者名}</span></div></li>
|
|
8
|
+
</ol>
|
|
9
|
+
<p>自测:</p>
|
|
10
|
+
<p>{自测说明}</p>
|
|
11
|
+
<p></p>
|
|
12
|
+
<p>测试用例:</p>
|
|
13
|
+
<p>{测试用例}</p>
|
|
14
|
+
<p></p>
|
|
15
|
+
<p>提测人&验收人</p>
|
|
16
|
+
<p><span data-type="mention" data-id="{提测人ID}">@{提测人}</span>&{验收人}</p>
|
|
17
|
+
</article>
|