Repository Versions

For background on use cases and value, please see this thread:

Publications and RepositoryVersions

As one addendum, it’s worth reminding ourselves how a managed Publication relates to a RepositoryVersion. In the time since the above email thread, we moved forward with the Publication and Distribution models being first-class.

A Publication is a set of artifacts and metadata that can be presented to a particular type of client for consumption. It is produced from the set of content that was present in a repository at the time of publication.

A RepositoryVersion is an immutable content set that represents the state of a repository’s content at a point in time. It can be used to create (or recreate) a Publication. It can be used to make two different types of publications from exactly the same content set. It can be used to answer the question: given a publication, what content was used to create it? What content is currently available to my production environment? What content was available to that environment last week when some event took place? Exactly what changed between two publishes, or since the most recent publish?

Neither takes the place of the other, and each provides the most value when both are in use.

Planning Details

Having updated the proof of concept to work with the latest Pulp 3 code base (as of late Nov 2017), and with all of the REST API improvements we have made, it became clear that the following changes would be necessary in the REST API and Plugin API to enable versioning of repositories.

The most problematic endpoint is /api/v3/repositorycontents/. It’s not entirely unreasonable to think that a client could add relationships by POSTing to this endpoint with a reference to a repository and another to a content unit, which would spawn a task that creates a new version along with the requested relationship. The side-effect of creating a version isn’t ideal, but it could be livable.

The real problem came with removing content from a repo via this endpoint. Calling DELETE on a relationship would not be allowed, because removal of a content unit from a repo requires creating a new repo version and updating the relationship to reference the new version as the one which removes the content. Allowing a client to directly create a new version, and then PUT/PATCH a specific relationship to reference that version, would be full of problems; the repo wouldn’t be locked, the content set in the version would be mutable (violating the value proposition of immutable content sets), and we’d be exposing the implementation details of how additions and removals are tracked (something that’s otherwise not necessary).


Changed Endpoints


  • Change: Takes an optional reference to a repo version. If none is provided, it defaults to the latest.


  • Change: Includes a reference to a repo version as the created resource for any task that modifies the set of content in a repo.

Moved Endpoints


Moved Attributes

“content_summary” at /api/v3/repositories/{id}/
“content_summary” at /api/v3/repositories/{id}/versions/{number}/

New Endpoints


  • Read: see a list of repo versions.
  • Read: see the details of a particular version
  • Delete: delete a version, squashing its changes into the next one
  • Read: see the content added by the version
  • Read: see the content removed by the version

Removed Endpoints


  • Replaced by /api/v3/repositories/{id}/versions/

Plugin API


The task in core should retrieve the current version, create a new version, and hand each of them to the importer’s sync method. The current version is used to determine what content is currently in the repository, which is necessary to know during sync. The new version is used as the API for adding a removing content:



The task in core should determine the version to use and pass it to the Publisher’s publish method. It should be determined either based on a reference provided by a client, or default to the latest.


The RepositoryContent model should be removed from the plugin API, because it would no longer be intended for direct use by a plugin writer.