Commit Graph

435 Commits

Author SHA1 Message Date
Bob Lail 5b36573738 feat: Allow kong.Path to describe remaining unparsed args (#472)
As Kong traces a sequence of command line arguments, it parses them and appends them to the parsed `Path` sequence. For each element in `Path`, these is a corresponding sequence of unparsed arguments. This change enables `Path` to yield these.

I have a package that uses Kong's hooks to instrument Kong applications (to monitor usage, reliability, etc of internal tools). I would like to instrument the commandline arguments as well.

This change would enable it to work roughly as follows:
```golang
func (Foo) BeforeApply(app *kong.Kong, ctx *kong.Context, t *Tracker) error {
	command := []string{ctx.Model.Name}
	var args  []string

	for _, path := range ctx.Path {
		if path.Command != nil {
			command = append(command, path.Command.Name)
			args = path.Remainder()
		}
	}

	app.Exit = t.exit(app.Exit)

	t.WithCommand(strings.Join(command, " ")).WithArgs(args)
	return nil
}
```
2025-03-08 09:28:09 +11:00
Alec Thomas 0c495e4936 feat: add IgnoreDefault optional interface 2025-02-26 14:37:56 +11:00
Cam Hutchison 300cba8c27 feat: Allow ignoring fields from embedded structs (#499)
If a field in a struct is ignored with `kong:"-"`, any embedded fields
with the same name are also ignored. This allows an outer struct to
remove flags from an embedded struct by redefining it and adding a kong
ignore tag.
2025-02-17 20:06:02 +11:00
Abhinav Gupta 3b9af5bdce feat: Support singleton providers (#501)
* feat: Support singleton providers

This change adds support for provider functions that are
not reinvoked even if requested by multiple other providers.
Instead, their value is cached and reused between invocations.

To make this possible, we change how bindings are stored:
instead of just a function reference, we now store a binding object
which records whether the binding is a singleton,
and records the resolved singleton value (if any).

Resolves #500

* refac(bindings): hide singleton status

Don't require callAnyFunction to be aware of
whether a binding is a singleton or not.
2025-02-17 17:44:03 +11:00
renovate[bot] 7f94c902b9 chore(deps): update module github.com/alecthomas/kong to v1.8.1 (#503)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-17 15:41:24 +11:00
Abhinav Gupta 9f71a49767 ci: Test with Go 1.23 and 1.24 (#502)
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.
2025-02-17 14:10:57 +11:00
Alec Thomas cab639ab83 chore: add test for decoding 2025-02-13 11:22:03 -08:00
Alec Thomas 7747b4146b Revert "Load environment variables as a resolver (#480)"
This reverts commit 3cedc44821.

Fixes #497, #498
2025-02-13 11:17:47 -08:00
Maxime Vidori 3cedc44821 Load environment variables as a resolver (#480) 2025-02-10 09:53:27 +11:00
renovate[bot] 6590294c3d chore(deps): update all non-major dependencies (#486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-08 22:24:06 +11:00
Alec Thomas 705e259cd6 chore: reduce lefthook output 2025-01-30 14:11:42 +11:00
Alec Thomas a6efd403cc chore: add lefthook 2025-01-30 14:10:48 +11:00
Alec Thomas 5765c11522 refactor: minor simplification of getMethods 2025-01-30 14:08:44 +11:00
Abhinav Gupta 4be6ae6168 hooks: Recursively search embedded fields for methods (#494)
* hooks: Recursively search embedded fields for methods

Follow up to #493 and 840220c

Kong currently supports hooks on embedded fields of a parsed node,
but only at the first level of embedding:

```
type mainCmd struct {
    FooOptions
}

type FooOptions struct {
    BarOptions
}

func (f *FooOptions) BeforeApply() error {
    // this will be called
}

type BarOptions struct {
}

func (b *BarOptions) BeforeApply() error {
    // this will not be called
}
```

This change adds support for hooks to be defined
on embedded fields of embedded fields so that the above
example would work as expected.

Per #493, the definition of "embedded" field is adjusted to mean:

- Any anonymous (Go-embedded) field that is exported
- Any non-anonymous field that is tagged with `embed:""`

*Testing*:
Includes a test case for embedding an anonymous field in an `embed:""`
and an `embed:""` field in an anonymous field.

* Use recursion to build up the list of receivers

The 'receivers' parameter helps avoid constant memory allocation
as the backing storage for the slice is reused across recursive calls.
2025-01-30 13:43:10 +11:00
Alec Thomas 4e1757c0e8 feat: allow use of providers that don't return errors 2025-01-30 13:41:09 +11:00
Abhinav Gupta 9c08a58eb2 Support hooks on embed:"" fields (#493)
Relates to 840220c (#90)

This change adds support for hooks to be called on fields
that are tagged with `embed:""`.

### Use case

If a command has several subcommands,
many (but not all) of which need the same external resource,
this allows defining the flag-level inputs for that resource centrally,
and then using `embed:""` in any command that needs that resource.

For example, imagine:

```go
type githubClientProvider struct {
    Token string `name:"github-token" env:"GITHUB_TOKEN"`
    URL   string `name:"github-url" env:"GITHUB_URL"`
}

func (g *githubClientProvider) BeforeApply(kctx *kong.Context) error {
  return kctx.BindToProvider(func() (*github.Client, error) {
    return github.NewClient(...), nil
  })
}
```

Then, any command that needs GitHub client will add this field,
any other resource providers it needs,
and add parameters to its `Run` method to accept those resources:

```go
type listUsersCmd struct {
    GitHub githubClientProvider `embed:""`
    S3     s3ClientProvider     `embed:""`
}

func (l *listUsersCmd) Run(gh *github.Client, s3 *s3.Client) error {
    ...
}
```

### Alternatives

It is possible to do the same today if the `*Provider` struct above
is actually a Go embed instead of a Kong embed, *and* it is exported.

```
type GitHubClientProvider struct{ ... }

type listUsersCmd struct {
    GithubClientProvider
    S3ClientProvider
}
```

The difference is whether the struct defining the flags
is required to be exported or not.
2025-01-29 16:04:52 +11:00
Hritik Vijay 042a3258ec Document about binds with example (#491) 2025-01-25 10:51:46 +11:00
renovate[bot] 8d238c88fa chore(deps): update all non-major dependencies (#485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-13 22:13:14 +11:00
Abhinav Gupta 7ca846736c fix(Context.Run): Don't panic on unselected root node (#484) 2025-01-04 11:13:14 +09:00
Alec Thomas b811e32243 fix: whoops, forgot to prefix "and" 2024-12-29 18:02:02 +09:00
Alec Thomas 47b090f2f4 fix: add an xorprefix:"..." option for prefixing xor/and groups
Fixes #343
2024-12-29 17:55:06 +09:00
Alec Thomas cacaace969 fix: don't append ... for fields with an explicit type
Fixes #346
2024-12-29 17:42:20 +09:00
Alec Thomas a32b94b705 chore: interface{} -> any 2024-12-29 08:10:34 +09:00
Alec Thomas 36257680f1 refactor(test): replace os.Setenv() with t.Setenv() 2024-12-29 08:02:45 +09:00
Alec Thomas a14bb2072c fix: don't call Apply() twice
For some reason this was called by `Run()`. All tests pass without it,
so I'm not sure why it was there.

Fixes #481
2024-12-29 07:43:05 +09:00
Alec Thomas 840220c2ed feat: allow hooks to be declared on embedded fields
Specifically, on Go embedded fields, not on fields tagged with `embed`.

Fixes #90.
2024-12-27 22:29:45 +09:00
renovate[bot] 565ae9b740 chore(deps): update all non-major dependencies (#476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-12 22:32:41 +11:00
Alec Thomas f2fcd34abf docs: fix README TOC 2024-12-07 19:43:01 +11:00
Alec Thomas 388ba35f1a feat: add support for Provide*() (<type>, error) methods on commands 2024-12-07 17:09:03 +11:00
renovate[bot] 87ee7dc3db chore(deps): update all non-major dependencies (#474)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 10:29:00 +11:00
Alec Thomas 81d0c29303 fix: regression where all args became passthrough
Fixes #475
2024-12-03 08:22:10 +11:00
Alec Thomas 96647c30af feat: add old "passthrough" behaviour back in as an option
`passthrough:""` or `passthrough:"all"` (the default) will pass through
all further arguments including unrecognised flags.

`passthrough:"partial"` will validate flags up until the `--` or the
first positional argument, then pass through all subsequent flags and
arguments.
2024-12-01 20:02:03 +11:00
Alec Thomas 88e13d750a chore: fix all golangci-lint warnings 2024-12-01 11:12:48 +11:00
renovate[bot] 5221ebb8fb chore(deps): update all non-major dependencies (#469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 17:24:56 +11:00
Alec Thomas f388f6cd39 fix: NPE due to checking if error is nil when it can be a value
Fixes #468
2024-11-06 09:36:22 +11:00
renovate[bot] c90c6732cc chore(deps): update module github.com/alecthomas/kong to v1.3.0 (#467) 2024-11-04 13:51:07 +11:00
Alec Thomas 2544d3f008 feat: add AfterRun() hook
Fixes #288
2024-11-03 14:49:27 +11:00
Alec Thomas d0beaf7df3 fix: update enum+default vars after interpolation
This doesn't recursively apply interpolation, as discussed in the issue,
but that's a much bigger change.

Fixes #337
2024-11-03 14:28:27 +11:00
Alec Thomas 1b9d57eec1 feat: support optionally passing kong.Context to Validate()
Fixes #340
2024-11-03 14:14:55 +11:00
Alec Thomas 64229c9fe7 fix: format enum value
Fixed in #415
2024-11-03 14:02:03 +11:00
Alec Thomas 7bbb0b76ad feat: support recursive injection of provider parameters
This allows provider functions to accept parameters that are injected by other
bindings or binding providers, eg. call the provider function with the root CLI
struct (which is automatically bound by Kong):

  kong.BindToProvider(func(cli *CLI) (*Injected, error) { ... })
2024-11-01 12:25:41 +11:00
Alec Thomas 373692af87 refactor: reuse callAnyFunction for callFunction
Rather than duplicating basically identical calling logic
2024-11-01 11:59:18 +11:00
市川恭佑 (ebi) 07c8821614 Fix broken anchor link in README.md (#464) 2024-10-27 07:54:43 +11:00
renovate[bot] 56e990fc15 chore(deps): update all non-major dependencies (#462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-07 14:25:31 +11:00
renovate[bot] c9fbc305f4 chore(deps): update module github.com/alecthomas/assert/v2 to v2.11.0 (#459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-23 10:05:14 +10:00
Alexey Palazhchenko b34e9952de Fix Markdown in README.md (#458) 2024-09-19 18:27:07 +10:00
Alec Thomas 31301f527c docs: add note about 1.0 to README 2024-09-19 04:10:05 +10:00
renovate[bot] 3b28c2c83a chore(deps): update module github.com/alecthomas/kong to v1 (#457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-16 19:49:21 +10:00
Alec Thomas 26c1c9ad05 fix: allow duplicate custom negated flags
Fixes #456
2024-09-12 12:05:09 +10:00
Bob Lail 9924ec4461 fix!: Include -- in passthrough args (#436)
Given a grammar like this:

```golang
var cli struct {
        Args []string `arg:"" optional:"" passthrough:""`
}
```

If Kong parses `cli foo -- bar`, it will populate `Args` with `[]string{"foo", "--", "bar"}` (including "`--`").
However, if Kong parses `cli -- foo bar`, will populate `Args` with `[]string{"foo", "bar"}` (leaving off `"--"`).

This differs from the behavior of a passthrough Command, where `"--"` is included with the args in both cases.

There are 3 places where `c.endParsing()` is called
1. When `node.Passthrough` is true: https://github.com/alecthomas/kong/blob/5f9c5cc822bdb888a3671c44d4688a6f602ecb90/context.go#L366-L368
2. When `arg.Passthrough` is true: https://github.com/alecthomas/kong/blob/5f9c5cc822bdb888a3671c44d4688a6f602ecb90/context.go#L451-L453
3. When `"--"` is encountered: https://github.com/alecthomas/kong/blob/5f9c5cc822bdb888a3671c44d4688a6f602ecb90/context.go#L384-L387

The first two do not also pop any tokens. The third one does.

This commit makes `c.scan.Pop()` conditional, skipping it when the next positional argument is passthrough.

I believe this will cause Kong to behave a little more consistently — and from my perspective, `--` is relevant for args intended to be passed through! — but it will change the behavior of existing projects that use `arg:"" passthrough:""`.
2024-09-11 10:51:37 +10:00