pulp-ansible 0.25.1__py3-none-any.whl → 0.25.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,5 +8,5 @@ class PulpAnsiblePluginAppConfig(PulpPluginAppConfig):
8
8
 
9
9
  name = "pulp_ansible.app"
10
10
  label = "ansible"
11
- version = "0.25.1"
11
+ version = "0.25.3"
12
12
  python_package_name = "pulp-ansible"
@@ -2,6 +2,7 @@ from datetime import datetime
2
2
  from gettext import gettext as _
3
3
  import semantic_version
4
4
  import base64
5
+ import re
5
6
 
6
7
  from django.db import DatabaseError, IntegrityError
7
8
  from django.db.models import F, OuterRef, Exists, Subquery, Prefetch
@@ -621,7 +622,7 @@ class CollectionArtifactDownloadView(GalaxyAuthMixin, views.APIView, AnsibleDist
621
622
  DEFAULT_ACCESS_POLICY = _PERMISSIVE_ACCESS_POLICY
622
623
 
623
624
  @staticmethod
624
- def log_download(request, filename, distro_base_path):
625
+ def log_download(request, namespace, name, version, distro_base_path):
625
626
  """Log the download of the collection version."""
626
627
 
627
628
  def _get_org_id(request):
@@ -639,7 +640,7 @@ class CollectionArtifactDownloadView(GalaxyAuthMixin, views.APIView, AnsibleDist
639
640
 
640
641
  return identity["internal"]["org_id"]
641
642
 
642
- # Gettung user IP
643
+ # Get user IP
643
644
  x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
644
645
  ip = x_forwarded_for.split(",")[0] if x_forwarded_for else request.META.get("REMOTE_ADDR")
645
646
 
@@ -650,13 +651,9 @@ class CollectionArtifactDownloadView(GalaxyAuthMixin, views.APIView, AnsibleDist
650
651
  distribution.repository_version or distribution.repository.latest_version()
651
652
  )
652
653
 
653
- # Getting collection version
654
- ns, name, version = filename.split("-", maxsplit=2)
655
- # Get off the ending .tar.gz
656
- version = ".".join(version.split(".")[:3])
657
654
  collection_version = get_object_or_404(
658
655
  CollectionVersion.objects.filter(pk__in=repository_version.content),
659
- namespace=ns,
656
+ namespace=namespace,
660
657
  name=name,
661
658
  version=version,
662
659
  )
@@ -681,11 +678,10 @@ class CollectionArtifactDownloadView(GalaxyAuthMixin, views.APIView, AnsibleDist
681
678
  return
682
679
  raise
683
680
 
684
- def count_download(filename):
685
- ns, name, _ = filename.split("-", maxsplit=2)
681
+ def count_download(namespace, name):
686
682
  try:
687
683
  collection, created = CollectionDownloadCount.objects.get_or_create(
688
- namespace=ns, name=name, defaults={"download_count": 1}
684
+ namespace=namespace, name=name, defaults={"download_count": 1}
689
685
  )
690
686
  if not created:
691
687
  collection.download_count = F("download_count") + 1
@@ -713,13 +709,23 @@ class CollectionArtifactDownloadView(GalaxyAuthMixin, views.APIView, AnsibleDist
713
709
  filename=self.kwargs["filename"],
714
710
  )
715
711
 
712
+ match = re.fullmatch(
713
+ r"(?P<namespace>\w+)-(?P<name>\w+)-(?P<version>[\w.-]+)\.tar\.gz",
714
+ self.kwargs["filename"],
715
+ )
716
+ if not match:
717
+ raise NotFound()
718
+ namespace = match.group("namespace")
719
+ name = match.group("name")
720
+ version = match.group("version")
721
+
716
722
  if settings.ANSIBLE_COLLECT_DOWNLOAD_LOG:
717
723
  CollectionArtifactDownloadView.log_download(
718
- request, self.kwargs["filename"], distro_base_path
724
+ request, namespace, name, version, distro_base_path
719
725
  )
720
726
 
721
727
  if settings.ANSIBLE_COLLECT_DOWNLOAD_COUNT:
722
- CollectionArtifactDownloadView.count_download(self.kwargs["filename"])
728
+ CollectionArtifactDownloadView.count_download(namespace, name)
723
729
 
724
730
  if (
725
731
  distribution.content_guard
@@ -16,11 +16,11 @@ def add_sha256_to_current_models(apps, schema_editor):
16
16
 
17
17
  for collection_version in (
18
18
  CollectionVersion.objects.prefetch_related(
19
- "content_artifacts", "content_artifacts__artifact"
19
+ "contentartifact_set", "contentartifact_set__artifact"
20
20
  )
21
21
  .filter(sha256="")
22
22
  .only("pk", "sha256")
23
- .iterator()
23
+ .iterator(chunk_size=2000)
24
24
  ):
25
25
  content_artifact = collection_version.contentartifact_set.get()
26
26
  if content_artifact.artifact:
@@ -658,6 +658,22 @@ class CollectionVersionSerializer(ContentChecksumSerializer, CollectionVersionUp
658
658
 
659
659
  creating = True
660
660
 
661
+ def __init__(self, *args, **kwargs):
662
+ super().__init__(*args, **kwargs)
663
+ try:
664
+ request = self.context["request"]
665
+ if request.method != "GET":
666
+ return
667
+ except (AttributeError, TypeError, KeyError):
668
+ # The serializer was not initialized with request context.
669
+ return
670
+ query_params = request.query_params
671
+ if self.include_arg_name in query_params or self.exclude_arg_name in query_params:
672
+ return
673
+ for fieldname in ["files", "manifest", "docs_blob", "contents"]:
674
+ # Redact these fields by default as they have no size limit.
675
+ self.fields.pop(fieldname)
676
+
661
677
  def validate(self, data):
662
678
  """Run super() validate if creating, else return data."""
663
679
  # This validation is for creating CollectionVersions
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import functools
2
3
  import hashlib
3
4
  import json
4
5
  import logging
@@ -8,11 +9,11 @@ from gettext import gettext as _
8
9
  from operator import attrgetter
9
10
  from urllib.parse import urljoin
10
11
  from uuid import uuid4
12
+ import tempfile
11
13
 
12
14
  import yaml
13
15
  from aiohttp.client_exceptions import ClientError, ClientResponseError
14
16
  from asgiref.sync import sync_to_async
15
- from async_lru import alru_cache
16
17
  from django.conf import settings
17
18
  from django.db import transaction
18
19
  from django.db.models import Q
@@ -32,7 +33,6 @@ from pulpcore.plugin.models import (
32
33
  ProgressReport,
33
34
  PulpTemporaryFile,
34
35
  Remote,
35
- RepositoryContent,
36
36
  RepositoryVersion,
37
37
  Task,
38
38
  )
@@ -40,6 +40,8 @@ from pulpcore.plugin.stages import (
40
40
  ArtifactDownloader,
41
41
  ArtifactSaver,
42
42
  ContentSaver,
43
+ ContentAssociation,
44
+ EndStage,
43
45
  DeclarativeArtifact,
44
46
  DeclarativeContent,
45
47
  DeclarativeVersion,
@@ -49,6 +51,7 @@ from pulpcore.plugin.stages import (
49
51
  RemoteArtifactSaver,
50
52
  ResolveContentFutures,
51
53
  Stage,
54
+ create_pipeline,
52
55
  )
53
56
  from rest_framework.serializers import ValidationError
54
57
  from semantic_version import SimpleSpec, Version
@@ -79,6 +82,26 @@ from pulp_ansible.app.tasks.utils import (
79
82
  log = logging.getLogger(__name__)
80
83
 
81
84
 
85
+ def async_cache(f):
86
+ # A simple implementation for caching an async function with hashable arguments.
87
+ _cache = {}
88
+
89
+ @functools.wraps(f)
90
+ async def _wrapped_f(*args):
91
+ try:
92
+ return _cache[args]
93
+ except KeyError:
94
+ result = await f(*args)
95
+ _cache[args] = result
96
+ if len(_cache) > 128:
97
+ # This is a bit ad hoc and will give fifo instead of lru behaviour.
98
+ # I doubt it even makes a difference here.
99
+ _cache.pop(next(iter(_cache.keys())))
100
+ return result
101
+
102
+ return _wrapped_f
103
+
104
+
82
105
  # semantic_version.SimpleSpec interpretes "*" as ">=0.0.0"
83
106
  class AnsibleSpec(SimpleSpec):
84
107
  def __init__(self, expression):
@@ -106,13 +129,15 @@ async def declarative_content_from_git_repo(remote, url, git_ref=None, metadata_
106
129
  if git_ref:
107
130
  try:
108
131
  gitrepo = Repo.clone_from(
109
- url, uuid4(), depth=1, branch=git_ref, multi_options=["--recurse-submodules"]
132
+ url, str(uuid4()), depth=1, branch=git_ref, multi_options=["--recurse-submodules"]
110
133
  )
111
134
  except GitCommandError:
112
- gitrepo = Repo.clone_from(url, uuid4(), multi_options=["--recurse-submodules"])
135
+ gitrepo = Repo.clone_from(url, str(uuid4()), multi_options=["--recurse-submodules"])
113
136
  gitrepo.git.checkout(git_ref)
114
137
  else:
115
- gitrepo = Repo.clone_from(url, uuid4(), depth=1, multi_options=["--recurse-submodules"])
138
+ gitrepo = Repo.clone_from(
139
+ url, str(uuid4()), depth=1, multi_options=["--recurse-submodules"]
140
+ )
116
141
  commit_sha = gitrepo.head.commit.hexsha
117
142
  metadata, artifact_path = sync_collection(gitrepo.working_dir, ".")
118
143
  artifact = Artifact.init_and_validate(artifact_path)
@@ -196,14 +221,7 @@ def sync(remote_pk, repository_pk, mirror, optimize):
196
221
  if not remote.url:
197
222
  raise ValueError(_("A CollectionRemote must have a 'url' specified to synchronize."))
198
223
 
199
- deprecation_before_sync = set()
200
- for namespace, name in AnsibleCollectionDeprecated.objects.filter(
201
- pk__in=repository.latest_version().content
202
- ).values_list("namespace", "name"):
203
- deprecation_before_sync.add(f"{namespace}.{name}")
204
- first_stage = CollectionSyncFirstStage(
205
- remote, repository, is_repo_remote, deprecation_before_sync, optimize
206
- )
224
+ first_stage = CollectionSyncFirstStage(remote, repository, is_repo_remote, optimize)
207
225
  if first_stage.should_sync is False:
208
226
  log.debug(_("no-op: remote wasn't updated since last sync."))
209
227
  return
@@ -217,23 +235,6 @@ def sync(remote_pk, repository_pk, mirror, optimize):
217
235
  repository.last_synced_metadata_time = first_stage.last_synced_metadata_time
218
236
  repository.save(update_fields=["last_synced_metadata_time"])
219
237
 
220
- # This goes against all rules!
221
- # Content must be added and removed via the dedicated functions, which is impossible after the
222
- # repository version was finalized.
223
- # TODO Fix this!
224
- to_undeprecate = Q()
225
- undeprecated = deprecation_before_sync.difference(first_stage.deprecation_after_sync)
226
- if undeprecated:
227
- for collection in undeprecated:
228
- namespace, name = collection.split(".")
229
- to_undeprecate |= Q(namespace=namespace, name=name)
230
- deprecated = AnsibleCollectionDeprecated.objects.filter(to_undeprecate)
231
- RepositoryContent.objects.filter(
232
- repository=repository,
233
- content__in=deprecated,
234
- version_removed__isnull=True,
235
- ).update(version_removed=repo_version)
236
-
237
238
 
238
239
  def import_collection(
239
240
  temp_file_pk,
@@ -478,13 +479,58 @@ class AnsibleDeclarativeVersion(DeclarativeVersion):
478
479
 
479
480
  return pipeline
480
481
 
482
+ def create(self):
483
+ """
484
+ Perform the work. This is the long-blocking call where all syncing occurs.
485
+
486
+ Returns: The created RepositoryVersion or None if it represents no change from the latest.
487
+ """
488
+ with tempfile.TemporaryDirectory(dir="."):
489
+ with self.repository.new_version() as new_version:
490
+ deprecation_before_sync = {
491
+ (namespace, name)
492
+ for namespace, name in AnsibleCollectionDeprecated.objects.filter(
493
+ pk__in=self.repository.latest_version().content
494
+ ).values_list("namespace", "name")
495
+ }
496
+ loop = asyncio.get_event_loop()
497
+ stages = self.pipeline_stages(new_version)
498
+ stages.append(UndeprecateStage(deprecation_before_sync))
499
+ stages.append(ContentAssociation(new_version, self.mirror))
500
+ stages.append(EndStage())
501
+ pipeline = create_pipeline(stages)
502
+ loop.run_until_complete(pipeline)
503
+
504
+ if deprecation_before_sync:
505
+ to_undeprecate = Q()
506
+ for namespace, name in deprecation_before_sync:
507
+ to_undeprecate |= Q(namespace=namespace, name=name)
508
+ new_version.remove_content(
509
+ AnsibleCollectionDeprecated.objects.filter(to_undeprecate)
510
+ )
511
+
512
+ return new_version if new_version.complete else None
513
+
514
+
515
+ class UndeprecateStage(Stage):
516
+ def __init__(self, deprecation_before_sync):
517
+ self.deprecation_before_sync = deprecation_before_sync
518
+
519
+ async def run(self):
520
+ async for batch in self.batches():
521
+ for d_content in batch:
522
+ if isinstance(d_content.content, AnsibleCollectionDeprecated):
523
+ key = (d_content.content.namespace, d_content.content.name)
524
+ self.deprecation_before_sync.discard(key)
525
+ await self.put(d_content)
526
+
481
527
 
482
528
  class CollectionSyncFirstStage(Stage):
483
529
  """
484
530
  The first stage of a pulp_ansible sync pipeline.
485
531
  """
486
532
 
487
- def __init__(self, remote, repository, is_repo_remote, deprecation_before_sync, optimize):
533
+ def __init__(self, remote, repository, is_repo_remote, optimize):
488
534
  """
489
535
  The first stage of a pulp_ansible sync pipeline.
490
536
 
@@ -492,15 +538,12 @@ class CollectionSyncFirstStage(Stage):
492
538
  remote (CollectionRemote): The remote data to be used when syncing
493
539
  repository (AnsibleRepository): The repository being syncedself.
494
540
  is_repo_remote (bool): True if the remote is the repository's remote.
495
- deprecation_before_sync (set): Set of deprecations before the sync.
496
541
  optimize (boolean): Whether to optimize sync or not.
497
542
 
498
543
  """
499
544
  super().__init__()
500
545
  self.remote = remote
501
546
  self.repository = repository
502
- self.deprecation_before_sync = deprecation_before_sync
503
- self.deprecation_after_sync = set()
504
547
  self.collection_info = parse_collections_requirements_file(remote.requirements_file)
505
548
  self.exclude_info = {}
506
549
  self.add_dependents = self.collection_info and self.remote.sync_dependencies
@@ -521,7 +564,7 @@ class CollectionSyncFirstStage(Stage):
521
564
  self._should_we_sync()
522
565
  )
523
566
 
524
- @alru_cache(maxsize=128)
567
+ @async_cache
525
568
  async def _get_root_api(self, root):
526
569
  """
527
570
  Returns the root api path and api version.
@@ -557,7 +600,7 @@ class CollectionSyncFirstStage(Stage):
557
600
 
558
601
  return endpoint, api_version
559
602
 
560
- @alru_cache(maxsize=128)
603
+ @async_cache
561
604
  async def _get_paginated_collection_api(self, root):
562
605
  """
563
606
  Returns the collection api path and api version.
@@ -767,7 +810,6 @@ class CollectionSyncFirstStage(Stage):
767
810
  d_content = DeclarativeContent(
768
811
  content=AnsibleCollectionDeprecated(namespace=namespace, name=name),
769
812
  )
770
- self.deprecation_after_sync.add(f"{namespace}.{name}")
771
813
  await self.put(d_content)
772
814
  tasks.append(
773
815
  loop.create_task(
@@ -802,7 +844,6 @@ class CollectionSyncFirstStage(Stage):
802
844
  d_content = DeclarativeContent(
803
845
  content=AnsibleCollectionDeprecated(namespace=namespace, name=name),
804
846
  )
805
- self.deprecation_after_sync.add(f"{namespace}.{name}")
806
847
  await self.put(d_content)
807
848
 
808
849
  all_versions_of_collection = self._unpaginated_collection_version_metadata[namespace][name]
@@ -925,9 +966,6 @@ class CollectionSyncFirstStage(Stage):
925
966
  namespace=collection["namespace"], name=collection["name"]
926
967
  ),
927
968
  )
928
- self.deprecation_after_sync.add(
929
- f"{collection['namespace']}.{collection['name']}"
930
- )
931
969
  await self.put(d_content)
932
970
 
933
971
  for collections_in_namespace in self._unpaginated_collection_version_metadata.values():
@@ -118,6 +118,13 @@ def collection_detail(http_session, collection_upload, pulp_dist, collection_art
118
118
  return response.json()
119
119
 
120
120
 
121
+ @pytest.fixture(scope="class")
122
+ def collection_highest_version(http_session, collection_detail):
123
+ response = http_session.get(collection_detail["highest_version"]["href"])
124
+ response.raise_for_status()
125
+ return response.json()
126
+
127
+
121
128
  @pytest.fixture(scope="class")
122
129
  def pulp_dist(ansible_repository_factory, ansible_distribution_factory):
123
130
  """Create an Ansible Distribution to simulate the automation hub environment for testing."""
@@ -291,34 +298,52 @@ class TestCollection:
291
298
  # # 'repository': 'http://github.example.com/orionuser1/skeleton',
292
299
  # # 'tags': ['collectiontest']},
293
300
 
294
- def test_collection_download(
301
+ def test_collection_download_metadata_unauthorized_fails(
295
302
  self,
296
303
  http_session,
297
304
  collection_detail,
298
- collection_artifact,
299
305
  ):
300
- """Test collection download URL.
301
-
302
- Should require authentication and redirect to a download location.
303
- """
304
306
  response = http_session.get(collection_detail["highest_version"]["href"], auth=NullAuth())
305
307
  assert response.status_code == 401
306
- response = http_session.get(collection_detail["highest_version"]["href"])
307
- response.raise_for_status()
308
- version = response.json()
309
308
 
309
+ def test_collection_download_redirects(
310
+ self,
311
+ http_session,
312
+ collection_highest_version,
313
+ collection_artifact,
314
+ ):
310
315
  # Artifact Download Endoint
311
- url = version["download_url"]
316
+ url = collection_highest_version["download_url"]
312
317
 
313
318
  with open(collection_artifact.filename, "rb") as fp:
314
319
  tarball = fp.read()
315
320
 
316
- response = http_session.get(url, auth=NullAuth())
317
- assert response.status_code == 401
318
321
  response = http_session.get(url)
319
322
  assert response.status_code == 200, (url, response.request.headers)
320
323
  assert response.content == tarball
321
324
 
325
+ def test_collection_download_redirect_fails_unauthorized(
326
+ self,
327
+ http_session,
328
+ collection_highest_version,
329
+ ):
330
+ # Artifact Download Endoint
331
+ url = collection_highest_version["download_url"]
332
+
333
+ response = http_session.get(url, auth=NullAuth())
334
+ assert response.status_code == 401
335
+
336
+ def test_downloading_collection_with_bad_name_returns_not_found(
337
+ self,
338
+ http_session,
339
+ collection_highest_version,
340
+ ):
341
+ # Artifact Download Endoint, but we mess up the address.
342
+ url = collection_highest_version["download_url"].replace("-", "_")
343
+
344
+ response = http_session.get(url)
345
+ assert response.status_code == 404
346
+
322
347
  def test_collection_upload_repeat(
323
348
  self, http_session, ansible_collection_factory, pulp_dist, collection_upload
324
349
  ):
@@ -35,7 +35,6 @@ def test_deprecation(
35
35
  collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
36
36
  first_distribution.base_path, namespace="testing"
37
37
  )
38
-
39
38
  assert collections.data[0].deprecated
40
39
  collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
41
40
  first_distribution.base_path, namespace="pulp"
@@ -62,15 +61,12 @@ def test_deprecation(
62
61
  )
63
62
  assert collections.data[0].deprecated
64
63
 
65
- # Change the deprecated status for the testing collection on the original repo to False
66
- result = ansible_bindings.PulpAnsibleApiV3CollectionsApi.update(
67
- "k8s_demo_collection", "testing", first_distribution.base_path, {"deprecated": False}
68
- )
69
- monitor_task(result.task)
64
+ # Sync again to see if the deprecated state is kept.
65
+ ansible_sync_factory(second_repo, optimize=False)
70
66
  collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
71
- first_distribution.base_path, namespace="testing"
67
+ second_distribution.base_path, namespace="testing"
72
68
  )
73
- assert not collections.data[0].deprecated
69
+ assert collections.data[0].deprecated
74
70
 
75
71
  # Update the requirements to sync down both collections this time
76
72
  requirements = (
@@ -83,9 +79,34 @@ def test_deprecation(
83
79
  # Sync the second repo again
84
80
  second_repo = ansible_sync_factory(second_repo)
85
81
 
82
+ # Assert the state of deprecated True for testing, False for pulp
83
+ collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
84
+ second_distribution.base_path, namespace="testing"
85
+ )
86
+ assert collections.data[0].deprecated
87
+ collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
88
+ second_distribution.base_path, namespace="pulp"
89
+ )
90
+ assert not collections.data[0].deprecated
91
+
92
+ # Change the deprecated status for the testing collection on the original repo to False
93
+ monitor_task(
94
+ ansible_bindings.PulpAnsibleApiV3CollectionsApi.update(
95
+ "k8s_demo_collection", "testing", first_distribution.base_path, {"deprecated": False}
96
+ ).task
97
+ )
98
+ collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
99
+ first_distribution.base_path, namespace="testing"
100
+ )
101
+ assert not collections.data[0].deprecated
102
+
103
+ # Sync the second repo again
104
+ second_repo = ansible_sync_factory(second_repo)
105
+
86
106
  # Assert both collections show deprecated=False
87
107
  collections = ansible_bindings.PulpAnsibleApiV3CollectionsApi.list(
88
108
  second_distribution.base_path
89
109
  )
110
+ assert len(collections.data) == 2, collections
90
111
  for collection in collections.data:
91
112
  assert not collection.deprecated
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulp-ansible
3
- Version: 0.25.1
3
+ Version: 0.25.3
4
4
  Summary: Pulp plugin to manage Ansible content, e.g. roles
5
5
  Author-email: Pulp Ansible Plugin Project Developers <pulp-dev@redhat.com>
6
6
  Project-URL: Homepage, https://pulpproject.org
@@ -18,13 +18,12 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Requires-Python: >=3.9
19
19
  Description-Content-Type: text/x-rst
20
20
  License-File: LICENSE
21
- Requires-Dist: async_lru<2.1,>=1.0
22
- Requires-Dist: galaxy_importer<0.5,>=0.4.5
21
+ Requires-Dist: galaxy_importer<0.5,>=0.4.27
23
22
  Requires-Dist: GitPython<3.2,>=3.1.24
24
- Requires-Dist: jsonschema<4.24,>=4.9
25
- Requires-Dist: Pillow<11.2,>=10.3
23
+ Requires-Dist: jsonschema<4.26,>=4.9
24
+ Requires-Dist: Pillow<11.4,>=10.3
26
25
  Requires-Dist: pulpcore<3.85,>=3.49.0
27
- Requires-Dist: PyYAML<7.0,>=5.4.1
26
+ Requires-Dist: PyYAML<7.0,>=6.0.1
28
27
  Requires-Dist: semantic_version<2.11,>=2.9
29
28
  Dynamic: license-file
30
29
 
@@ -1,6 +1,6 @@
1
1
  pulp_ansible/__init__.py,sha256=WXL3JyOZzh4tALN4OBNgqj412O2LXVr8iYSn14Av0_o,67
2
2
  pulp_ansible/pytest_plugin.py,sha256=1x_Nb39VqNmI8KMEA4RS0fkvOPpkpp-7Dwzo9mjvyJQ,8763
3
- pulp_ansible/app/__init__.py,sha256=Ri3VbFUqIn36m0F2sUOMrEAKMkITFikjc_Rwt3a9tRg,279
3
+ pulp_ansible/app/__init__.py,sha256=6nupvvxeUj_IdcAjY2Tjb7CjgrdojFb3_6x2PjStQj0,279
4
4
  pulp_ansible/app/constants.py,sha256=cRrWMbJU-v1nCY2CjmGTOFGzz5aggn4ZKIs4-zeYADQ,78
5
5
  pulp_ansible/app/downloaders.py,sha256=0xrAXzhTMJ6ywvs6XyYNAKvRzYb_UZR6A5_WgaHvuiE,8331
6
6
  pulp_ansible/app/fields.py,sha256=yV3FL-47K-nxbiBxgzWi1hk3tfLsRdgic59LiwT2Fvs,624
@@ -8,7 +8,7 @@ pulp_ansible/app/global_access_conditions.py,sha256=ayV_LbQIa4ReuDYQycdDY7WysfGk
8
8
  pulp_ansible/app/logutils.py,sha256=My4XivZMYLKeJqPHFwk3pIZSGlspALhI93vZxwWzlSY,846
9
9
  pulp_ansible/app/modelresource.py,sha256=Kqhmhd53JPfOthoOzLPxN1TnGERJBFckvwQoJfaIKnw,7839
10
10
  pulp_ansible/app/models.py,sha256=N-xlOAKttNzC6_3XifFSDIlUssURy8tr3EVxvQVpqe0,22648
11
- pulp_ansible/app/serializers.py,sha256=ffC1kgmdoQUwmthc8fJHr9dJu8BYk8-wyeN2E58m8dY,35450
11
+ pulp_ansible/app/serializers.py,sha256=T2egPZ2a1ZsCGMCxfg72BB0o9wfFhGOd7jVZm8-QNe4,36139
12
12
  pulp_ansible/app/settings.py,sha256=M9OdR-EiHjmskVCGHBjHkBMts66kx4F22sS2dgb7YAw,1186
13
13
  pulp_ansible/app/urls.py,sha256=PM-kGhBX7eQTJgsomUCxbIUHpIhyVZCyDUywQ21KAxU,8443
14
14
  pulp_ansible/app/utils.py,sha256=ClI_WvVy73kOZQB2mS8Gftf80Vye7pOxrbodTmPQgmk,1686
@@ -22,7 +22,7 @@ pulp_ansible/app/galaxy/v3/exceptions.py,sha256=uKTj_LteLusc9Wu0iSYO-U8Gq9UK1eVR
22
22
  pulp_ansible/app/galaxy/v3/filters.py,sha256=xkb_m8chPZBJzElwuFkhLV5Hx8I1A7ZnxdTqGYFnpyc,8087
23
23
  pulp_ansible/app/galaxy/v3/pagination.py,sha256=FhFKtPfljjmKrnB_EWz7FxAhKPX9gkuvbOx-2KU9V4Y,4042
24
24
  pulp_ansible/app/galaxy/v3/serializers.py,sha256=se2BpCnU-Pa0HfxNwu1My78qyloR_ahbuXNBlJM_VjU,13030
25
- pulp_ansible/app/galaxy/v3/views.py,sha256=AgvzJhfVMbvKSvoiqHcJx5taA32rnQBJSfDRHxSTRBk,47073
25
+ pulp_ansible/app/galaxy/v3/views.py,sha256=hk9UbE7z3dBzlJA4Z_gAO6qxWNwn5CBAKQRgECDuCU4,47199
26
26
  pulp_ansible/app/galaxy/v3/viewsets.py,sha256=z6vuXnROCraS5OLonHe4iPRt7jvI0bjDbeiLi_infjs,3858
27
27
  pulp_ansible/app/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  pulp_ansible/app/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -84,14 +84,14 @@ pulp_ansible/app/migrations/0053_collectiondownloadcount.py,sha256=XK3FJf2P9XX7i
84
84
  pulp_ansible/app/migrations/0054_split_collection_version_numbers.py,sha256=QdJkJ48A_ZcgD2WyyRrAdPMmQe8OWkEgs4FtMFa-rDg,2369
85
85
  pulp_ansible/app/migrations/0055_alter_collectionversion_version_alter_role_version.py,sha256=g_4p81Owqi6sY0-KAv_mSPya1MNlj8pbJkMpHZ4hLpc,904
86
86
  pulp_ansible/app/migrations/0056_collectionversion_sha256.py,sha256=6gLDAEcULJag1_L3jpbmrA42EeP5wsWhlq0VALK_Lpg,487
87
- pulp_ansible/app/migrations/0057_collectionversion_sha256_migrate.py,sha256=VnFl99Wywslr53VKwfd6RNBB5HEBaUCsqX0awEVOkMU,2395
87
+ pulp_ansible/app/migrations/0057_collectionversion_sha256_migrate.py,sha256=MoMVQ2wnSmJqu826yqCKf3VGXmJCCiAXbUluWO8wMAY,2414
88
88
  pulp_ansible/app/migrations/0058_fix_0056_regression.py,sha256=VTmiG_VlpC6wXb4R28TDC4rbd1KLTuPItgzcrq0R28w,1021
89
89
  pulp_ansible/app/migrations/0059_collectionversion_unique_sha256.py,sha256=_4MAElCkv5OUjv7v9eL43h9PhtLl85vOfMiTZKEGD-Q,1291
90
90
  pulp_ansible/app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  pulp_ansible/app/schema/__init__.py,sha256=eGi2QVJ0kJgXwiDNjQsvqWDSr3EA8TFqFZATTY8xwT8,207
92
92
  pulp_ansible/app/schema/copy_config.json,sha256=AJz8riON7_rh-L7jM5iev2Imc5UKjlNvGfwF7KrFH7Y,568
93
93
  pulp_ansible/app/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
- pulp_ansible/app/tasks/collections.py,sha256=tL4Ph4UEeChObxSbzn0ao32xNnrjSKMU2DCLyJjECDE,50840
94
+ pulp_ansible/app/tasks/collections.py,sha256=_cDqU7_fhNmAJCboDDbth-QNu1n11-fXyQa3VPYg4cY,51932
95
95
  pulp_ansible/app/tasks/collectionversion_index.py,sha256=_cnQeWRpFXrreTJM9aaEc2HuknTksZa0lLZ7XUfmQ_c,9401
96
96
  pulp_ansible/app/tasks/copy.py,sha256=dO_DnLT5hck6GpZomEHurrDHJM0Wkh2B0_wgHHOtbuY,5563
97
97
  pulp_ansible/app/tasks/deletion.py,sha256=f-VNTMzDMQiJpCLN34fY5gwhAGlh3RACj4VWc_tOaP0,3579
@@ -121,12 +121,12 @@ pulp_ansible/tests/functional/api/collection/test_signatures.py,sha256=Oos2kyUMz
121
121
  pulp_ansible/tests/functional/api/collection/test_sync.py,sha256=ITeATktxSpXbV4emJ8xXl4EGuebBRmrBdDRarVmSgJ8,14818
122
122
  pulp_ansible/tests/functional/api/collection/v3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
123
123
  pulp_ansible/tests/functional/api/collection/v3/test_client_configuration.py,sha256=Tk8PdvG2Y1mZs5pUm2z91Tlpxaw0_8TvhshNbioMkKg,648
124
- pulp_ansible/tests/functional/api/collection/v3/test_collection.py,sha256=HSzkFt5HHURk56TqJBy6ZziMBKyraMxzbb1_r1fF4Js,12790
124
+ pulp_ansible/tests/functional/api/collection/v3/test_collection.py,sha256=NAkW8SDhgHsVg88Fy0FTBzaOgDB2hHei-uFBMRZops0,13524
125
125
  pulp_ansible/tests/functional/api/collection/v3/test_collection_naming_edgecases.py,sha256=qPYFf-lWg2-i8xRvRGMKmGHbg00Cyd0EqGjzXF4ET-8,5492
126
126
  pulp_ansible/tests/functional/api/collection/v3/test_collection_version_search.py,sha256=uQGWs5ny0R-dP9YjZcspFRPDQTA-_OSuy6Dm4TLPrT8,48422
127
127
  pulp_ansible/tests/functional/api/collection/v3/test_content_guard.py,sha256=lid_TY4ANaU1fmoDAn6xuApOcP8UnrBuXlYfaqGXyvA,3311
128
128
  pulp_ansible/tests/functional/api/collection/v3/test_deletion.py,sha256=V25G4VgJybNeMbElunE1cOSm_6KRk8FkYBAW-L1ZLWc,11620
129
- pulp_ansible/tests/functional/api/collection/v3/test_deprecation.py,sha256=EavR6QErQkuCG5LYi_smilzQSqu7egrCdaw0KQeaC3I,3326
129
+ pulp_ansible/tests/functional/api/collection/v3/test_deprecation.py,sha256=n8khr_JySTXWDl-SiSDt4SLcdncMBGa5lBMIGyItyak,4185
130
130
  pulp_ansible/tests/functional/api/collection/v3/test_namespace.py,sha256=6eOazDAQXnx3rxwhSX1cpSjWMrqj63DFtNnsHrswpGA,8828
131
131
  pulp_ansible/tests/functional/api/collection/v3/test_proxy.py,sha256=Yb6BOZu0bnSGcy9zC57W5a-ohh7MpKRVJhZ6tgSS_LY,2817
132
132
  pulp_ansible/tests/functional/api/collection/v3/test_redirects.py,sha256=ffolGXCJUp20YWk-ix_dWmCxtLN5yePHVywys3yDEZI,5170
@@ -160,9 +160,9 @@ pulp_ansible/tests/unit/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
160
160
  pulp_ansible/tests/unit/migrations/conftest.py,sha256=61n56aJuwEuAcUS27xnmnEDx6Ie7M5zxh851doWm7Ok,438
161
161
  pulp_ansible/tests/unit/migrations/test_0057_collection_version_sha256_migrate.py,sha256=NmU-frZNO1qHvhdxfw-bwPTEkqN4Wdc3dEs9dWME47o,2174
162
162
  pulp_ansible/tests/unit/migrations/test_x_repo_search_migration.py,sha256=IrC_V_Gss4nqhkdL-60upcEzGcz8IsiI2d-MfUtFY-g,657
163
- pulp_ansible-0.25.1.dist-info/licenses/LICENSE,sha256=2ylvL381vKOhdO-w6zkrOxe9lLNBhRQpo9_0EbHC_HM,18046
164
- pulp_ansible-0.25.1.dist-info/METADATA,sha256=AAZQBK7wlPhive3yk3CL-80va6B0e8rmc3kAp_8EhMk,3207
165
- pulp_ansible-0.25.1.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
166
- pulp_ansible-0.25.1.dist-info/entry_points.txt,sha256=6PFqCdT7Yn7U5MlioYRsyyWbJDcZI2aAJuzc7yXHqGk,119
167
- pulp_ansible-0.25.1.dist-info/top_level.txt,sha256=5Rrg5DSM_F9wH8vu8Fxjb5EmroC-I8RVKp05fhXH6kQ,13
168
- pulp_ansible-0.25.1.dist-info/RECORD,,
163
+ pulp_ansible-0.25.3.dist-info/licenses/LICENSE,sha256=2ylvL381vKOhdO-w6zkrOxe9lLNBhRQpo9_0EbHC_HM,18046
164
+ pulp_ansible-0.25.3.dist-info/METADATA,sha256=I-i1_OORETYhkS2s21gyaOMLzJaprA7NWAoD4-1YKzA,3173
165
+ pulp_ansible-0.25.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
166
+ pulp_ansible-0.25.3.dist-info/entry_points.txt,sha256=6PFqCdT7Yn7U5MlioYRsyyWbJDcZI2aAJuzc7yXHqGk,119
167
+ pulp_ansible-0.25.3.dist-info/top_level.txt,sha256=5Rrg5DSM_F9wH8vu8Fxjb5EmroC-I8RVKp05fhXH6kQ,13
168
+ pulp_ansible-0.25.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5