Sort host lists in state file for consistent output (#174)
Some checks failed
CI / test (macos-latest, 3.11) (push) Has been cancelled
CI / test (macos-latest, 3.12) (push) Has been cancelled
CI / test (macos-latest, 3.13) (push) Has been cancelled
CI / test (ubuntu-latest, 3.11) (push) Has been cancelled
CI / test (ubuntu-latest, 3.12) (push) Has been cancelled
CI / test (ubuntu-latest, 3.13) (push) Has been cancelled
CI / browser-tests (push) Has been cancelled
CI / lint (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
Update README.md / update_readme (push) Has been cancelled

* Sort host lists in state file for consistent output

Multi-host stacks (like glances) now have their host lists sorted
alphabetically when saving state. This makes git diffs cleaner by
avoiding spurious reordering changes.
This commit is contained in:
Bas Nijholt
2026-01-30 15:29:13 -08:00
committed by GitHub
parent 596a05e39d
commit 4d65702868
3 changed files with 45 additions and 32 deletions

View File

@@ -486,32 +486,32 @@ Full `--help` output for each command. See the [Usage](#usage) table above for a
│ --help -h Show this message and exit. │ │ --help -h Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Configuration ────────────────────────────────────────────────────────────────────────╮ ╭─ Configuration ────────────────────────────────────────────────────────────────────────╮
│ traefik-file Generate a Traefik file-provider fragment from compose Traefik labels. │ │ traefik-file Generate a Traefik file-provider fragment from compose Traefik labels.
│ refresh Update local state from running stacks. │ │ refresh Update local state from running stacks.
│ check Validate configuration, traefik labels, mounts, and networks. │ │ check Validate configuration, traefik labels, mounts, and networks.
│ init-network Create Docker network on hosts with consistent settings. │ │ init-network Create Docker network on hosts with consistent settings.
│ config Manage compose-farm configuration files. │ │ config Manage compose-farm configuration files.
│ ssh Manage SSH keys for passwordless authentication. │ │ ssh Manage SSH keys for passwordless authentication.
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Lifecycle ────────────────────────────────────────────────────────────────────────────╮ ╭─ Lifecycle ────────────────────────────────────────────────────────────────────────────╮
│ up Start stacks (docker compose up -d). Auto-migrates if host changed. │ │ up Start stacks (docker compose up -d). Auto-migrates if host changed.
│ down Stop stacks (docker compose down). │ │ down Stop stacks (docker compose down).
│ stop Stop services without removing containers (docker compose stop). │ │ stop Stop services without removing containers (docker compose stop).
│ pull Pull latest images (docker compose pull). │ │ pull Pull latest images (docker compose pull).
│ restart Restart running containers (docker compose restart). │ │ restart Restart running containers (docker compose restart).
│ update Update stacks (pull + build + up). Shorthand for 'up --pull --build'. │ │ update Update stacks (pull + build + up). Shorthand for 'up --pull --build'.
│ apply Make reality match config (start, migrate, stop strays/orphans as │ │ apply Make reality match config (start, migrate, stop strays/orphans as
needed). │ │ needed).
│ compose Run any docker compose command on a stack. │ │ compose Run any docker compose command on a stack.
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Monitoring ───────────────────────────────────────────────────────────────────────────╮ ╭─ Monitoring ───────────────────────────────────────────────────────────────────────────╮
│ logs Show stack logs. With --service, shows logs for just that service. │ │ logs Show stack logs. With --service, shows logs for just that 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. │ │ list List all stacks and their assigned hosts.
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Server ───────────────────────────────────────────────────────────────────────────────╮ ╭─ Server ───────────────────────────────────────────────────────────────────────────────╮
│ web Start the web UI server. │ │ web Start the web UI server.
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
``` ```
@@ -1017,13 +1017,13 @@ Full `--help` output for each command. See the [Usage](#usage) table above for a
│ --help -h Show this message and exit. │ │ --help -h Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────────────────────────╮ ╭─ Commands ─────────────────────────────────────────────────────────────────────────────╮
│ init Create a new config file with documented example. │ │ init Create a new config file with documented example.
│ edit Open the config file in your default editor. │ │ edit Open the config file in your default editor.
│ show Display the config file location and contents. │ │ show Display the config file location and contents.
│ path Print the config file path (useful for scripting). │ │ path Print the config file path (useful for scripting).
│ validate Validate the config file syntax and schema. │ │ validate Validate the config file syntax and schema.
│ symlink Create a symlink from the default config location to a config file. │ │ symlink Create a symlink from the default config location to a config file.
│ init-env Generate a .env file for Docker deployment. │ │ init-env Generate a .env file for Docker deployment.
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
``` ```
@@ -1056,9 +1056,9 @@ Full `--help` output for each command. See the [Usage](#usage) table above for a
│ --help -h Show this message and exit. │ │ --help -h Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────────────────────────╮ ╭─ Commands ─────────────────────────────────────────────────────────────────────────────╮
│ keygen Generate SSH key (does not distribute to hosts). │ │ keygen Generate SSH key (does not distribute to hosts).
│ setup Generate SSH key and distribute to all configured hosts. │ │ setup Generate SSH key and distribute to all configured hosts.
│ status Show SSH key status and host connectivity. │ │ status Show SSH key status and host connectivity.
╰────────────────────────────────────────────────────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────────────────────────────────────╯
``` ```

View File

@@ -64,8 +64,11 @@ def load_state(config: Config) -> dict[str, str | list[str]]:
def _sorted_dict(d: dict[str, str | list[str]]) -> dict[str, str | list[str]]: def _sorted_dict(d: dict[str, str | list[str]]) -> dict[str, str | list[str]]:
"""Return a dictionary sorted by keys.""" """Return a dictionary sorted by keys, with list values also sorted."""
return dict(sorted(d.items(), key=lambda item: item[0])) return {
k: sorted(v) if isinstance(v, list) else v
for k, v in sorted(d.items(), key=lambda item: item[0])
}
def save_state(config: Config, deployed: dict[str, str | list[str]]) -> None: def save_state(config: Config, deployed: dict[str, str | list[str]]) -> None:

View File

@@ -67,6 +67,16 @@ class TestSaveState:
assert "plex: nas01" in content assert "plex: nas01" in content
assert "jellyfin: nas02" in content assert "jellyfin: nas02" in content
def test_save_state_sorts_host_lists(self, config: Config) -> None:
"""Saves state with sorted host lists for consistent output."""
# Pass hosts in unsorted order
save_state(config, {"glances": ["pc", "nas", "hp", "anton"]})
state_file = config.get_state_path()
content = state_file.read_text()
# Hosts should be sorted alphabetically
assert "- anton\n - hp\n - nas\n - pc" in content
class TestGetStackHost: class TestGetStackHost:
"""Tests for get_stack_host function.""" """Tests for get_stack_host function."""