Skip to content

Commit

Permalink
[feat] Add CollectionVersionMark as a content.
Browse files Browse the repository at this point in the history
fixes: pulp#1325
  • Loading branch information
rochacbruno committed Feb 17, 2023
1 parent 9913172 commit 74bd9f8
Show file tree
Hide file tree
Showing 12 changed files with 361 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES/1325.feature
@@ -0,0 +1 @@
Add CollectionVersionMark as a content
10 changes: 10 additions & 0 deletions pulp_ansible/app/galaxy/v3/serializers.py
@@ -1,3 +1,4 @@
from typing import List
import semantic_version
from django.conf import settings
from drf_spectacular.utils import extend_schema_field
Expand Down Expand Up @@ -101,6 +102,7 @@ class CollectionVersionListSerializer(serializers.ModelSerializer):
href = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(source="collection.pulp_created")
updated_at = serializers.DateTimeField(source="collection.pulp_last_updated")
marks = serializers.SerializerMethodField()

class Meta:
fields = (
Expand All @@ -109,9 +111,17 @@ class Meta:
"created_at",
"updated_at",
"requires_ansible",
"marks",
)
model = models.CollectionVersion

def get_marks(self, obj) -> List[str]:
"""Get a list of mark values filtering only those in the current repo."""
# The viewset adds "marks" to the context
return list(
obj.marks.filter(pk__in=self.context.get("marks", [])).values_list("value", flat=True)
)

def get_href(self, obj) -> str:
"""
Get href.
Expand Down
2 changes: 2 additions & 0 deletions pulp_ansible/app/galaxy/v3/views.py
Expand Up @@ -52,6 +52,7 @@
AnsibleNamespaceMetadata,
Collection,
CollectionVersion,
CollectionVersionMark,
CollectionVersionSignature,
CollectionImport,
DownloadLog,
Expand Down Expand Up @@ -118,6 +119,7 @@ def get_serializer_context(self):
context["path"] = self.kwargs["path"]

distro_content = self._distro_content
context["marks"] = CollectionVersionMark.objects.filter(pk__in=distro_content)
context["sigs"] = CollectionVersionSignature.objects.filter(pk__in=distro_content)
context["namespaces"] = AnsibleNamespaceMetadata.objects.filter(pk__in=distro_content)
context["namespaces_map"] = {
Expand Down
28 changes: 28 additions & 0 deletions pulp_ansible/app/migrations/0047_collectionversionmark.py
@@ -0,0 +1,28 @@
# Generated by Django 3.2.16 on 2023-01-17 15:01

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('core', '0098_pulp_labels'),
('ansible', '0046_add_fulltext_search_fix'),
]

operations = [
migrations.CreateModel(
name='CollectionVersionMark',
fields=[
('content_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, related_name='ansible_collectionversionmark', serialize=False, to='core.content')),
('value', models.SlugField()),
('marked_collection', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='marks', to='ansible.collectionversion')),
],
options={
'default_related_name': '%(app_label)s_%(model_name)s',
'unique_together': {('value', 'marked_collection')},
},
bases=('core.content',),
),
]
17 changes: 17 additions & 0 deletions pulp_ansible/app/modelresource.py
Expand Up @@ -3,6 +3,7 @@
from pulpcore.plugin.importexport import BaseContentResource, QueryModelResource
from pulp_ansible.app.models import (
AnsibleCollectionDeprecated,
CollectionVersionMark,
Role,
Collection,
Tag,
Expand Down Expand Up @@ -75,6 +76,22 @@ class Meta:
exclude = BaseContentResource.Meta.exclude + ("signing_service",)


class CollectionVersionMarkResource(BaseContentResource):
"""
Resource for import/export of ansible_collectionversionmark entities.
"""

def set_up_queryset(self):
"""
:return: CollectionVersionMark content specific to a specified repo-version.
"""
return CollectionVersionMark.objects.filter(pk__in=self.repo_version.content)

class Meta:
model = CollectionVersionMark
import_id_fields = ("value", "marked_collection")


class CollectionResource(QueryModelResource):
"""
Resource for import/export of ansible_collection entities.
Expand Down
23 changes: 23 additions & 0 deletions pulp_ansible/app/models.py
Expand Up @@ -212,6 +212,28 @@ class Meta:
]


class CollectionVersionMark(Content):
"""
A content type representing a mark that is attached to a content unit.
Fields:
value (models.CharField): The value of the mark.
marked_collection (models.ForeignKey): Reference to a CollectionVersion.
"""

PROTECTED_FROM_RECLAIM = False
TYPE = "collection_mark"

value = models.SlugField()
marked_collection = models.ForeignKey(
CollectionVersion, null=False, on_delete=models.CASCADE, related_name="marks"
)

class Meta:
default_related_name = "%(app_label)s_%(model_name)s"
unique_together = ("value", "marked_collection")


