From e9490d29a4c6144e7bfdf3e9b9a5ebf1be9c18b7 Mon Sep 17 00:00:00 2001 From: tdruez Date: Tue, 28 May 2024 19:26:51 +0400 Subject: [PATCH] Add update_from_purldb method on the Package model #45 Signed-off-by: tdruez --- component_catalog/models.py | 23 +++++++++++-- component_catalog/tests/test_models.py | 45 ++++++++++++++++++++++++++ component_catalog/tests/test_views.py | 4 +-- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/component_catalog/models.py b/component_catalog/models.py index e4917f4c..52236809 100644 --- a/component_catalog/models.py +++ b/component_catalog/models.py @@ -2291,7 +2291,7 @@ def where_used(self, user): f"Component {self.component_set.count()}\n" ) - def get_purldb_entries(self, user, max_request_call=0, timeout=None): + def get_purldb_entries(self, user, max_request_call=0, timeout=10): """ Return the PurlDB entries that correspond to this Package instance. @@ -2320,10 +2320,27 @@ def get_purldb_entries(self, user, max_request_call=0, timeout=None): if max_request_call and index >= max_request_call: return - packages_data = PurlDB(user).find_packages(payload, timeout) - if packages_data: + if packages_data := PurlDB(user).find_packages(payload, timeout): return packages_data + def update_from_purldb(self, user): + """ + Find this Package in the PurlDB and update empty fields with PurlDB data + when available. + """ + purldb_entries = self.get_purldb_entries(user) + if not purldb_entries or len(purldb_entries) != 1: + return + + package_data = purldb_entries[0] + # The format from PURLDB is "2019-11-18T00:00:00Z" + if release_date := package_data.get("release_date"): + package_data["release_date"] = release_date.split("T")[0] + package_data["license_expression"] = package_data.get("declared_license_expression") + + updated_fields = self.update_from_data(user, package_data, override=False) + return updated_fields + class PackageAssignedLicense(DataspacedModel): package = models.ForeignKey( diff --git a/component_catalog/tests/test_models.py b/component_catalog/tests/test_models.py index 03d5ced0..60e54786 100644 --- a/component_catalog/tests/test_models.py +++ b/component_catalog/tests/test_models.py @@ -2416,3 +2416,48 @@ def test_package_model_inferred_url_property(self): package1.save() expected = "https://github.com/package-url/packageurl-python/tree/v0.10.4" self.assertEqual(expected, package1.inferred_url) + + @mock.patch("component_catalog.models.Package.get_purldb_entries") + def test_package_model_update_from_purldb(self, mock_get_purldb_entries): + purldb_entry = { + "uuid": "326aa7a8-4f28-406d-89f9-c1404916925b", + "purl": "pkg:pypi/django@3.0", + "type": "pypi", + "name": "django", + "version": "3.0", + "primary_language": "Python", + "description": "Description", + "release_date": "2019-11-18T00:00:00Z", + "parties": [], + "keywords": ["Keyword1", "Keyword2"], + "download_url": "https://files.pythonhosted.org/packages/38/Django-3.0.tar.gz", + "sha1": "96ae8d8dd673d4fc92ce2cb2df9cdab6f6fd7d9f", + "sha256": "0a1efde1b685a6c30999ba00902f23613cf5db864c5a1532d2edf3eda7896a37", + "copyright": "(c) Copyright", + "declared_license_expression": "(bsd-simplified AND bsd-new) AND unknown", + } + + mock_get_purldb_entries.return_value = [purldb_entry] + package1 = Package.objects.create(filename="package", dataspace=self.dataspace) + updated_fields = package1.update_from_purldb(self.user) + # Note: PURL fields are never updated. + expected = [ + "primary_language", + "description", + "release_date", + "keywords", + "download_url", + "sha1", + "sha256", + "copyright", + "license_expression", + ] + self.assertEqual(expected, updated_fields) + + package1.refresh_from_db() + # Handle release_date separatly + updated_fields.remove("release_date") + self.assertEqual(purldb_entry["release_date"], str(package1.release_date)) + + for field_name in updated_fields: + self.assertEqual(purldb_entry[field_name], getattr(package1, field_name)) diff --git a/component_catalog/tests/test_views.py b/component_catalog/tests/test_views.py index 6877f687..a875de21 100644 --- a/component_catalog/tests/test_views.py +++ b/component_catalog/tests/test_views.py @@ -3688,7 +3688,7 @@ def test_component_catalog_package_add_view_initial_data( puyrldb_entry = { "filename": "abbot-1.4.0.jar", - "release_date": "2015-09-22", + "release_date": "2010-05-24T00:00:00Z", "type": "maven", "namespace": "abbot", "name": "abbot", @@ -3714,7 +3714,7 @@ def test_component_catalog_package_add_view_initial_data( response = self.client.get(add_url + "?package_url=pkg:maven/abbot/abbot@1.4.0") expected = { "filename": "abbot-1.4.0.jar", - "release_date": "2015-09-22", + "release_date": "2010-05-24T00:00:00Z", "type": "maven", "namespace": "abbot", "name": "abbot",