* feat: Allow Kong to exit with semantic exit codes
At Block, we've instrumented a number of commandline tools and set SLOs on some tools' reliability. To do that effectively, we had to partition usage errors from reliability issues. We looked at [prior art](https://github.com/square/exit?tab=readme-ov-file#reserved-codes-and-prior-art) and, taking inspiration from HTTP, defined [a set of semantic exit codes](https://github.com/square/exit?tab=readme-ov-file#about) in ranges: 80-99 for user errors, 100-119 for system errors.
We've been wrapping errors in `exit.Error` at whatever level of the stack can tell which class an error is and unwrapping them at exit (`os.Exit(exit.FromError(err))`).
This adds support for semantic exit codes to Kong, to `FatalIfErrorf`, which is used internally by `kong.Parse` and often used in Kong applications.
* feat: Exit 80 (Usage Error) when usage is syntactically or semantically invalid
* refactor: Always exit 80 (Usage Error) on a `ParseError` but don't wrap errors from hooks in `ParseError`
In CI, test with Go 1.23 and 1.24,
and upgrade the Hermit-managed Go and golangci-lint to latest versions.
The new golangci-lint had a number of warnings and minor issues
that were either fixed or opted-out of.
* fix: Check if negatable duplicates another flag
Add a check for flags with the `negatable` option if the negative flag
conflicts with another tag, such as:
Flag bool `negatable:""`
NoFlag bool
The flag `--no-flag` is ambiguous in this scenario.
* feat: Make negatable flag name customisable
Allow a value on the `negatable` tag to specify a flag name to use for
negation instead of using `--no-<flag-name>` as the flag.
e.g.
Approve bool `default:"true",negatable:"deny"`
This example will allow `--deny` to set the `Approve` field to false.
The golangci-lint being used was quite dated.
This change upgrades to the latest version.
Adds and updates exclusions based on new failures.
Note on revive:
I've included an opt-out for unused parameters for revive
because turning `newThing(required bool)` to `newThing(_ bool)`
is a loss of useful information.
The changes to the Go files are to fix the following issues:
```
camelcase.go:16: File is not `gofmt`-ed with `-s` (gofmt)
config_test.go:50:18: directive `//nolint: gosec` is unused for linter "gosec" (nolintlint)
defaults_test.go:28:25: G601: Implicit memory aliasing in for loop. (gosec)
doc.go:5: File is not `gofmt`-ed with `-s` (gofmt)
kong.go:446:18: directive `//nolint: gosec` is unused for linter "gosec" (nolintlint)
kong_test.go:503:20: G601: Implicit memory aliasing in for loop. (gosec)
model.go:493:10: composites: reflect.ValueError struct literal uses unkeyed fields (govet)
scanner.go:112: File is not `gofmt`-ed with `-s` (gofmt)
```
And to address broken nolint directives reported as follows by
golangci-lint.
```
[.. skipped .. ]
tag.go:65:1: directive `// nolint:gocyclo` should be written without leading space as `//nolint:gocyclo` (nolintlint)
tag.go:206:51: directive `// nolint: gocyclo` should be written without leading space as `//nolint: gocyclo` (nolintlint)
util_test.go:23:43: directive `// nolint: errcheck` should be written without leading space as `//nolint: errcheck` (nolintlint)
util_test.go:51:22: directive `// nolint: errcheck` should be written without leading space as `//nolint: errcheck` (nolintlint)
```
Add kong.ShortUsageOnError() option similar to kong.UsageOnError().
Add tests for UsageOnError and ShortUsageOnError.
Remove the HelpOption summary reset at the beginning of DefaultHelpPrinter:
func DefaultHelpPrinter(options HelpOptions, ctx *Context) error {
- if ctx.Empty() {
- options.Summary = false
- }
⚠️ I'm not really sure what the implications of this are, tests still
seem to pass, but maybe this has unintended side effects.
Commit c77deac080 in PR #83 added `h` as
the short flag for help, but the help tests were not updated. Update the
tests with the `-h` in the help output.
Add a command tree help view.
Following up #29 and #30, I noticed that the default help looks quite duplicative since only the help text of the last command in chain is viewed. I needed an option to also show the help text of the command nodes in an appropriate way. This is what I came up with.
Previously, there was a confusing mix of functionality shared between
the two wherein you would need to use the Kong type for printing errors,
etc. but it did not have access to the context in order to print
context-sensitive usage information. This has been fixed.
Additionally, there are now fuzzy correction suggestions for flags and
commands
Also added a server example which shows how Kong can be used for parsing
in interactive shells. Run with:
$ go run ./_examples/server/*.go
Then interact with:
$ ssh -p 6740 127.0.0.1
* Propagate errors.
* Use junit test output.
* Expand role of DecodeContext to include Scanner.
* Inject resolved flags as Path elements in the Context.
This allows all existing logic to apply seamlessly: hooks, required
flags, etc.
* Clarify that hooks can be called multiple times.
This allows help to be called even when the parse trace is invalid.
Without this, the command-line would have to be valid in order to use
help at all, which defeats the purpose.