Skip to content

v0.10.0

Choose a tag to compare

@snonux snonux released this 17 Sep 05:41
· 519 commits to main since this release

Release v0.10.0

Release Notes

Overview

This release focuses on making fleet-based configuration simpler and more idiomatic. If your recipes manage multiple hosts, you no longer need to thread host lists and parallel value maps through your code manually. You can now attach arbitrary typed values directly to hosts in your inventory, associate a fleet with your task methods once, and iterate over that fleet's hosts cleanly from within your recipe bodies.


Features

Per-host recipe values

You can now store arbitrary typed values on individual hosts at inventory time:

Host("web", WithSSHHost("web.example"),
    WithValue("cron", [2]string{"6", "7"}),
)

Values are retrieved inside task bodies with a type-safe accessor:

window := MustHostValue[[2]string](host, "cron")

Why this is useful: Previously, you'd maintain a separate map[string]T alongside your host registry and use MustMapValue to look entries up, risking drift between the fleet membership and the value map. Now the value lives on the host record itself, so a host is registered or isn't — there's no second source of truth to keep in sync. Missing keys and type mismatches fail fast with clear error messages, the same contract as MustHost / MustFleet.

FleetHosts() — iterate the current task's fleet from inside a task body

func (MyTasks) Cron() {
    for _, host := range FleetHosts() {
        w := MustHostValue[[2]string](host, "cron")
        WhenHostname(host, func() { /* … */ })
    }
}

FleetHosts() returns the list of inventory names for the fleet associated with the currently running task. It fails fast if called outside a fleet-scoped task.

Why this is useful: Previously you'd need to pass the fleet name or host list around explicitly to know which hosts the current task operates on. Now the association is implicit — set once at registration, available anywhere in the body.

WithFleet on RegisterMethods and WithTaskFleet on Task

  • RegisterMethods(MyTasks{}, WithPrefix("edge_"), WithFleet("edge")) associates a fleet with every method on a struct in one declaration.
  • Task("name", "desc", fn, WithTaskFleet("edge")) does the same for a single task.

Why this is useful: For a struct with many methods that all target the same fleet, you declare the association once rather than repeating it per method. Nested task execution is handled correctly — an inner Aggregate calling a child task pushes its own fleet frame, so each task body always sees its own fleet.


Improvements

List(...) promoted to the canonical DSL alias for []string

List("a", "b", "c") is now documented and recommended everywhere you'd otherwise write []string{"a", "b", "c"} — in multi-path resources, Command args, WhenHostname hosts, EachKV pairs, and similar.

Why this is useful: A single, discoverable spelling for "a list of strings" across the DSL reduces cognitive load and makes recipes more uniform. Docs and examples have been updated to prefer List(...) throughout.

MustMapValue replaced by MustHostValue

The old generic MustMapValue[K, V] helper has been removed in favor of MustHostValue[T], which reads from the host registry directly.

Why this is useful: The old helper required you to carry a map around and explain what it was for. The new one is self-contained — you name the host and the key, and it fetches from the inventory.


Documentation

  • New "Fleet hosts and per-host values" section in helpers.md with a complete worked example.
  • WhenHostname docs and examples updated to show List(...) instead of []string{...}.
  • plan.md and tasks.md tables updated to reflect the List(...) spelling.

Migration Notes

Old New
MustMapValue(m, key, what) MustHostValue[T](host, key)
[]string{"a", "b"} in DSL recipes List("a", "b")
Manual fleet-name threading in task bodies WithFleet / WithTaskFleet + FleetHosts()

If you have existing recipes using MustMapValue, replace the parallel map with WithValue / SetValue on each host and switch the lookups to MustHostValue. The List(...) change is cosmetic — []string{...} still works, but List(...) is now preferred in docs and examples.