class CollectionVersionSignature(Content):
"""
A content type representing a signature that is attached to a content unit.
Expand Down Expand Up @@ -446,6 +468,7 @@ class AnsibleRepository(Repository):
AnsibleCollectionDeprecated,
CollectionVersionSignature,
AnsibleNamespaceMetadata,
CollectionVersionMark,
]
REMOTE_TYPES = [RoleRemote, CollectionRemote, GitRemote]

Expand Down
44 changes: 44 additions & 0 deletions pulp_ansible/app/serializers.py
Expand Up @@ -29,6 +29,7 @@

from .models import (
AnsibleDistribution,
CollectionVersionMark,
GitRemote,
RoleRemote,
AnsibleNamespace,
Expand Down Expand Up @@ -865,6 +866,49 @@ class Meta:
)


class CollectionVersionMarkSerializer(ModelSerializer):
"""
A serializer for mark models.
"""

marked_collection = DetailRelatedField(
help_text=_("The content this mark is pointing to."),
view_name_pattern=r"content(-.*/.*)-detail",
queryset=CollectionVersion.objects.all(),
)
value = serializers.SlugField(
help_text=_("The string value of this mark."),
allow_null=False,
)

class Meta:
model = CollectionVersionMark
fields = ["marked_collection", "value"]


class AnsibleRepositoryMarkSerializer(serializers.Serializer):
"""
A serializer for the mark action.
"""

content_units = serializers.ListField(
required=True,
help_text=_(
"List of collection version hrefs to mark, use * to mark all content in repository"
),
)
value = serializers.SlugField(
required=True,
help_text=_("The string value of this mark."),
)

def validate_content_units(self, value):
"""Make sure the list is correctly formatted."""
if len(value) > 1 and "*" in value:
raise serializers.ValidationError("Cannot supply content units and '*'.")
return value


class AnsibleRepositorySignatureSerializer(serializers.Serializer):
"""
A serializer for the signing action.
Expand Down
11 changes: 10 additions & 1 deletion pulp_ansible/app/tasks/collections.py
Expand Up @@ -62,6 +62,7 @@
CollectionImport,
CollectionRemote,
CollectionVersion,
CollectionVersionMark,
CollectionVersionSignature,
Tag,
)
Expand Down Expand Up @@ -589,6 +590,7 @@ async def _add_collection_version(self, api_version, collection_version_url, met

info = metadata["metadata"]
signatures = metadata.get("signatures")
marks = metadata.get("marks") # List[str]

if self.signed_only and not signatures:
return
Expand Down Expand Up @@ -633,7 +635,7 @@ async def _add_collection_version(self, api_version, collection_version_url, met
await self.parsing_metadata_progress_bar.aincrement()
await self.put(d_content)

if signatures:
if signatures or marks:
collection_version = await d_content.resolution()
for signature in signatures:
sig = signature["signature"]
Expand All @@ -645,6 +647,13 @@ async def _add_collection_version(self, api_version, collection_version_url, met
)
await self.put(DeclarativeContent(content=cv_signature))

for mark_value in marks:
cv_mark = CollectionVersionMark(
marked_collection=collection_version,
value=mark_value,
)
await self.put(DeclarativeContent(content=cv_mark))

# Process syncing CV Namespace Metadata if present
if metadata["namespace"].get("metadata_sha256"):
namespace = collection_version.namespace
Expand Down
60 changes: 60 additions & 0 deletions pulp_ansible/app/tasks/mark.py
@@ -0,0 +1,60 @@
"""Tasks for CollectionVersionMark"""
from pulpcore.plugin.tasking import add_and_remove
from pulp_ansible.app.models import AnsibleRepository, CollectionVersion, CollectionVersionMark


def mark(repository_href, content_hrefs, value):
"""The mark task."""
repository = AnsibleRepository.objects.get(pk=repository_href)
content = _get_content_queryset(repository, content_hrefs)
marks_in_repo = _get_list_of_marks_pk_in_repo(repository, content, value)

marks_to_add = []
for collection_version in content:
# A mark for the same collection and value may exist in another repo.
mark, _created = CollectionVersionMark.objects.get_or_create(
marked_collection=collection_version, value=value
)
if mark.pk not in marks_in_repo:
marks_to_add.append(mark.pk)

add_and_remove(
repository_pk=repository.pk,
add_content_units=marks_to_add,
remove_content_units=[],
)


def unmark(repository_href, content_hrefs, value):
"""The unmark task."""
repository = AnsibleRepository.objects.get(pk=repository_href)
content = _get_content_queryset(repository, content_hrefs)
marks_in_repo = _get_list_of_marks_pk_in_repo(repository, content, value)
add_and_remove(
repository_pk=repository.pk,
add_content_units=[],
remove_content_units=marks_in_repo,
)


def _get_list_of_marks_pk_in_repo(repository, content, value):
"""Get all the marks from repo having value and content"""
return (
repository.latest_version()
.content.filter(
pulp_type=CollectionVersionMark.get_pulp_type(),
ansible_collectionversionmark__value=value,
ansible_collectionversionmark__marked_collection__in=content,
)
.values_list("pk", flat=True)
)


def _get_content_queryset(repository, content_hrefs):
"""Return content queryset based on a repo and content hrefs"""
if content_hrefs == ["*"]:
content_in_latest_version = repository.latest_version().content.filter(
pulp_type=CollectionVersion.get_pulp_type()
)
return CollectionVersion.objects.filter(pk__in=content_in_latest_version)
return CollectionVersion.objects.filter(pk__in=content_hrefs)

0 comments on commit 74bd9f8

Please sign in to comment.