feat(review): 重构项目级单方案验收协作

This commit is contained in:
yuzhe
2026-07-22 16:41:03 +08:00
parent 6091d61612
commit e7e268d4eb
45 changed files with 1830 additions and 812 deletions

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""通过 Delivery Desk API 创建作品或上传作品新版本"""
"""通过 Delivery Desk API 创建作品或提交新的验收轮次"""
from __future__ import annotations
@@ -37,11 +37,10 @@ def request_json(opener, url: str, *, method: str = "GET", data: bytes | None =
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="通过 API 创建测试作品或上传新版本")
parser = argparse.ArgumentParser(description="通过 API 创建测试作品或提交新的验收轮次")
parser.add_argument("--base-url", default=os.getenv("DELIVERY_DESK_BASE_URL", "http://127.0.0.1:3010"))
parser.add_argument("--project-id", type=int, default=None, help="不传时自动选择唯一可访问的项目")
parser.add_argument("--collection-id", type=int, default=None, help="不传时自动选择项目下唯一的作品交付集")
parser.add_argument("--work-id", type=int, default=None, help="传入后为该作品创建新版本")
parser.add_argument("--work-id", type=int, default=None, help="传入后为该作品提交新的验收轮次")
parser.add_argument("--external-id", default=None, help="调用方作品唯一标识,用于幂等创建和找回作品")
parser.add_argument("--api-key", default=os.getenv("DELIVERY_DESK_API_KEY"))
parser.add_argument("--username", default=os.getenv("DELIVERY_DESK_USERNAME", "operator"))
@@ -99,16 +98,6 @@ def main() -> int:
_, projects, _ = request_json(opener, f"{base_url}/api/projects", headers=auth_headers)
project = choose_item(projects, args.project_id, "项目")
project_id = int(project["id"])
_, collections, _ = request_json(
opener,
f"{base_url}/api/projects/{project_id}/collections",
headers=auth_headers,
)
collection = choose_item(collections, args.collection_id, "作品交付集")
collection_id = int(collection["id"])
if int(collection["project_id"]) != project_id:
raise ApiError(f"作品交付集 {collection_id} 不属于项目 {project_id}")
title = args.title or f"API 测试作品 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
image_urls = args.image_urls or ["https://placehold.co/1200x800/png?text=Delivery+Desk+API+Test"]
upload_headers = {**auth_headers, "Content-Type": "application/json"}
@@ -120,28 +109,29 @@ def main() -> int:
}
if args.work_id is not None:
_, current, _ = request_json(opener, f"{base_url}/api/notes/{args.work_id}", headers=auth_headers)
if int(current["project"]["id"]) != project_id or int(current["collection"]["id"]) != collection_id:
raise ApiError(f"作品 {args.work_id} 不属于选定的项目和作品交付集")
_, current, _ = request_json(opener, f"{base_url}/api/works/{args.work_id}", headers=auth_headers)
if int(current["project"]["id"]) != project_id:
raise ApiError(f"作品 {args.work_id} 不属于选定的项目")
status, work, _ = request_json(
opener,
f"{base_url}/api/notes/{args.work_id}/versions",
f"{base_url}/api/works/{args.work_id}/rounds",
method="POST",
data=json.dumps(payload).encode("utf-8"),
headers=upload_headers,
)
if status != 201 or not work or int(work.get("id", 0)) != args.work_id:
raise ApiError("版本接口没有返回目标作品")
action = "version_created"
raise ApiError("验收轮次接口没有返回目标作品")
action = "round_created"
external_id = work.get("external_id")
else:
external_id = args.external_id or f"api-smoke-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
create_payload = {**payload, "collectionId": collection_id, "externalId": external_id}
create_payload = {**payload, "externalId": external_id}
body = json.dumps(create_payload).encode("utf-8")
status, work, _ = request_json(opener, f"{base_url}/api/notes", method="POST", data=body, headers=upload_headers)
if status not in (200, 201) or not work or int(work.get("collection_id", 0)) != collection_id:
raise ApiError("接口未返回属于目标作品交付集的作品")
_, repeated, _ = request_json(opener, f"{base_url}/api/notes", method="POST", data=body, headers=upload_headers)
works_url = f"{base_url}/api/projects/{project_id}/works"
status, work, _ = request_json(opener, works_url, method="POST", data=body, headers=upload_headers)
if status not in (200, 201) or not work or int(work.get("project_id", 0)) != project_id:
raise ApiError("接口未返回属于目标项目的作品")
_, repeated, _ = request_json(opener, works_url, method="POST", data=body, headers=upload_headers)
if int(repeated.get("id", 0)) != int(work["id"]) or not repeated.get("idempotent"):
raise ApiError("相同 externalId 的重复请求未通过幂等校验")
action = "work_created" if status == 201 else "existing_work_returned"
@@ -153,7 +143,6 @@ def main() -> int:
"action": action,
"group": project.get("group_name"),
"project": project.get("name"),
"collection": collection.get("name"),
"work_id": work.get("id"),
"external_id": external_id,
"version_number": work.get("version_number"),