zt-devops-cli 0.2.1__tar.gz → 0.2.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zt-devops-cli
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: DevOps 平台迭代管理 CLI
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "zt-devops-cli"
7
- version = "0.2.1"
7
+ version = "0.2.3"
8
8
  description = "DevOps 平台迭代管理 CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -3,7 +3,7 @@ import os
3
3
  import click
4
4
  import json
5
5
  import shutil
6
- from typing import Optional
6
+ from typing import Callable, Optional
7
7
 
8
8
  from .api import BUG_DIRECTION_NEXT_NODE_IDS, DevOpsAPI
9
9
  from .auth import login
@@ -98,6 +98,85 @@ def render_table(headers, rows, max_width=120, no_truncate_headers=None):
98
98
  click.echo(border)
99
99
 
100
100
 
101
+ def _extract_api_message(payload) -> str:
102
+ if not isinstance(payload, dict):
103
+ return ""
104
+ for key in ("message", "msg", "errorMsg", "error"):
105
+ value = payload.get(key)
106
+ if isinstance(value, str) and value.strip():
107
+ return value.strip()
108
+ return ""
109
+
110
+
111
+ def _is_api_success(payload) -> bool:
112
+ """兼容不同后端返回结构,判断请求是否成功。"""
113
+ if payload is None:
114
+ return False
115
+
116
+ # HTTP 2xx 但无 body 的场景,_request 会返回 {}
117
+ if isinstance(payload, dict) and not payload:
118
+ return True
119
+
120
+ if not isinstance(payload, dict):
121
+ return False
122
+
123
+ for key in ("success", "ok"):
124
+ if key in payload:
125
+ return bool(payload.get(key))
126
+
127
+ code = payload.get("code")
128
+ if code is not None:
129
+ if str(code).strip() in {"0", "200"}:
130
+ return True
131
+ return False
132
+
133
+ status = payload.get("status")
134
+ if isinstance(status, str):
135
+ norm_status = status.strip().lower()
136
+ if norm_status in {"success", "ok", "succeeded"}:
137
+ return True
138
+ if norm_status in {"fail", "failed", "error"}:
139
+ return False
140
+
141
+ message = _extract_api_message(payload).lower()
142
+ if message:
143
+ if any(word in message for word in ("失败", "错误", "error", "fail")):
144
+ return False
145
+ if any(word in message for word in ("成功", "success")):
146
+ return True
147
+
148
+ if "data" in payload:
149
+ return payload.get("data") is not None
150
+
151
+ return False
152
+
153
+
154
+ def _print_action_result(
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
+ ) -> bool:
162
+ """统一处理命令结果输出;返回是否成功。"""
163
+ checker = success_checker or _is_api_success
164
+
165
+ if ctx.obj.get("output_format") == "json":
166
+ click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
167
+ return checker(result)
168
+
169
+ if checker(result):
170
+ text = success_text_builder(result) if success_text_builder else success_text
171
+ if text:
172
+ click.echo(text)
173
+ return True
174
+
175
+ msg = _extract_api_message(result) or "未返回成功状态"
176
+ click.echo(f"{fail_prefix}: {msg}", err=True)
177
+ return False
178
+
179
+
101
180
  @click.group()
102
181
  @click.option("--project", "-p", default=None, help="项目 ID")
