product:commands
Table of contents
Introduction
product:commands lists the CLI commands your product’s features contribute, and your product’s own. It needs a selected product (SPLENT_APP) whose app boots.
splent product:commands
Feature Commands
Feature Command Flags Description
------- -------------------------- ------------------- ------------------------------
notes feature:notes export-notes --format FORMAT Print every note of the acti...
feature:notes purge-drafts --older-than DAYS * Delete the drafts older than...
2 command(s) from 1 feature(s).
Product Commands
Product Command Flags Description
-------- ----------------- ----------------- ------------------------------
my_shop product:reprice --dry-run Recompute every price from...
1 command(s) of my_shop's own.
Feature is the short name, without splent_feature_. Flags lists each option with its value type, and * marks a required one.
Adding a command to a feature
Give the feature a commands.py with a cli_commands list.
# splent_feature_notes/commands.py
import click
from splent_framework.services.service_locator import service_proxy
@click.command("purge-drafts")
@click.option("--older-than", required=True, type=int, metavar="DAYS", help="Age in days.")
def purge_drafts(older_than):
"""Delete the drafts older than a number of days."""
count = service_proxy("NotesService").purge_drafts(days=older_than)
click.secho(f" Deleted {count} draft(s).", fg="green")
cli_commands = [purge_drafts]
The framework finds it when it loads the feature, and the CLI exposes the command under feature:<name>.
splent feature:notes purge-drafts --older-than 30
feature:contract --write records the commands in the feature’s contract. Only the features your product declares contribute commands.
Adding a command to the product
Your product declares its own commands the same way, in <product>/src/<product>/commands.py. Name them without a prefix.
# my_shop/src/my_shop/commands.py
import click
@click.command("reprice")
@click.option("--dry-run", is_flag=True, help="Say what would change.")
def reprice(dry_run):
"""Recompute every price from the catalogue."""
...
cli_commands = [reprice]
The CLI runs each one as product:<name>, in your product’s app context.
splent product:reprice --dry-run
splent --help lists them under Product Commands.
A built-in command always wins. A product command named
testwould beproduct:test, which is the CLI’s, so it cannot be reached.product:commandswarns with⚠ my_shop has a command product:test, which is the CLI's own and wins: rename it to reach it.
Advanced
When the CLI’s container cannot build the app because a feature needs a package only the product’s image has, a
feature:<name>orproduct:<name>command runs in the product’s web container.
A product
commands.pythat fails to import leaves its commands out, and the built-ins still work.product:commandssays why, as in⚠ my_shop's own commands are not available: my_shop.commands: No module named '...'.
While the product is deployed, these commands run against the production app and database, which is how a command that creates the first account works there. See the CLI while production is deployed.