Skip to content
Merged
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/1000.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecated publications and added documentation for migrating off of them.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The REST API documentation for `pulp_python` is available [here](site:pulp_pytho

- [Create local mirrors of PyPI](site:pulp_python/docs/user/guides/sync/) that you have full control over
- [Upload your own Python packages](site:pulp_python/docs/user/guides/upload/)
- [Perform pip install](site:pulp_python/docs/user/guides/publish/) from your Pulp Python repositories
- [Perform pip install](site:pulp_python/docs/user/guides/host/) from your Pulp Python repositories
- Download packages on-demand to reduce disk usage
- Every operation creates a restorable snapshot with Versioned Repositories
- Curate your Python repositories with allowed and disallowed packages
Expand Down
2 changes: 1 addition & 1 deletion docs/user/guides/_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
* [Set up your own PyPI](pypi.md)
* [Sync from Remote Repositories](sync.md)
* [Upload and Manage Content](upload.md)
* [Publish and Host Python Content](publish.md)
* [Host Python Content](host.md)
* [Vulnerability Report](vulnerability_report.md)
* [Attestation Hosting](attestation.md)
79 changes: 24 additions & 55 deletions docs/user/guides/publish.md → docs/user/guides/host.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,18 @@
# Publish and Host Your Python Content
# Host Your Python Content

This section assumes that you have a repository with content in it. To do this, see the
[sync](site:pulp_python/docs/user/guides/sync/) or [upload](site:pulp_python/docs/user/guides/upload/) documentation.

## Create a Publication (manually)
## Make a Python Index (Create a Distribution)

Kick off a publish task by creating a new publication. The publish task will generate all the
metadata that `pip` needs to install packages (although it will need to be hosted through a
Distribution before it is consumable).
To host your Python content as a PyPI compatible index, (which makes it consumable by `pip`), users create a distribution which will serve the content in the repository at `${BASE_ADDR}/pypi/${DIST_BASE_PATH}/`.

=== "Run"

```bash
# Create a new publication specifying the repository_version.
# Alternatively, you can specify just the repository, and Pulp will assume the latest version.
pulp python publication create --repository foo --version 1

# Publications can only be referenced through their pulp_href
PUBLICATION_HREF=$(pulp python publication list | jq -r .[0].pulp_href)
```

=== "Output"

```
{
"pulp_href": "/pulp/api/v3/publications/python/pypi/0196ba31-cd04-7aba-a7b4-71a98a976745/",
"prn": "prn:python.pythonpublication:0196ba31-cd04-7aba-a7b4-71a98a976745",
"pulp_created": "2025-05-10T12:35:48.103758Z",
"pulp_last_updated": "2025-05-10T12:35:48.205361Z",
"repository_version": "/pulp/api/v3/repositories/python/python/0196ba30-e15e-71ea-9867-33aeceb5a87e/versions/1/",
"repository": "/pulp/api/v3/repositories/python/python/0196ba30-e15e-71ea-9867-33aeceb5a87e/",
"distributions": []
}
```

## Host a Publication (Create a Distribution)

To host a publication, (which makes it consumable by `pip`), users create a distribution which
will serve the associated publication at `${BASE_ADDR}/pypi/${DIST_BASE_PATH}/`.

=== "Run"

```bash
# Distributions are created asynchronously. Create one, and specify the publication that will
# Distributions are created asynchronously. Create one, and specify the repository that will
# be served at the base path specified.
pulp python distribution create --name foo --base-path foo --publication "$PUBLICATION_HREF"
pulp python distribution create --name foo --base-path foo --repository foo
```

=== "Output"
Expand All @@ -62,29 +30,15 @@ will serve the associated publication at `${BASE_ADDR}/pypi/${DIST_BASE_PATH}/`.
"hidden": false,
"pulp_labels": {},
"name": "foo",
"repository": null,
"publication": "/pulp/api/v3/publications/python/pypi/0196ba31-cd04-7aba-a7b4-71a98a976745/",
"repository": "/pulp/api/v3/repositories/python/python/019cf738-6951-7b25-b26f-182683dc32f2/",
"repository_version": null,
"publication": null,
"allow_uploads": true,
"remote": null
}
```

## Automate Publication and Distribution

With a little more initial setup, you can have publications and distributions for your repositories
updated automatically when new repository versions are created.

```bash
# This configures the repository to produce new publications when a new version is created
pulp python repository update --name foo --autopublish
# This configures the distribution to track the latest repository version for a given repository
pulp python distribution update --name foo --repository foo
```

!!! warning
Support for automatic publication and distribution is provided as a tech preview in Pulp 3.
Functionality may not work or may be incomplete. Also, backwards compatibility when upgrading
is not guaranteed.
Setting the distribution's `repository` field will auto-serve the latest version of that repository. If you wish to only serve content from a specific version you can use the `repository_version` field.

## Enable Pull-Through Caching

Expand Down Expand Up @@ -150,3 +104,18 @@ pip install --trusted-host localhost shelf-reader
```

