diff --git a/scanpipe/models.py b/scanpipe/models.py index 61b9efc39e..8accd1c3eb 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -2864,7 +2864,7 @@ def __str__(self): def save(self, *args, **kwargs): if self.path and not self.parent_path: - self.parent_path = self.parent_directory() or "" + self.parent_path = self.compute_parent_directory() or "" super().save(*args, **kwargs) def get_absolute_url(self): @@ -2935,17 +2935,21 @@ def get_path_segments_with_subpath(self): return part_and_subpath - def parent_directory(self): + def compute_parent_directory(self): """Return the parent path for this CodebaseResource or None.""" - parent_path = parent_directory(str(self.path), with_trail=False) - return parent_path or None + if parent_path := parent_directory(str(self.path), with_trail=False): + return parent_path def has_parent(self): """ Return True if this CodebaseResource has a parent CodebaseResource or False otherwise. """ - parent_path = self.parent_directory() + if self.parent_path: + return True + + # Support for resources created before the parent_path was stored as a field. + parent_path = self.compute_parent_directory() if not parent_path: return False if self.project.codebaseresources.filter(path=parent_path).exists(): @@ -2960,7 +2964,13 @@ def parent(self, codebase=None): `codebase` is not used in this context but required for compatibility with the commoncode.resource.Codebase class API. """ - parent_path = self.parent_directory() + if self.parent_path: + parent_path = self.parent_path + + # Support for resources created before the parent_path was stored as a field. + else: + parent_path = self.compute_parent_directory() + return parent_path and self.project.codebaseresources.get(path=parent_path) def siblings(self, codebase=None): diff --git a/scanpipe/pipes/__init__.py b/scanpipe/pipes/__init__.py index 788a1ce828..31c9c2ba44 100644 --- a/scanpipe/pipes/__init__.py +++ b/scanpipe/pipes/__init__.py @@ -73,7 +73,6 @@ def make_codebase_resource(project, location, save=True, **extra_fields): relative_path = Path(location).relative_to(project.codebase_path) parent_path = str(relative_path.parent) - if parent_path == ".": parent_path = "" diff --git a/scanpipe/tests/pipes/test_scancode.py b/scanpipe/tests/pipes/test_scancode.py index 5f37f6e754..147086bc4a 100644 --- a/scanpipe/tests/pipes/test_scancode.py +++ b/scanpipe/tests/pipes/test_scancode.py @@ -502,7 +502,7 @@ def test_scanpipe_pipes_scancode_assemble_package_function(self): resource = project.codebaseresources.get(name="package.json") # This assembly should not trigger that many queries. - with self.assertNumQueries(18): + with self.assertNumQueries(17): scancode.assemble_package(resource, project, processed_paths) self.assertEqual(1, project.discoveredpackages.count()) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 503072cffb..398c54d451 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -1638,6 +1638,25 @@ def test_scanpipe_codebase_resource_model_compliance_alert_update_fields(self): resource.refresh_from_db() self.assertEqual("ok", resource.compliance_alert) + def test_scanpipe_codebase_resource_model_parent_path_set_during_save(self): + resource = self.project1.codebaseresources.create(path="") + self.assertEqual("", resource.parent_path) + + resource = self.project1.codebaseresources.create(path=".") + self.assertEqual("", resource.parent_path) + + resource = self.project1.codebaseresources.create(path="file") + self.assertEqual("", resource.parent_path) + + resource = self.project1.codebaseresources.create(path="dir/") + self.assertEqual("", resource.parent_path) + + resource = self.project1.codebaseresources.create(path="dir1/dir2/") + self.assertEqual("dir1", resource.parent_path) + + resource = self.project1.codebaseresources.create(path="dir1/dir2/file") + self.assertEqual("dir1/dir2", resource.parent_path) + @patch.object(scanpipe_app, "policies", new=global_policies) def test_scanpipe_can_compute_compliance_alert_for_license_exceptions(self): scanpipe_app.license_policies_index = license_policies_index @@ -1646,16 +1665,6 @@ def test_scanpipe_can_compute_compliance_alert_for_license_exceptions(self): resource.update(detected_license_expression=license_expression) self.assertEqual("warning", resource.compute_compliance_alert()) - def test_scanpipe_codebase_root_parent_path(self): - resource1 = self.project1.codebaseresources.create(path="file") - - self.assertEqual("", resource1.parent_path) - - def test_scanpipe_codebase_regular_parent_path(self): - resource2 = self.project1.codebaseresources.create(path="dir1/dir2/file") - - self.assertEqual("dir1/dir2", resource2.parent_path) - def test_scanpipe_scan_fields_model_mixin_methods(self): expected = [ "detected_license_expression", @@ -2136,7 +2145,9 @@ def test_scanpipe_codebase_resource_model_walk_method(self): path="asgiref-3.3.0.whl-extract/asgiref/compatibility.py" ) expected_parent_path = "asgiref-3.3.0.whl-extract/asgiref" - self.assertEqual(expected_parent_path, asgiref_resource.parent_directory()) + self.assertEqual( + expected_parent_path, asgiref_resource.compute_parent_directory() + ) self.assertTrue(asgiref_resource.has_parent()) expected_parent = self.project_asgiref.codebaseresources.get( path="asgiref-3.3.0.whl-extract/asgiref"