diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml index 3333879d..09f0aa89 100644 --- a/.github/workflows/ci-docker.yml +++ b/.github/workflows/ci-docker.yml @@ -1,6 +1,10 @@ name: Test on Docker CI -on: [push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] jobs: test: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbb5e3c..21bdac9a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,10 @@ name: Test CI -on: [push, pull_request] +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] env: DATABASE_NAME: dejacode diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2be142b3..69e25cc3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,57 @@ Release notes ### Version 5.1.1-dev +- Add visual indicator in hierarchy views, when an object on the far left or far right + also belong or have a hierarchy (relationship tree). + https://github.com/nexB/dejacode/issues/70 + +- Add search and pagination on the Product Inventory tab. + https://github.com/nexB/dejacode/issues/3 + https://github.com/nexB/dejacode/issues/112 + +- Fix an issue displaying the "Delete" button in the "Edit Product Relationship" + modal form. + https://github.com/nexB/dejacode/issues/128 + +- Add support for PURL(s) in the "Add Package" modal. + If the PURL type is supported by the packageurl_python library, a download URL + will be generated for creating the package and submitting a scan. + https://github.com/nexB/dejacode/issues/131 + +- Leverage PurlDB during the "Add Package" process. + DejaCode will look up the PurlDB to retrieve and fetch all available data to + create the package. + https://github.com/nexB/dejacode/issues/131 + +- Populate the Package notice_text using "*NOTICE*" file content from Scan "key files". + https://github.com/nexB/dejacode/issues/136 + +- Added 2 new license related fields on the Component and Package models: + * declared_license_expression + * other_license_expression + https://github.com/nexB/dejacode/issues/63 + +- Added 2 properties on the Component and Package models: + * declared_license_expression_spdx (computed from declared_license_expression) + * other_license_expression_spdx (computed from other_license_expression) + https://github.com/nexB/dejacode/issues/63 + +- Removed 2 fields: Package.declared_license and Component.concluded_license + https://github.com/nexB/dejacode/issues/63 + +- The new license fields are automatically populated from the Package scan + "Update packages automatically from scan". + The new license fields are pre-filled in the Package form when using the + "Add Package" from a PurlDB entry. + The new license fields are pre-filled in the Component form when using the + "Add Component from Package data". + The license expression values provided in the form for the new field is now + properly checked and return a validation error when incorrect. + https://github.com/nexB/dejacode/issues/63 + +- Use the declared_license_expression_spdx value in SPDX outputs. + https://github.com/nexB/dejacode/issues/63 + ### Version 5.1.0 - Upgrade Python version to 3.12 and Django to 5.0.x diff --git a/Makefile b/Makefile index 1ccbbf21..f914f489 100644 --- a/Makefile +++ b/Makefile @@ -126,6 +126,7 @@ postgresdb: @dropdb ${DB_NAME} || true @echo "-> Create ${DB_NAME} database" @createdb --owner=${DB_USERNAME} ${POSTGRES_INITDB_ARGS} ${DB_NAME} + @gunzip < ${DB_INIT_FILE} | psql --username=${DB_USERNAME} ${DB_NAME} run: ${MANAGE} runserver 8000 --insecure diff --git a/component_catalog/admin.py b/component_catalog/admin.py index 6f745659..4b2751a4 100644 --- a/component_catalog/admin.py +++ b/component_catalog/admin.py @@ -324,6 +324,8 @@ class ComponentAdmin( "copyright", "holder", "license_expression", + "declared_license_expression", + "other_license_expression", "reference_notes", "release_date", "description", @@ -394,7 +396,6 @@ class ComponentAdmin( "ip_sensitivity_approved", "affiliate_obligations", "affiliate_obligation_triggers", - "concluded_license", "legal_comments", "sublicense_allowed", "express_patent_grant", @@ -418,7 +419,10 @@ class ComponentAdmin( autocomplete_lookup_fields = {"fk": ["owner"]} # We have to use 'completion_level' rather than the 'completion_level_pct' # callable to keep the help_text available during render in the template. - readonly_fields = DataspacedAdmin.readonly_fields + ("urn_link", "completion_level") + readonly_fields = DataspacedAdmin.readonly_fields + ( + "urn_link", + "completion_level", + ) form = ComponentAdminForm inlines = [ SubcomponentChildInline, @@ -826,6 +830,8 @@ class PackageAdmin( { "fields": ( "license_expression", + "declared_license_expression", + "other_license_expression", "copyright", "holder", "author", @@ -864,7 +870,6 @@ class PackageAdmin( "Others", { "fields": ( - "declared_license", "parties", "datasource_id", "file_references", @@ -880,7 +885,10 @@ class PackageAdmin( ), get_additional_information_fieldset(), ] - readonly_fields = DataspacedAdmin.readonly_fields + ("package_url", "inferred_url") + readonly_fields = DataspacedAdmin.readonly_fields + ( + "package_url", + "inferred_url", + ) form = PackageAdminForm importer_class = PackageImporter mass_update_form = PackageMassUpdateForm diff --git a/component_catalog/api.py b/component_catalog/api.py index e9ad4fbf..f19f71a7 100644 --- a/component_catalog/api.py +++ b/component_catalog/api.py @@ -140,6 +140,8 @@ class Meta: "holder", "author", "license_expression", + "declared_license_expression", + "other_license_expression", "reference_notes", "homepage_url", "vcs_url", @@ -305,7 +307,6 @@ class Meta: "ip_sensitivity_approved", "affiliate_obligations", "affiliate_obligation_triggers", - "concluded_license", "legal_comments", "sublicense_allowed", "express_patent_grant", @@ -323,6 +324,8 @@ class Meta: "licenses_summary", "license_choices_expression", "license_choices", + "declared_license_expression", + "other_license_expression", "created_date", "last_modified_date", ) @@ -524,6 +527,8 @@ class Meta(ComponentSerializer.Meta): "copyright", "holder", "license_expression", + "declared_license_expression", + "other_license_expression", "reference_notes", "release_date", "description", @@ -551,7 +556,6 @@ class Meta(ComponentSerializer.Meta): "ip_sensitivity_approved", "affiliate_obligations", "affiliate_obligation_triggers", - "concluded_license", "legal_comments", "sublicense_allowed", "express_patent_grant", @@ -639,6 +643,8 @@ class Meta: "licenses_summary", "license_choices_expression", "license_choices", + "declared_license_expression", + "other_license_expression", "reference_notes", "homepage_url", "vcs_url", @@ -656,7 +662,6 @@ class Meta: "version", "qualifiers", "subpath", - "declared_license", "parties", "datasource_id", "file_references", @@ -682,6 +687,7 @@ class Meta: def create(self, validated_data): """Collect data, purl, and submit scan if `collect_data` is provided.""" user = self.context["request"].user + dataspace = user.dataspace collect_data = validated_data.pop("collect_data", None) download_url = validated_data.get("download_url") @@ -701,14 +707,14 @@ def create(self, validated_data): package = super().create(validated_data) # Submit the scan if Package was properly created - scancodeio = ScanCodeIO(user) - if scancodeio.is_configured() and user.dataspace.enable_package_scanning: + scancodeio = ScanCodeIO(dataspace) + if scancodeio.is_configured() and dataspace.enable_package_scanning: # Ensure the task is executed after the transaction is successfully committed transaction.on_commit( lambda: tasks.scancodeio_submit_scan.delay( uris=download_url, user_uuid=user.uuid, - dataspace_uuid=user.dataspace.uuid, + dataspace_uuid=dataspace.uuid, ) ) @@ -799,7 +805,8 @@ class Meta: def collect_create_scan(download_url, user): - package_qs = Package.objects.filter(download_url=download_url, dataspace=user.dataspace) + dataspace = user.dataspace + package_qs = Package.objects.filter(download_url=download_url, dataspace=dataspace) if package_qs.exists(): return False @@ -814,12 +821,12 @@ def collect_create_scan(download_url, user): package = Package.create_from_data(user, package_data) - scancodeio = ScanCodeIO(user) - if scancodeio.is_configured() and user.dataspace.enable_package_scanning: + scancodeio = ScanCodeIO(dataspace) + if scancodeio.is_configured() and dataspace.enable_package_scanning: tasks.scancodeio_submit_scan.delay( uris=download_url, user_uuid=user.uuid, - dataspace_uuid=user.dataspace.uuid, + dataspace_uuid=dataspace.uuid, ) return package diff --git a/component_catalog/forms.py b/component_catalog/forms.py index e6c3ddf8..e2c2cb9f 100644 --- a/component_catalog/forms.py +++ b/component_catalog/forms.py @@ -14,6 +14,7 @@ from django.urls import reverse from django.urls import reverse_lazy from django.utils.functional import cached_property +from django.utils.text import Truncator import packageurl from crispy_forms.helper import FormHelper @@ -82,6 +83,11 @@ class ComponentForm( DataspacedModelForm, ): default_on_addition_fields = ["configuration_status"] + expression_field_names = [ + "license_expression", + "declared_license_expression", + "other_license_expression", + ] save_as = True clone_m2m_classes = [ ComponentAssignedPackage, @@ -106,6 +112,8 @@ class Meta: "holder", "notice_text", "license_expression", + "declared_license_expression", + "other_license_expression", "release_date", "description", "homepage_url", @@ -130,6 +138,8 @@ class Meta: "owner": OwnerChoiceField, } widgets = { + "declared_license_expression": forms.Textarea(attrs={"rows": 2}), + "other_license_expression": forms.Textarea(attrs={"rows": 2}), "copyright": forms.Textarea(attrs={"rows": 2}), "notice_text": forms.Textarea(attrs={"rows": 2}), "description": forms.Textarea(attrs={"rows": 2}), @@ -188,6 +198,7 @@ def helper(self): Group("name", "version", "owner"), HTML("