Skip to content

Commit

Permalink
Add retrieve functionality
Browse files Browse the repository at this point in the history
closes #1010

In particular we are adding the new behaviour for:

- ReleaseArchitecture
- ReleaseComponent

but deliberately not for PackageReleaseComponent, which should only be
created indirectly using package actions.
  • Loading branch information
quba42 committed Mar 4, 2024
1 parent 82ece97 commit cbec80f
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES/1010.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added retrieve functionality for ReleaseArchitecture and ReleaseComponent content.
2 changes: 2 additions & 0 deletions CHANGES/1010.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The API endpoints for ReleaseArchitecture and ReleaseComponent creation will no longer return a 400 ``non_field_errors`` if the content to be created already exists.
Instead a task is triggered that will list the existing content in its ``created_resources`` field.
30 changes: 30 additions & 0 deletions pulp_deb/app/serializers/content_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,21 @@ class ReleaseArchitectureSerializer(NoArtifactContentSerializer):
architecture = CharField(help_text="Name of the architecture.")
distribution = CharField(help_text="Name of the distribution.")

def get_unique_together_validators(self):
"""
We do not want UniqueTogetherValidator since we have retrieve logic!
"""
return []

def retrieve(self, validated_data):
"""
If the ReleaseArchitecture already exists, retrieve it!
"""
return ReleaseComponent.objects.filter(
architecture=validated_data["architecture"],
distribution=validated_data["distribution"],
).first()

class Meta(NoArtifactContentSerializer.Meta):
model = ReleaseArchitecture
fields = NoArtifactContentSerializer.Meta.fields + (
Expand All @@ -763,6 +778,21 @@ class ReleaseComponentSerializer(NoArtifactContentSerializer):
A Serializer for ReleaseComponent.
"""

def get_unique_together_validators(self):
"""
We do not want UniqueTogetherValidator since we have retrieve logic!
"""
return []

def retrieve(self, validated_data):
"""
If the ReleaseComponent already exists, retrieve it!
"""
return ReleaseComponent.objects.filter(
distribution=validated_data["distribution"],
component=validated_data["component"],
).first()

component = CharField(help_text="Name of the component.")
distribution = CharField(help_text="Name of the distribution.")

Expand Down
39 changes: 37 additions & 2 deletions pulp_deb/app/viewsets/content.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,54 @@
from gettext import gettext as _ # noqa

from django_filters import Filter
from drf_spectacular.utils import extend_schema
from pulpcore.plugin.tasking import general_create
from pulpcore.plugin.models import Repository, RepositoryVersion
from pulpcore.plugin.serializers import AsyncOperationResponseSerializer
from pulpcore.plugin.serializers.content import ValidationError
from pulpcore.plugin.tasking import dispatch
from pulpcore.plugin.viewsets import (
NAME_FILTER_OPTIONS,
ContentFilter,
ContentViewSet,
NamedModelViewSet,
OperationPostponedResponse,
SingleArtifactContentUploadViewSet,
)
from pulpcore.plugin.viewsets.content import DefaultDeferredContextMixin

from pulp_deb.app import models, serializers


class NoArtifactContentViewSet(DefaultDeferredContextMixin, ContentViewSet):
"""A ViewSet for content creation that does not require a file to be uploaded."""

@extend_schema(
description="Trigger an asynchronous task to create content,"
"optionally create new repository version.",
responses={202: AsyncOperationResponseSerializer},
)
def create(self, request):
"""Create a content unit."""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)

exclusive_resources = [
item for item in (serializer.validated_data.get(key) for key in ("repository",)) if item
]

task = dispatch(
general_create,
exclusive_resources=exclusive_resources,
args=(self.queryset.model._meta.app_label, serializer.__class__.__name__),
kwargs={
"data": {k: v for k, v in request.data.items()},
"context": self.get_deferred_context(request),
},
)
return OperationPostponedResponse(task, request)


class GenericContentFilter(ContentFilter):
"""
FilterSet for GenericContent.
Expand Down Expand Up @@ -440,7 +475,7 @@ class Meta:
fields = ["architecture", "distribution"]


class ReleaseArchitectureViewSet(ContentViewSet):
class ReleaseArchitectureViewSet(NoArtifactContentViewSet):
# The doc string is a top level element of the user facing REST API documentation:
"""
A ReleaseArchitecture represents a single dpkg architecture string.
Expand Down Expand Up @@ -479,7 +514,7 @@ class Meta:
fields = ["component", "distribution"]


class ReleaseComponentViewSet(ContentViewSet):
class ReleaseComponentViewSet(NoArtifactContentViewSet):
# The doc string is a top level element of the user facing REST API documentation:
"""
A ReleaseComponent represents a single APT repository component.
Expand Down
35 changes: 35 additions & 0 deletions pulp_deb/tests/functional/api/test_crud_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,38 @@ def test_structured_package_upload(

results = package_list.results[0]
assert results.relative_path == attrs["relative_path"]


def test_release_component_upload(
apt_release_component_api,
deb_get_repository_by_href,
deb_release_component_factory,
deb_repository_factory,
monitor_task,
):
"""Test creating a ReleaseComponent directly in a repository."""
repository = deb_repository_factory()
assert repository.latest_version_href.endswith("/0/")

attrs = {
"repository": repository.pulp_href,
"distribution": str(uuid4()),
"component": str(uuid4()),
}

component = deb_release_component_factory(**attrs)
repository = deb_get_repository_by_href(repository.pulp_href)
assert repository.latest_version_href.endswith("/1/")

repo_version_components = apt_release_component_api.list(
repository_version=repository.latest_version_href
)

assert len(repo_version_components.results) == 1
assert repo_version_components.results[0].pulp_href == component.pulp_href

component2 = deb_release_component_factory(**attrs)
repository = deb_get_repository_by_href(repository.pulp_href)

assert repository.latest_version_href.endswith("/1/")
assert component.pulp_href == component2.pulp_href
32 changes: 32 additions & 0 deletions pulp_deb/tests/functional/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
Copy,
DebAptPublication,
DebCopyApi,
DebReleaseComponent,
DebVerbatimPublication,
PublicationsVerbatimApi,
)
Expand Down Expand Up @@ -70,6 +71,12 @@ def apt_release_component_api(apt_client):
return ContentReleaseComponentsApi(apt_client)


@pytest.fixture(scope="session")
def deb_release_component():
"""Fixture for APT release API."""
return DebReleaseComponent


@pytest.fixture(scope="session")
def apt_generic_content_api(apt_client):
"""Fixture for APT generic content API."""
Expand Down Expand Up @@ -104,6 +111,31 @@ def _deb_package_factory(**kwargs):
return _deb_package_factory


@pytest.fixture(scope="class")
def deb_release_component_factory(
deb_release_component, apt_release_component_api, gen_object_with_cleanup
):
"""Fixture that generates deb package with cleanup."""

def _deb_release_component_factory(**kwargs):
"""Create an APT ReleaseComponent.
:returns: The created ReleaseComponent.
"""
args = {
"component": kwargs.pop("component"),
"distribution": kwargs.pop("distribution"),
}
if "repository" in kwargs:
args["repository"] = kwargs.pop("repository")
release_component_object = deb_release_component(**args)
return gen_object_with_cleanup(
apt_release_component_api, release_component_object, **kwargs
)

return _deb_release_component_factory


@pytest.fixture
def deb_publication_by_version_factory(apt_publication_api, gen_object_with_cleanup):
"""Fixture that generates a deb publication with cleanup from a given repository version."""
Expand Down

0 comments on commit cbec80f

Please sign in to comment.