zt-devops-cli 0.1.7__tar.gz → 0.1.9__tar.gz
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.
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/PKG-INFO +32 -1
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/README.md +31 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/pyproject.toml +1 -1
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/devops_cli/api.py +68 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/devops_cli/auth.py +4 -4
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/devops_cli/cli.py +263 -16
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/zt_devops_cli.egg-info/PKG-INFO +32 -1
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/setup.cfg +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/devops_cli/__init__.py +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/devops_cli/config.py +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/zt_devops_cli.egg-info/SOURCES.txt +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/zt_devops_cli.egg-info/dependency_links.txt +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/zt_devops_cli.egg-info/entry_points.txt +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/zt_devops_cli.egg-info/requires.txt +0 -0
- {zt_devops_cli-0.1.7 → zt_devops_cli-0.1.9}/src/zt_devops_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zt-devops-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: DevOps 平台迭代管理 CLI
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -58,6 +58,14 @@ zt-devops-cli zteam-project list --project f39507
|
|
|
58
58
|
zt-devops-cli sprint list --project k64352
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
#### 迭代提测列表
|
|
62
|
+
```bash
|
|
63
|
+
zt-devops-cli sprint test-list --project b9f157 \
|
|
64
|
+
--search "BSC_V26.701.01" \
|
|
65
|
+
--num 1 \
|
|
66
|
+
--size 10
|
|
67
|
+
```
|
|
68
|
+
|
|
61
69
|
#### 创建迭代
|
|
62
70
|
|
|
63
71
|
```bash
|
|
@@ -93,6 +101,29 @@ zt-devops-cli task list --project f39507 \
|
|
|
93
101
|
--creator zt07905
|
|
94
102
|
```
|
|
95
103
|
|
|
104
|
+
### 缺陷管理
|
|
105
|
+
|
|
106
|
+
#### 查询缺陷列表(BUG)
|
|
107
|
+
```bash
|
|
108
|
+
zt-devops-cli bug list --project b9f157 \
|
|
109
|
+
--num 1 \
|
|
110
|
+
--size 20 \
|
|
111
|
+
--no-remember
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### 新增缺陷(BUG)
|
|
115
|
+
```bash
|
|
116
|
+
zt-devops-cli bug create --project b9f157 \
|
|
117
|
+
--title "test" \
|
|
118
|
+
--owner zt07905 \
|
|
119
|
+
--zteam-project-id 15678224 \
|
|
120
|
+
--field f05cf2f5dc614dbaa05a13894abb5683=9Clfj3I8fR \
|
|
121
|
+
--field f672b38532614f428828d9a68a514e24=bgEHPFOjFt \
|
|
122
|
+
--field 684f26d36cd747f68dde32104a701956=3129a9cd7315457eb2963bfe19919e72 \
|
|
123
|
+
--field bcee87c140d3475496a2a31c236631f4=vENjmMhXMC \
|
|
124
|
+
--field 8756c5b483434c2bb54bd6bc6586b09b=
|
|
125
|
+
```
|
|
126
|
+
|
|
96
127
|
#### 新增任务(TASK)
|
|
97
128
|
```bash
|
|
98
129
|
zt-devops-cli task create --project <project-id> \ # 通过 project list 获取
|
|
@@ -47,6 +47,14 @@ zt-devops-cli zteam-project list --project f39507
|
|
|
47
47
|
zt-devops-cli sprint list --project k64352
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
#### 迭代提测列表
|
|
51
|
+
```bash
|
|
52
|
+
zt-devops-cli sprint test-list --project b9f157 \
|
|
53
|
+
--search "BSC_V26.701.01" \
|
|
54
|
+
--num 1 \
|
|
55
|
+
--size 10
|
|
56
|
+
```
|
|
57
|
+
|
|
50
58
|
#### 创建迭代
|
|
51
59
|
|
|
52
60
|
```bash
|
|
@@ -82,6 +90,29 @@ zt-devops-cli task list --project f39507 \
|
|
|
82
90
|
--creator zt07905
|
|
83
91
|
```
|
|
84
92
|
|
|
93
|
+
### 缺陷管理
|
|
94
|
+
|
|
95
|
+
#### 查询缺陷列表(BUG)
|
|
96
|
+
```bash
|
|
97
|
+
zt-devops-cli bug list --project b9f157 \
|
|
98
|
+
--num 1 \
|
|
99
|
+
--size 20 \
|
|
100
|
+
--no-remember
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### 新增缺陷(BUG)
|
|
104
|
+
```bash
|
|
105
|
+
zt-devops-cli bug create --project b9f157 \
|
|
106
|
+
--title "test" \
|
|
107
|
+
--owner zt07905 \
|
|
108
|
+
--zteam-project-id 15678224 \
|
|
109
|
+
--field f05cf2f5dc614dbaa05a13894abb5683=9Clfj3I8fR \
|
|
110
|
+
--field f672b38532614f428828d9a68a514e24=bgEHPFOjFt \
|
|
111
|
+
--field 684f26d36cd747f68dde32104a701956=3129a9cd7315457eb2963bfe19919e72 \
|
|
112
|
+
--field bcee87c140d3475496a2a31c236631f4=vENjmMhXMC \
|
|
113
|
+
--field 8756c5b483434c2bb54bd6bc6586b09b=
|
|
114
|
+
```
|
|
115
|
+
|
|
85
116
|
#### 新增任务(TASK)
|
|
86
117
|
```bash
|
|
87
118
|
zt-devops-cli task create --project <project-id> \ # 通过 project list 获取
|
|
@@ -98,6 +98,32 @@ class DevOpsAPI:
|
|
|
98
98
|
return self._request("GET",
|
|
99
99
|
f"/ms/vteam/api/user/issue_sprint/{self.project_id}/flat?num=1&count=1&size=20&content=&start_time=&end_time=&state=ACTIVE%2CNOT_STARTED&sort_field=CREATED_TIME&sort_rule=DESC")
|
|
100
100
|
|
|
101
|
+
def list_sprint_tests(
|
|
102
|
+
self,
|
|
103
|
+
num: int = 1,
|
|
104
|
+
size: int = 20,
|
|
105
|
+
search: str = "",
|
|
106
|
+
result: Optional[list] = None,
|
|
107
|
+
create_user: Optional[list] = None,
|
|
108
|
+
create_time: Optional[list] = None,
|
|
109
|
+
principal: Optional[list] = None,
|
|
110
|
+
obj_id: Optional[list] = None,
|
|
111
|
+
) -> dict:
|
|
112
|
+
"""查询迭代提测列表"""
|
|
113
|
+
data = {
|
|
114
|
+
"result": result or [],
|
|
115
|
+
"createUser": create_user or [],
|
|
116
|
+
"createTime": create_time or [],
|
|
117
|
+
"principal": principal or [],
|
|
118
|
+
"objId": obj_id or [],
|
|
119
|
+
"search": search,
|
|
120
|
+
}
|
|
121
|
+
return self._request(
|
|
122
|
+
"POST",
|
|
123
|
+
f"/ms/vteam/api/user/test/{self.project_id}/all?num={num}&size={size}",
|
|
124
|
+
data=data,
|
|
125
|
+
)
|
|
126
|
+
|
|
101
127
|
def list_projects(self) -> dict:
|
|
102
128
|
"""查询项目列表"""
|
|
103
129
|
return self._request("GET",
|
|
@@ -139,6 +165,33 @@ class DevOpsAPI:
|
|
|
139
165
|
}
|
|
140
166
|
return self._request("POST", f"/ms/vteam/api/user/issue/{self.project_id}", data=data)
|
|
141
167
|
|
|
168
|
+
def create_bug(
|
|
169
|
+
self,
|
|
170
|
+
title: str,
|
|
171
|
+
model_type_id: str,
|
|
172
|
+
priority: str = "CENTRAL",
|
|
173
|
+
editor_type: str = "RICHTEXT",
|
|
174
|
+
desc: str = "",
|
|
175
|
+
parent_id: str = "",
|
|
176
|
+
demand_classify: str = "-1",
|
|
177
|
+
instance_values: Optional[list] = None,
|
|
178
|
+
) -> dict:
|
|
179
|
+
"""创建 BUG 缺陷"""
|
|
180
|
+
data = {
|
|
181
|
+
"title": title,
|
|
182
|
+
"modelTypeId": model_type_id,
|
|
183
|
+
"priority": priority,
|
|
184
|
+
"editorType": editor_type,
|
|
185
|
+
"desc": desc,
|
|
186
|
+
"parentId": parent_id,
|
|
187
|
+
"relationIssue": {},
|
|
188
|
+
"demandClassify": demand_classify,
|
|
189
|
+
"fileVO": [],
|
|
190
|
+
"labelId": [],
|
|
191
|
+
"instanceValue": instance_values or [],
|
|
192
|
+
}
|
|
193
|
+
return self._request("POST", f"/ms/vteam/api/user/issue/{self.project_id}", data=data)
|
|
194
|
+
|
|
142
195
|
def list_tasks(
|
|
143
196
|
self,
|
|
144
197
|
creator: Optional[str] = None,
|
|
@@ -163,3 +216,18 @@ class DevOpsAPI:
|
|
|
163
216
|
f"/ms/vteam/api/user/issue/{self.project_id}/table/TASK?num={num}&size={size}&remember={remember_value}",
|
|
164
217
|
data=data,
|
|
165
218
|
)
|
|
219
|
+
|
|
220
|
+
def list_bugs(
|
|
221
|
+
self,
|
|
222
|
+
num: int = 1,
|
|
223
|
+
size: int = 20,
|
|
224
|
+
remember: bool = False,
|
|
225
|
+
) -> dict:
|
|
226
|
+
"""查询 BUG 列表(缺陷)"""
|
|
227
|
+
remember_value = str(remember).lower()
|
|
228
|
+
data = [{"name": "exclude", "value": []}]
|
|
229
|
+
return self._request(
|
|
230
|
+
"POST",
|
|
231
|
+
f"/ms/vteam/api/user/issue/{self.project_id}/table/BUG?num={num}&size={size}&remember={remember_value}",
|
|
232
|
+
data=data,
|
|
233
|
+
)
|
|
@@ -89,12 +89,12 @@ def open_login_page(page) -> bool:
|
|
|
89
89
|
|
|
90
90
|
return False
|
|
91
91
|
|
|
92
|
-
def get_cookies_from_browser() -> dict:
|
|
92
|
+
def get_cookies_from_browser(headless) -> dict:
|
|
93
93
|
"""通过 Playwright 从浏览器获取 cookie"""
|
|
94
94
|
print("正在启动浏览器(无头模式),请登录...")
|
|
95
95
|
|
|
96
96
|
with sync_playwright() as p:
|
|
97
|
-
browser = p.chromium.launch(headless=
|
|
97
|
+
browser = p.chromium.launch(headless=headless)
|
|
98
98
|
context = browser.new_context()
|
|
99
99
|
page = context.new_page()
|
|
100
100
|
|
|
@@ -156,10 +156,10 @@ def get_cookies_from_browser() -> dict:
|
|
|
156
156
|
|
|
157
157
|
return cookie_dict
|
|
158
158
|
|
|
159
|
-
def login() -> dict:
|
|
159
|
+
def login(headless) -> dict:
|
|
160
160
|
"""手动登录 - 强制打开浏览器重新获取 cookie"""
|
|
161
161
|
print("正在启动浏览器(无头模式),请重新登录...")
|
|
162
|
-
cookies = get_cookies_from_browser()
|
|
162
|
+
cookies = get_cookies_from_browser(headless)
|
|
163
163
|
save_cookies(cookies)
|
|
164
164
|
print("登录成功,cookie 已缓存!")
|
|
165
165
|
return cookies
|
|
@@ -7,6 +7,19 @@ from .auth import login
|
|
|
7
7
|
from .config import config
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
def _parse_custom_fields(entries):
|
|
11
|
+
result = []
|
|
12
|
+
for item in entries:
|
|
13
|
+
if "=" not in item:
|
|
14
|
+
raise click.ClickException(f"--field 参数格式错误: {item},应为 fieldId=value")
|
|
15
|
+
field_id, value = item.split("=", 1)
|
|
16
|
+
field_id = field_id.strip()
|
|
17
|
+
if not field_id:
|
|
18
|
+
raise click.ClickException(f"--field 参数格式错误: {item},fieldId 不能为空")
|
|
19
|
+
result.append({"fieldId": field_id, "value": value})
|
|
20
|
+
return result
|
|
21
|
+
|
|
22
|
+
|
|
10
23
|
def _normalize_cell(value):
|
|
11
24
|
if value is None:
|
|
12
25
|
return "-"
|
|
@@ -102,10 +115,14 @@ def cli(ctx, project, output_format):
|
|
|
102
115
|
|
|
103
116
|
|
|
104
117
|
@cli.command("login")
|
|
105
|
-
|
|
106
|
-
""
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
@click.option(
|
|
119
|
+
"--headed",
|
|
120
|
+
is_flag=True,
|
|
121
|
+
help="显示浏览器窗口,用于无环境变量时的手动登录",
|
|
122
|
+
)
|
|
123
|
+
def cmd_login(headed):
|
|
124
|
+
"""登录 - 打开浏览器重新获取 cookie(默认无头;需手动登录时请传 --headed)"""
|
|
125
|
+
login(headless=not headed)
|
|
109
126
|
|
|
110
127
|
@cli.group()
|
|
111
128
|
def sprint():
|
|
@@ -124,6 +141,11 @@ def issue():
|
|
|
124
141
|
"""需求管理命令组"""
|
|
125
142
|
pass
|
|
126
143
|
|
|
144
|
+
@cli.group()
|
|
145
|
+
def bug():
|
|
146
|
+
"""缺陷管理命令组"""
|
|
147
|
+
pass
|
|
148
|
+
|
|
127
149
|
|
|
128
150
|
@cli.group()
|
|
129
151
|
def task():
|
|
@@ -292,6 +314,72 @@ def list_sprint(ctx, project):
|
|
|
292
314
|
click.echo(f"错误: {e}", err=True)
|
|
293
315
|
|
|
294
316
|
|
|
317
|
+
@sprint.command("test-list")
|
|
318
|
+
@click.option("--project", "-p", default=None, help="项目 ID")
|
|
319
|
+
@click.option("--num", default=1, show_default=True, type=int, help="页码")
|
|
320
|
+
@click.option("--size", default=20, show_default=True, type=int, help="每页条数")
|
|
321
|
+
@click.option("--search", default="", show_default=True, help="搜索关键词(如迭代名称)")
|
|
322
|
+
@click.option("--result", "results", multiple=True, help="提测结果,可重复传入")
|
|
323
|
+
@click.option("--create-user", "create_users", multiple=True, help="创建人账号,可重复传入")
|
|
324
|
+
@click.option("--create-time", "create_times", multiple=True, help="创建时间筛选值,可重复传入")
|
|
325
|
+
@click.option("--principal", "principals", multiple=True, help="负责人账号,可重复传入")
|
|
326
|
+
@click.option("--obj-id", "obj_ids", multiple=True, help="对象 ID,可重复传入")
|
|
327
|
+
@click.pass_context
|
|
328
|
+
def list_sprint_tests(ctx, project, num, size, search, results, create_users, create_times, principals, obj_ids):
|
|
329
|
+
"""查询迭代提测列表"""
|
|
330
|
+
project_id = project or ctx.obj["project"]
|
|
331
|
+
if not project_id:
|
|
332
|
+
click.echo("错误: 请通过 -p 指定项目 ID 或在配置中设置 default_project")
|
|
333
|
+
raise click.Abort()
|
|
334
|
+
api = DevOpsAPI(project_id)
|
|
335
|
+
|
|
336
|
+
try:
|
|
337
|
+
payload = api.list_sprint_tests(
|
|
338
|
+
num=num,
|
|
339
|
+
size=size,
|
|
340
|
+
search=search,
|
|
341
|
+
result=list(results),
|
|
342
|
+
create_user=list(create_users),
|
|
343
|
+
create_time=list(create_times),
|
|
344
|
+
principal=list(principals),
|
|
345
|
+
obj_id=list(obj_ids),
|
|
346
|
+
)
|
|
347
|
+
data = payload.get("data", {}) if isinstance(payload, dict) else {}
|
|
348
|
+
test_list = data.get("content", []) if isinstance(data, dict) else []
|
|
349
|
+
if not isinstance(test_list, list):
|
|
350
|
+
test_list = []
|
|
351
|
+
|
|
352
|
+
if ctx.obj.get("output_format") == "json":
|
|
353
|
+
click.echo(
|
|
354
|
+
json.dumps(
|
|
355
|
+
test_list,
|
|
356
|
+
ensure_ascii=False,
|
|
357
|
+
indent=2,
|
|
358
|
+
default=str,
|
|
359
|
+
)
|
|
360
|
+
)
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
render_table(
|
|
364
|
+
headers=["提测ID", "迭代名称", "提测标题", "提测结果", "负责人", "创建人", "创建时间"],
|
|
365
|
+
rows=[
|
|
366
|
+
[
|
|
367
|
+
s.get("id"),
|
|
368
|
+
s.get("objName") or s.get("sprintName"),
|
|
369
|
+
s.get("title") or s.get("name"),
|
|
370
|
+
s.get("result"),
|
|
371
|
+
s.get("principal"),
|
|
372
|
+
s.get("createUser"),
|
|
373
|
+
s.get("createTime"),
|
|
374
|
+
]
|
|
375
|
+
for s in test_list
|
|
376
|
+
],
|
|
377
|
+
no_truncate_headers=["提测ID", "迭代名称", "提测标题"],
|
|
378
|
+
)
|
|
379
|
+
except Exception as e:
|
|
380
|
+
click.echo(f"错误: {e}", err=True)
|
|
381
|
+
|
|
382
|
+
|
|
295
383
|
@project.command("list")
|
|
296
384
|
@click.pass_context
|
|
297
385
|
def list_project(ctx):
|
|
@@ -478,6 +566,177 @@ def list_task(ctx, project, start_date, end_date, creator, num, size, remember):
|
|
|
478
566
|
click.echo(f"错误: {e}", err=True)
|
|
479
567
|
|
|
480
568
|
|
|
569
|
+
@bug.command("list")
|
|
570
|
+
@click.option("--project", "-p", required=True, help="项目 ID")
|
|
571
|
+
@click.option("--num", default=1, show_default=True, type=int, help="页码")
|
|
572
|
+
@click.option("--size", default=20, show_default=True, type=int, help="每页条数")
|
|
573
|
+
@click.option("--remember/--no-remember", default=False, show_default=True, help="是否启用后端记忆筛选条件")
|
|
574
|
+
@click.pass_context
|
|
575
|
+
def list_bugs(ctx, project, num, size, remember):
|
|
576
|
+
"""查询缺陷列表(BUG)"""
|
|
577
|
+
def _extract_bug_list(payload):
|
|
578
|
+
if not isinstance(payload, dict):
|
|
579
|
+
return []
|
|
580
|
+
data = payload.get("data")
|
|
581
|
+
if isinstance(data, list):
|
|
582
|
+
return data
|
|
583
|
+
if not isinstance(data, dict):
|
|
584
|
+
return []
|
|
585
|
+
|
|
586
|
+
content = None
|
|
587
|
+
if isinstance(data.get("content"), list):
|
|
588
|
+
content = data.get("content")
|
|
589
|
+
else:
|
|
590
|
+
records = data.get("records")
|
|
591
|
+
if isinstance(records, dict) and isinstance(records.get("content"), list):
|
|
592
|
+
content = records.get("content")
|
|
593
|
+
|
|
594
|
+
if not isinstance(content, list):
|
|
595
|
+
return []
|
|
596
|
+
|
|
597
|
+
def _unwrap_value(v):
|
|
598
|
+
if not isinstance(v, dict):
|
|
599
|
+
return v
|
|
600
|
+
for key in ("value", "label", "name", "displayName", "text", "title"):
|
|
601
|
+
if key in v and v.get(key) not in (None, ""):
|
|
602
|
+
return v.get(key)
|
|
603
|
+
return None
|
|
604
|
+
|
|
605
|
+
result = []
|
|
606
|
+
for item in content:
|
|
607
|
+
if not isinstance(item, dict):
|
|
608
|
+
continue
|
|
609
|
+
prop = item.get("property")
|
|
610
|
+
if isinstance(prop, dict):
|
|
611
|
+
flattened = {}
|
|
612
|
+
for k, v in prop.items():
|
|
613
|
+
flattened[k] = _unwrap_value(v)
|
|
614
|
+
result.append(flattened)
|
|
615
|
+
continue
|
|
616
|
+
|
|
617
|
+
normalized = {}
|
|
618
|
+
for k, v in item.items():
|
|
619
|
+
normalized[k] = _unwrap_value(v)
|
|
620
|
+
result.append(normalized)
|
|
621
|
+
return result
|
|
622
|
+
|
|
623
|
+
project_id = project or ctx.obj["project"]
|
|
624
|
+
if not project_id:
|
|
625
|
+
click.echo("错误: 请通过 -p 指定项目 ID 或在配置中设置 default_project")
|
|
626
|
+
raise click.Abort()
|
|
627
|
+
api = DevOpsAPI(project_id)
|
|
628
|
+
|
|
629
|
+
try:
|
|
630
|
+
result = api.list_bugs(
|
|
631
|
+
num=num,
|
|
632
|
+
size=size,
|
|
633
|
+
remember=remember,
|
|
634
|
+
)
|
|
635
|
+
bug_list = _extract_bug_list(result)
|
|
636
|
+
|
|
637
|
+
if ctx.obj.get("output_format") == "json":
|
|
638
|
+
click.echo(
|
|
639
|
+
json.dumps(
|
|
640
|
+
bug_list,
|
|
641
|
+
ensure_ascii=False,
|
|
642
|
+
indent=2,
|
|
643
|
+
default=str,
|
|
644
|
+
)
|
|
645
|
+
)
|
|
646
|
+
return
|
|
647
|
+
|
|
648
|
+
render_table(
|
|
649
|
+
headers=["缺陷ID", "标题", "状态", "创建人", "负责人", "优先级", "严重程度"],
|
|
650
|
+
rows=[
|
|
651
|
+
[
|
|
652
|
+
b.get("id") or b.get("issue_id"),
|
|
653
|
+
b.get("title") or b.get("name"),
|
|
654
|
+
b.get("state") or b.get("status"),
|
|
655
|
+
b.get("createUser") or b.get("creator"),
|
|
656
|
+
b.get("currentOwner") or b.get("handler"),
|
|
657
|
+
b.get("priority"),
|
|
658
|
+
b.get("severity"),
|
|
659
|
+
]
|
|
660
|
+
for b in bug_list
|
|
661
|
+
],
|
|
662
|
+
no_truncate_headers=["缺陷ID", "标题"],
|
|
663
|
+
)
|
|
664
|
+
except Exception as e:
|
|
665
|
+
click.echo(f"错误: {e}", err=True)
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
@bug.command("create")
|
|
669
|
+
@click.option("--project", "-p", required=True, help="项目 ID")
|
|
670
|
+
@click.option("--title", "-t", required=True, help="缺陷标题")
|
|
671
|
+
@click.option("--model-type-id", default="808fb2fd3da74f1da4c772712e10c665", show_default=True, help="缺陷模型 ID")
|
|
672
|
+
@click.option("--priority", default="CENTRAL", show_default=True, help="优先级")
|
|
673
|
+
@click.option("--editor-type", default="RICHTEXT", show_default=True, help="编辑器类型")
|
|
674
|
+
@click.option(
|
|
675
|
+
"--desc",
|
|
676
|
+
default="<h2><span style=\"font-size: 16px;\">【前置条件】</span></h2>\n"
|
|
677
|
+
"<h2><span style=\"font-size: 16px;\">【操作步骤】</span></h2>\n"
|
|
678
|
+
"<h2><span style=\"font-size: 16px;\">【实际结果】</span></h2>\n"
|
|
679
|
+
"<h2><span style=\"font-size: 16px;\">【预期结果】</span></h2>",
|
|
680
|
+
show_default=True,
|
|
681
|
+
help="缺陷描述(支持 HTML)",
|
|
682
|
+
)
|
|
683
|
+
@click.option("--parent-id", default="", show_default=True, help="父缺陷 ID")
|
|
684
|
+
@click.option("--demand-classify", default="-1", show_default=True, help="需求分类")
|
|
685
|
+
@click.option("--owner", required=True, help="提单人账号,例如 zt07905")
|
|
686
|
+
@click.option("--handler", default="", show_default=True, help="处理人账号,默认与 --owner 一致")
|
|
687
|
+
@click.option("--zteam-project-id", required=True, help="ZTeam 项目 ID")
|
|
688
|
+
@click.option("--field", "custom_fields", multiple=True, help="自定义字段,格式: fieldId=value,可重复")
|
|
689
|
+
@click.pass_context
|
|
690
|
+
def create_bug(
|
|
691
|
+
ctx,
|
|
692
|
+
project,
|
|
693
|
+
title,
|
|
694
|
+
model_type_id,
|
|
695
|
+
priority,
|
|
696
|
+
editor_type,
|
|
697
|
+
desc,
|
|
698
|
+
parent_id,
|
|
699
|
+
demand_classify,
|
|
700
|
+
owner,
|
|
701
|
+
handler,
|
|
702
|
+
zteam_project_id,
|
|
703
|
+
custom_fields,
|
|
704
|
+
):
|
|
705
|
+
"""创建缺陷(BUG)"""
|
|
706
|
+
project_id = project or ctx.obj["project"]
|
|
707
|
+
if not project_id:
|
|
708
|
+
click.echo("错误: 请通过 -p 指定项目 ID 或在配置中设置 default_project")
|
|
709
|
+
raise click.Abort()
|
|
710
|
+
|
|
711
|
+
# 基础字段沿用页面创建缺陷抓包;其余字段可通过 --field 传入
|
|
712
|
+
instance_values = [
|
|
713
|
+
{"fieldId": "456e808faf85419b912535da923b7f22", "value": owner},
|
|
714
|
+
{"fieldId": "5abdcb4c783e11edbef4fa819a160800", "value": zteam_project_id},
|
|
715
|
+
{"fieldId": "3cd53ac875944b599f5e70e035327d42", "value": handler or owner},
|
|
716
|
+
]
|
|
717
|
+
instance_values.extend(_parse_custom_fields(custom_fields))
|
|
718
|
+
|
|
719
|
+
api = DevOpsAPI(project_id)
|
|
720
|
+
try:
|
|
721
|
+
result = api.create_bug(
|
|
722
|
+
title=title,
|
|
723
|
+
model_type_id=model_type_id,
|
|
724
|
+
priority=priority,
|
|
725
|
+
editor_type=editor_type,
|
|
726
|
+
desc=desc,
|
|
727
|
+
parent_id=parent_id,
|
|
728
|
+
demand_classify=demand_classify,
|
|
729
|
+
instance_values=instance_values,
|
|
730
|
+
)
|
|
731
|
+
if ctx.obj.get("output_format") == "json":
|
|
732
|
+
click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
|
|
733
|
+
return
|
|
734
|
+
bug_id = result.get("data", {}).get("id") if isinstance(result, dict) else None
|
|
735
|
+
click.echo(f"创建成功! 缺陷 ID: {bug_id or '-'}")
|
|
736
|
+
except Exception as e:
|
|
737
|
+
click.echo(f"错误: {e}", err=True)
|
|
738
|
+
|
|
739
|
+
|
|
481
740
|
@task.command("create")
|
|
482
741
|
@click.option("--project", "-p", required=True, help="项目 ID")
|
|
483
742
|
@click.option("--title", "-t", required=True, help="任务标题")
|
|
@@ -519,18 +778,6 @@ def create_task(
|
|
|
519
778
|
click.echo("错误: 请通过 -p 指定项目 ID 或在配置中设置 default_project")
|
|
520
779
|
raise click.Abort()
|
|
521
780
|
|
|
522
|
-
def _parse_custom_fields(entries):
|
|
523
|
-
result = []
|
|
524
|
-
for item in entries:
|
|
525
|
-
if "=" not in item:
|
|
526
|
-
raise click.ClickException(f"--field 参数格式错误: {item},应为 fieldId=value")
|
|
527
|
-
field_id, value = item.split("=", 1)
|
|
528
|
-
field_id = field_id.strip()
|
|
529
|
-
if not field_id:
|
|
530
|
-
raise click.ClickException(f"--field 参数格式错误: {item},fieldId 不能为空")
|
|
531
|
-
result.append({"fieldId": field_id, "value": value})
|
|
532
|
-
return result
|
|
533
|
-
|
|
534
781
|
# 与浏览器抓包参数保持一致,便于直接复现页面创建行为
|
|
535
782
|
instance_values = [
|
|
536
783
|
{"fieldId": "456e808faf85419b912535da923b7f22", "value": owner},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zt-devops-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: DevOps 平台迭代管理 CLI
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -58,6 +58,14 @@ zt-devops-cli zteam-project list --project f39507
|
|
|
58
58
|
zt-devops-cli sprint list --project k64352
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
#### 迭代提测列表
|
|
62
|
+
```bash
|
|
63
|
+
zt-devops-cli sprint test-list --project b9f157 \
|
|
64
|
+
--search "BSC_V26.701.01" \
|
|
65
|
+
--num 1 \
|
|
66
|
+
--size 10
|
|
67
|
+
```
|
|
68
|
+
|
|
61
69
|
#### 创建迭代
|
|
62
70
|
|
|
63
71
|
```bash
|
|
@@ -93,6 +101,29 @@ zt-devops-cli task list --project f39507 \
|
|
|
93
101
|
--creator zt07905
|
|
94
102
|
```
|
|
95
103
|
|
|
104
|
+
### 缺陷管理
|
|
105
|
+
|
|
106
|
+
#### 查询缺陷列表(BUG)
|
|
107
|
+
```bash
|
|
108
|
+
zt-devops-cli bug list --project b9f157 \
|
|
109
|
+
--num 1 \
|
|
110
|
+
--size 20 \
|
|
111
|
+
--no-remember
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### 新增缺陷(BUG)
|
|
115
|
+
```bash
|
|
116
|
+
zt-devops-cli bug create --project b9f157 \
|
|
117
|
+
--title "test" \
|
|
118
|
+
--owner zt07905 \
|
|
119
|
+
--zteam-project-id 15678224 \
|
|
120
|
+
--field f05cf2f5dc614dbaa05a13894abb5683=9Clfj3I8fR \
|
|
121
|
+
--field f672b38532614f428828d9a68a514e24=bgEHPFOjFt \
|
|
122
|
+
--field 684f26d36cd747f68dde32104a701956=3129a9cd7315457eb2963bfe19919e72 \
|
|
123
|
+
--field bcee87c140d3475496a2a31c236631f4=vENjmMhXMC \
|
|
124
|
+
--field 8756c5b483434c2bb54bd6bc6586b09b=
|
|
125
|
+
```
|
|
126
|
+
|
|
96
127
|
#### 新增任务(TASK)
|
|
97
128
|
```bash
|
|
98
129
|
zt-devops-cli task create --project <project-id> \ # 通过 project list 获取
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|