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
4 changes: 4 additions & 0 deletions CHANGES/plugin_api/7606.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Added a `publish` parameter to the repository modify endpoint and the `add_and_remove` task.
Plugins can opt in by accepting `publish` in their `on_new_version` override or custom
`modify_task`. The `RepositoryVersion` context manager will pass `publish=True` to
`on_new_version` if the plugin's method signature supports it.
4 changes: 4 additions & 0 deletions CHANGES/pulp_file/7606.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The file repository now supports the `publish` parameter on the modify endpoint. When
`publish=True` is passed, the repository version will be published after modification even if
`autopublish` is not enabled on the repository. Publication parameters configured on the
repository (e.g. `manifest`) will be used when publishing.
5 changes: 3 additions & 2 deletions pulp_file/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,20 @@ class Meta:
("repair_filerepository", "Can repair repository versions"),
]

def on_new_version(self, version):
def on_new_version(self, version, publish=False):
"""
Called when new repository versions are created.

Args:
version: The new repository version.
publish: Whether to publish this version.
"""
super().on_new_version(version)

# avoid circular import issues
from pulp_file.app import tasks

if self.autopublish:
if self.autopublish or publish:
tasks.publish(
manifest=self.manifest,
repository_version_pk=version.pk,
Expand Down
73 changes: 72 additions & 1 deletion pulp_file/tests/functional/api/test_auto_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,75 @@ def test_auto_publish_and_distribution(
distros = file_bindings.DistributionsFileApi.list(
repository=nonexistent_repository_href
).results
assert len(distros) == 0


@pytest.mark.parallel
def test_modify_with_publish(
file_bindings,
file_repository_factory,
file_random_content_unit,
monitor_task,
):
"""Test that passing publish=True to modify creates a publication."""
repo = file_repository_factory(manifest="TEST_MANIFEST")
repo = file_bindings.RepositoriesFileApi.read(repo.pulp_href)

# Verify no publications exist yet
assert file_bindings.PublicationsFileApi.list(repository=repo.pulp_href).count == 0

# Modify the repository with publish=True
monitor_task(
file_bindings.RepositoriesFileApi.modify(
repo.pulp_href,
{
"add_content_units": [file_random_content_unit.pulp_href],
"publish": True,
},
).task
)
repo = file_bindings.RepositoriesFileApi.read(repo.pulp_href)

# A new version should have been created and a publication should exist
assert repo.latest_version_href.endswith("/versions/1/")
assert file_bindings.PublicationsFileApi.list(repository=repo.pulp_href).count == 1
assert (
file_bindings.PublicationsFileApi.list(repository_version=repo.latest_version_href).count
== 1
)

# Verify the publication uses the custom manifest from the repository
publication = file_bindings.PublicationsFileApi.list(
repository_version=repo.latest_version_href
).results[0]
assert publication.manifest == "TEST_MANIFEST"

# Verify the publication's repository version contains the content unit
content = file_bindings.ContentFilesApi.list(
repository_version=repo.latest_version_href
).results
content_hrefs = [c.pulp_href for c in content]
assert file_random_content_unit.pulp_href in content_hrefs


@pytest.mark.parallel
def test_modify_without_publish(
file_bindings,
file_repo,
file_random_content_unit,
monitor_task,
):
"""Test that modify without publish=True does not create a publication."""
repo = file_bindings.RepositoriesFileApi.read(file_repo.pulp_href)

# Modify the repository without publish
monitor_task(
file_bindings.RepositoriesFileApi.modify(
repo.pulp_href,
{"add_content_units": [file_random_content_unit.pulp_href]},
).task
)
repo = file_bindings.RepositoriesFileApi.read(repo.pulp_href)

# A new version should have been created but no publication
assert repo.latest_version_href.endswith("/versions/1/")
assert file_bindings.PublicationsFileApi.list(repository=repo.pulp_href).count == 0
14 changes: 13 additions & 1 deletion pulpcore/app/models/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Repository related Django models.
"""

import inspect
from contextlib import suppress
from gettext import gettext as _
from os import path
Expand Down Expand Up @@ -1414,7 +1415,18 @@ def __exit__(self, exc_type, exc_value, traceback):
self.save()
self._compute_counts()
self.repository.cleanup_old_versions()
repository.on_new_version(self)
publish = getattr(self, "_publish", False)
sig = inspect.signature(repository.on_new_version)
if publish and "publish" in sig.parameters:
repository.on_new_version(self, publish=True)
else:
if publish:
_logger.warning(
"publish=True was requested but the repository type "
"'%s' does not support it in on_new_version.",
repository.TYPE,
)
repository.on_new_version(self)
except Exception:
self.delete()
raise
Expand Down
10 changes: 9 additions & 1 deletion pulpcore/app/serializers/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@ class RepositoryAddRemoveContentSerializer(ModelSerializer, NestedHyperlinkedMod
"for the new repository version"
),
)
publish = serializers.BooleanField(
required=False,
default=False,
help_text=_(
"Whether to publish the repository version created by this modification. "
"The repository's modify task must support the ``publish`` parameter."
),
)

def validate_add_content_units(self, value):
add_content_units = {}
Expand Down Expand Up @@ -366,4 +374,4 @@ def validate_remove_content_units(self, value):

class Meta:
model = models.RepositoryVersion
fields = ["add_content_units", "remove_content_units", "base_version"]
fields = ["add_content_units", "remove_content_units", "base_version", "publish"]
11 changes: 10 additions & 1 deletion pulpcore/app/tasks/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,13 @@ def repair_all_artifacts(verify_checksums):
loop.run_until_complete(_repair_artifacts_for_content(verify_checksums=verify_checksums))


def add_and_remove(repository_pk, add_content_units, remove_content_units, base_version_pk=None):
def add_and_remove(
repository_pk,
add_content_units,
remove_content_units,
base_version_pk=None,
publish=False,
):
"""
Create a new repository version by adding and then removing content units.

Expand All @@ -218,6 +224,7 @@ def add_and_remove(repository_pk, add_content_units, remove_content_units, base_
should be removed from the previous Repository Version for this Repository.
base_version_pk (uuid): the primary key for a RepositoryVersion whose content will be used
as the initial set of content for our new RepositoryVersion
publish (bool): whether to publish the new repository version after creation
"""
repository = models.Repository.objects.get(pk=repository_pk).cast()

Expand All @@ -234,6 +241,8 @@ def add_and_remove(repository_pk, add_content_units, remove_content_units, base_
remove_content_units = []

with repository.new_version(base_version=base_version) as new_version:
if publish:
new_version._publish = True
new_version.remove_content(models.Content.objects.filter(pk__in=remove_content_units))
new_version.add_content(models.Content.objects.filter(pk__in=add_content_units))

Expand Down
27 changes: 21 additions & 6 deletions pulpcore/plugin/actions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import inspect

from drf_spectacular.utils import extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError

from pulpcore.app import tasks
from pulpcore.app.models import RepositoryVersion
Expand Down Expand Up @@ -35,14 +38,26 @@ def modify(self, request, pk):
else:
base_version_pk = None

publish = serializer.validated_data.get("publish", False)

task_kwargs = {
"repository_pk": pk,
"base_version_pk": base_version_pk,
"add_content_units": serializer.validated_data.get("add_content_units", []),
"remove_content_units": serializer.validated_data.get("remove_content_units", []),
}

if publish:
sig = inspect.signature(self.modify_task)
if "publish" not in sig.parameters:
raise ValidationError(
{"publish": "This repository type does not support the publish parameter."}
)
task_kwargs["publish"] = True

task = dispatch(
self.modify_task,
exclusive_resources=[repository],
kwargs={
"repository_pk": pk,
"base_version_pk": base_version_pk,
"add_content_units": serializer.validated_data.get("add_content_units", []),
"remove_content_units": serializer.validated_data.get("remove_content_units", []),
},
kwargs=task_kwargs,
)
return OperationPostponedResponse(task, request)
Loading