zt-devops-cli 0.2.3__tar.gz → 0.2.4__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.2.3 → zt_devops_cli-0.2.4}/PKG-INFO +1 -1
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/pyproject.toml +1 -1
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli/api.py +7 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli/cli.py +89 -14
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli.egg-info/PKG-INFO +1 -1
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/README.md +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/setup.cfg +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli/__init__.py +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli/auth.py +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli/config.py +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli.egg-info/SOURCES.txt +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli.egg-info/dependency_links.txt +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli.egg-info/entry_points.txt +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli.egg-info/requires.txt +0 -0
- {zt_devops_cli-0.2.3 → zt_devops_cli-0.2.4}/src/zt_devops_cli.egg-info/top_level.txt +0 -0
|
@@ -346,6 +346,13 @@ class DevOpsAPI:
|
|
|
346
346
|
data=data,
|
|
347
347
|
)
|
|
348
348
|
|
|
349
|
+
def get_bug(self, bug_id: str) -> dict:
|
|
350
|
+
"""查询单个工作项详情(GET issue/{projectId}/{issueId},缺陷详情页同源接口)。"""
|
|
351
|
+
return self._request(
|
|
352
|
+
"GET",
|
|
353
|
+
f"/ms/vteam/api/user/issue/{self.project_id}/{bug_id}",
|
|
354
|
+
)
|
|
355
|
+
|
|
349
356
|
def bug_direction_next(
|
|
350
357
|
self,
|
|
351
358
|
issue_id: str,
|
|
@@ -152,12 +152,12 @@ def _is_api_success(payload) -> bool:
|
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
def _print_action_result(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
ctx,
|
|
156
|
+
result,
|
|
157
|
+
success_text: str = "",
|
|
158
|
+
fail_prefix: str = "操作失败",
|
|
159
|
+
success_checker: Optional[Callable[[dict], bool]] = None,
|
|
160
|
+
success_text_builder: Optional[Callable[[dict], str]] = None,
|
|
161
161
|
) -> bool:
|
|
162
162
|
"""统一处理命令结果输出;返回是否成功。"""
|
|
163
163
|
checker = success_checker or _is_api_success
|
|
@@ -249,8 +249,8 @@ def zteam_project():
|
|
|
249
249
|
@click.option("--start-date", "-s", required=True, help="开始日期 (YYYY-MM-DD)")
|
|
250
250
|
@click.option("--end-date", "-e", required=True, help="结束日期 (YYYY-MM-DD)")
|
|
251
251
|
@click.option("--purpose", required=True, help="迭代目标")
|
|
252
|
-
@click.option("--test-start", required=True,
|
|
253
|
-
@click.option("--test-end",required=True,
|
|
252
|
+
@click.option("--test-start", required=True, help="测试开始日期")
|
|
253
|
+
@click.option("--test-end", required=True, help="测试结束日期")
|
|
254
254
|
@click.pass_context
|
|
255
255
|
def create_sprint(ctx, project, title, start_date, end_date, purpose, test_start, test_end):
|
|
256
256
|
"""创建迭代"""
|
|
@@ -283,6 +283,7 @@ def create_sprint(ctx, project, title, start_date, end_date, purpose, test_start
|
|
|
283
283
|
except Exception as e:
|
|
284
284
|
click.echo(f"错误: {e}", err=True)
|
|
285
285
|
|
|
286
|
+
|
|
286
287
|
@sprint.command("start")
|
|
287
288
|
@click.option("--project", "-p", default=None, help="项目 ID")
|
|
288
289
|
@click.option("--sprint-id", "-i", required=True, help="迭代 ID")
|
|
@@ -881,6 +882,79 @@ def list_bugs(
|
|
|
881
882
|
click.echo(f"错误: {e}", err=True)
|
|
882
883
|
|
|
883
884
|
|
|
885
|
+
def _flatten_issue_detail_for_table(detail):
|
|
886
|
+
"""将详情接口返回的 data 展平为 {字段: 显示值},供 human 表格使用。"""
|
|
887
|
+
if not isinstance(detail, dict):
|
|
888
|
+
return {}
|
|
889
|
+
|
|
890
|
+
def _unwrap_value(v):
|
|
891
|
+
if not isinstance(v, dict):
|
|
892
|
+
return v
|
|
893
|
+
for key in ("value", "label", "name", "displayName", "text", "title"):
|
|
894
|
+
if key in v and v.get(key) not in (None, ""):
|
|
895
|
+
return v.get(key)
|
|
896
|
+
return json.dumps(v, ensure_ascii=False)
|
|
897
|
+
|
|
898
|
+
rows = {}
|
|
899
|
+
prop = detail.get("property")
|
|
900
|
+
if isinstance(prop, dict):
|
|
901
|
+
for k, v in prop.items():
|
|
902
|
+
rows[k] = _unwrap_value(v)
|
|
903
|
+
|
|
904
|
+
for k, v in detail.items():
|
|
905
|
+
if k == "property":
|
|
906
|
+
continue
|
|
907
|
+
if k in rows:
|
|
908
|
+
continue
|
|
909
|
+
if isinstance(v, (dict, list)):
|
|
910
|
+
rows[k] = json.dumps(v, ensure_ascii=False) if v else ""
|
|
911
|
+
else:
|
|
912
|
+
rows[k] = v
|
|
913
|
+
|
|
914
|
+
return rows
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
@bug.command("detail")
|
|
918
|
+
@click.option("--project", "-p", default=None, help="项目 ID")
|
|
919
|
+
@click.option("--bug-id", "-i", required=True, help="缺陷 ID(与列表「缺陷ID」、详情页 URL 中 id 一致)")
|
|
920
|
+
@click.pass_context
|
|
921
|
+
def get_bug_detail(ctx, project, bug_id):
|
|
922
|
+
"""查询单个缺陷详情"""
|
|
923
|
+
project_id = project or ctx.obj["project"]
|
|
924
|
+
if not project_id:
|
|
925
|
+
click.echo("错误: 请通过 -p 指定项目 ID 或在配置中设置 default_project", err=True)
|
|
926
|
+
raise click.Abort()
|
|
927
|
+
|
|
928
|
+
api = DevOpsAPI(project_id)
|
|
929
|
+
try:
|
|
930
|
+
payload = api.get_bug(bug_id)
|
|
931
|
+
data = payload.get("data") if isinstance(payload, dict) else None
|
|
932
|
+
|
|
933
|
+
if ctx.obj.get("output_format") == "json":
|
|
934
|
+
out = data if data is not None else payload
|
|
935
|
+
click.echo(json.dumps(out, ensure_ascii=False, indent=2, default=str))
|
|
936
|
+
return
|
|
937
|
+
|
|
938
|
+
if data is None:
|
|
939
|
+
msg = _extract_api_message(payload) if isinstance(payload, dict) else ""
|
|
940
|
+
click.echo(msg or "未返回详情数据", err=True)
|
|
941
|
+
return
|
|
942
|
+
|
|
943
|
+
flat = _flatten_issue_detail_for_table(data)
|
|
944
|
+
if not flat:
|
|
945
|
+
click.echo(json.dumps(data, ensure_ascii=False, indent=2, default=str))
|
|
946
|
+
return
|
|
947
|
+
|
|
948
|
+
keys = sorted(flat.keys(), key=lambda x: (str(x).lower(), str(x)))
|
|
949
|
+
render_table(
|
|
950
|
+
headers=["字段", "值"],
|
|
951
|
+
rows=[[k, flat[k]] for k in keys],
|
|
952
|
+
no_truncate_headers=["字段", "值"],
|
|
953
|
+
)
|
|
954
|
+
except Exception as e:
|
|
955
|
+
click.echo(f"错误: {e}", err=True)
|
|
956
|
+
|
|
957
|
+
|
|
884
958
|
@bug.command("get-states")
|
|
885
959
|
@click.option("--project", "-p", required=True, help="项目 ID")
|
|
886
960
|
@click.option(
|
|
@@ -1110,12 +1184,13 @@ def list_bug_types(ctx, project, all_options, field_id):
|
|
|
1110
1184
|
@click.option("--zteam-project-id", required=True, help="ZTeam 项目 ID")
|
|
1111
1185
|
@click.option("--sprint-id", required=True, default="", show_default=True, help="迭代 id")
|
|
1112
1186
|
@click.option("--title", "-t", required=True, help="缺陷标题")
|
|
1113
|
-
@click.option("--priority",
|
|
1187
|
+
@click.option("--priority", default="CENTRAL", show_default=True, help="缺陷优先级")
|
|
1114
1188
|
@click.option("--desc-editor-type", default="RICHTEXT", show_default=True, help="缺陷描述编辑器类型")
|
|
1115
|
-
@click.option("--desc",default="<h2><span style=\"font-size: 16px;\">【前置条件】</span></h2>\n"
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1189
|
+
@click.option("--desc", default="<h2><span style=\"font-size: 16px;\">【前置条件】</span></h2>\n"
|
|
1190
|
+
"<h2><span style=\"font-size: 16px;\">【操作步骤】</span></h2>\n"
|
|
1191
|
+
"<h2><span style=\"font-size: 16px;\">【实际结果】</span></h2>\n"
|
|
1192
|
+
"<h2><span style=\"font-size: 16px;\">【预期结果】</span></h2>", show_default=True,
|
|
1193
|
+
help="缺陷描述(支持 HTML")
|
|
1119
1194
|
@click.option("--severity", required=True, default="", show_default=True, help="缺陷严重程度")
|
|
1120
1195
|
@click.option("--type", required=True, default="", show_default=True, help="缺陷分类")
|
|
1121
1196
|
@click.option("--discovery-phase", required=True, default="", show_default=True, help="缺陷发现阶段")
|
|
@@ -1232,7 +1307,6 @@ def _bug_direction_go(ctx, project, bug_id, target_key, comment, operators):
|
|
|
1232
1307
|
|
|
1233
1308
|
|
|
1234
1309
|
def _bug_direction_options(cmd):
|
|
1235
|
-
|
|
1236
1310
|
cmd = click.option(
|
|
1237
1311
|
"-i",
|
|
1238
1312
|
"--bug-id",
|
|
@@ -1428,6 +1502,7 @@ def create_task(
|
|
|
1428
1502
|
except Exception as e:
|
|
1429
1503
|
click.echo(f"错误: {e}", err=True)
|
|
1430
1504
|
|
|
1505
|
+
|
|
1431
1506
|
def main():
|
|
1432
1507
|
cli()
|
|
1433
1508
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|