How to Create a Pulp CLI Plugin¶
This guide shows you how to create a Pulp CLI plugin using the provided bootstrap templates. Instead of manually creating all the required files, the bootstrap process will automatically generate the correct structure and files for you.
Overview¶
Pulp CLI plugin extend the functionality of the Pulp CLI by adding custom commands and features.
The pulp-cli
project includes templates that make it easy to bootstrap a new plugin with the correct structure and configuration.
Prerequisites¶
Before you begin, ensure you have the following installed:
pip install cookiecutter click pyyaml tomlkit
Bootstrap a New Pulp CLI Plugin¶
Using the Bootstrap Template¶
Navigate to the directory where you want to create your new plugin and run:
# Clone the pulp-cli repository if you don't have it already
git clone https://github.com/pulp/pulp-cli.git
# Run the bootstrap script
pulp-cli/cookiecutter/apply_templates.py --bootstrap
Answer the Prompts¶
You will be prompted for several values during the bootstrap process.
The most important is app_label, which by convention (when applicable) should match the Pulp server component your plugin targets (for example, use file
for pulp-file
).
This value determines the import paths and command names for your plugin.
You will also see additional prompts for options such as glue integration, documentation, translations, version, repository URL, and CI configuration.
Answer these as appropriate for your project.
Key Files and Directories¶
The bootstrap process creates several important directories and files:
pulpcore/cli/my-plugin/__init__.py
: Main entry point where you define command groups. See below for more detailspulp-glue-my-plugin/pulp_glue/my-plugin/context.py
: API context class for interacting with Pulp. See below for more detailspyproject.toml
: Project metadata, dependencies, and build configuration. This file contains essential project information including author details, licensing information, version numbers, package dependencies, and build system configuration. You'll need to customize the author name, email, project description, license type to match your plugin's specific requirements.CHANGES/
: Directory for changelog fragments (.feature, .bugfix, etc. files). See the changelog update guide for more details..github/workflows/
: This directory contains GitHub Actions workflow configurations for automated testing and continuous integration. These files are pre-configured and do not require modification when initially setting up your plugin development environment. The CI workflows will automatically run tests and validation checks on your plugin code when you push changes to your repository.
Customizing Your Plugin¶
Create API Context Classes¶
Edit pulp-glue-my-plugin/pulp_glue/my_plugin/context.py
to define context classes that handle API interactions:
import typing as t
from pulp_glue.common.context import (
PulpEntityContext,
PluginRequirement
)
class PulpMyResourceContext():
"""Context for working with my custom resource."""
ID_PREFIX = "my_resource"
NEEDS_PLUGINS = [PluginRequirement("my_plugin", specifier=">=0.0.1")]
def example_action(self, data: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]:
"""Execute an example action with specific data.
Args:
data: The data dictionary to send to the API
Returns:
The action result
"""
response = self.call(
operation="example_action",
body=data,
)
return response
Add Subcommands to the CLI¶
Edit pulpcore/cli/my_plugin/__init__.py
to define your command groups and add functionality:
import typing as t
import click
from pulp_cli.generic import pulp_group
from pulp_glue.common.i18n import get_translation
# Import your command plugins
from pulpcore.cli.my_plugin.my_resource import my_resource
translation = get_translation(__package__)
_ = translation.gettext
__version__ = "0.1.0" # Matches version in pyproject.toml
@pulp_group(name="my_plugin")
def my_plugin_group() -> None:
"""My plugin commands."""
pass
def mount(main: click.Group, **kwargs: t.Any) -> None:
# Add your command groups here
my_plugin_group.add_command(my_resource)
main.add_command(my_plugin_group)
Create Plugin Commands¶
Create a new file for your resource, e.g., pulpcore/cli/my_plugin/my_resource.py
:
import click
from pulp_cli.common.context import pass_pulp_context
from pulp_glue.common.context import PulpContext
from pulp_glue.my_plugin.context import PulpMyResourceContext
from pulp_cli.common.generic import pass_entity_context
@click.group()
@pass_pulp_context
@click.pass_context
def my_resource(ctx: click.Context, pulp_ctx: PulpContext, /) -> None:
"""My custom commands."""
ctx.obj = PulpMyResourceContext(pulp_ctx)
@my_resource.command()
@click.option("--data", required=True, help="Data for the example action")
@pass_entity_context
@pass_pulp_context
def my_command(pulp_ctx: PulpContext, my_resource_ctx: PulpMyResourceContext, /, data: str):
"""Calling example action."""
result = my_resource_ctx.example_action({"data": data})
pulp_ctx.output_result(result)
Development Workflow¶
Install Your plugin in Development Mode¶
For installation instructions, see here.
Test Your Commands¶
After installation, you can test your commands:
pulp my-plugin my-resource my-command --data "example"
Consider writing tests for your commands as soon as you implement them.
Update Templates¶
If you need to update the project structure with new template changes:
cd pulp-cli-my-plugin
../pulp-cli/cookiecutter/apply_templates.py