103
182
  @click.option(
@@ -190,11 +269,20 @@ def create_sprint(ctx, project, title, start_date, end_date, purpose, test_start
190
269
  test_start_date=test_start,
191
270
  test_end_date=test_end,
192
271
  )
193
- click.echo(f"创建成功! 迭代 ID: {result.get('id')}")
272
+
273
+ _print_action_result(
274
+ ctx,
275
+ result,
276
+ fail_prefix="创建失败",
277
+ success_checker=lambda payload: bool(
278
+ payload.get("data", {}).get("id")
279
+ ) if isinstance(payload, dict) else False,
280
+ success_text_builder=lambda payload: f"创建成功! 迭代 ID: {payload.get('data', {}).get('id')}",
281
+ )
282
+
194
283
  except Exception as e:
195
284
  click.echo(f"错误: {e}", err=True)
196
285
 
197
-
198
286
  @sprint.command("start")
199
287
  @click.option("--project", "-p", default=None, help="项目 ID")
200
288
  @click.option("--sprint-id", "-i", required=True, help="迭代 ID")
@@ -220,7 +308,7 @@ def start_sprint(ctx, project, sprint_id):
220
308
  return
221
309
 
222
310
  result = api.start_sprint(sprint_data)
223
- click.echo(f"启用成功!")
311
+ _print_action_result(ctx, result, "启用成功!", "启用失败")
224
312
  except Exception as e:
225
313
  click.echo(f"错误: {e}", err=True)
226
314
 
@@ -241,8 +329,8 @@ def delete_sprint(ctx, project, sprint_id):
241
329
  return
242
330
 
243
331
  try:
244
- api.delete_sprint(sprint_id)
245
- click.echo(f"删除成功!")
332
+ result = api.delete_sprint(sprint_id)
333
+ _print_action_result(ctx, result, "删除成功!", "删除失败")
246
334
  except Exception as e:
247
335
  click.echo(f"错误: {e}", err=True)
248
336
 
@@ -263,8 +351,8 @@ def done_sprint(ctx, project, sprint_id):
263
351
  return
264
352
 
265
353
  try:
266
- api.done_sprint(sprint_id)
267
- click.echo(f"完成成功!")
354
+ result = api.done_sprint(sprint_id)
355
+ _print_action_result(ctx, result, "完成成功!", "完成失败")
268
356
  except Exception as e:
269
357
  click.echo(f"错误: {e}", err=True)
270
358
 
@@ -1085,11 +1173,15 @@ def create_bug(
1085
1173
  demand_classify=demand_classify,
1086
1174
  instance_values=instance_values,
1087
1175
  )
1088
- if ctx.obj.get("output_format") == "json":
1089
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1090
- return
1091
- bug_id = result.get("data", {}).get("id") if isinstance(result, dict) else None
1092
- click.echo(f"创建成功! 缺陷 ID: {bug_id or '-'}")
1176
+ _print_action_result(
1177
+ ctx,
1178
+ result,
1179
+ fail_prefix="创建失败",
1180
+ success_checker=lambda payload: bool(
1181
+ payload.get("data", {}).get("id")
1182
+ ) if isinstance(payload, dict) else False,
1183
+ success_text_builder=lambda payload: f"创建成功! 缺陷 ID: {payload.get('data', {}).get('id')}",
1184
+ )
1093
1185
  except Exception as e:
1094
1186
  click.echo(f"错误: {e}", err=True)
1095
1187
 
@@ -1134,10 +1226,7 @@ def _bug_direction_go(ctx, project, bug_id, target_key, comment, operators):
1134
1226
  operators=op_list,
1135
1227
  comment=comment,
1136
1228
  )
1137
- if ctx.obj.get("output_format") == "json":
1138
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1139
- return
1140
- click.echo("流转请求已提交")
1229
+ _print_action_result(ctx, result, "流转请求已提交", "流转失败")
1141
1230
  except Exception as e:
1142
1231
  click.echo(f"错误: {e}", err=True)
1143
1232
 
@@ -1253,10 +1342,7 @@ def bug_delete(ctx, project, bug_id, yes):
1253
1342
  api = DevOpsAPI(project_id)
1254
1343
  try:
1255
1344
  result = api.delete_issue(bug_id)
1256
- if ctx.obj.get("output_format") == "json":
1257
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1258
- return
1259
- click.echo("删除成功")
1345
+ _print_action_result(ctx, result, "删除成功", "删除失败")
1260
1346
  except Exception as e:
1261
1347
  click.echo(f"错误: {e}", err=True)
1262
1348
 
@@ -1329,15 +1415,19 @@ def create_task(
1329
1415
  demand_classify=demand_classify,
1330
1416
  instance_values=instance_values,
1331
1417
  )
1332
- if ctx.obj.get("output_format") == "json":
1333
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1334
- return
1335
- task_id = result.get("data", {}).get("id") if isinstance(result, dict) else None
1336
- click.echo(f"创建成功! 任务 ID: {task_id or '-'}")
1418
+ _print_action_result(
1419
+ ctx,
1420
+ result,
1421
+ fail_prefix="创建失败",
1422
+ success_checker=lambda payload: bool(
1423
+ payload.get("data", {}).get("id")
1424
+ ) if isinstance(payload, dict) else False,
1425
+ success_text_builder=lambda payload: f"创建成功! 任务 ID: {payload.get('data', {}).get('id')}",
1426
+ )
1427
+
1337
1428
  except Exception as e:
1338
1429
  click.echo(f"错误: {e}", err=True)
1339
1430
 
1340
-
1341
1431
  def main():
1342
1432
  cli()
1343
1433
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zt-devops-cli
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: DevOps 平台迭代管理 CLI
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes