Skip to content

Commit

Permalink
feat: implement paging for releases and components
Browse files Browse the repository at this point in the history
  • Loading branch information
t-graf committed Oct 2, 2023
1 parent 7f41187 commit d21b79d
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 25 deletions.
10 changes: 9 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@

# SW360 Base Library for Python

## V1.2.3
## V1.3.0

* `get_projects` fixed - paging work now as expected.
* `get_projects` now also supports a sort order.
* `get_all_releases` now also support paging.
**IMPORTANT:** Due to compatibility reasons `get_all_releases` without `page` parameter returns
a list of releases. But when the `page` parameter is used, a dict will be returned that also contains
information about paging.
* `get_all_components` now supports `allDetails` and `sort`.
**IMPORTANT:** Due to compatibility reasons `get_all_components` without `page` parameter returns
a list of components. But when the `page` parameter is used, a dict will be returned that also contains
information about paging.

## V1.2.2

Expand Down
33 changes: 25 additions & 8 deletions sw360/components.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# Copyright (c) 2019-2022 Siemens
# Copyright (c) 2019-2023 Siemens
# Copyright (c) 2022 BMW CarIT GmbH
# All Rights Reserved.
# Authors: [email protected], [email protected]
Expand All @@ -15,24 +15,40 @@


class ComponentsMixin:
def get_all_components(self, fields=None, page=-1, page_size=-1):
def get_all_components(self, fields=None, page=-1, page_size=-1, all_details: bool = False, sort: str = ""):
"""Get information of about all components
API endpoint: GET /components
:param page: page to retrieve
:type page: int
:param page_size: page size to use
:type page_size: int
:param all_details: retrieve all component details (optional))
:type all_details: bool
:param sort: sort order for the components ("name,desc"; "name,asc")
:type sort: str
:return: list of components
:rtype: list of JSON component objects
:raises SW360Error: if there is a negative HTTP response
"""

url = self.url + "resource/api/components"

if all_details:
url = self._add_param(url, "allDetails=true")

if fields:
url = self.url + "resource/api/components?fields=" + fields
else:
url = self.url + "resource/api/components"
url = self._add_param(url, "fields=" + fields)

if page > -1:
url = url + "?page=" + str(page) + "&page_entries="
url = url + str(page_size) + "&sort=name%2Cdesc"
url = self._add_param(url, "page=" + str(page))
url = self._add_param(url, "page_entries=" + str(page_size))

if sort:
# ensure HTML encoding
sort = sort.replace(",", "%2C")
url = self._add_param(url, "sort=" + sort)

resp = self.api_get(url)
if not resp:
Expand All @@ -44,7 +60,8 @@ def get_all_components(self, fields=None, page=-1, page_size=-1):
if "sw360:components" not in resp["_embedded"]:
return None

resp = resp["_embedded"]["sw360:components"]
if page == -1:
resp = resp["_embedded"]["sw360:components"]
return resp

