@josephyan/qingflow-cli 0.2.0-beta.59 → 0.2.0-beta.61
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.
|
@@ -236,8 +236,14 @@ class SolutionExecutor:
|
|
|
236
236
|
existing_role_id = existing.get("role_id")
|
|
237
237
|
if existing_role_id:
|
|
238
238
|
return
|
|
239
|
-
|
|
240
|
-
|
|
239
|
+
try:
|
|
240
|
+
page = self.role_tools.role_search(profile=profile, keyword=role.name, page_num=1, page_size=50).get("page") or {}
|
|
241
|
+
role_list = page.get("list") if isinstance(page, dict) else []
|
|
242
|
+
except Exception as exc: # noqa: BLE001
|
|
243
|
+
api_error = _coerce_qingflow_error(exc)
|
|
244
|
+
if api_error is None or not _is_permission_restricted_error(api_error):
|
|
245
|
+
raise
|
|
246
|
+
role_list = []
|
|
241
247
|
matched_role = next(
|
|
242
248
|
(
|
|
243
249
|
item
|
|
@@ -312,7 +318,18 @@ class SolutionExecutor:
|
|
|
312
318
|
if not isinstance(app_key, str) or not app_key:
|
|
313
319
|
raise ValueError(f"missing app_key for package attach on entity '{entity.entity_id}'")
|
|
314
320
|
|
|
315
|
-
|
|
321
|
+
try:
|
|
322
|
+
package_detail = self.package_tools.package_get(profile=profile, tag_id=tag_id, include_raw=True)
|
|
323
|
+
except Exception as exc: # noqa: BLE001
|
|
324
|
+
api_error = _coerce_qingflow_error(exc)
|
|
325
|
+
if api_error is None or not _is_permission_restricted_error(api_error):
|
|
326
|
+
raise
|
|
327
|
+
raise _required_state_read_blocked_error(
|
|
328
|
+
resource="package_attach",
|
|
329
|
+
message=f"package attach requires readable package state before sorting items for tag '{tag_id}'",
|
|
330
|
+
error=api_error,
|
|
331
|
+
details={"tag_id": tag_id, "app_key": app_key},
|
|
332
|
+
) from exc
|
|
316
333
|
package_result = package_detail.get("result") if isinstance(package_detail.get("result"), dict) else {}
|
|
317
334
|
tag_items = [deepcopy(item) for item in package_result.get("tagItems", []) if isinstance(item, dict)]
|
|
318
335
|
if any(_package_item_app_key(item) == app_key for item in tag_items):
|
|
@@ -675,7 +692,18 @@ class SolutionExecutor:
|
|
|
675
692
|
if dash_key:
|
|
676
693
|
store.set_artifact("portal", "dash_key", dash_key)
|
|
677
694
|
if dash_key:
|
|
678
|
-
|
|
695
|
+
try:
|
|
696
|
+
base_payload = self.portal_tools.portal_get(profile=profile, dash_key=dash_key, being_draft=True).get("result") or {}
|
|
697
|
+
except Exception as exc: # noqa: BLE001
|
|
698
|
+
api_error = _coerce_qingflow_error(exc)
|
|
699
|
+
if api_error is None or not _is_permission_restricted_error(api_error):
|
|
700
|
+
raise
|
|
701
|
+
raise _required_state_read_blocked_error(
|
|
702
|
+
resource="portal",
|
|
703
|
+
message=f"portal update requires readable draft state for dash '{dash_key}'",
|
|
704
|
+
error=api_error,
|
|
705
|
+
details={"dash_key": dash_key},
|
|
706
|
+
) from exc
|
|
679
707
|
update_payload = self._resolve_portal_payload(compiled.portal_plan["update_payload"], store, base_payload=base_payload)
|
|
680
708
|
self.portal_tools.portal_update(profile=profile, dash_key=dash_key, payload=update_payload)
|
|
681
709
|
self._refresh_portal_artifact(profile=profile, store=store, being_draft=True, artifact_key="draft_result")
|
|
@@ -2123,6 +2151,37 @@ def _coerce_qingflow_error(error: Exception) -> QingflowApiError | None:
|
|
|
2123
2151
|
)
|
|
2124
2152
|
|
|
2125
2153
|
|
|
2154
|
+
def _is_permission_restricted_error(error: QingflowApiError) -> bool:
|
|
2155
|
+
return error.backend_code in {40002, 40027}
|
|
2156
|
+
|
|
2157
|
+
|
|
2158
|
+
def _required_state_read_blocked_error(
|
|
2159
|
+
*,
|
|
2160
|
+
resource: str,
|
|
2161
|
+
message: str,
|
|
2162
|
+
error: QingflowApiError,
|
|
2163
|
+
details: dict[str, Any] | None = None,
|
|
2164
|
+
) -> QingflowApiError:
|
|
2165
|
+
merged_details = deepcopy(details) if isinstance(details, dict) else {}
|
|
2166
|
+
merged_details["state_read_blocked"] = {
|
|
2167
|
+
"resource": resource,
|
|
2168
|
+
"transport_error": {
|
|
2169
|
+
"http_status": error.http_status,
|
|
2170
|
+
"backend_code": error.backend_code,
|
|
2171
|
+
"category": error.category,
|
|
2172
|
+
"request_id": error.request_id,
|
|
2173
|
+
},
|
|
2174
|
+
}
|
|
2175
|
+
return QingflowApiError(
|
|
2176
|
+
category=error.category,
|
|
2177
|
+
message=message,
|
|
2178
|
+
backend_code=error.backend_code,
|
|
2179
|
+
request_id=error.request_id,
|
|
2180
|
+
http_status=error.http_status,
|
|
2181
|
+
details=merged_details,
|
|
2182
|
+
)
|
|
2183
|
+
|
|
2184
|
+
|
|
2126
2185
|
def _portal_component_position(
|
|
2127
2186
|
source_type: Any,
|
|
2128
2187
|
*,
|
|
@@ -1855,10 +1855,30 @@ class SolutionTools(ToolBase):
|
|
|
1855
1855
|
try:
|
|
1856
1856
|
result = packages.package_get(profile=profile, tag_id=package_tag_id, include_raw=False)
|
|
1857
1857
|
except (QingflowApiError, RuntimeError) as exc:
|
|
1858
|
+
error = _coerce_solution_api_error(exc)
|
|
1859
|
+
if error.backend_code in {40002, 40027}:
|
|
1860
|
+
return {
|
|
1861
|
+
"status": "resolved",
|
|
1862
|
+
"matched_via": "tag_id",
|
|
1863
|
+
"tag_id": package_tag_id,
|
|
1864
|
+
"tag_name": None,
|
|
1865
|
+
"candidates": [],
|
|
1866
|
+
"metadata_unverified": True,
|
|
1867
|
+
"lookup_permission_blocked": {
|
|
1868
|
+
"scope": "package",
|
|
1869
|
+
"target": {"tag_id": package_tag_id},
|
|
1870
|
+
"transport_error": {
|
|
1871
|
+
"http_status": error.http_status,
|
|
1872
|
+
"backend_code": error.backend_code,
|
|
1873
|
+
"category": error.category,
|
|
1874
|
+
"request_id": error.request_id,
|
|
1875
|
+
},
|
|
1876
|
+
},
|
|
1877
|
+
}
|
|
1858
1878
|
return _builder_package_resolution_failed(
|
|
1859
1879
|
package_name=normalized_name,
|
|
1860
1880
|
package_tag_id=package_tag_id,
|
|
1861
|
-
error=
|
|
1881
|
+
error=error,
|
|
1862
1882
|
retried=False,
|
|
1863
1883
|
)
|
|
1864
1884
|
summary = result.get("result") if isinstance(result.get("result"), dict) else {}
|