From 6c3ac3d131d3b6c73382477f6110fcc766f17a8c Mon Sep 17 00:00:00 2001 From: Gernot Hillier Date: Wed, 5 Feb 2025 15:46:15 +0100 Subject: [PATCH] fix(project create): optimize release state handling on update Instead of storing all release states before project update and restoring it in a big loop afterwards, SW360 REST API also allows to pass full release information during release update. We however don't keep the release states set in SW360, but use the states provided in the SBOM. --- ChangeLog.md | 1 + capycli/project/create_project.py | 51 +++++++------------------------ 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index cf5dd62..394da76 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -8,6 +8,7 @@ ## UNRELEASED * `project createbom` stores release relations (`CONTAINED`, `SIDE_BY_SIDE` etc.) as capycli:projectRelation +* fix slowdown/crash in `project update` for large projects (#121) introduced in 2.7.0 ## 2.7.0 diff --git a/capycli/project/create_project.py b/capycli/project/create_project.py index 68a86a2..bfeff86 100644 --- a/capycli/project/create_project.py +++ b/capycli/project/create_project.py @@ -34,8 +34,8 @@ def __init__(self, onlyUpdateProject: bool = False) -> None: self.project_mainline_state: str = "" def bom_to_release_list(self, sbom: Bom) -> List[str]: - """Creates a list with linked releases""" - linkedReleases = [] + """Creates a list with linked releases from the SBOM.""" + linkedReleases = {} for cx_comp in sbom.components: rid = CycloneDxSupport.get_property_value(cx_comp, CycloneDxSupport.CDX_PROP_SW360ID) @@ -45,31 +45,17 @@ def bom_to_release_list(self, sbom: Bom) -> List[str]: + ", " + str(cx_comp.version)) continue - linkedReleases.append(rid) + linkedReleases[rid] = {} - return linkedReleases - - def get_release_project_mainline_states(self, project: Optional[Dict[str, Any]]) -> List[Dict[str, Any]]: - pms: List[Dict[str, Any]] = [] - if not project: - return pms + mainlineState = CycloneDxSupport.get_property_value(cx_comp, CycloneDxSupport.CDX_PROP_PROJ_STATE) + if mainlineState: + linkedReleases[rid]["mainlineState"] = mainlineState + relation = CycloneDxSupport.get_property_value(cx_comp, CycloneDxSupport.CDX_PROP_PROJ_RELATION) + if relation: + # No typo. In project structure, it's "relation", while release update API uses "releaseRelation". + linkedReleases[rid]["releaseRelation"] = relation - if "linkedReleases" not in project: - return pms - - for release in project["linkedReleases"]: # NOT ["sw360:releases"] - pms_release = release.get("release", "") - if not pms_release: - continue - pms_state = release.get("mainlineState", "OPEN") - pms_relation = release.get("relation", "UNKNOWN") - pms_entry: Dict[str, Any] = {} - pms_entry["release"] = pms_release - pms_entry["mainlineState"] = pms_state - pms_entry["new_relation"] = pms_relation - pms.append(pms_entry) - - return pms + return linkedReleases def update_project(self, project_id: str, project: Optional[Dict[str, Any]], sbom: Bom, project_info: Dict[str, Any]) -> None: @@ -79,7 +65,6 @@ def update_project(self, project_id: str, project: Optional[Dict[str, Any]], sys.exit(ResultCode.RESULT_ERROR_ACCESSING_SW360) data = self.bom_to_release_list(sbom) - pms = self.get_release_project_mainline_states(project) ignore_update_elements = ["name", "version"] # remove elements from list because they are handled separately @@ -114,20 +99,6 @@ def update_project(self, project_id: str, project: Optional[Dict[str, Any]], if not result2: print_red(" Error updating project!") - if pms and project: - print_text(" Restoring original project mainline states...") - for pms_entry in pms: - update_release = False - for r in project.get("linkedReleases", []): - if r["release"] == pms_entry["release"]: - update_release = True - break - - if update_release: - rid = self.client.get_id_from_href(pms_entry["release"]) - self.client.update_project_release_relationship( - project_id, rid, pms_entry["mainlineState"], pms_entry["new_relation"], "") - except SW360Error as swex: if swex.response is None: print_red(" Unknown error: " + swex.message)