Refresh operator documentation and CLI help
This commit is contained in:
@@ -1,36 +1,30 @@
|
||||
# CommandKit ckconfig
|
||||
|
||||
`ckconfig` is the optional ConfigKit integration for CommandKit. It adapts
|
||||
ConfigKit loaders and scopes into reusable `commandkit.Command` declarations;
|
||||
installing the integration is explicit and does not modify an application by
|
||||
itself.
|
||||
`ckconfig` adds configuration inspection commands to Go applications that use
|
||||
CommandKit and ConfigKit. Operators can view settings, validate configuration,
|
||||
find where values came from, and compare two configurations.
|
||||
|
||||
The application chooses which commands to install. Importing the package alone
|
||||
does not install commands.
|
||||
|
||||
## Module
|
||||
|
||||
The module path is `go.maximumdirect.net/ckconfig`. Version v0.4.0 requires Go
|
||||
1.27.0 and uses `go.maximumdirect.net/commandkit v0.4.0` and
|
||||
`go.maximumdirect.net/configkit v1.1.0`; it does not import PromptKit. See the
|
||||
[consumer guide](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
|
||||
for exact callback and lifetime contracts.
|
||||
The module path is `go.maximumdirect.net/ckconfig`. It does not import PromptKit.
|
||||
See the [consumer guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#module-selection)
|
||||
for compatible releases and Go requirements.
|
||||
|
||||
## Example
|
||||
|
||||
For one application configuration scope, install the convenience declaration:
|
||||
To inspect one application configuration, pass your loader to `AppCommand`:
|
||||
|
||||
```go
|
||||
app, err := commandkit.New(identity, ckconfig.AppCommand(loadAppConfig))
|
||||
```
|
||||
|
||||
Use `ckconfig.Command(ckconfig.Suite[Input, State]{...})` to define named
|
||||
scopes, selectors, input checks, and state shared by the selected acquisitions
|
||||
or comparison in a config invocation. `ckconfig.FromConfigKit` adapts a typed
|
||||
ConfigKit loader. The `config` command family exposes scope discovery and the
|
||||
validate, show, sources, explain, and diff operations supported by the declared
|
||||
scopes. Source reports include native destination, placement, destination
|
||||
fallback, version evidence, and empty-import selections. Comparison returns
|
||||
ConfigKit's native records to shared report rendering; the
|
||||
[CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#compare-configuration-selections)
|
||||
owns its operator details.
|
||||
For multiple named configurations or application-specific flags, use
|
||||
`ckconfig.Command` with a `ckconfig.Suite`. The
|
||||
[integration guide](https://forge.maximumdirect.net/base-layer/commandkit/src/branch/main/docs/consumers/guide.md#configkit-scopes)
|
||||
explains loader setup, inputs, and shared state.
|
||||
|
||||
The maintained [simple example](examples/simple) shows a complete consumer.
|
||||
The [CommandKit CLI reference](https://gitea.maximumdirect.net/eric/CommandKit/src/branch/main/docs/cli.md#configuration-scopes)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Package ckconfig, provided by go.maximumdirect.net/ckconfig, provides
|
||||
// CommandKit's optional ConfigKit v1.1.0 integration, requiring Go 1.27.0. Its
|
||||
// canonical Command declaration installs the standard config command family
|
||||
// through the core commandkit package. Applications can install CommandKit
|
||||
// RoutingRule declarations alongside it through commandkit.New or
|
||||
// App.Register. Source reports preserve ConfigKit's destination, placement,
|
||||
// version, and empty-import evidence. Invocation reporting applies CommandKit's shared
|
||||
// visibility and delivery policy; provider warnings remain independent of
|
||||
// failure explanations. Importing ckconfig alone installs no commands.
|
||||
// Package ckconfig adds commands to view, validate, explain, and compare
|
||||
// ConfigKit configuration in CommandKit applications.
|
||||
//
|
||||
// Use AppCommand for one application configuration loader, or Command with a
|
||||
// Suite for multiple named configurations and application-specific flags.
|
||||
// Install the returned command with commandkit.New or App.Register.
|
||||
// Importing this package alone installs no commands.
|
||||
//
|
||||
// ConfigKit owns configuration loading and interpretation. CommandKit formats
|
||||
// reports and messages using its shared reporting policy.
|
||||
package ckconfig
|
||||
|
||||
@@ -1,37 +1,90 @@
|
||||
# Simple consumer
|
||||
# ConfigKit example
|
||||
|
||||
This example imports `go.maximumdirect.net/ckconfig` and
|
||||
`go.maximumdirect.net/commandkit`; ckconfig v0.4.0 uses core
|
||||
v0.4.0, ConfigKit v1.1.0, and Go 1.27.0. Set `GOWORK=off GOTOOLCHAIN=local`
|
||||
for the commands below.
|
||||
This example adds configuration inspection and a custom `greet` command to a
|
||||
small application. It uses local fixtures and in-memory defaults, with no
|
||||
external services. See [module selection](../../../../docs/consumers/guide.md#module-selection)
|
||||
for dependencies and Go requirements. Use Go 1.27.0 on `PATH` for this checkout.
|
||||
|
||||
Run the maintained example with:
|
||||
From the repository root:
|
||||
|
||||
```sh
|
||||
cd integrations/ckconfig/examples/simple
|
||||
export GOWORK=off GOTOOLCHAIN=local
|
||||
go run . config show
|
||||
go run . config show --config fixtures/before.yml --verbose
|
||||
go run . config show --config fixtures/before.yml --quiet
|
||||
```
|
||||
|
||||
The output includes the default greeting, `Hello`, and schema version 2.
|
||||
This example can run against its declared released dependencies with the
|
||||
workspace disabled.
|
||||
|
||||
## Inspect and override a value
|
||||
|
||||
```sh
|
||||
# Discover configuration paths under schema.
|
||||
go run . config explain --list --under /schema
|
||||
# Change the greeting for this invocation and show just that value.
|
||||
go run . config show --path /greeting --set '/greeting="Hi"'
|
||||
```
|
||||
|
||||
The second command prints `Hi`. It does not edit a file.
|
||||
|
||||
## Compare configurations
|
||||
|
||||
```sh
|
||||
go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml
|
||||
```
|
||||
|
||||
The report includes `changes.greeting: Goodbye`.
|
||||
|
||||
```sh
|
||||
# Expected status 3: the overridden greeting differs from the ordinary default.
|
||||
go run . config diff --set '/greeting="Hi"' --details --check
|
||||
```
|
||||
|
||||
This compares the overridden left side with ordinary configuration on the
|
||||
right. `go run` prints `exit status 3` and itself exits with status 1; a built
|
||||
executable returns the application's status 3 directly.
|
||||
|
||||
## Inspect warnings and failed loads
|
||||
|
||||
```sh
|
||||
# Schema version 1 produces a warning, visible in verbose mode.
|
||||
go run . config show --config fixtures/before.yml --verbose
|
||||
# Quiet mode hides the configuration report and warning.
|
||||
go run . config show --config fixtures/before.yml --quiet
|
||||
```
|
||||
|
||||
Ordinary mode hides the warning but still displays configuration.
|
||||
|
||||
```sh
|
||||
# Intentional failure: show detailed validation findings for the invalid fixture.
|
||||
go run . config validate --config fixtures/invalid.yml --details --severity error
|
||||
# Intentional failure: still show the source recorded before loading failed.
|
||||
go run . config sources --config fixtures/invalid.yml --source-id source-1
|
||||
```
|
||||
|
||||
Both commands retain the load failure. `source-1` belongs to this fixture's
|
||||
load; other configurations can have different source IDs. See the
|
||||
[CLI reference](../../../../docs/cli.md#configuration-scopes) for report and status rules.
|
||||
|
||||
## Try a custom command
|
||||
|
||||
```sh
|
||||
go run . greet
|
||||
go run . greet --count=0 --tag=first --tag second
|
||||
```
|
||||
|
||||
The `config` family comes from one typed ConfigKit scope. The custom `greet`
|
||||
command uses CommandKit's typed bindings and shows the difference between an
|
||||
omitted `--count` and an explicitly supplied zero, plus ordered repeated tags.
|
||||
With no `--config`, application settings use the in-memory default. A supplied
|
||||
configuration and overlay are passed to ConfigKit unchanged. The comparison
|
||||
command loads the two local fixtures and reports `changes.greeting: Goodbye`.
|
||||
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
|
||||
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.
|
||||
The handler reports its greeting, count, and tags. It distinguishes an omitted
|
||||
count from an explicitly supplied zero and preserves repeated tag order.
|
||||
|
||||
## How it is wired
|
||||
|
||||
One ConfigKit scope supplies the standard `config` commands. Without `--config`,
|
||||
its loader uses an in-memory default. Supplied configuration and overlay values
|
||||
are passed to ConfigKit unchanged. The scope enables temporary overrides and
|
||||
passes them into its ordinary ConfigKit load. The
|
||||
[consumer guide](../../../../docs/consumers/guide.md#configkit-scopes) explains
|
||||
loader and scope setup.
|
||||
|
||||
Run `GOWORK=off GOTOOLCHAIN=local go test ./...` from this example directory to
|
||||
check it against its declared dependencies.
|
||||
|
||||
@@ -73,13 +73,13 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
scopeChoices = append(scopeChoices, commandkit.CompletionChoice{Value: "all"})
|
||||
}
|
||||
flags := []commandkit.Flag[*configCommandInput[I, S]]{
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "scope", Usage: "Configuration scope name or all where supported.", Completion: commandkit.CompleteChoices(scopeChoices...)}, &defaultScope, parseConfigString,
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "scope", Usage: "Select a named configuration, or all where supported.", Completion: commandkit.CompleteChoices(scopeChoices...)}, &defaultScope, parseConfigString,
|
||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).scope = value }),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Select the configuration source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
||||
(*input).selection.Config = value
|
||||
}),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Overlay source.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Select the configuration overlay.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
||||
(*input).selection.Overlay = value
|
||||
}),
|
||||
@@ -89,11 +89,11 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
}
|
||||
if operation == Validate {
|
||||
flags = append(flags,
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show native validation findings."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show detailed validation findings."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
||||
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "severity", Usage: "Filter detailed findings by error or warning."}, []configkit.Severity(nil), parseValidationSeverity, func(input **configCommandInput[I, S], value commandkit.Supplied[[]configkit.Severity]) {
|
||||
(*input).severities = value.Value
|
||||
}),
|
||||
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "code", Usage: "Filter detailed findings by exact native code."}, []string(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[[]string]) {
|
||||
commandkit.RepeatFlag(commandkit.FlagMeta{Name: "code", Usage: "Filter detailed findings by exact diagnostic code."}, []string(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[[]string]) {
|
||||
(*input).codes = value.Value
|
||||
}),
|
||||
)
|
||||
@@ -114,16 +114,16 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
flags = append(flags,
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer path to explain."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "list", Usage: "List configuration paths."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).list = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include historical-only paths when listing."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "historical", Usage: "Include paths that exist only in configuration history."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).historical = value }),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "under", Usage: "List paths under a JSON Pointer."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).under = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter listed current paths by explicitness."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "explicit", Usage: "Filter current paths by whether ConfigKit marks them explicit."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).explicit = value }),
|
||||
)
|
||||
}
|
||||
if operation == Show {
|
||||
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "path", Usage: "JSON Pointer to one effective value."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).path = value }))
|
||||
}
|
||||
if operation == Sources {
|
||||
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "source-id", Usage: "Select one source ID from this acquisition."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).sourceID = value }))
|
||||
flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "source-id", Usage: "Show one source ID from this configuration load."}, (*string)(nil), parseConfigString, func(input **configCommandInput[I, S], value commandkit.Supplied[string]) { (*input).sourceID = value }))
|
||||
}
|
||||
flags = append(flags, commandkit.CaptureFlags(prepared.bindingsByOperation[operation], func(input **configCommandInput[I, S]) *commandkit.FlagValues[I] {
|
||||
if input == nil || *input == nil {
|
||||
@@ -160,7 +160,7 @@ func newConfigOperationCommand[I, S any](prepared *preparedSuite[I, S], operatio
|
||||
|
||||
func comparisonOperationFlags[I, S any]() []commandkit.Flag[*configCommandInput[I, S]] {
|
||||
return []commandkit.Flag[*configCommandInput[I, S]]{
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show native before and after difference evidence."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "details", Usage: "Show before and after values with presence and redaction details."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).details = value }),
|
||||
commandkit.BoolFlag(commandkit.FlagMeta{Name: "check", Usage: "Return status 3 when differences are found."}, false, func(input **configCommandInput[I, S], value commandkit.Supplied[bool]) { (*input).check = value }),
|
||||
commandkit.ValueFlag(commandkit.FlagMeta{Name: "against-config", Usage: "Configuration source for the right side.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseConfigString,
|
||||
func(input **configCommandInput[I, S], value commandkit.Supplied[string]) {
|
||||
@@ -191,7 +191,7 @@ func operationDeclaration(operation Operation) (string, string) {
|
||||
case Explain:
|
||||
return "explain", "Explain a configuration path."
|
||||
case Diff:
|
||||
return "diff", "Compare two configuration selections."
|
||||
return "diff", "Compare two configurations."
|
||||
default:
|
||||
return string(operation), "Inspect configuration."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user