Skip to content

Commit b5bc3e3

Browse files
committed
Merge branch 'main' into doc-slash-commands
* main: (39 commits) Add '--version' flag to Help output (spf13#1707) Expose ValidateRequiredFlags and ValidateFlagGroups (spf13#1760) Document option to hide the default completion cmd (spf13#1779) ci: add workflow_dispatch (spf13#1387) add missing license headers (spf13#1809) ci: use action/setup-go's cache (spf13#1783) Adjustments to documentation (spf13#1656) Rename Powershell completion tests (spf13#1803) Support for case-insensitive command names (spf13#1802) Deprecate ExactValidArgs() and test combinations of args validators (spf13#1643) Use correct stale action `exempt-` yaml keys (spf13#1800) With go 1.18, we must use go install for a binary (spf13#1726) Clarify SetContext documentation (spf13#1748) ci: test on Golang 1.19 (spf13#1782) fix: show flags that shadow parent persistent flag in child help (spf13#1776) Update gopkg.in/yaml.v2 to gopkg.in/yaml.v3 (spf13#1766) fix(bash-v2): activeHelp length check syntax (spf13#1762) fix: correct command path in see_also for YAML doc (spf13#1771) build(deps): bump github.com/inconshreveable/mousetrap (spf13#1774) docs: add zitadel to the list (spf13#1772) ...
2 parents 0bfd1c1 + 7039e1f commit b5bc3e3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2159
-170
lines changed

.github/workflows/stale.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ jobs:
3939
days-before-close: 30
4040
stale-issue-label: 'lifecycle/stale'
4141
stale-pr-label: 'lifecycle/stale'
42-
exempt-issue-label: 'lifecycle/frozen'
43-
exempt-pr-label: 'lifecycle/frozen'
42+
exempt-issue-labels: 'lifecycle/frozen'
43+
exempt-pr-labels: 'lifecycle/frozen'
4444
close-issue-label: 'lifecycle/rotten'
4545
close-pr-label: 'lifecycle/rotten'
4646

.github/workflows/test.yml

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,52 @@ name: Test
33
on:
44
push:
55
pull_request:
6+
workflow_dispatch:
67

78
env:
89
GO111MODULE: on
910

1011
jobs:
1112

13+
14+
lic-headers:
15+
runs-on: ubuntu-latest
16+
steps:
17+
18+
- uses: actions/checkout@v3
19+
20+
- run: >-
21+
docker run
22+
-v $(pwd):/wrk -w /wrk
23+
ghcr.io/google/addlicense
24+
-c 'The Cobra Authors'
25+
-y '2013-2022'
26+
-l apache
27+
-ignore '.github/**'
28+
-check
29+
.
30+
31+
1232
golangci-lint:
1333
runs-on: ubuntu-latest
1434
steps:
1535

16-
- uses: actions/setup-go@v2
36+
- uses: actions/checkout@v3
37+
38+
- uses: actions/setup-go@v3
1739
with:
18-
go-version: '1.17'
40+
go-version: '^1.19'
41+
check-latest: true
42+
cache: true
1943

2044
- uses: actions/checkout@v3
2145

22-
- uses: golangci/golangci-lint-action@v3.1.0
46+
- uses: golangci/golangci-lint-action@v3.2.0
2347
with:
2448
version: latest
2549
args: --verbose
2650

51+
2752
test-unix:
2853
strategy:
2954
fail-fast: false
@@ -32,38 +57,34 @@ jobs:
3257
- ubuntu
3358
- macOS
3459
go:
35-
- 14
3660
- 15
3761
- 16
3862
- 17
3963
- 18
64+
- 19
4065
name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x'
4166
runs-on: ${{ matrix.platform }}-latest
4267
steps:
4368

44-
- uses: actions/setup-go@v2
45-
with:
46-
go-version: 1.${{ matrix.go }}.x
47-
4869
- uses: actions/checkout@v3
4970

50-
- uses: actions/cache@v3
71+
- uses: actions/setup-go@v3
5172
with:
52-
path: ~/go/pkg/mod
53-
key: ${{ runner.os }}-1.${{ matrix.go }}.x-${{ hashFiles('**/go.sum') }}
54-
restore-keys: ${{ runner.os }}-1.${{ matrix.go }}.x-
73+
go-version: 1.${{ matrix.go }}.x
74+
cache: true
5575

5676
- run: |
5777
export GOBIN=$HOME/go/bin
5878
case "${{ matrix.go }}" in
59-
16|17|18) _version='@latest';;
60-
*) _version='';;
79+
14|15) _version='';;
80+
*) _version='@latest';;
6181
esac
6282
go install github.com/kyoh86/richgo"${_version}"
6383
go install github.com/mitchellh/gox"${_version}"
6484
6585
- run: RICHGO_FORCE_COLOR=1 PATH=$HOME/go/bin/:$PATH make test
6686

87+
6788
test-win:
6889
name: MINGW64
6990
defaults:

