From 2608bee30ae2f1e79a14d633907c3cd275223e17 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Mon, 11 Aug 2025 14:44:16 +0100 Subject: [PATCH] feat(api): add list_inventory_tags --- pkgs/clan-cli/clan_lib/inventory/actions.py | 29 ++++++++ .../clan_lib/inventory/actions_test.py | 72 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 pkgs/clan-cli/clan_lib/inventory/actions.py create mode 100644 pkgs/clan-cli/clan_lib/inventory/actions_test.py diff --git a/pkgs/clan-cli/clan_lib/inventory/actions.py b/pkgs/clan-cli/clan_lib/inventory/actions.py new file mode 100644 index 000000000..7977521e3 --- /dev/null +++ b/pkgs/clan-cli/clan_lib/inventory/actions.py @@ -0,0 +1,29 @@ +from typing import TypedDict + +from clan_lib.api import API +from clan_lib.flake import Flake +from clan_lib.persist.inventory_store import InventoryStore + +readonly_tags = {"all", "nixos", "darwin"} + + +class MachineTag(TypedDict): + name: str + readonly: bool + + +@API.register +def list_inventory_tags(flake: Flake) -> list[MachineTag]: + inventory_store = InventoryStore(flake=flake) + inventory = inventory_store.read() + + machines = inventory.get("machines", {}) + + tags: dict[str, MachineTag] = {} + + for _, machine in machines.items(): + machine_tags = machine.get("tags", []) + for tag in machine_tags: + tags[tag] = MachineTag(name=tag, readonly=tag in readonly_tags) + + return sorted(tags.values(), key=lambda x: x["name"]) diff --git a/pkgs/clan-cli/clan_lib/inventory/actions_test.py b/pkgs/clan-cli/clan_lib/inventory/actions_test.py new file mode 100644 index 000000000..f55d43896 --- /dev/null +++ b/pkgs/clan-cli/clan_lib/inventory/actions_test.py @@ -0,0 +1,72 @@ +from collections.abc import Callable + +import pytest + +from clan_lib.flake import Flake + +from .actions import MachineTag, list_inventory_tags + + +@pytest.mark.with_core +def test_list_inventory_tags(clan_flake: Callable[..., Flake]) -> None: + flake = clan_flake( + { + "inventory": { + "machines": { + "jon": { + # machineClass defaults to nixos + "tags": ["foo", "bar"], + }, + "sara": { + "machineClass": "darwin", + "tags": ["foo", "baz", "fizz"], + }, + "bob": { + "machineClass": "nixos", + "tags": ["foo", "bar"], + }, + }, + } + }, + ) + + tags = list_inventory_tags(flake) + + assert tags == [ + MachineTag(name="all", readonly=True), + MachineTag(name="bar", readonly=False), + MachineTag(name="baz", readonly=False), + MachineTag(name="darwin", readonly=True), + MachineTag(name="fizz", readonly=False), + MachineTag(name="foo", readonly=False), + MachineTag(name="nixos", readonly=True), + ] + + +@pytest.mark.with_core +def test_list_inventory_tags_defaults(clan_flake: Callable[..., Flake]) -> None: + flake = clan_flake( + { + "inventory": { + "machines": { + "jon": { + # machineClass defaults to nixos + }, + "sara": { + "machineClass": "darwin", + }, + "bob": { + "machineClass": "nixos", + }, + }, + } + }, + ) + + tags = list_inventory_tags(flake) + + assert tags == [ + MachineTag(name="all", readonly=True), + MachineTag(name="darwin", readonly=True), + MachineTag(name="nixos", readonly=True), + ]