Documentation
¶
Overview ¶
Package kongusage adds usage spec support for Kong CLI.
A CLI declares a Flag, which prints the spec of the CLI for a shell completion script, a mise task, docs or a compatibility check. WriteSpec can be used to generate the spec without using a Flag.
How Kong maps to the spec and which Kong features are lost is described in docs/mapping.md.
Usage features ¶
Features of usage which have no counterpart in Kong are supplied by the author of the CLI in KDL v2, as nodes of the usage spec:
- by KDLProvider of the named root, command, flag or positional argument type;
- by the tag `usage-kdl` of the field of a command, a flag or a positional argument.
UsageKDL of the root returns top-level nodes of the spec. UsageKDL of another type returns the node for a field of that type with an empty value, as the type does not know the name of the field: `cmd ""`, `flag ""` or `arg ""` (the last two are interchangeable) with properties and child nodes. Nested `cmd`, `flag` and `arg` nodes describe descendants of a node, named exactly as in the spec printed by Flag, e.g. `flag "-f --force"` or `arg "<file>..."`; UsageKDL of the type of a field is ignored when an ancestor describes its node.
Typical features, as UsageKDL of the root would give them:
license MIT
repository "https://github.com/example/my-kong-cli"
cmd "deploy" effect=destructive {
help_md "Deploys the **current** release."
example "my-kong-cli deploy --env=prod web1" header="Deploy to production"
exit_code 3 "The deployment was rolled back."
// The flag has placeholder:"ENV" and enum:"prod,dev".
flag "--env <ENV>" long_help="Environment to deploy to." {
note "Deploying to prod needs approval."
choices { choice prod help="Production." }
}
arg "<host>" { complete run="my-kong-cli hosts" }
}
The tag holds properties and child nodes of the node of its field, without its name and value, and merges with the node given by UsageKDL (if any):
- `usage-kdl:"effect=destructive"` adds the property or changes its value;
- `usage-kdl:"{ note \"Slow.\" }"` adds the child node or replaces all child nodes of that name;
- `usage-kdl:"long_help=\"Text.\""` and `usage-kdl:"{ long_help \"Text.\" }"` are the same node, as usage accepts it in either form;
- `usage-kdl:"effect=#null"` or `usage-kdl:"{ example #null }"` removes it;
- `usage-kdl:"{ flag \"--force\" effect=destructive }"` on a command changes the node of its flag, keeping the rest of the node.
Where to put features:
- UsageKDL of the root: features of the whole CLI, long texts, and features of commands without a named type.
- UsageKDL of a reusable type: features which hold wherever the type is used, e.g. `effect` of a command or `complete` of a value.
- The tag: short features of one field, and changes of the node of its type for it.
For example:
type CLI struct {
Force bool `help:"Overwrite files." usage-kdl:"effect=destructive"`
Run RunCmd `cmd:"" help:"Run a container."`
Rm RmCmd `cmd:"" help:"Remove a container." usage-kdl:"effect=destructive"`
Ls struct{} `cmd:"" help:"List containers."`
}
func (CLI) UsageKDL() string {
return `
license MIT
flag "--force" long_help="Overwrites existing files without asking."
cmd "ls" effect=read
`
}
type RunCmd struct {
Image string `arg:"" help:"Image to run."`
}
func (RunCmd) UsageKDL() string {
return `cmd "" effect=write { example "my-kong-cli run alpine" }`
}
type RmCmd struct {
ID ContainerID `arg:"" help:"Container." usage-kdl:"{ note \"Stops it first.\" }"`
}
type ContainerID string
func (ContainerID) UsageKDL() string {
return `arg "" { complete run="my-kong-cli ls" }`
}
The spec printed by Flag then has these nodes, besides other ones derived from Kong:
license MIT
flag "--force" help="Overwrite files." effect=destructive {
long_help "Overwrites existing files without asking."
}
cmd "run" help="Run a container." effect=write {
example "my-kong-cli run alpine"
arg "<image>" help="Image to run."
}
cmd "rm" help="Remove a container." effect=destructive {
arg "<id>" help="Container." {
complete run="my-kong-cli ls"
note "Stops it first."
}
}
cmd "ls" help="List containers." effect=read
Which nodes, values and properties are accepted and how exactly the tag changes the node is described in docs/usage-features.md.
A CLI with usage features must have a test which calls CheckSpec, with the `usage` CLI installed, because Flag panics on a mistake in them. The test is recommended for any CLI: it also runs `usage lint` and logs parts of the CLI which the spec fixes silently.
Index ¶
Constants ¶
const MinUsageVersion = "6.12.0"
MinUsageVersion is the oldest supported usage version. The spec sets it as `min_usage_version`, and CheckSpec requires at least this version.
Variables ¶
This section is empty.
Functions ¶
func CheckSpec ¶ added in v0.2.0
func CheckSpec(t interface {
Helper()
Context() context.Context
Logf(format string, args ...any)
Fatalf(format string, args ...any)
}, k *kong.Kong,
)
CheckSpec fails the test t on mistakes in the usage spec of the CLI k:
- on mistakes in usage features which make WriteSpec and thus Flag panic, e.g. a node, value or property which is not accepted, a name of a command, a flag or a positional argument which is not in the spec, or a node derived from Kong (see "Usage features" in the package doc);
- on errors and warnings of `usage lint`, e.g. an example which the spec cannot parse.
Use it in a test of the CLI:
func TestUsageSpec(t *testing.T) {
kongusage.CheckSpec(t, kong.Must(&CLI{}))
}
The spec is generated with the same Config as by Flag. CheckSpec logs each part of the CLI which the spec fixes silently, e.g. a placeholder which usage cannot take as a value name, as it is likely a mistake which is worth correcting in the CLI. It requires the `usage` CLI in PATH, of a version not older than MinUsageVersion; otherwise the test fails with the version to install. When the environment variable KONGUSAGE_TEST_SKIP_USAGE is not empty, it does not run usage, e.g. on platforms without it, and checks only usage features.
Types ¶
type Config ¶ added in v0.2.0
type Config struct {
// NoDisplayOrder disables `display_order` of commands,
// which keeps the order of their declaration in help of usage;
// without it help of usage sorts commands by name.
NoDisplayOrder bool
}
Config controls generation of the usage spec. The zero value of every field means "unset, use default". Usage features of the CLI are supplied by KDLProvider instead.
type ConfigProvider ¶ added in v0.2.0
type ConfigProvider interface {
UsageConfig() Config
}
ConfigProvider may be implemented by the root of a Kong CLI to give Flag and CheckSpec a Config.
type Flag ¶
type Flag bool
Flag prints the usage spec of the CLI in KDL and exits, like kong.VersionFlag.
Declare it as a field of the root of the CLI:
type CLI struct {
UsageSpec kongusage.Flag
}
The flag has the default tag help (see Flag.Signature), which the tag of the field overrides.
Only the command line sets the flag, not an environment variable or a resolver: they are inherited by every run of the CLI, which would print the spec instead of doing its job. Add the tag `env:"-"` if using kong.DefaultEnvars, otherwise help shows a variable which the flag ignores.
The spec is generated by WriteSpec with the Config returned by the root of the CLI when it implements ConfigProvider or zero Config otherwise.
In a mise task the shell completes paths relative to its current directory, while the task runs in its own directory (by default the root of the mise config), so the program has to resolve relative paths given by the user against MISE_ORIGINAL_CWD when it is set.
func (*Flag) BeforeReset ¶
BeforeReset implements the Kong hook. Kong calls it before it applies defaults, environment variables and resolvers and checks required flags and arguments, so the flag works without them and despite invalid values in them.
func (*Flag) Signature ¶ added in v0.2.0
Signature implements kong.Signature.
type KDLProvider ¶ added in v0.2.0
type KDLProvider interface {
UsageKDL() string
}
KDLProvider may be implemented by the root of a Kong CLI and by the type of a command, a flag or a positional argument to supply usage features in KDL (see "Usage features" in the package doc).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
kdl
Package kdl builds a tree of KDL nodes and writes it as a KDL v2 document.
|
Package kdl builds a tree of KDL nodes and writes it as a KDL v2 document. |
|
usagecli
Package usagecli runs the usage CLI for tests of kongusage and for its CheckSpec.
|
Package usagecli runs the usage CLI for tests of kongusage and for its CheckSpec. |
|
usagekdl
Package usagekdl parses usage features of a CLI, given in KDL v2, merges them and adds them to the usage spec as docs/usage-features.md describes.
|
Package usagekdl parses usage features of a CLI, given in KDL v2, merges them and adds them to the usage spec as docs/usage-features.md describes. |
|
usagetest
Package usagetest runs the usage CLI in tests.
|
Package usagetest runs the usage CLI in tests. |