See the [pip docs](https://pip.pypa.io/en/stable/topics/configuration) for more details.


## Migrating off Publications

Ever since the release of `pulp-python` 3.4, publications have no longer been required to serve content to Python compatible tooling. Publications became deprecated in version 3.27, but it is recommended to move off of them even on early versions as many new features like pull-through caching, simple JSON, attestations, were not built to work with publications. To move off publications follow these three steps:

1. Switch any distribution serving a publication to a repository or repository-version
2. Set `autopublish=False` for all repositories
3. Delete all python publications

!!! warning
Publications may be removed in a future `pulp-python` version.

!!! note
To maintain backwards compatibility, `/pypi/` endpoints will always try to use a publication if there is one available for the repository. We recommend deleting every publication for a repository if you wish to use the newer features.
1 change: 1 addition & 0 deletions docs/user/guides/pypi.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Distributions serve the content stored in repositories so that it can be used by
"pulp_labels": {},
"name": "my-pypi",
"repository": "/pulp/api/v3/repositories/python/python/0196ba29-52b9-7cf4-b12e-f3247f0eb3dc/",
"repository_version": null,
"publication": null,
"allow_uploads": true,
"remote": null
Expand Down
2 changes: 1 addition & 1 deletion docs/user/guides/sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ Python remotes involve syncing with PyPI which requires terabytes of disk space.
modifying the "policy" field.

Syncing all of PyPI can take a long time depending on your network and disk speeds. Check out
[pull-through caching](site:pulp_python/docs/user/guides/publish/#enable-pull-through-caching)
[pull-through caching](site:pulp_python/docs/user/guides/host/#enable-pull-through-caching)
to learn about another way to mirror PyPI.

## Sync repository foo with remote
Expand Down
3 changes: 1 addition & 2 deletions pulp_python/app/replica.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ def url(self, upstream_distribution):
return None

def repository_extra_fields(self, remote):
# Use autopublish since publications result in faster serving times
return {"autopublish": True}
return {"autopublish": False}

def sync_params(self, repository, remote):
return {"remote_pk": str(remote.pk), "repository_pk": str(repository.pk), "mirror": True}
Expand Down
15 changes: 13 additions & 2 deletions pulp_python/app/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from gettext import gettext as _
from django.conf import settings
from django.db.utils import IntegrityError
from drf_spectacular.utils import extend_schema_serializer
from packaging.requirements import Requirement
from rest_framework import serializers
from pypi_attestations import AttestationError
Expand Down Expand Up @@ -33,6 +34,11 @@
log = logging.getLogger(__name__)


@extend_schema_serializer(
deprecate_fields=[
"autopublish",
]
)
class PythonRepositorySerializer(core_serializers.RepositorySerializer):
"""
Serializer for Python Repositories.
Expand All @@ -41,7 +47,7 @@ class PythonRepositorySerializer(core_serializers.RepositorySerializer):
autopublish = serializers.BooleanField(
help_text=_(
"Whether to automatically create publications for new repository versions, "
"and update any distributions pointing to this repository."
"and update any distributions pointing to this repository. [Deprecated]"
),
default=False,
required=False,
Expand All @@ -52,14 +58,19 @@ class Meta:
model = python_models.PythonRepository


@extend_schema_serializer(
deprecate_fields=[
"publication",
]
)
class PythonDistributionSerializer(core_serializers.DistributionSerializer):
"""
Serializer for Pulp distributions for the Python type.
"""

publication = core_serializers.DetailRelatedField(
required=False,
help_text=_("Publication to be served"),
help_text=_("Publication to be served. [Deprecated]"),
view_name_pattern=r"publications(-.*/.*)?-detail",
queryset=core_models.Publication.objects.exclude(complete=False),
allow_null=True,
Expand Down
26 changes: 22 additions & 4 deletions pulp_python/app/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from bandersnatch.configuration import BandersnatchConfig
from django.db import transaction
from drf_spectacular.utils import extend_schema
from drf_spectacular.utils import extend_schema, extend_schema_view
from pathlib import Path
from rest_framework import status
from rest_framework.decorators import action
Expand Down Expand Up @@ -605,11 +605,21 @@ def from_bandersnatch(self, request):
return Response(remote.data, status=status.HTTP_201_CREATED, headers=headers)


@extend_schema_view(
list=extend_schema(deprecated=True),
add_role=extend_schema(deprecated=True),
remove_role=extend_schema(deprecated=True),
list_roles=extend_schema(deprecated=True),
my_permissions=extend_schema(deprecated=True),
)
class PythonPublicationViewSet(core_viewsets.PublicationViewSet, core_viewsets.RolesMixin):
"""
<!-- User-facing documentation, rendered as html-->
Python Publications refer to the Python Package content in a repository version, and include
metadata about that content.
metadata about that content. [Deprecated] See
https://pulpproject.org/pulp_python/docs/user/guides/host/#migrating-off-publications for more
information.

Use a repository or repository-version to serve content instead.

"""

Expand Down Expand Up @@ -677,7 +687,7 @@ class PythonPublicationViewSet(core_viewsets.PublicationViewSet, core_viewsets.R
"python.pythonpublication_viewer": ["python.view_pythonpublication"],
}

@extend_schema(responses={202: AsyncOperationResponseSerializer})
@extend_schema(responses={202: AsyncOperationResponseSerializer}, deprecated=True)
def create(self, request):
"""
<!-- User-facing documentation, rendered as html-->
Expand All @@ -698,3 +708,11 @@ def create(self, request):
kwargs={"repository_version_pk": str(repository_version.pk)},
)
return core_viewsets.OperationPostponedResponse(result, request)

@extend_schema(deprecated=True)
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)

@extend_schema(deprecated=True)
def destroy(self, request, *args, **kwargs):
return super().destroy(request, *args, **kwargs)
4 changes: 0 additions & 4 deletions pulp_python/tests/functional/api/test_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ def test_domain_content_replication(
python_bindings.ContentPackagesApi,
python_bindings.RepositoriesPythonApi,
python_bindings.RemotesPythonApi,
python_bindings.PublicationsPypiApi,
python_bindings.DistributionsPypiApi,
):
result = api_client.list(pulp_domain=replica_domain.name)
Expand All @@ -204,9 +203,6 @@ def test_domain_content_replication(

response = python_bindings.ContentPackagesApi.list(pulp_domain=replica_domain.name)
assert PYTHON_SM_PACKAGE_COUNT + 1 == response.count
response = python_bindings.PublicationsPypiApi.list(pulp_domain=replica_domain.name)
assert 2 == response.count
add_to_cleanup(python_bindings.PublicationsPypiApi, response.results[0])
assert 1 == python_bindings.RepositoriesPythonApi.list(pulp_domain=replica_domain.name).count
assert 1 == python_bindings.DistributionsPypiApi.list(pulp_domain=replica_domain.name).count
assert 1 == python_bindings.RemotesPythonApi.list(pulp_domain=replica_domain.name).count
Expand Down
Loading