Generate config docs/json-schema from structs, add "k0sctl validate" and "k0sctl docs"#1029
Generate config docs/json-schema from structs, add "k0sctl validate" and "k0sctl docs"#1029kke wants to merge 3 commits into
Conversation
Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
There was a problem hiding this comment.
Pull request overview
This PR moves k0sctl configuration documentation/schema generation to be derived from the Go config structs, and exposes that documentation (and config validation) via CLI subcommands.
Changes:
- Add an internal schema/doc generator (
internal/schemagen) that emitsdocs/k0sctl-schema.jsonanddocs/configuration.md. - Add
k0sctl docscommand to display the embedded configuration documentation (Markdown) or JSON Schema. - Enrich config structs with field comments and
jsonschematags to drive generated docs/schema output.
Reviewed changes
Copilot reviewed 21 out of 22 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster/uploadfile.go | Adds documentation comments + jsonschema metadata for file upload config fields. |
| pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster/spec.go | Adds doc comments and jsonschema-required markers for spec fields. |
| pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster/options.go | Adds doc comments and jsonschema defaults/enums for options. |
| pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster/k0s.go | Adds doc comments and jsonschema defaults/enums for k0s settings. |
| pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster/host.go | Adds doc comments and jsonschema required/enums/defaults for host fields. |
| pkg/apis/k0sctl.k0sproject.io/v1beta1/cluster.go | Adds doc comments and jsonschema required/defaults for top-level Cluster config. |
| internal/schemagen/rig_schemas.go | Provides hand-written JSON schema for external rig connection structs. |
| internal/schemagen/preamble.md | Adds a generated-doc preamble and example config used in docs output. |
| internal/schemagen/markdown.go | Renders Markdown field reference from generated JSON schema. |
| internal/schemagen/main.go | Implements the schema/doc generation entrypoint (go run ./internal/schemagen). |
| internal/schemagen/appendix.md | Adds an appendix with connection types, hooks, uploads, tokens, etc. |
| docs/k0sctl-schema.json | Generated JSON Schema committed to the repo for editor validation. |
| docs/configuration.md | Generated Markdown reference committed to the repo for user docs. |
| docs/docs.go | Embeds generated docs/schema into the binary for k0sctl docs. |
| cmd/root.go | Registers new CLI commands (validate, docs) in the root command list. |
| cmd/docs.go | Implements k0sctl docs command and terminal rendering logic. |
| cmd/apply.go | Minor formatting-only diff (blank line removal). |
| README.md | Updates README to link to generated docs/schema and documents k0sctl validate. |
| Makefile | Adds docs and check-docs targets for generating/verifying docs outputs. |
| go.mod | Adds schema/doc generation and terminal markdown rendering dependencies. |
| go.sum | Updates dependency checksums for newly introduced modules. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Commands: []*cli.Command{ | ||
| versionCommand, | ||
| applyCommand, | ||
| validateCommand, | ||
| docsCommand, |
There was a problem hiding this comment.
validateCommand is referenced in the command list, but there is no definition of validateCommand in the cmd package in this PR state. This will fail to compile. Add the missing validate command implementation (e.g. cmd/validate.go) or remove the reference until it's included.
| md := string(k0sctldocs.ConfigurationMD) | ||
|
|
||
| outFile, isTerminal := ctx.App.Writer.(*os.File) | ||
| if isTerminal { | ||
| fi, err := outFile.Stat() | ||
| if err != nil || (fi.Mode()&os.ModeCharDevice) == 0 { | ||
| isTerminal = false |
There was a problem hiding this comment.
outFile, isTerminal := ctx.App.Writer.(*os.File) will panic if ctx.App.Writer is not an *os.File (e.g. when NewK0sctl is used with a bytes.Buffer in tests or other integrations). Use a safe type assertion (outFile, ok := ...) and treat non-*os.File writers as non-terminals.
| // injectDefaults walks the schema definitions and copies `default` values from | ||
| // Go struct tags (already parsed by the reflector into Extras) into the Default | ||
| // field. | ||
| func injectDefaults(schema *jsonschema.Schema) { | ||
| if schema.Definitions != nil { | ||
| for _, def := range schema.Definitions { | ||
| injectDefaultsInSchema(def) | ||
| } | ||
| } | ||
| injectDefaultsInSchema(schema) | ||
| } | ||
|
|
||
| func injectDefaultsInSchema(s *jsonschema.Schema) { | ||
| if s == nil { | ||
| return | ||
| } | ||
| if s.Properties != nil { | ||
| for pair := s.Properties.Oldest(); pair != nil; pair = pair.Next() { | ||
| injectDefaultsInSchema(pair.Value) | ||
| } | ||
| } | ||
| if s.Items != nil { | ||
| injectDefaultsInSchema(s.Items) | ||
| } | ||
| } |
There was a problem hiding this comment.
injectDefaults/injectDefaultsInSchema is documented as copying default values from the reflector's Extras into Schema.Default, but the current implementation only recurses and never reads Extras or sets Default. As a result, defaults expressed via default:"..." struct tags won't appear in the generated schema/docs (e.g. Spec.K0s.DynamicConfig has default:"false" but no schema default). Either implement the default extraction/parsing or remove/update this logic and rely solely on explicit jsonschema:"default=..." tags.
| PermMode any `yaml:"perm,omitempty"` | ||
| DirPermMode any `yaml:"dirPerm,omitempty"` | ||
| // Permission mode for directories created by k0sctl during upload. | ||
| DirPermMode any `yaml:"dirPerm,omitempty" jsonschema:"default=0755"` | ||
| // Owner user name for the uploaded file(s) and created directories. Must already |
There was a problem hiding this comment.
DirPermMode is documented/tagged with a JSON Schema default of 0755, but because the field type is any and there is no runtime defaulting in UnmarshalYAML, DirPermMode/DirPermString remain unset when the user omits dirPerm. This also results in the generated docs/k0sctl-schema.json lacking a default for dirPerm. Consider changing the type to a concrete type (e.g. string or int) and/or applying an explicit default during unmarshalling so both behavior and generated schema/docs match the documented default.
Config docs no longer live in the README.md and instead end up in docs/configuration.md.
k0sctl validateallows validating a config.k0sctl docsoutputs the config docs so you don't have to open a browser.