Problem
Declaring the matrix in Go is fine, but the declaration (versions, exclude, fixtures with their CR spec and Requires/Forbids) is pure data, and many consumers would rather keep fixtures as real CR manifests they already maintain, especially at the component level where a fixture is just the top-level CR. An optional loader lets the whole declaration live in a matrix.yaml without forcing it on anyone.
Approach
Add an optional loader that produces a Config[T] from a YAML file; everything except the Go Build closure and Scheme lives in the file.
func LoadMatrix[T any](path string, newSpec func() T, build func(version string, spec T) (Unit, error), scheme *runtime.Scheme) (Config[T], error)
newSpec returns a freshly allocated T so each fixture's spec unmarshals into its own typed value (the loader cannot allocate a generic T itself). The matrix file mirrors Config minus the Go-only fields:
versions: ["8.7.0", "8.8.2", "8.9.0"]
exclude: ["Pre8p5RestAPI"]
fixtures:
- name: default
spec: { apiVersion: my.group/v1, kind: MyCluster, spec: {} } # inline CR ...
requires: [{ name: ContainerImage }, { name: ClusterEnv/Unified89, for: "8.9.0" }]
forbids: [{ name: ClusterEnv/Unified89, for: "8.8.2" }]
- name: s3
specFile: fixtures/s3-cluster.yaml # ... or an external manifest
requires: [{ name: BackupStorageEnv/S3 }]
A fixture supplies its CR either inline under spec: or by reference via specFile: (resolved relative to the matrix file); exactly one of the two is set, and supplying both or neither is a load error. Dir may be set in the matrix or supplied after load. The loader validates the same invariants the generator does where it can (for example for values) so typos surface at load time. The loader is itself opt-in: a consumer who prefers the typed Config[T] never imports it and writes no YAML.
Verification
- A matrix with inline-spec fixtures and a matrix with
specFile fixtures both load into a Config[T] that runs identically to a hand-written one.
- A fixture with both
spec and specFile, or neither, is a load error; a specFile path is resolved relative to the matrix file.
- An
Expect.For value not in versions is rejected at load time.
make all passes.
Context
Sub-issue of #131. Builds on the goldengen core.
Problem
Declaring the matrix in Go is fine, but the declaration (versions, exclude, fixtures with their CR spec and
Requires/Forbids) is pure data, and many consumers would rather keep fixtures as real CR manifests they already maintain, especially at the component level where a fixture is just the top-level CR. An optional loader lets the whole declaration live in amatrix.yamlwithout forcing it on anyone.Approach
Add an optional loader that produces a
Config[T]from a YAML file; everything except the GoBuildclosure andSchemelives in the file.newSpecreturns a freshly allocatedTso each fixture's spec unmarshals into its own typed value (the loader cannot allocate a genericTitself). The matrix file mirrorsConfigminus the Go-only fields:A fixture supplies its CR either inline under
spec:or by reference viaspecFile:(resolved relative to the matrix file); exactly one of the two is set, and supplying both or neither is a load error.Dirmay be set in the matrix or supplied after load. The loader validates the same invariants the generator does where it can (for exampleforvalues) so typos surface at load time. The loader is itself opt-in: a consumer who prefers the typedConfig[T]never imports it and writes no YAML.Verification
specFilefixtures both load into aConfig[T]that runs identically to a hand-written one.specandspecFile, or neither, is a load error; aspecFilepath is resolved relative to the matrix file.Expect.Forvalue not inversionsis rejected at load time.make allpasses.Context
Sub-issue of #131. Builds on the goldengen core.