Update the simple configuration consumer
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Shared reporting and PromptKit v0.20.0 implementation plan
|
# Shared reporting and PromptKit v0.20.0 implementation plan
|
||||||
|
|
||||||
Status: implementation in progress; Stages 1–20 complete.
|
Status: implementation in progress; Stages 1–21 complete.
|
||||||
|
|
||||||
## Scope, authority, and execution
|
## Scope, authority, and execution
|
||||||
|
|
||||||
@@ -756,6 +756,11 @@ snapshots and upstream validation-rule tests.
|
|||||||
|
|
||||||
## Stage 21: Simple consumer and core/configuration API exercise
|
## Stage 21: Simple consumer and core/configuration API exercise
|
||||||
|
|
||||||
|
**Complete.** The simple consumer opts into native overrides and demonstrates
|
||||||
|
the new inspection and failure workflows. The core consumer's structured report
|
||||||
|
and template remain exercised. Core example and ckconfig workspace tests passed
|
||||||
|
with Go 1.27.0.
|
||||||
|
|
||||||
Update the maintained [simple ckconfig consumer](../../integrations/ckconfig/examples/simple)
|
Update the maintained [simple ckconfig consumer](../../integrations/ckconfig/examples/simple)
|
||||||
to install an explicitly configured FromConfigKit scope with Overrides enabled,
|
to install an explicitly configured FromConfigKit scope with Overrides enabled,
|
||||||
replacing AppCommand convenience wiring there. Append the selected native CLI
|
replacing AppCommand convenience wiring there. Append the selected native CLI
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ Run the maintained example with:
|
|||||||
go run . config show
|
go run . config show
|
||||||
go run . config show --config fixtures/before.yml --verbose
|
go run . config show --config fixtures/before.yml --verbose
|
||||||
go run . config show --config fixtures/before.yml --quiet
|
go run . config show --config fixtures/before.yml --quiet
|
||||||
|
go run . config explain --list --under /schema
|
||||||
|
go run . config show --path /greeting --set '/greeting="Hi"'
|
||||||
go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml
|
go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml
|
||||||
|
go run . config diff --set '/greeting="Hi"' --details --check
|
||||||
|
go run . config validate --config fixtures/invalid.yml --details --severity error
|
||||||
|
go run . config sources --config fixtures/invalid.yml --source-id source-1
|
||||||
go run . greet
|
go run . greet
|
||||||
go run . greet --count=0 --tag=first --tag second
|
go run . greet --count=0 --tag=first --tag second
|
||||||
```
|
```
|
||||||
@@ -25,3 +30,8 @@ command loads the two local fixtures and reports `changes.greeting: Goodbye`.
|
|||||||
The before fixture uses schema version 1, which ConfigKit reports as a provider
|
The before fixture uses schema version 1, which ConfigKit reports as a provider
|
||||||
warning in verbose mode. Ordinary mode hides the warning while preserving the
|
warning in verbose mode. Ordinary mode hides the warning while preserving the
|
||||||
effective YAML report; quiet mode suppresses that report.
|
effective YAML report; quiet mode suppresses that report.
|
||||||
|
The invalid fixture demonstrates a failed-load report and captured source
|
||||||
|
inventory; `source-1` is the ID from that fixture's acquisition. The scope opts
|
||||||
|
in to transient overrides and passes them into its normal ConfigKit load. The
|
||||||
|
diff example compares an overridden left side with ordinary configuration on
|
||||||
|
the right and returns status 3 because the values differ.
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
schema:
|
||||||
|
version: 2
|
||||||
|
greeting: [invalid]
|
||||||
@@ -49,10 +49,15 @@ func loadAppConfiguration(_ context.Context, selection ckconfig.Selection) (*con
|
|||||||
options.Overlay = selection.Overlay.Value
|
options.Overlay = selection.Overlay.Value
|
||||||
options.Filesystem = &configkit.FilesystemContext{Root: ".", BaseDir: "."}
|
options.Filesystem = &configkit.FilesystemContext{Root: ".", BaseDir: "."}
|
||||||
}
|
}
|
||||||
|
options.Overrides = append(options.Overrides, selection.Overrides...)
|
||||||
return configkit.Load(source, options)
|
return configkit.Load(source, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newApp() (*commandkit.App, error) {
|
func newApp() (*commandkit.App, error) {
|
||||||
|
return newAppWithLoader(loadAppConfiguration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAppWithLoader(load func(context.Context, ckconfig.Selection) (*configkit.Result[appConfiguration], error)) (*commandkit.App, error) {
|
||||||
countDefault := 1
|
countDefault := 1
|
||||||
tagDefaults := []string{"example"}
|
tagDefaults := []string{"example"}
|
||||||
greet := commandkit.NewCommand(commandkit.CommandSpec[greetInput]{
|
greet := commandkit.NewCommand(commandkit.CommandSpec[greetInput]{
|
||||||
@@ -68,7 +73,7 @@ func newApp() (*commandkit.App, error) {
|
|||||||
},
|
},
|
||||||
Run: func(invocation commandkit.Invocation, input greetInput) commandkit.Outcome {
|
Run: func(invocation commandkit.Invocation, input greetInput) commandkit.Outcome {
|
||||||
reporter := invocation.Reporter()
|
reporter := invocation.Reporter()
|
||||||
configuration, err := loadAppConfiguration(invocation.Context, ckconfig.Selection{})
|
configuration, err := load(invocation.Context, ckconfig.Selection{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return commandkit.Failure("Could not load application configuration.").WithCause(err)
|
return commandkit.Failure("Could not load application configuration.").WithCause(err)
|
||||||
}
|
}
|
||||||
@@ -87,9 +92,13 @@ func newApp() (*commandkit.App, error) {
|
|||||||
return commandkit.Success()
|
return commandkit.Success()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
scope := ckconfig.FromConfigKit("app", "Application configuration.", func(ctx context.Context, selection ckconfig.Selection, _, _ struct{}) (*configkit.Result[appConfiguration], error) {
|
||||||
|
return load(ctx, selection)
|
||||||
|
})
|
||||||
|
scope.Features.Overrides = true
|
||||||
return commandkit.New(
|
return commandkit.New(
|
||||||
commandkit.Identity{Name: "simple-example", Version: "1.0"},
|
commandkit.Identity{Name: "simple-example", Version: "1.0"},
|
||||||
ckconfig.AppCommand(loadAppConfiguration),
|
ckconfig.Command(ckconfig.Suite[struct{}, struct{}]{Scopes: []ckconfig.Scope[struct{}, struct{}]{scope}}),
|
||||||
greet,
|
greet,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.maximumdirect.net/ckconfig"
|
"go.maximumdirect.net/ckconfig"
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -147,3 +149,55 @@ func decodeReport(data []byte) (*yaml.Node, error) {
|
|||||||
}
|
}
|
||||||
return document.Content[0], nil
|
return document.Content[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSimpleInspectionAndIndependentOverrides(t *testing.T) {
|
||||||
|
outcome, output, _ := executeSimple(t, "config", "explain", "--list", "--under=/schema", "--format=json")
|
||||||
|
if outcome.Kind != commandkit.OutcomeSuccess || !strings.Contains(output, `"path": "/schema/version"`) {
|
||||||
|
t.Fatalf("discovery = %#v %q", outcome, output)
|
||||||
|
}
|
||||||
|
outcome, output, _ = executeSimple(t, "config", "show", "--path=/greeting", "--set=/greeting=\"Hi\"")
|
||||||
|
if outcome.Kind != commandkit.OutcomeSuccess || output != "Hi\n" {
|
||||||
|
t.Fatalf("focused override = %#v %q", outcome, output)
|
||||||
|
}
|
||||||
|
outcome, output, _ = executeSimple(t, "config", "diff", "--set=/greeting=\"Hi\"", "--details", "--check", "--format=json")
|
||||||
|
if outcome.Kind != commandkit.OutcomeDomain || outcome.Status != 3 || !strings.Contains(output, `"before"`) || !strings.Contains(output, `"after"`) {
|
||||||
|
t.Fatalf("independent diff = %#v %q", outcome, output)
|
||||||
|
}
|
||||||
|
outcome, output, _ = executeSimple(t, "config", "diff", "--set=/greeting=\"Hi\"", "--against-set=/greeting=\"Hi\"", "--details", "--check", "--format=json")
|
||||||
|
if outcome.Kind != commandkit.OutcomeSuccess || !strings.Contains(output, `"differences": []`) {
|
||||||
|
t.Fatalf("equal overrides = %#v %q", outcome, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimpleFailedLoadReportsEvidence(t *testing.T) {
|
||||||
|
_, failure := loadAppConfiguration(context.Background(), ckconfig.Selection{Config: commandkit.Supplied[string]{Value: "fixtures/invalid.yml", Set: true}})
|
||||||
|
var native *configkit.LoadError
|
||||||
|
if !errors.As(failure, &native) || len(native.Sources()) == 0 {
|
||||||
|
t.Fatalf("fixture failure = %v", failure)
|
||||||
|
}
|
||||||
|
outcome, output, _ := executeSimple(t, "config", "validate", "--config=fixtures/invalid.yml", "--details", "--severity=error", "--format=json")
|
||||||
|
if outcome.Kind != commandkit.OutcomeOperational || !strings.Contains(output, `"state": "present"`) || !strings.Contains(output, `"severity": "error"`) {
|
||||||
|
t.Fatalf("detailed failure = %#v %q", outcome, output)
|
||||||
|
}
|
||||||
|
outcome, output, _ = executeSimple(t, "config", "sources", "--config=fixtures/invalid.yml", "--source-id="+native.Sources()[0].ID, "--format=json")
|
||||||
|
if outcome.Kind != commandkit.OutcomeOperational || !strings.Contains(output, `"id":`) || !strings.Contains(output, "invalid.yml") {
|
||||||
|
t.Fatalf("source failure = %#v %q", outcome, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimpleMetadataCommandsDoNotLoadConfiguration(t *testing.T) {
|
||||||
|
loads := 0
|
||||||
|
app, err := newAppWithLoader(func(context.Context, ckconfig.Selection) (*configkit.Result[appConfiguration], error) {
|
||||||
|
loads++
|
||||||
|
return nil, errors.New("unexpected load")
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, args := range [][]string{{"version"}, {"config", "scopes"}, {"config", "explain"}, {"config", "show", "--help"}} {
|
||||||
|
result := app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||||
|
if result.Kind != commandkit.OutcomeSuccess || loads != 0 {
|
||||||
|
t.Fatalf("%v: %#v loads=%d", args, result, loads)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user