zt-devops-cli 0.2.2__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.2
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.2"
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(
@@ -191,15 +270,19 @@ def create_sprint(ctx, project, title, start_date, end_date, purpose, test_start
191
270
  test_end_date=test_end,
192
271
  )
193
272
 
194
- if result.get("0") == "0":
195
- click.echo(f"创建成功! 迭代 ID: {result.get('id')}")
196
- else:
197
- click.echo(f"错误: {result.get('message')}", err=True)
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
+ )
198
282
 
199
283
  except Exception as e:
200
284
  click.echo(f"错误: {e}", err=True)
201
285
 
202
-
203
286
  @sprint.command("start")
204
287
  @click.option("--project", "-p", default=None, help="项目 ID")
205
288
  @click.option("--sprint-id", "-i", required=True, help="迭代 ID")
@@ -225,7 +308,7 @@ def start_sprint(ctx, project, sprint_id):
225
308
  return
226
309
 
227
310
  result = api.start_sprint(sprint_data)
228
- click.echo(f"启用成功!")
311
+ _print_action_result(ctx, result, "启用成功!", "启用失败")
229
312
  except Exception as e:
230
313
  click.echo(f"错误: {e}", err=True)
231
314
 
@@ -246,8 +329,8 @@ def delete_sprint(ctx, project, sprint_id):
246
329
  return
247
330
 
248
331
  try:
249
- api.delete_sprint(sprint_id)
250
- click.echo(f"删除成功!")
332
+ result = api.delete_sprint(sprint_id)
333
+ _print_action_result(ctx, result, "删除成功!", "删除失败")
251
334
  except Exception as e:
252
335
  click.echo(f"错误: {e}", err=True)
253
336
 
@@ -268,8 +351,8 @@ def done_sprint(ctx, project, sprint_id):
268
351
  return
269
352
 
270
353
  try:
271
- api.done_sprint(sprint_id)
272
- click.echo(f"完成成功!")
354
+ result = api.done_sprint(sprint_id)
355
+ _print_action_result(ctx, result, "完成成功!", "完成失败")
273
356
  except Exception as e:
274
357
  click.echo(f"错误: {e}", err=True)
275
358
 
@@ -1090,11 +1173,15 @@ def create_bug(
1090
1173
  demand_classify=demand_classify,
1091
1174
  instance_values=instance_values,
1092
1175
  )
1093
- if ctx.obj.get("output_format") == "json":
1094
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1095
- return
1096
- bug_id = result.get("data", {}).get("id") if isinstance(result, dict) else None
1097
- 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
+ )
1098
1185
  except Exception as e:
1099
1186
  click.echo(f"错误: {e}", err=True)
1100
1187
 
@@ -1139,10 +1226,7 @@ def _bug_direction_go(ctx, project, bug_id, target_key, comment, operators):
1139
1226
  operators=op_list,
1140
1227
  comment=comment,
1141
1228
  )
1142
- if ctx.obj.get("output_format") == "json":
1143
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1144
- return
1145
- click.echo("流转请求已提交")
1229
+ _print_action_result(ctx, result, "流转请求已提交", "流转失败")
1146
1230
  except Exception as e:
1147
1231
  click.echo(f"错误: {e}", err=True)
1148
1232
 
@@ -1258,10 +1342,7 @@ def bug_delete(ctx, project, bug_id, yes):
1258
1342
  api = DevOpsAPI(project_id)
1259
1343
  try:
1260
1344
  result = api.delete_issue(bug_id)
1261
- if ctx.obj.get("output_format") == "json":
1262
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1263
- return
1264
- click.echo("删除成功")
1345
+ _print_action_result(ctx, result, "删除成功", "删除失败")
1265
1346
  except Exception as e:
1266
1347
  click.echo(f"错误: {e}", err=True)
1267
1348
 
@@ -1334,15 +1415,19 @@ def create_task(
1334
1415
  demand_classify=demand_classify,
1335
1416
  instance_values=instance_values,
1336
1417
  )
1337
- if ctx.obj.get("output_format") == "json":
1338
- click.echo(json.dumps(result, ensure_ascii=False, indent=2, default=str))
1339
- return
1340
- task_id = result.get("data", {}).get("id") if isinstance(result, dict) else None
1341
- 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
+
1342
1428
  except Exception as e:
1343
1429
  click.echo(f"错误: {e}", err=True)
1344
1430
 
1345
-
1346
1431
  def main():
1347
1432
  cli()
1348
1433
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zt-devops-cli
3
- Version: 0.2.2
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