package buildstep import ( "context" "encoding/json" "fmt" "git.novox.be/novox/mesh-sdk/go/delivery" ) // Guard is a build module's check that the toolchain installed on its node is the one its recipe builds with // (novox/hq ADR 0469 §1; issue 1473). The same guard serves ADR 0470 §4's postgres major for the integration // level, with its own Probe and Want. type Guard struct { // Language is the toolchain's key part: go or typescript (delivery.ToolchainKey). Language string // Want is the toolchain version the recipe builds with, and Recipe the recipe's own version. The indexer // compares both texts as they are written here. Want, Recipe string // Probe reads the installed version (go version, node --version). Probe func(ctx context.Context) (installed string, err error) Node string // Put is the toolchains state's Put (stdio.State(delivery.ToolchainsState).Put). Put Put } // Check probes the installed version, writes it to . of the toolchains state every time it runs, // and answers nil when it is the recipe's. Otherwise it answers a *Refusal naming both versions; the installed // version is written even then, so the indexer sees that builders disagree. A probe that fails is a *Refusal // naming its failure, and nothing is written. A write that fails is an error that is not a Refusal. func (g Guard) Check(ctx context.Context) error { installed, err := g.Probe(ctx) if err != nil { return &Refusal{Text: fmt.Sprintf("the installed %s version could not be read: %v", g.Language, err), Want: g.Want} } key, err := delivery.ToolchainKey(g.Node, g.Language) if err != nil { return err } raw, err := delivery.EncodeToolchain(delivery.Toolchain{Language: g.Language, Version: installed, Recipe: g.Recipe, At: now().UTC()}) if err != nil { return err } if _, err := g.Put(key, json.RawMessage(raw)); err != nil { return fmt.Errorf("buildstep: writing the toolchain %s: %w", key, err) } if installed != g.Want { return &Refusal{Text: fmt.Sprintf("%s %s installed, the recipe builds with %s %s", g.Language, installed, g.Language, g.Want), Want: g.Want, Have: installed} } return nil }