from __future__ import annotations from .shared import * from ...services.sstc.entity_lookup import _ensure_charter, _ensure_project, _ensure_release from ...services.sstc.governance import _assert_release_transition_allowed, _require_manager from ...services.sstc.signal_core import _as_dict, _parse_node_id, _parse_project_id router = APIRouter(tags=["sstc"]) @router.patch("/projects/{project_id}/releases/{release_node_id}/status") async def patch_release_status( project_id: str, release_node_id: str, body: ReleaseStatusPatchRequest, permission_user: User = Depends(require_project_member_or_manager), db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): _ = permission_user _require_manager(current_user) pid = _parse_project_id(project_id) rid = _parse_node_id(release_node_id, "release_node_id") tenant_id = int(current_user.tenant_id) await _ensure_project(SSTCService(db, tenant_id=tenant_id), pid) release_node = await _ensure_release( db, tenant_id=tenant_id, project_id=pid, release_node_id=rid ) await _assert_release_transition_allowed( db, tenant_id=tenant_id, project_id=pid, release_node=release_node, target_status=body.status, ) before = {"status": release_node.status} release_node.status = body.status content = _as_dict(release_node.content) content["status_note"] = body.note content["last_status_changed_at"] = now_cn_aware().isoformat() release_node.content = content await log_operation( db, tenant_id=tenant_id, user_id=int(current_user.id), project_id=pid, entity_type="release", entity_id=str(rid), action="status_change", before_data=before, after_data={"status": body.status, "note": body.note}, ) await db.commit() return success_response({"id": str(release_node.id), "status": release_node.status}) @router.post("/projects/{project_id}/releases/{release_node_id}/verification/generate") async def generate_release_verification( project_id: str, release_node_id: str, permission_user: User = Depends(require_project_member_or_manager), db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): _ = permission_user _require_manager(current_user) pid = _parse_project_id(project_id) rid = _parse_node_id(release_node_id, "release_node_id") tenant_id = int(current_user.tenant_id) await _ensure_project(SSTCService(db, tenant_id=tenant_id), pid) release_node = await _ensure_release( db, tenant_id=tenant_id, project_id=pid, release_node_id=rid ) content = _as_dict(release_node.content) charter_id = int(content.get("charter_id") or 0) charter = await _ensure_charter( db, tenant_id=tenant_id, project_id=pid, charter_id=charter_id, ) charter_content = _as_dict(charter.content) success_metrics = charter_content.get("success_metrics") or charter_content.get("core_metrics") or [] if not success_metrics: success_metrics = ["功能验收通过", "核心流程无阻塞", "关键性能指标达标"] items = [ { "id": f"check-{i+1}", "title": str(metric), "expected": "达到预期", "status": "pending", "required": True, "source": "charter_success_metric", "verified_by": None, "verified_at": None, "note": None, } for i, metric in enumerate(success_metrics) ] content["verification_items"] = items content["verification_progress"] = {"done": 0, "total": len(items)} content["verification_done"] = False release_node.content = content await db.commit() return success_response({"release_id": str(release_node.id), "verification_items": items})