diff --git a/CHANGES/pulp-glue/1391.feature b/CHANGES/pulp-glue/1391.feature index fcdcbf20a..10c0fe394 100644 --- a/CHANGES/pulp-glue/1391.feature +++ b/CHANGES/pulp-glue/1391.feature @@ -1 +1 @@ -Added `PulpPythonBlocklistEntryContext` for `pulp_python>=3.30.0`. +Added `PulpPythonBlocklistEntryContext` for `pulp_python>=3.30.2`. diff --git a/pulp-glue/src/pulp_glue/python/context.py b/pulp-glue/src/pulp_glue/python/context.py index 8a708a5d3..5b309d368 100644 --- a/pulp-glue/src/pulp_glue/python/context.py +++ b/pulp-glue/src/pulp_glue/python/context.py @@ -174,7 +174,7 @@ class PulpPythonBlocklistEntryContext(PulpEntityContext): ENTITIES = _("blocklist entries") HREF = "python_python_python_blocklist_entry_href" ID_PREFIX = "repositories_python_python_blocklist_entries" - NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.30.0")] + NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.30.2")] repository_ctx: PulpPythonRepositoryContext def __init__( diff --git a/src/pulpcore/cli/python/repository.py b/src/pulpcore/cli/python/repository.py index e457abf15..05379b44b 100644 --- a/src/pulpcore/cli/python/repository.py +++ b/src/pulpcore/cli/python/repository.py @@ -155,7 +155,7 @@ def repository() -> None: ) -@repository.group(needs_plugins=[PluginRequirement("python", specifier=">=3.30.0")]) +@repository.group(needs_plugins=[PluginRequirement("python", specifier=">=3.30.2")]) @pass_repository_context @pass_pulp_context @click.pass_context @@ -172,42 +172,76 @@ def blocklist( ctx.obj = PulpPythonBlocklistEntryContext(pulp_ctx, repository_ctx) -_HELP_BLOCKLIST_NAME = _("Package name to block. Required when 'filename' is not provided.") -_HELP_BLOCKLIST_VERSION = _("Exact version to block. Only used when 'name' is set.") -_HELP_BLOCKLIST_FILENAME = _("Exact filename to block. Required when 'name' is not provided.") +_HELP_BLOCKLIST_NAME = _( + "Package name to block (all versions). Required when 'filename' is not provided." +) +_HELP_BLOCKLIST_VERSION = _("Package version to block. Only used when 'name' is set.") +_HELP_BLOCKLIST_FILENAME = _("Package filename to block. Required when 'name' is not provided.") blocklist_options = [ click.option("--name", help=_HELP_BLOCKLIST_NAME), click.option("--version", help=_HELP_BLOCKLIST_VERSION), click.option("--filename", help=_HELP_BLOCKLIST_FILENAME), ] -blocklist_lookup_options = [ - pulp_option( - "--name", - help=_HELP_BLOCKLIST_NAME, - callback=lookup_callback("name"), - expose_value=False, - ), - pulp_option( - "--version", - help=_HELP_BLOCKLIST_VERSION, - callback=lookup_callback("version"), - expose_value=False, - ), - pulp_option( - "--filename", - help=_HELP_BLOCKLIST_FILENAME, - callback=lookup_callback("filename"), - expose_value=False, - ), - href_option, +blocklist_list_options = [ + click.option("--name", help="Package name to block."), + click.option("--version", help="Package version to block."), + click.option("--filename", help="Package filename to block."), ] blocklist.add_command( create_command(name="add", decorators=nested_lookup_options + blocklist_options) ) -blocklist.add_command(list_command(decorators=nested_lookup_options + blocklist_options)) -blocklist.add_command(show_command(decorators=nested_lookup_options + blocklist_lookup_options)) +blocklist.add_command(list_command(decorators=nested_lookup_options + blocklist_list_options)) + + +def _blocklist_lookup( + name: str | None, + version: str | None, + filename: str | None, +) -> dict[str, t.Any]: + if version and filename: + raise click.ClickException(_("'version' cannot be used with 'filename'.")) + if version and not name: + raise click.ClickException(_("'version' requires 'name' to be provided.")) + if name and filename: + raise click.ClickException(_("Exactly one of 'name' or 'filename' must be provided.")) + + lookup: dict[str, t.Any] = {} + if name and version: + lookup = {"name": name, "version": version} + elif name: + lookup = {"name": name, "version__isnull": True} + elif filename: + lookup = {"filename": filename} + return lookup + + +@blocklist.command(name="show") +@repository_href_option +@repository_lookup_option +@click.option("--name", help=_HELP_BLOCKLIST_NAME) +@click.option("--version", help=_HELP_BLOCKLIST_VERSION) +@click.option("--filename", help=_HELP_BLOCKLIST_FILENAME) +@href_option +@pass_entity_context +@pass_pulp_context +def blocklist_show( + pulp_ctx: PulpCLIContext, + entity_ctx: PulpEntityContext, + /, + name: str | None, + version: str | None, + filename: str | None, +) -> None: + """ + Show a blocklist entry. + """ + assert isinstance(entity_ctx, PulpPythonBlocklistEntryContext) + lookup = _blocklist_lookup(name, version, filename) + if lookup: + entity_ctx.entity = lookup + pulp_ctx.output_result(entity_ctx.entity) @blocklist.command(name="remove") @@ -229,19 +263,9 @@ def blocklist_remove( Remove a blocklist entry. """ assert isinstance(entity_ctx, PulpPythonBlocklistEntryContext) - if version and filename: - raise click.ClickException(_("'version' cannot be used with 'filename'.")) - if version and not name: - raise click.ClickException(_("'version' requires 'name' to be provided.")) - if name and filename: - raise click.ClickException(_("Exactly one of 'name' or 'filename' must be provided.")) - - if name: - entity_ctx.entity = {"name": name} - if version: - entity_ctx.entity = {"version": version} - if filename: - entity_ctx.entity = {"filename": filename} + lookup = _blocklist_lookup(name, version, filename) + if lookup: + entity_ctx.entity = lookup entity_ctx.delete() diff --git a/tests/scripts/pulp_python/test_blocklist.sh b/tests/scripts/pulp_python/test_blocklist.sh index 171d04c0e..72708ee92 100755 --- a/tests/scripts/pulp_python/test_blocklist.sh +++ b/tests/scripts/pulp_python/test_blocklist.sh @@ -4,7 +4,7 @@ set -eu # shellcheck source=tests/scripts/config.source . "$(dirname "$(dirname "$(realpath "$0")")")"/config.source -pulp debug has-plugin --name "python" --specifier ">=3.30.0" || exit 23 +pulp debug has-plugin --name "python" --specifier ">=3.30.2" || exit 23 cleanup() { pulp python repository destroy --name "cli_test_python_blocklist" || true @@ -13,45 +13,38 @@ trap cleanup EXIT expect_succ pulp python repository create --name "cli_test_python_blocklist" -# Test adding a blocklist entry by package name +# Test adding blocklist entries expect_succ pulp python repository blocklist add --repository "cli_test_python_blocklist" --name "pkg" test "$(echo "$OUTPUT" | jq -r '.name')" = "pkg" test "$(echo "$OUTPUT" | jq -r '.version')" = "null" test "$(echo "$OUTPUT" | jq -r '.filename')" = "null" ENTRY_HREF="$(echo "$OUTPUT" | jq -r '.pulp_href')" +expect_succ pulp python repository blocklist add --repository "cli_test_python_blocklist" --name "pkg" --version "2.0" +expect_succ pulp python repository blocklist add --repository "cli_test_python_blocklist" --filename "pkg-3.0.tar.gz" # Test listing blocklist entries expect_succ pulp python repository blocklist list --repository "cli_test_python_blocklist" -expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "1" +expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "3" expect_succ pulp python repository blocklist list --repository "cli_test_python_blocklist" --name "pkg" -expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "1" +expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "2" expect_succ pulp python repository blocklist list --repository "cli_test_python_blocklist" --name "nonexistent" expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "0" # Test showing a specific blocklist entry expect_succ pulp python repository blocklist show --repository "cli_test_python_blocklist" --href "$ENTRY_HREF" -expect_succ test "$(echo "$OUTPUT" | jq -r '.name')" = "pkg" +test "$(echo "$OUTPUT" | jq -r '.name')" = "pkg" +test "$(echo "$OUTPUT" | jq -r '.version')" = "null" expect_succ pulp python repository blocklist show --repository "cli_test_python_blocklist" --name "pkg" -expect_succ test "$(echo "$OUTPUT" | jq -r '.name')" = "pkg" +test "$(echo "$OUTPUT" | jq -r '.pulp_href')" = "$ENTRY_HREF" -# Test remove validation -expect_fail pulp python repository blocklist remove --repository "cli_test_python_blocklist" --version "1.0" --filename "pkg-1.0.tar.gz" -expect_fail pulp python repository blocklist remove --repository "cli_test_python_blocklist" --version "1.0" -expect_fail pulp python repository blocklist remove --repository "cli_test_python_blocklist" --name "pkg" --filename "pkg-1.0.tar.gz" +# Test input validation +expect_fail pulp python repository blocklist show --repository "cli_test_python_blocklist" --version "1.0" --filename "pkg-1.0.tar.gz" +expect_fail pulp python repository blocklist show --repository "cli_test_python_blocklist" --version "1.0" +expect_fail pulp python repository blocklist show --repository "cli_test_python_blocklist" --name "pkg" --filename "pkg-1.0.tar.gz" -# Test removing a blocklist entry by href +# Test removing blocklist entries expect_succ pulp python repository blocklist remove --repository "cli_test_python_blocklist" --href "$ENTRY_HREF" -expect_succ pulp python repository blocklist list --repository "cli_test_python_blocklist" -expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "0" - -# Test removing a blocklist entry by package name + version -expect_succ pulp python repository blocklist add --repository "cli_test_python_blocklist" --name "pkg" --version "2.0" expect_succ pulp python repository blocklist remove --repository "cli_test_python_blocklist" --name "pkg" --version "2.0" -expect_succ pulp python repository blocklist list --repository "cli_test_python_blocklist" -expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "0" - -# Test removing a blocklist entry by package filename -expect_succ pulp python repository blocklist add --repository "cli_test_python_blocklist" --filename "pkg-3.0.tar.gz" expect_succ pulp python repository blocklist remove --repository "cli_test_python_blocklist" --filename "pkg-3.0.tar.gz" expect_succ pulp python repository blocklist list --repository "cli_test_python_blocklist" expect_succ test "$(echo "$OUTPUT" | jq -r '.|length')" = "0"