Creating a command¶
We will create a command dda agent-release data that shows Agent release information.
Structure¶
If you run the root dda command, you'll notice that the subcommands are directories within the src/dda/cli directory:
Every command and command group is defined as a Python package with an __init__.py file containing a function cmd that represents the command or command group. A command is a function decorated with @dynamic_command that performs a user-requested action and a command group is a function decorated with @dynamic_group that groups commands together.
Group¶
First, let's create the dda agent-release command group:
Note
Directory names containing multiple words must be separated by underscores. For example, the agent-release command group is located in the src/dda/cli/agent_release directory.
Now running the dda command will show the agent-release command group:
$ dda
...
╭─ Commands ────────────────────────────────────╮
│ agent-release Agent release-related commands │
...
Initial command¶
Next, let's create the initial dda agent-release data command and have it display a message:
from __future__ import annotations
from typing import TYPE_CHECKING
from dda.cli.base import dynamic_command, pass_app
if TYPE_CHECKING:
from dda.cli.application import Application
@dynamic_command(
short_help="Show Agent release data",
)
@pass_app
def cmd(app: Application) -> None:
"""
Show Agent release data.
"""
app.display("Agent release data")
Now running the dda agent-release data command will show:
Requiring dependencies¶
Fetching the Agent's release.json file requires using an HTTP client. Add the http feature to the command to make sure dependencies such as httpx are available:
from __future__ import annotations
from typing import TYPE_CHECKING
from dda.cli.base import dynamic_command, pass_app
if TYPE_CHECKING:
from dda.cli.application import Application
@dynamic_command(
short_help="Show Agent release data",
features=["http"],
)
@pass_app
def cmd(app: Application) -> None:
"""
Show Agent release data.
"""
import httpx
base = "https://raw.githubusercontent.com"
repo = "DataDog/datadog-agent"
branch = "main"
path = "release.json"
with app.status("Fetching Agent release data"):
response = httpx.get(f"{base}/{repo}/{branch}/{path}")
response.raise_for_status()
app.display_table(response.json())
Running the command will now show the Agent release data:
$ dda agent-release data
┌───────────────────┬────────────────┐
│ base_branch │ main │
│ current_milestone │ 7.66.0 │
│ last_stable │ ┌───┬────────┐ │
│ │ │ 6 │ 6.53.1 │ │
│ │ │ 7 │ 7.64.3 │ │
│ │ └───┴────────┘ │
...
Using feature flags¶
You can guard behavior behind feature flags using the app.features manager. It evaluates a remote flag for the current user/machine with a default fallback.
Update the command to check a flag before performing the network request:
from __future__ import annotations
from typing import TYPE_CHECKING
from dda.cli.base import dynamic_command, pass_app
if TYPE_CHECKING:
from dda.cli.application import Application
@dynamic_command(
short_help="Show Agent release data",
features=["http"],
)
@pass_app
def cmd(app: Application) -> None:
"""
Show Agent release data.
"""
# Check a feature flag to enable this command's behavior
# Replace "agent-release-enabled" with your flag key
enabled = app.features.enabled(
"agent-release-enabled",
default=True,
scopes={"module": "agent-release"},
)
if not enabled:
app.display_warning("This command is currently disabled by feature flag.")
return
import httpx
base = "https://raw.githubusercontent.com"
repo = "DataDog/datadog-agent"
branch = "main"
path = "release.json"
with app.status("Fetching Agent release data"):
response = httpx.get(f"{base}/{repo}/{branch}/{path}")
response.raise_for_status()
app.display_table(response.json())
Note
app.features.enabled(key, default, scopes) returns the evaluated value for key, or default if the flag is not found. The client automatically includes base context like platform, CI, environment, and user; you can add scopes to refine targeting.