Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES/7831.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added an opt-in ``content_ids`` field to the repository version detail, returning the list of content unit UUIDs in the version when the request includes the ``content_ids=true`` query parameter. This lets clients diff content sets between versions directly instead of issuing expensive content filter queries.
17 changes: 17 additions & 0 deletions pulpcore/app/serializers/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,26 @@ class RepositoryVersionSerializer(ModelSerializer, NestedHyperlinkedModelSeriali
vuln_report = serializers.SerializerMethodField(
read_only=True,
)
content_ids = serializers.SerializerMethodField(
help_text=_(
"The list of content unit UUIDs in this version. Only returned when the request "
"includes the 'content_ids=true' query parameter; otherwise null."
),
read_only=True,
)

def get_vuln_report(self, object):
return f"{reverse('vuln_report-list')}?repo_versions={get_prn(object)}"

def get_content_ids(self, object):
request = self.context.get("request")
if request is None:
return None
value = request.query_params.get("content_ids")
if value is None or value.lower() not in ("true", "1", "yes"):
return None
return object.content_ids

class Meta:
model = models.RepositoryVersion
fields = ModelSerializer.Meta.fields + (
Expand All @@ -304,6 +320,7 @@ class Meta:
"base_version",
"content_summary",
"vuln_report",
"content_ids",
)


Expand Down
35 changes: 35 additions & 0 deletions pulpcore/tests/unit/serializers/test_repository.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from types import SimpleNamespace
from unittest.mock import Mock
from uuid import uuid4

import pytest
from rest_framework import serializers
Expand All @@ -10,6 +11,7 @@
PublicationSerializer,
RemoteSerializer,
RepositorySyncURLSerializer,
RepositoryVersionSerializer,
ValidateFieldsMixin,
)

Expand Down Expand Up @@ -265,3 +267,36 @@ def test_create_remote_with_invalid_parameter():
serializer = RemoteSerializer(data=data)
with pytest.raises(serializers.ValidationError, match="Unexpected field"):
serializer.validate(data)


def _content_ids_serializer(query_params=None):
"""Build a RepositoryVersionSerializer with an optional fake request in its context."""
context = {}
if query_params is not None:
context["request"] = SimpleNamespace(query_params=query_params)
return RepositoryVersionSerializer(context=context)


def test_get_content_ids_omitted_without_request():
"""content_ids is null when there is no request in the serializer context."""
obj = SimpleNamespace(content_ids=[uuid4()])
serializer = _content_ids_serializer()
assert serializer.get_content_ids(obj) is None


@pytest.mark.parametrize("value", [None, "", "false", "0", "no", "False"])
def test_get_content_ids_omitted_when_not_requested(value):
"""content_ids is null unless the request explicitly opts in via the query parameter."""
query_params = {} if value is None else {"content_ids": value}
obj = SimpleNamespace(content_ids=[uuid4()])
serializer = _content_ids_serializer(query_params=query_params)
assert serializer.get_content_ids(obj) is None


@pytest.mark.parametrize("value", ["true", "True", "TRUE", "1", "yes"])
def test_get_content_ids_returned_when_requested(value):
"""content_ids returns the version's UUIDs when the request opts in."""
content_ids = [uuid4(), uuid4()]
obj = SimpleNamespace(content_ids=content_ids)
serializer = _content_ids_serializer(query_params={"content_ids": value})
assert serializer.get_content_ids(obj) == content_ids
Loading