cli: Add list command with ls alias (#158)

This commit is contained in:
Bas Nijholt
2026-01-07 15:59:30 +01:00
committed by GitHub
parent c3e3aeb538
commit f32057aa7b
4 changed files with 112 additions and 3 deletions

View File

@@ -17,7 +17,7 @@ src/compose_farm/
│ ├── config.py # Config subcommand (init, show, path, validate, edit, symlink) │ ├── config.py # Config subcommand (init, show, path, validate, edit, symlink)
│ ├── lifecycle.py # up, down, stop, pull, restart, update, apply, compose commands │ ├── lifecycle.py # up, down, stop, pull, restart, update, apply, compose commands
│ ├── management.py # refresh, check, init-network, traefik-file commands │ ├── management.py # refresh, check, init-network, traefik-file commands
│ ├── monitoring.py # logs, ps, stats commands │ ├── monitoring.py # logs, ps, stats, list commands
│ ├── ssh.py # SSH key management (setup, status, keygen) │ ├── ssh.py # SSH key management (setup, status, keygen)
│ └── web.py # Web UI server command │ └── web.py # Web UI server command
├── compose.py # Compose file parsing (.env, ports, volumes, networks) ├── compose.py # Compose file parsing (.env, ports, volumes, networks)
@@ -157,6 +157,7 @@ CLI available as `cf` or `compose-farm`.
| `logs` | Show stack logs | | `logs` | Show stack logs |
| `ps` | Show status of all stacks | | `ps` | Show status of all stacks |
| `stats` | Show overview (hosts, stacks, pending migrations; `--live` for container counts) | | `stats` | Show overview (hosts, stacks, pending migrations; `--live` for container counts) |
| `list` | List stacks and hosts (`--simple` for scripting, `--host` to filter) |
| `refresh` | Update state from reality: discover running stacks, capture image digests | | `refresh` | Update state from reality: discover running stacks, capture image digests |
| `check` | Validate config, traefik labels, mounts, networks; show host compatibility | | `check` | Validate config, traefik labels, mounts, networks; show host compatibility |
| `init-network` | Create Docker network on hosts with consistent subnet/gateway | | `init-network` | Create Docker network on hosts with consistent subnet/gateway |

View File

@@ -395,6 +395,7 @@ Multi-host orchestration that Docker Compose can't do:
| `cf traefik-file` | Generate Traefik file-provider config | | `cf traefik-file` | Generate Traefik file-provider config |
| `cf config` | Manage config files (init, show, validate, edit, symlink) | | `cf config` | Manage config files (init, show, validate, edit, symlink) |
| `cf ssh` | Manage SSH keys (setup, status, keygen) | | `cf ssh` | Manage SSH keys (setup, status, keygen) |
| `cf list` | List all stacks and their assigned hosts |
### Aliases ### Aliases
@@ -403,10 +404,11 @@ Short aliases for frequently used commands:
| Alias | Command | Alias | Command | | Alias | Command | Alias | Command |
|-------|---------|-------|---------| |-------|---------|-------|---------|
| `cf a` | `apply` | `cf s` | `stats` | | `cf a` | `apply` | `cf s` | `stats` |
| `cf l` | `logs` | `cf c` | `compose` | | `cf l` | `logs` | `cf ls` | `list` |
| `cf r` | `restart` | `cf rf` | `refresh` | | `cf r` | `restart` | `cf rf` | `refresh` |
| `cf u` | `update` | `cf ck` | `check` | | `cf u` | `update` | `cf ck` | `check` |
| `cf p` | `pull` | `cf tf` | `traefik-file` | | `cf p` | `pull` | `cf tf` | `traefik-file` |
| `cf c` | `compose` | | |
Each command replaces: look up host → SSH → find compose file → run `ssh host "cd /opt/compose/plex && docker compose up -d"`. Each command replaces: look up host → SSH → find compose file → run `ssh host "cd /opt/compose/plex && docker compose up -d"`.
@@ -511,6 +513,7 @@ Full `--help` output for each command. See the [Usage](#usage) table above for a
│ service. │ │ service. │
│ ps Show status of stacks. │ │ ps Show status of stacks. │
│ stats Show overview statistics for hosts and stacks. │ │ stats Show overview statistics for hosts and stacks. │
│ list List all stacks and their assigned hosts. │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Server ─────────────────────────────────────────────────────────────────────╮ ╭─ Server ─────────────────────────────────────────────────────────────────────╮
│ web Start the web UI server. │ │ web Start the web UI server. │
@@ -1191,6 +1194,38 @@ Full `--help` output for each command. See the [Usage](#usage) table above for a
</details> </details>
<details>
<summary>See the output of <code>cf list --help</code></summary>
<!-- CODE:BASH:START -->
<!-- echo '```yaml' -->
<!-- export NO_COLOR=1 -->
<!-- export TERM=dumb -->
<!-- export TERMINAL_WIDTH=90 -->
<!-- cf list --help -->
<!-- echo '```' -->
<!-- CODE:END -->
<!-- OUTPUT:START -->
<!-- ⚠️ This content is auto-generated by `markdown-code-runner`. -->
```yaml
Usage: cf list [OPTIONS]
List all stacks and their assigned hosts.
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --host -H TEXT Filter to stacks on this host │
│ --simple -s Plain output (one stack per line, for scripting) │
│ --config -c PATH Path to config file │
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
```
<!-- OUTPUT:END -->
</details>
**Server** **Server**
<details> <details>

View File

@@ -23,6 +23,7 @@ Commands are either **Docker Compose wrappers** (`up`, `down`, `stop`, `restart`
| **Monitoring** | `ps` | Show stack status | | **Monitoring** | `ps` | Show stack status |
| | `logs` | Show stack logs | | | `logs` | Show stack logs |
| | `stats` | Show overview statistics | | | `stats` | Show overview statistics |
| | `list` | List stacks and hosts |
| **Configuration** | `check` | Validate config and mounts | | **Configuration** | `check` | Validate config and mounts |
| | `refresh` | Sync state from reality | | | `refresh` | Sync state from reality |
| | `init-network` | Create Docker network | | | `init-network` | Create Docker network |
@@ -45,10 +46,11 @@ Short aliases for frequently used commands:
| Alias | Command | Alias | Command | | Alias | Command | Alias | Command |
|-------|---------|-------|---------| |-------|---------|-------|---------|
| `cf a` | `apply` | `cf s` | `stats` | | `cf a` | `apply` | `cf s` | `stats` |
| `cf l` | `logs` | `cf c` | `compose` | | `cf l` | `logs` | `cf ls` | `list` |
| `cf r` | `restart` | `cf rf` | `refresh` | | `cf r` | `restart` | `cf rf` | `refresh` |
| `cf u` | `update` | `cf ck` | `check` | | `cf u` | `update` | `cf ck` | `check` |
| `cf p` | `pull` | `cf tf` | `traefik-file` | | `cf p` | `pull` | `cf tf` | `traefik-file` |
| `cf c` | `compose` | | |
--- ---
@@ -466,6 +468,40 @@ cf stats --live
--- ---
### cf list
List all stacks and their assigned hosts.
```bash
cf list [OPTIONS]
```
**Options:**
| Option | Description |
|--------|-------------|
| `--host, -H TEXT` | Filter to stacks on this host |
| `--simple, -s` | Plain output for scripting (one stack per line) |
| `--config, -c PATH` | Path to config file |
**Examples:**
```bash
# List all stacks
cf list
# Filter by host
cf list --host nas
# Plain output for scripting
cf list --simple
# Combine: list stack names on a specific host
cf list --host nuc --simple
```
---
## Configuration Commands ## Configuration Commands
### cf check ### cf check

View File

@@ -203,6 +203,43 @@ def stats(
console.print(_build_summary_table(cfg, state, pending)) console.print(_build_summary_table(cfg, state, pending))
@app.command("list", rich_help_panel="Monitoring")
def list_(
host: HostOption = None,
simple: Annotated[
bool,
typer.Option("--simple", "-s", help="Plain output (one stack per line, for scripting)"),
] = False,
config: ConfigOption = None,
) -> None:
"""List all stacks and their assigned hosts."""
cfg = load_config_or_exit(config)
stacks: list[tuple[str, str | list[str]]] = list(cfg.stacks.items())
if host:
stacks = [(s, h) for s, h in stacks if str(h) == host or host in str(h).split(",")]
if simple:
for stack, _ in sorted(stacks):
console.print(stack)
else:
# Assign colors to hosts for visual grouping
host_colors = ["magenta", "cyan", "green", "yellow", "blue", "red"]
unique_hosts = sorted({str(h) for _, h in stacks})
host_color_map = {h: host_colors[i % len(host_colors)] for i, h in enumerate(unique_hosts)}
table = Table(title="Stacks", show_header=True, header_style="bold cyan")
table.add_column("Stack")
table.add_column("Host")
for stack, host_val in sorted(stacks):
color = host_color_map.get(str(host_val), "white")
table.add_row(f"[{color}]{stack}[/]", f"[{color}]{host_val}[/]")
console.print(table)
# Aliases (hidden from help) # Aliases (hidden from help)
app.command("l", hidden=True)(logs) # cf l = cf logs app.command("l", hidden=True)(logs) # cf l = cf logs
app.command("ls", hidden=True)(list_) # cf ls = cf list
app.command("s", hidden=True)(stats) # cf s = cf stats app.command("s", hidden=True)(stats) # cf s = cf stats