diff --git a/CHANGES/1236.feature b/CHANGES/1236.feature new file mode 100644 index 000000000..22b7ac472 --- /dev/null +++ b/CHANGES/1236.feature @@ -0,0 +1 @@ +Added a prn argument to `pulp show`. diff --git a/CHANGES/pulp-glue/1236.feature b/CHANGES/pulp-glue/1236.feature new file mode 100644 index 000000000..852d104f4 --- /dev/null +++ b/CHANGES/pulp-glue/1236.feature @@ -0,0 +1 @@ +Added `resolve_prn` to the `PulpContext` as a factory for `PulpEntityContext` objects. diff --git a/docs/dev/guides/contributing.md b/docs/dev/guides/contributing.md index 0c60d7048..03d9e6582 100644 --- a/docs/dev/guides/contributing.md +++ b/docs/dev/guides/contributing.md @@ -61,6 +61,6 @@ To run tests: ```bash make test # all tests -pytest -m pulp_file # tests for pulp_file -pytest -m pulp_file -k test_remote # run tests/scripts/pulp_file/test_remote.sh +pytest tests -m pulp_file # tests for pulp_file +pytest tests -m pulp_file -k test_remote # run tests/scripts/pulp_file/test_remote.sh ``` diff --git a/pulp-glue/src/pulp_glue/common/context.py b/pulp-glue/src/pulp_glue/common/context.py index addb7b8b3..6ae605a22 100644 --- a/pulp-glue/src/pulp_glue/common/context.py +++ b/pulp-glue/src/pulp_glue/common/context.py @@ -19,6 +19,7 @@ PulpHTTPError, PulpNoWait, UnsafeCallError, + ValidationError, ) from pulp_glue.common.i18n import get_translation from pulp_glue.common.openapi import METHODS, OpenAPI @@ -61,6 +62,11 @@ def _inner(f: T) -> T: ] href_regex = re.compile(r"\/([a-z0-9-_]+\/)+", flags=re.IGNORECASE) +# Be careful model in this regex differs from resource_type in others. +# model: "file.repository" ; resource_type: "file" +prn_regex = re.compile( + r"^prn:(?P[a-z][a-z0-9-_]*)\.(?P[a-z][a-z0-9_]*):(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", # noqa: E501 +) class PreprocessedEntityDefinition(dict[str, t.Any]): @@ -548,7 +554,8 @@ def call( task_href = result["task"] result = self.api.call("tasks_read", parameters={"task_href": task_href}) self.echo( - _("Started background task {task_href}").format(task_href=task_href), err=True + _("Started background task {task_href}").format(task_href=task_href), + err=True, ) if not non_blocking: result = self.wait_for_task(result) @@ -672,7 +679,8 @@ def wait_for_task_group(self, task_group: EntityDefinition) -> t.Any: time.sleep(1) self.echo(".", nl=False, err=True) task_group = self.api.call( - "task_groups_read", parameters={"task_group_href": task_group["pulp_href"]} + "task_groups_read", + parameters={"task_group_href": task_group["pulp_href"]}, ) except KeyboardInterrupt: raise PulpNoWait( @@ -713,6 +721,21 @@ def needs_plugin( # Schedule for later checking self._needed_plugins.append(plugin_requirement) + def resolve_prn(self, prn: str) -> "PulpEntityContext": + """ + A factory to provide subclasses of `PulpEntityContext` based on a given PRN. + """ + match = prn_regex.fullmatch(prn) + if match is None: + raise ValidationError(f"{prn} is not a PRN.") + plugin = match.group("plugin") + model = match.group("model") + pulp_id = match.group("pulp_id") + if (ctx_class := PulpEntityContext.PRN_TYPE_REGISTRY.get(f"{plugin}:{model}")) is not None: + result = ctx_class.from_pulp_id(self, pulp_id) + return result + raise ValidationError(f"Resource type {plugin}:{model} unknown.") + class PulpViewSetContext: """ @@ -815,6 +838,17 @@ class PulpEntityContext(PulpViewSetContext): """ HREF_PATTERN: str """Regular expression with capture groups for 'plugin' and 'resource_type' to match URIs.""" + HREF_TEMPLATE: str + + PLUGIN: t.ClassVar[str] + RESOURCE_TYPE: t.ClassVar[str] + MODEL: t.ClassVar[str] + PRN_TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpEntityContext"]]] = {} + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + if hasattr(cls, "PLUGIN") and hasattr(cls, "MODEL"): + cls.PRN_TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.MODEL}"] = cls # Hidden values for the lazy entity lookup _entity: EntityDefinition | None @@ -887,6 +921,15 @@ def pulp_href(self, value: str) -> None: self._entity_lookup = {"pulp_href": value} self._entity = None + @classmethod + def from_pulp_id(cls, pulp_ctx: PulpContext, pulp_id: str) -> "t.Self": + if hasattr(cls, "HREF_TEMPLATE"): + return cls( + pulp_ctx, + pulp_href=pulp_ctx.api_path + cls.HREF_TEMPLATE.replace("{pulp_id}", pulp_id), + ) + raise NotImplementedError("Subclasses should implement this or provide an HREF_TEMPLATE.") + @property def tangible(self) -> bool: """Indicate whether an entity is available or specified by search parameters.""" @@ -1003,7 +1046,8 @@ def _list(self, limit: int, offset: int, parameters: dict[str, t.Any]) -> list[t pass else: self.pulp_ctx.echo( - _("Not all {count} entries were shown.").format(count=stats["count"]), err=True + _("Not all {count} entries were shown.").format(count=stats["count"]), + err=True, ) return entities @@ -1101,7 +1145,8 @@ def create( h for h in result["created_resources"] if re.match( - re.escape(self.pulp_ctx.api_path) + self.HREF_PATTERN, h + re.escape(self.pulp_ctx.api_path) + self.HREF_PATTERN, + h, ) ) ) @@ -1229,7 +1274,9 @@ def unset_label(self, key: str, non_blocking: bool = False) -> t.Any: if self.pulp_ctx.has_plugin(PluginRequirement("core", specifier=">=3.34.0")): try: return self.call( - "unset_label", parameters={self.HREF: self.pulp_href}, body={"key": key} + "unset_label", + parameters={self.HREF: self.pulp_href}, + body={"key": key}, ) except PulpHTTPError as e: if e.status_code != 403: @@ -1382,6 +1429,7 @@ class PulpRemoteContext(PulpEntityContext): ENTITIES = _("remotes") ID_PREFIX = "remotes" HREF_PATTERN = r"remotes/(?P[\w\-_]+)/(?P[\w\-_]+)/" + HREF_TEMPLATE = "remotes/{plugin}/{resource_type}/{pulp_id}/" NULLABLES = { "ca_cert", "client_cert", @@ -1402,8 +1450,13 @@ class PulpRemoteContext(PulpEntityContext): TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpRemoteContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}remote" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls @@ -1414,11 +1467,17 @@ class PulpPublicationContext(PulpEntityContext): ENTITIES = _("publications") ID_PREFIX = "publications" HREF_PATTERN = r"publications/(?P[\w\-_]+)/(?P[\w\-_]+)/" + HREF_TEMPLATE = "publications/{plugin}/{resource_type}/{pulp_id}/" TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpPublicationContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}publication" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls def list(self, limit: int, offset: int, parameters: dict[str, t.Any]) -> list[t.Any]: @@ -1436,12 +1495,24 @@ class PulpDistributionContext(PulpEntityContext): ENTITIES = _("distributions") ID_PREFIX = "distributions" HREF_PATTERN = r"distributions/(?P[\w\-_]+)/(?P[\w\-_]+)/" - NULLABLES = {"content_guard", "publication", "remote", "repository", "repository_version"} + HREF_TEMPLATE = "distributions/{plugin}/{resource_type}/{pulp_id}/" + NULLABLES = { + "content_guard", + "publication", + "remote", + "repository", + "repository_version", + } TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpDistributionContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}distribution" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls @@ -1511,14 +1582,20 @@ class PulpRepositoryContext(PulpEntityContext): ENTITY = _("repository") ENTITIES = _("repositories") HREF_PATTERN = r"repositories/(?P[\w\-_]+)/(?P[\w\-_]+)/" + HREF_TEMPLATE = "repositories/{plugin}/{resource_type}/{pulp_id}/" ID_PREFIX = "repositories" VERSION_CONTEXT: t.ClassVar[t.Type[PulpRepositoryVersionContext]] = PulpRepositoryVersionContext NULLABLES = {"description", "remote", "retain_repo_versions"} TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpRepositoryContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}repository" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls def get_version_context( @@ -1633,11 +1710,17 @@ class PulpContentContext(PulpEntityContext): ENTITIES = _("content") ID_PREFIX = "content" HREF_PATTERN = r"content/(?P[\w\-_]+)/(?P[\w\-_]+)/" + HREF_TEMPLATE = "content/{plugin}/{resource_type}/{pulp_id}/" TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpContentContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}content" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls def __init__( @@ -1743,12 +1826,18 @@ class PulpACSContext(PulpEntityContext): ENTITY = _("ACS") ENTITIES = _("ACSes") HREF_PATTERN = r"acs/(?P[\w\-_]+)/(?P[\w\-_]+)/" + HREF_TEMPLATE = "acs/{plugin}/{resource_type}/{pulp_id}/" ID_PREFIX = "acs" TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpACSContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}acs" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls def refresh(self, href: str | None = None) -> t.Any: @@ -1762,12 +1851,18 @@ class PulpContentGuardContext(PulpEntityContext): ENTITIES = "content guards" ID_PREFIX = "contentguards" HREF_PATTERN = r"contentguards/(?P[\w\-_]+)/(?P[\w\-_]+)/" + HREF_TEMPLATE = "contentguards/{plugin}/{resource_type}/{pulp_id}/" NULLABLES = {"description"} TYPE_REGISTRY: t.Final[dict[str, t.Type["PulpContentGuardContext"]]] = {} def __init_subclass__(cls, **kwargs: t.Any) -> None: + if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.MODEL = f"{cls.RESOURCE_TYPE}contentguard" super().__init_subclass__(**kwargs) if hasattr(cls, "PLUGIN") and hasattr(cls, "RESOURCE_TYPE"): + cls.HREF_TEMPLATE = cls.HREF_TEMPLATE.replace("{plugin}", cls.PLUGIN).replace( + "{resource_type}", cls.RESOURCE_TYPE + ) cls.TYPE_REGISTRY[f"{cls.PLUGIN}:{cls.RESOURCE_TYPE}"] = cls diff --git a/pulp-glue/src/pulp_glue/core/context.py b/pulp-glue/src/pulp_glue/core/context.py index e1e1f1c3d..1aae27baf 100644 --- a/pulp-glue/src/pulp_glue/core/context.py +++ b/pulp-glue/src/pulp_glue/core/context.py @@ -42,6 +42,9 @@ class PulpArtifactContext(PulpEntityContext): ENTITY = _("artifact") ENTITIES = _("artifacts") HREF = "artifact_href" + PLUGIN = "core" + MODEL = "artifact" + HREF_TEMPLATE = "artifacts/{pulp_id}/" ID_PREFIX = "artifacts" def upload( @@ -398,6 +401,9 @@ class PulpTaskContext(PulpEntityContext): HREF = "task_href" ID_PREFIX = "tasks" CAPABILITIES = {"roles": [PluginRequirement("core", specifier=">=3.17.0")]} + PLUGIN = "core" + MODEL = "task" + HREF_TEMPLATE = "tasks/{pulp_id}/" resource_context: PulpEntityContext | None = None @@ -513,6 +519,9 @@ class PulpUploadContext(PulpEntityContext): ENTITIES = _("uploads") HREF = "upload_href" ID_PREFIX = "uploads" + PLUGIN = "core" + MODEL = "upload" + HREF_TEMPLATE = "uploads/{pulp_id}/" def upload_chunk( self, diff --git a/pulp-glue/tests/conftest.py b/pulp-glue/tests/conftest.py index 8ab80b48d..7e927f9f3 100644 --- a/pulp-glue/tests/conftest.py +++ b/pulp-glue/tests/conftest.py @@ -7,10 +7,14 @@ from pulp_glue.common.context import PulpContext from pulp_glue.common.openapi import OpenAPI -FAKE_OPENAPI_SPEC = json.dumps( +MOCK_OPENAPI_SPEC = json.dumps( { "openapi": "3.0.3", - "info": {"title": "test", "version": "0.0.0", "x-pulp-app-versions": {"core": "3.75.0"}}, + "info": { + "title": "test", + "version": "0.0.0", + "x-pulp-app-versions": {"core": "3.75.0", "file": "3.75.0"}, + }, "paths": {}, } ) @@ -35,7 +39,7 @@ def mock_pulp_ctx( monkeypatch: pytest.MonkeyPatch, ) -> PulpContext: monkeypatch.setattr( - OpenAPI, "load_api", lambda self, refresh_cache: self._parse_api(FAKE_OPENAPI_SPEC) + OpenAPI, "load_api", lambda self, refresh_cache: self._parse_api(MOCK_OPENAPI_SPEC) ) monkeypatch.setattr( OpenAPI, diff --git a/pulp-glue/tests/test_prn_routing.py b/pulp-glue/tests/test_prn_routing.py new file mode 100644 index 000000000..c9af2a349 --- /dev/null +++ b/pulp-glue/tests/test_prn_routing.py @@ -0,0 +1,70 @@ +import pytest + +from pulp_glue.common.context import PulpContext, PulpEntityContext +from pulp_glue.common.exceptions import ValidationError +from pulp_glue.core.context import PulpTaskContext, PulpUploadContext +from pulp_glue.file.context import PulpFileRemoteContext + +pytestmarks = pytest.mark.glue + + +class TestPRNRouting: + @pytest.mark.parametrize( + "prn,exc_pattern", + ( + pytest.param("not_a_prn", r"[Nn]ot.*PRN", id="invalid string"), + pytest.param( + "prn:file.filerepository:01234567-0123-0123-012-30123456789ab", + r"[Nn]ot.*PRN", + id="invalid uuid", + ), + pytest.param( + "prn:not_a_plugin.filerepository:01234567-0123-0123-0123-0123456789ab", + r"unknown", + id="unknown plugin", + ), + pytest.param( + "prn:file.not_a_resource:01234567-0123-0123-0123-0123456789ab", + r"unknown", + id="unknown resource type", + ), + ), + ) + def test_fails_if(self, mock_pulp_ctx: PulpContext, prn: str, exc_pattern: str) -> None: + with pytest.raises(ValidationError, match=exc_pattern): + mock_pulp_ctx.resolve_prn(prn) + + @pytest.mark.parametrize( + "prn,ctx_class,pulp_href", + ( + pytest.param( + "prn:core.upload:01234567-0123-0123-0123-0123456789ab", + PulpUploadContext, + "/api/v3/uploads/01234567-0123-0123-0123-0123456789ab/", + id="upload", + ), + pytest.param( + "prn:core.task:01234567-0123-0123-0123-0123456789ab", + PulpTaskContext, + "/api/v3/tasks/01234567-0123-0123-0123-0123456789ab/", + id="task", + ), + pytest.param( + "prn:file.fileremote:01234567-0123-0123-0123-0123456789ab", + PulpFileRemoteContext, + "/api/v3/remotes/file/file/01234567-0123-0123-0123-0123456789ab/", + id="file_remote", + ), + ), + ) + def test_returns_entity_context_with_href( + self, + mock_pulp_ctx: PulpContext, + prn: str, + ctx_class: type[PulpEntityContext], + pulp_href: str, + ) -> None: + entity_ctx = mock_pulp_ctx.resolve_prn(prn) + + assert isinstance(entity_ctx, ctx_class) + assert entity_ctx._entity_lookup["pulp_href"].endswith(pulp_href) diff --git a/src/pulp_cli/generic.py b/src/pulp_cli/generic.py index f9c940442..55730ba1d 100644 --- a/src/pulp_cli/generic.py +++ b/src/pulp_cli/generic.py @@ -28,6 +28,7 @@ PulpRepositoryContext, PulpRepositoryVersionContext, PulpViewSetContext, + prn_regex, ) from pulp_glue.common.exceptions import PulpException, PulpNoWait from pulp_glue.common.i18n import get_translation @@ -83,10 +84,6 @@ def _unset(value: t.Any) -> bool: HEADER_REGEX = r"^[-a-zA-Z0-9_]+:.+$" -prn_regex = re.compile( - r"^prn:(?P[a-z][a-z0-9-_]*)\.(?P[a-z][a-z0-9_]*):(?P[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$", # noqa: E501 -) - class IncompatibleContext(click.UsageError): """Exception to signal that an option or subcommand was used with an incompatible context.""" @@ -827,9 +824,6 @@ def pulp_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: return click.option(*args, **kwargs) -domain_pattern = r"(?P[-a-zA-Z0-9_]+)" - - def resource_lookup_option(*args: t.Any, **kwargs: t.Any) -> t.Callable[[FC], FC]: """ A factory to create a lookup option that will pass the lookup to the closest matching Context. @@ -853,10 +847,7 @@ def _option_callback( if value.startswith("/"): # The HREF of a resource was passed href_pattern = entity_ctx.HREF_PATTERN - if pulp_ctx.domain_enabled: - pattern = rf"^{pulp_ctx._api_root}{domain_pattern}/api/v3/{href_pattern}" - else: - pattern = rf"^{pulp_ctx.api_path}{href_pattern}" + pattern = rf"^{re.escape(pulp_ctx.api_path)}{href_pattern}" match = re.match(pattern, value) if match: entity_ctx.pulp_href = value @@ -951,10 +942,7 @@ def _option_callback( option_name=param.name ) ) - if pulp_ctx.domain_enabled: - pattern = rf"^{pulp_ctx._api_root}{domain_pattern}/api/v3/{href_pattern}" - else: - pattern = rf"^{pulp_ctx.api_path}{href_pattern}" + pattern = rf"^{re.escape(pulp_ctx.api_path)}{href_pattern}" match = re.match(pattern, value) if match is None: raise click.ClickException( diff --git a/src/pulpcore/cli/core/show.py b/src/pulpcore/cli/core/show.py index 43eb34060..5f7d90eb1 100644 --- a/src/pulpcore/cli/core/show.py +++ b/src/pulpcore/cli/core/show.py @@ -9,10 +9,19 @@ @pulp_command(name="show") -@click.option("--href", required=True, help=_("HREF of the entry")) +@click.option("--href", default=None, help=_("HREF of the resource")) +@click.option("--prn", default=None, help=_("PRN of the resource")) @pass_pulp_context -def show(pulp_ctx: PulpCLIContext, /, href: str) -> None: - """Show any resource given its href.""" - # use a random read operation to call the href - entity = pulp_ctx.call("artifacts_read", parameters={"artifact_href": href}) +def show(pulp_ctx: PulpCLIContext, /, href: str | None, prn: str | None) -> None: + """Show any resource given its href or prn.""" + if (href is None) == (prn is None): + raise click.UsageError(_("Either href or prn needs to be provided.")) + if href is not None: + # Use a random read operation to call the href. + # This is doomed to fail if we ever start validating responses. + entity = pulp_ctx.call("artifacts_read", parameters={"artifact_href": href}) + else: + assert prn is not None + entity_ctx = pulp_ctx.resolve_prn(prn) + entity = entity_ctx.entity pulp_ctx.output_result(entity) diff --git a/tests/scripts/pulpcore/test_show.sh b/tests/scripts/pulpcore/test_show.sh index 9768b68b7..567cde20b 100755 --- a/tests/scripts/pulpcore/test_show.sh +++ b/tests/scripts/pulpcore/test_show.sh @@ -13,9 +13,14 @@ cleanup() { trap cleanup EXIT expect_succ pulp file repository create --name "cli_test_core_show_repo" -repo_href="$(echo "$OUTPUT" | jq -r .pulp_href)" -expect_succ pulp show --href "$repo_href" +REPO_HREF="$(echo "$OUTPUT" | jq -r .pulp_href)" +expect_succ pulp show --href "$REPO_HREF" expect_succ pulp file remote create --name "cli_test_core_show_remote" --url "$FILE_REMOTE_URL" -remote_href="$(echo "$OUTPUT" | jq -r .pulp_href)" -expect_succ pulp show --href "$remote_href" +REMOTE_HREF="$(echo "$OUTPUT" | jq -r .pulp_href)" +REMOTE_PRN="$(echo "$OUTPUT" | jq -r .prn)" +expect_succ pulp show --href "$REMOTE_HREF" +if pulp debug has-plugin --name core --specifier ">=3.63.0" +then + expect_succ pulp show --prn "$REMOTE_PRN" +fi diff --git a/tests/test_prn_unit.py b/tests/test_prn_unit.py index 79b338502..fc5aa7609 100644 --- a/tests/test_prn_unit.py +++ b/tests/test_prn_unit.py @@ -1,10 +1,10 @@ import pytest -from pulp_cli.generic import prn_regex +from pulp_glue.common.context import prn_regex @pytest.mark.parametrize( - "prn,app,model,pk", + "prn,plugin,model,pulp_id", [ pytest.param( "prn:file.fileremote:0198b567-c482-7b28-8628-ea7f4be6d008", @@ -29,13 +29,13 @@ ), ], ) -def test_prn_match_succeeds_for(prn: str, app: str, model: str, pk: str) -> None: +def test_prn_match_succeeds_for(prn: str, plugin: str, model: str, pulp_id: str) -> None: match = prn_regex.match(prn) assert match assert 3 == len(match.groups()) - assert match.group("app") == app + assert match.group("plugin") == plugin assert match.group("model") == model - assert match.group("pk") == pk + assert match.group("pulp_id") == pulp_id @pytest.mark.parametrize(