.golangci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# Copyright 2013-2022 The Cobra Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
run:
216
deadline: 5m
317

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ $(warning "could not find golangci-lint in $(PATH), run: curl -sfL https://insta
66
endif
77

88
ifeq (, $(shell which richgo))
9-
$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo")
9+
$(warning "could not find richgo in $(PATH), run: go install github.com/kyoh86/richgo@latest")
1010
endif
1111

1212
.PHONY: fmt lint test install_deps clean

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
Cobra is a library for creating powerful modern CLI applications.
44

5-
Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/),
6-
[Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to
5+
Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/),
6+
[Hugo](https://gohugo.io), and [GitHub CLI](https://github.com/cli/cli) to
77
name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
88

99
[![](https://img.shields.io/github/workflow/status/spf13/cobra/Test?longCache=tru&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest)
@@ -28,7 +28,7 @@ Cobra provides:
2828
* Automatically generated man pages for your application
2929
* Command aliases so you can change things without breaking them
3030
* The flexibility to define your own help, usage, etc.
31-
* Optional seamless integration with [viper](http://github.com/spf13/viper) for 12-factor apps
31+
* Optional seamless integration with [viper](https://github.com/spf13/viper) for 12-factor apps
3232

3333
# Concepts
3434

@@ -40,9 +40,9 @@ The best applications read like sentences when used, and as a result, users
4040
intuitively know how to interact with them.
4141

4242
The pattern to follow is
43-
`APPNAME VERB NOUN --ADJECTIVE.`
43+
`APPNAME VERB NOUN --ADJECTIVE`
4444
or
45-
`APPNAME COMMAND ARG --FLAG`
45+
`APPNAME COMMAND ARG --FLAG`.
4646

4747
A few good real world examples may better illustrate this point.
4848

active_help.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2013-2022 The Cobra Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cobra
16+
17+
import (
18+
"fmt"
19+
"os"
20+
"strings"
21+
)
22+
23+
const (
24+
activeHelpMarker = "_activeHelp_ "
25+
// The below values should not be changed: programs will be using them explicitly
26+
// in their user documentation, and users will be using them explicitly.
27+
activeHelpEnvVarSuffix = "_ACTIVE_HELP"
28+
activeHelpGlobalEnvVar = "COBRA_ACTIVE_HELP"
29+
activeHelpGlobalDisable = "0"
30+
)
31+
32+
// AppendActiveHelp adds the specified string to the specified array to be used as ActiveHelp.
33+
// Such strings will be processed by the completion script and will be shown as ActiveHelp
34+
// to the user.
35+
// The array parameter should be the array that will contain the completions.
36+
// This function can be called multiple times before and/or after completions are added to
37+
// the array. Each time this function is called with the same array, the new
38+
// ActiveHelp line will be shown below the previous ones when completion is triggered.
39+
func AppendActiveHelp(compArray []string, activeHelpStr string) []string {
40+
return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr))
41+
}
42+
43+
// GetActiveHelpConfig returns the value of the ActiveHelp environment variable
44+
// <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the root command in upper
45+
// case, with all - replaced by _.
46+
// It will always return "0" if the global environment variable COBRA_ACTIVE_HELP
47+
// is set to "0".
48+
func GetActiveHelpConfig(cmd *Command) string {
49+
activeHelpCfg := os.Getenv(activeHelpGlobalEnvVar)
50+
if activeHelpCfg != activeHelpGlobalDisable {
51+
activeHelpCfg = os.Getenv(activeHelpEnvVar(cmd.Root().Name()))
52+
}
53+
return activeHelpCfg
54+
}
55+
56+
// activeHelpEnvVar returns the name of the program-specific ActiveHelp environment
57+
// variable. It has the format <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the
58+
// root command in upper case, with all - replaced by _.
59+
func activeHelpEnvVar(name string) string {
60+
// This format should not be changed: users will be using it explicitly.
61+
activeHelpEnvVar := strings.ToUpper(fmt.Sprintf("%s%s", name, activeHelpEnvVarSuffix))
62+
return strings.ReplaceAll(activeHelpEnvVar, "-", "_")
63+
}

active_help.md

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Active Help
2+
3+
Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.
4+
5+
For example,
6+
```
7+
bash-5.1$ helm repo add [tab]
8+
You must choose a name for the repo you are adding.
9+
10+
bash-5.1$ bin/helm package [tab]
11+
Please specify the path to the chart to package
12+
13+
bash-5.1$ bin/helm package [tab][tab]
14+
bin/ internal/ scripts/ pkg/ testdata/
15+
```
16+
17+
**Hint**: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.
18+
## Supported shells
19+
20+
Active Help is currently only supported for the following shells:
21+
- Bash (using [bash completion V2](shell_completions.md#bash-completion-v2) only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
22+
- Zsh
23+
24+
## Adding Active Help messages
25+
26+
As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to [Shell Completions](shell_completions.md).
27+
28+
Adding Active Help is done through the use of the `cobra.AppendActiveHelp(...)` function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.
29+
30+
### Active Help for nouns
31+
32+
Adding Active Help when completing a noun is done within the `ValidArgsFunction(...)` of a command. Please notice the use of `cobra.AppendActiveHelp(...)` in the following example:
33+
34+
```go
35+
cmd := &cobra.Command{
36+
Use: "add [NAME] [URL]",
37+
Short: "add a chart repository",
38+
Args: require.ExactArgs(2),
39+
RunE: func(cmd *cobra.Command, args []string) error {
40+
return addRepo(args)
41+
},
42+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
43+
var comps []string
44+
if len(args) == 0 {
45+
comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
46+
} else if len(args) == 1 {
47+
comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
48+
} else {
49+
comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
50+
}
51+
return comps, cobra.ShellCompDirectiveNoFileComp
52+
},
53+
}
54+
```
55+
The example above defines the completions (none, in this specific example) as well as the Active Help messages for the `helm repo add` command. It yields the following behavior:
56+
```
57+
bash-5.1$ helm repo add [tab]
58+
You must choose a name for the repo you are adding
59+
60+
bash-5.1$ helm repo add grafana [tab]
61+
You must specify the URL for the repo you are adding
62+
63+
bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
64+
This command does not take any more arguments
65+
```
66+
**Hint**: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.
67+
68+
### Active Help for flags
69+
70+
Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:
71+
```go
72+
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
73+
if len(args) != 2 {
74+
return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
75+
}
76+
return compVersionFlag(args[1], toComplete)
77+
})
78+
```
79+
The example above prints an Active Help message when not enough information was given by the user to complete the `--version` flag.
80+
```
81+
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
82+
You must first specify the chart to install before the --version flag can be completed
83+
84+
bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
85+
2.0.1 2.0.2 2.0.3
86+
```
87+
88+
## User control of Active Help
89+
90+
You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any.
91+
Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.
92+
93+
The way to configure Active Help is to use the program's Active Help environment
94+
variable. That variable is named `<PROGRAM>_ACTIVE_HELP` where `<PROGRAM>` is the name of your
95+
program in uppercase with any `-` replaced by an `_`. The variable should be set by the user to whatever
96+
Active Help configuration values are supported by the program.
97+
98+
For example, say `helm` has chosen to support three levels for Active Help: `on`, `off`, `local`. Then a user
99+
would set the desired behavior to `local` by doing `export HELM_ACTIVE_HELP=local` in their shell.
100+
101+
For simplicity, when in `cmd.ValidArgsFunction(...)` or a flag's completion function, the program should read the
102+
Active Help configuration using the `cobra.GetActiveHelpConfig(cmd)` function and select what Active Help messages
103+
should or should not be added (instead of reading the environment variable directly).
104+
105+
For example:
106+
```go
107+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
108+
activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
109+
110+
var comps []string
111+
if len(args) == 0 {
112+
if activeHelpLevel != "off" {
113+
comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
114+
}
115+
} else if len(args) == 1 {
116+
if activeHelpLevel != "off" {
117+
comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
118+
}
119+
} else {
120+
if activeHelpLevel == "local" {
121+
comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
122+
}
123+
}
124+
return comps, cobra.ShellCompDirectiveNoFileComp
125+
},
126+
```
127+
**Note 1**: If the `<PROGRAM>_ACTIVE_HELP` environment variable is set to the string "0", Cobra will automatically disable all Active Help output (even if some output was specified by the program using the `cobra.AppendActiveHelp(...)` function). Using "0" can simplify your code in situations where you want to blindly disable Active Help without having to call `cobra.GetActiveHelpConfig(cmd)` explicitly.
128+
129+
**Note 2**: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable `COBRA_ACTIVE_HELP` to "0". In this case `cobra.GetActiveHelpConfig(cmd)` will return "0" no matter what the variable `<PROGRAM>_ACTIVE_HELP` is set to.
130+
131+
**Note 3**: If the user does not set `<PROGRAM>_ACTIVE_HELP` or `COBRA_ACTIVE_HELP` (which will be a common case), the default value for the Active Help configuration returned by `cobra.GetActiveHelpConfig(cmd)` will be the empty string.
132+
## Active Help with Cobra's default completion command
133+
134+
Cobra provides a default `completion` command for programs that wish to use it.
135+
When using the default `completion` command, Active Help is configurable in the same
136+
fashion as described above using environment variables. You may wish to document this in more
137+
details for your users.
138+
139+
## Debugging Active Help
140+
141+
Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra's hidden `__complete` command. Please refer to [debugging shell completion](shell_completions.md#debugging) for details.
142+
143+
When debugging with the `__complete` command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named `<PROGRAM>_ACTIVE_HELP` where any `-` is replaced by an `_`. For example, we can test deactivating some Active Help as shown below:
144+
```
145+
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
146+
bitnami/haproxy
147+
bitnami/harbor
148+
_activeHelp_ WARNING: cannot re-use a name that is still in use
149+
:0
150+
Completion ended with directive: ShellCompDirectiveDefault
151+
152+
$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
153+
bitnami/haproxy
154+
bitnami/harbor
155+
:0
156+
Completion ended with directive: ShellCompDirectiveDefault
157+
```

0 commit comments

Comments
 (0)