def get_components_by_type(self, component_type):
Expand Down
8 changes: 4 additions & 4 deletions sw360/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,16 @@ def get_projects(self, all_details: bool = False, page: int = -1, page_size: int

full_url = self.url + "resource/api/projects"
if all_details:
full_url = full_url + "?allDetails=true"
full_url = self._add_param(full_url, "allDetails=true")

if page > -1:
full_url = full_url + "&page=" + str(page)
full_url = full_url + "&page_entries=" + str(page_size)
full_url = self._add_param(full_url, "page=" + str(page))
full_url = self._add_param(full_url, "page_entries=" + str(page_size))

if sort:
# ensure HTML encoding
sort = sort.replace(",", "%2C")
full_url = full_url + "&sort=" + sort
full_url = self._add_param(full_url, "sort=" + sort)

resp = self.api_get(full_url)
return resp
Expand Down
25 changes: 20 additions & 5 deletions sw360/releases.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# Copyright (c) 2019-2022 Siemens
# Copyright (c) 2019-2023 Siemens
# Copyright (c) 2022 BMW CarIT GmbH
# All Rights Reserved.
# Authors: [email protected], [email protected]
Expand Down Expand Up @@ -60,27 +60,42 @@ def get_releases_by_name(self, name):
resp = resp["_embedded"]["sw360:releases"]
return resp

def get_all_releases(self, fields=None, all_details=False):
def get_all_releases(self, fields=None, all_details=False, page: int = -1, page_size: int = -1, sort: str = ""):
"""Get information of about all releases
API endpoint: GET /releases
:param all_details: retrieve all project details (optional))
:type all_details: bool
:param page: page to retrieve
:type page: int
:param page_size: page size to use
:type page_size: int
:param sort: sort order for the releases ("name,desc"; "name,asc")
:type sort: str
:return: list of releases
:rtype: list of JSON release objects
:raises SW360Error: if there is a negative HTTP response
"""
full_url = self.url + "resource/api/releases"
if all_details:
full_url = full_url + "?allDetails=true"
full_url = self._add_param(full_url, "allDetails=true")

if fields:
full_url = full_url + "?fields=" + fields
full_url = self._add_param(full_url, "fields=" + fields)

if page > -1:
full_url = self._add_param(full_url, "page=" + str(page))
full_url = self._add_param(full_url, "page_entries=" + str(page_size))

if sort:
# ensure HTML encoding
sort = sort.replace(",", "%2C")
full_url = self._add_param(full_url, "sort=" + sort)

resp = self.api_get(full_url)

if resp and ("_embedded" in resp) and ("sw360:releases" in resp["_embedded"]):
if page == -1 and resp and ("_embedded" in resp) and ("sw360:releases" in resp["_embedded"]):
resp = resp["_embedded"]["sw360:releases"]
return resp

Expand Down
9 changes: 9 additions & 0 deletions sw360/sw360_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ def _update_external_ids(self, current_data, ext_id_name, ext_id_value,

return (old_value, ext_id_data, update)

def _add_param(self, url: str, param: str) -> str:
"""Add the given parameter to the given url"""
if "?" in url:
url = url + "&"
else:
url = url + "?"

return url + param

# ----- Health -------------------------------------------------------

def get_health_status(self):
Expand Down
5 changes: 3 additions & 2 deletions tests/test_sw360_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,15 @@ def test_get_all_components_with_fields_and_paging(self):

responses.add(
method=responses.GET,
url=self.MYURL + "resource/api/components?fields=ownerCountry?page=1&page_entries=2&sort=name%2Cdesc", # noqa
url=self.MYURL + "resource/api/components?fields=ownerCountry&page=1&page_entries=2", # noqa
body='{"_embedded": {"sw360:components": [{"name": "Tethys.Logging", "ownerCountry": "DE", "componentType": "OSS", "externalIds": {"package-url": "pkg:nuget/Tethys.Logging"}}]}}', # noqa
status=200,
content_type="application/json",
adding_headers={"Authorization": "Token " + self.MYTOKEN},
)

components = lib.get_all_components("ownerCountry", 1, 2)
dict = lib.get_all_components("ownerCountry", 1, 2)
components = dict["_embedded"]["sw360:components"]
self.assertIsNotNone(components)
self.assertTrue(len(components) > 0)
self.assertEqual("Tethys.Logging", components[0]["name"])
Expand Down
6 changes: 3 additions & 3 deletions tests/test_sw360_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def test_get_projects_with_paging(self):

responses.add(
responses.GET,
url=self.MYURL + "resource/api/projects?page=1&page_entries=2&sort=name%2Cdesc",
url=self.MYURL + "resource/api/projects?page=1&page_entries=2",
body='{"_embedded": {"sw360:projects": [{"name": "My Testproject"}]}}',
status=200,
content_type="application/json",
Expand All @@ -231,14 +231,14 @@ def test_get_projects_with_paging_and_details(self):

responses.add(
responses.GET,
url=self.MYURL + "resource/api/projects?allDetails=true?page=3&page_entries=4&sort=name%2Cdesc", # noqa
url=self.MYURL + "resource/api/projects?allDetails=true&page=3&page_entries=4&sort=name%2Cdesc", # noqa
body='{"_embedded": {"sw360:projects": [{"name": "My Testproject"}]}}',
status=200,
content_type="application/json",
adding_headers={"Authorization": "Token " + self.MYTOKEN},
)

projects = lib.get_projects(all_details=True, page=3, page_size=4)
projects = lib.get_projects(all_details=True, page=3, page_size=4, sort="name,desc")
self.assertIsNotNone(projects)
self.assertTrue("_embedded" in projects)
self.assertTrue("sw360:projects" in projects["_embedded"])
Expand Down
4 changes: 2 additions & 2 deletions tests/test_sw360_releases.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# Copyright (c) 2020 Siemens
# Copyright (c) 2023 Siemens
# All Rights Reserved.
# Author: [email protected]
#
Expand Down Expand Up @@ -191,7 +191,7 @@ def test_get_all_releases_with_fields_and_all_details(self):

responses.add(
method=responses.GET,
url=self.MYURL + "resource/api/releases?allDetails=true?fields=releaseDate",
url=self.MYURL + "resource/api/releases?allDetails=true&fields=releaseDate",
body='{"_embedded": {"sw360:releases": [{"name": "Tethys.Logging", "version": "1.3.0", "releaseDate": "2018-03-04"}]}}', # noqa
status=200,
content_type="application/json",
Expand Down

0 comments on commit d21b79d

Please sign in to comment.