mirror of
https://github.com/spf13/cobra
synced 2025-06-04 03:27:17 +00:00
Compare commits
16 commits
Author | SHA1 | Date | |
---|---|---|---|
|
6dec1ae266 | ||
|
c8289c1030 | ||
|
4af7b64d31 | ||
|
75790e48fb | ||
|
db3ddb5cf4 | ||
|
67171d6909 | ||
|
0ed70dcfd4 | ||
|
0846d166ee | ||
|
73f7846ba9 | ||
|
ba5108a470 | ||
|
ceb39aba25 | ||
|
c25b598345 | ||
|
4f9ef8cdbb | ||
|
1995054b00 | ||
|
f98cf4216d | ||
|
0d417d8f77 |
14 changed files with 295 additions and 69 deletions
.github/workflows
.golangci.ymlREADME.mdSECURITY.mdcommand.gocommand_test.gocompletions.gocompletions_test.godoc
site/content/completions
33
.github/workflows/size-labeler.yml
vendored
33
.github/workflows/size-labeler.yml
vendored
|
@ -1,33 +0,0 @@
|
|||
# Reference: https://github.com/CodelyTV/pr-size-labeler
|
||||
|
||||
name: size-labeler
|
||||
|
||||
on: [pull_request_target]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
size-labeler:
|
||||
permissions:
|
||||
pull-requests: write # for codelytv/pr-size-labeler to add labels & comment on PRs
|
||||
runs-on: ubuntu-latest
|
||||
name: Label the PR size
|
||||
steps:
|
||||
- uses: codelytv/pr-size-labeler@v1.8.1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
xs_label: 'size/XS'
|
||||
xs_max_size: '10'
|
||||
s_label: 'size/S'
|
||||
s_max_size: '24'
|
||||
m_label: 'size/M'
|
||||
m_max_size: '99'
|
||||
l_label: 'size/L'
|
||||
l_max_size: '200'
|
||||
xl_label: 'size/XL'
|
||||
fail_if_xl: 'false'
|
||||
message_if_xl: >
|
||||
'This PR exceeds the recommended size of 200 lines.
|
||||
Please make sure you are NOT addressing multiple issues with one PR.
|
||||
Note this PR might be rejected due to its size.’
|
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
|
@ -47,7 +47,7 @@ jobs:
|
|||
check-latest: true
|
||||
cache: true
|
||||
|
||||
- uses: golangci/golangci-lint-action@v4.0.0
|
||||
- uses: golangci/golangci-lint-action@v8.0.0
|
||||
with:
|
||||
version: latest
|
||||
args: --verbose
|
||||
|
@ -68,6 +68,7 @@ jobs:
|
|||
- 21
|
||||
- 22
|
||||
- 23
|
||||
- 24
|
||||
name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x'
|
||||
runs-on: ${{ matrix.platform }}-latest
|
||||
steps:
|
||||
|
|
|
@ -12,14 +12,20 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
deadline: 5m
|
||||
timeout: 5m
|
||||
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
default: none
|
||||
enable:
|
||||
#- bodyclose
|
||||
# - deadcode ! deprecated since v1.49.0; replaced by 'unused'
|
||||
#- depguard
|
||||
#- dogsled
|
||||
#- dupl
|
||||
|
@ -30,28 +36,24 @@ linters:
|
|||
- goconst
|
||||
- gocritic
|
||||
#- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
#- gomnd
|
||||
#- goprintffuncname
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
#- lll
|
||||
- misspell
|
||||
#- mnd
|
||||
#- nakedret
|
||||
#- noctx
|
||||
- nolintlint
|
||||
#- rowserrcheck
|
||||
#- scopelint
|
||||
- staticcheck
|
||||
#- structcheck ! deprecated since v1.49.0; replaced by 'unused'
|
||||
- stylecheck
|
||||
#- typecheck
|
||||
- unconvert
|
||||
#- unparam
|
||||
- unused
|
||||
# - varcheck ! deprecated since v1.49.0; replaced by 'unused'
|
||||
#- whitespace
|
||||
fast: false
|
||||
exclusions:
|
||||
presets:
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
|
|
14
README.md
14
README.md
|
@ -11,6 +11,20 @@ name a few. [This list](site/content/projects_using_cobra.md) contains a more ex
|
|||
[](https://pkg.go.dev/github.com/spf13/cobra)
|
||||
[](https://goreportcard.com/report/github.com/spf13/cobra)
|
||||
[](https://gophers.slack.com/archives/CD3LP1199)
|
||||
<hr>
|
||||
<div align="center" markdown="1">
|
||||
<sup>Supported by:</sup>
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://www.warp.dev/cobra">
|
||||
<img alt="Warp sponsorship" width="400" src="https://github.com/user-attachments/assets/ab8dd143-b0fd-4904-bdc5-dd7ecac94eae">
|
||||
</a>
|
||||
|
||||
### [Warp, the AI terminal for devs](https://www.warp.dev/cobra)
|
||||
[Try Cobra in Warp today](https://www.warp.dev/cobra)<br>
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
# Overview
|
||||
|
||||
|
|
105
SECURITY.md
Normal file
105
SECURITY.md
Normal file
|
@ -0,0 +1,105 @@
|
|||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
The `cobra` maintainers take security issues seriously and
|
||||
we appreciate your efforts to _**responsibly**_ disclose your findings.
|
||||
We will make every effort to swiftly respond and address concerns.
|
||||
|
||||
To report a security vulnerability:
|
||||
|
||||
1. **DO NOT** create a public GitHub issue for the vulnerability!
|
||||
2. **DO NOT** create a public GitHub Pull Request with a fix for the vulnerability!
|
||||
3. Send an email to `cobra-security@googlegroups.com`.
|
||||
4. Include the following details in your report:
|
||||
- Description of the vulnerability
|
||||
- Steps to reproduce
|
||||
- Potential impact of the vulnerability (to your downstream project, to the Go ecosystem, etc.)
|
||||
- Any potential mitigations you've already identified
|
||||
5. Allow up to 7 days for an initial response.
|
||||
You should receive an acknowledgment of your report and an estimated timeline for a fix.
|
||||
6. (Optional) If you have a fix and would like to contribute your patch, please work
|
||||
directly with the maintainers via `cobra-security@googlegroups.com` to
|
||||
coordinate pushing the patch to GitHub, cutting a new release, and disclosing the change.
|
||||
|
||||
## Response Process
|
||||
|
||||
When a security vulnerability report is received, the `cobra` maintainers will:
|
||||
|
||||
1. Confirm receipt of the vulnerability report within 7 days.
|
||||
2. Assess the report to determine if it constitutes a security vulnerability.
|
||||
3. If confirmed, assign the vulnerability a severity level and create a timeline for addressing it.
|
||||
4. Develop and test a fix.
|
||||
5. Patch the vulnerability and make a new GitHub release: the maintainers will coordinate disclosure with the reporter.
|
||||
6. Create a new GitHub Security Advisory to inform the broader Go ecosystem
|
||||
|
||||
## Disclosure Policy
|
||||
|
||||
The `cobra` maintainers follow a coordinated disclosure process:
|
||||
|
||||
1. Security vulnerabilities will be addressed as quickly as possible.
|
||||
2. A CVE (Common Vulnerabilities and Exposures) identifier will be requested for significant vulnerabilities
|
||||
that are within `cobra` itself.
|
||||
3. Once a fix is ready, the maintainers will:
|
||||
- Release a new version containing the fix.
|
||||
- Update the security advisory with details about the vulnerability.
|
||||
- Credit the reporter (unless they wish to remain anonymous).
|
||||
- Credit the fixer (unless they wish to remain anonymous, this may be the same as the reporter).
|
||||
- Announce the vulnerability through appropriate channels
|
||||
(GitHub Security Advisory, mailing lists, GitHub Releases, etc.)
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Security fixes will typically only be released for the most recent major release.
|
||||
|
||||
## Upstream Security Issues
|
||||
|
||||
`cobra` generally will not accept vulnerability reports that originate in upstream
|
||||
dependencies. I.e., if there is a problem in Go code that `cobra` depends on,
|
||||
it is best to engage that project's maintainers and owners.
|
||||
|
||||
This security policy primarily pertains only to `cobra` itself but if you believe you've
|
||||
identified a problem that originates in an upstream dependency and is being widely
|
||||
distributed by `cobra`, please follow the disclosure procedure above: the `cobra`
|
||||
maintainers will work with you to determine the severity and ecosystem impact.
|
||||
|
||||
## Security Updates and CVEs
|
||||
|
||||
Information about known security vulnerabilities and CVEs affecting `cobra` will
|
||||
be published as GitHub Security Advisories at
|
||||
https://github.com/spf13/cobra/security/advisories.
|
||||
|
||||
All users are encouraged to watch the repository and upgrade promptly when
|
||||
security releases are published.
|
||||
|
||||
## `cobra` Security Best Practices for Users
|
||||
|
||||
When using `cobra` in your CLIs, the `cobra` maintainers recommend the following:
|
||||
|
||||
1. Always use the latest version of `cobra`.
|
||||
2. [Use Go modules](https://go.dev/blog/using-go-modules) for dependency management.
|
||||
3. Always use the latest possible version of Go.
|
||||
|
||||
## Security Best Practices for Contributors
|
||||
|
||||
When contributing to `cobra`:
|
||||
|
||||
1. Be mindful of security implications when adding new features or modifying existing ones.
|
||||
2. Be aware of `cobra`'s extremely large reach: it is used in nearly every Go CLI
|
||||
(like Kubernetes, Docker, Prometheus, etc. etc.)
|
||||
3. Write tests that explicitly cover edge cases and potential issues.
|
||||
4. If you discover a security issue while working on `cobra`, please report it
|
||||
following the process above rather than opening a public pull request or issue that
|
||||
addresses the vulnerability.
|
||||
5. Take personal sec-ops seriously and secure your GitHub account: use [two-factor authentication](https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa),
|
||||
[sign your commits with a GPG or SSH key](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification),
|
||||
etc.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
The `cobra` maintainers would like to thank all security researchers and
|
||||
community members who help keep cobra, its users, and the entire Go ecosystem secure through responsible disclosures!!
|
||||
|
||||
---
|
||||
|
||||
*This security policy is inspired by the [Open Web Application Security Project (OWASP)](https://owasp.org/) guidelines and security best practices.*
|
|
@ -1296,6 +1296,11 @@ Simply type ` + c.DisplayName() + ` help [path to command] for full details.`,
|
|||
c.Printf("Unknown help topic %#q\n", args)
|
||||
CheckErr(c.Root().Usage())
|
||||
} else {
|
||||
// FLow the context down to be used in help text
|
||||
if cmd.ctx == nil {
|
||||
cmd.ctx = c.ctx
|
||||
}
|
||||
|
||||
cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
|
||||
cmd.InitDefaultVersionFlag() // make possible 'version' flag to be shown
|
||||
CheckErr(cmd.Help())
|
||||
|
@ -2020,7 +2025,7 @@ func defaultUsageFunc(w io.Writer, in interface{}) error {
|
|||
fmt.Fprint(w, trimRightSpace(c.InheritedFlags().FlagUsages()))
|
||||
}
|
||||
if c.HasHelpSubCommands() {
|
||||
fmt.Fprintf(w, "\n\nAdditional help topcis:")
|
||||
fmt.Fprintf(w, "\n\nAdditional help topics:")
|
||||
for _, subcmd := range c.Commands() {
|
||||
if subcmd.IsAdditionalHelpTopicCommand() {
|
||||
fmt.Fprintf(w, "\n %s %s", rpad(subcmd.CommandPath(), subcmd.CommandPathPadding()), subcmd.Short)
|
||||
|
|
|
@ -2921,3 +2921,34 @@ func TestUnknownFlagShouldReturnSameErrorRegardlessOfArgPosition(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelpFuncExecuted(t *testing.T) {
|
||||
helpText := "Long description"
|
||||
|
||||
// Create a context that will be unique, not just the background context
|
||||
//nolint:staticcheck // We can safely use a basic type as key in tests.
|
||||
executionCtx := context.WithValue(context.Background(), "testKey", "123")
|
||||
|
||||
child := &Command{Use: "child", Run: emptyRun}
|
||||
child.SetHelpFunc(func(cmd *Command, args []string) {
|
||||
_, err := cmd.OutOrStdout().Write([]byte(helpText))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Test for https://github.com/spf13/cobra/issues/2240
|
||||
if cmd.Context() != executionCtx {
|
||||
t.Error("Context doesn't equal the execution context")
|
||||
}
|
||||
})
|
||||
|
||||
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
output, err := executeCommandWithContext(executionCtx, rootCmd, "help", "child")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
checkStringContains(t, output, helpText)
|
||||
}
|
||||
|
|
|
@ -115,6 +115,13 @@ type CompletionOptions struct {
|
|||
DisableDescriptions bool
|
||||
// HiddenDefaultCmd makes the default 'completion' command hidden
|
||||
HiddenDefaultCmd bool
|
||||
// DefaultShellCompDirective sets the ShellCompDirective that is returned
|
||||
// if no special directive can be determined
|
||||
DefaultShellCompDirective *ShellCompDirective
|
||||
}
|
||||
|
||||
func (receiver *CompletionOptions) SetDefaultShellCompDirective(directive ShellCompDirective) {
|
||||
receiver.DefaultShellCompDirective = &directive
|
||||
}
|
||||
|
||||
// Completion is a string that can be used for completions
|
||||
|
@ -375,7 +382,7 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo
|
|||
// Error while attempting to parse flags
|
||||
if flagErr != nil {
|
||||
// If error type is flagCompError and we don't want flagCompletion we should ignore the error
|
||||
if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) {
|
||||
if _, ok := flagErr.(*flagCompError); !ok || flagCompletion {
|
||||
return finalCmd, []Completion{}, ShellCompDirectiveDefault, flagErr
|
||||
}
|
||||
}
|
||||
|
@ -480,6 +487,14 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo
|
|||
}
|
||||
} else {
|
||||
directive = ShellCompDirectiveDefault
|
||||
// check current and parent commands for a custom DefaultShellCompDirective
|
||||
for cmd := finalCmd; cmd != nil; cmd = cmd.parent {
|
||||
if cmd.CompletionOptions.DefaultShellCompDirective != nil {
|
||||
directive = *cmd.CompletionOptions.DefaultShellCompDirective
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if flag == nil {
|
||||
foundLocalNonPersistentFlag := false
|
||||
// If TraverseChildren is true on the root command we don't check for
|
||||
|
@ -773,7 +788,7 @@ See each sub-command's help for details on how to use the generated script.
|
|||
// shell completion for it (prog __complete completion '')
|
||||
subCmd, cmdArgs, err := c.Find(args)
|
||||
if err != nil || subCmd.Name() != compCmdName &&
|
||||
!(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) {
|
||||
(subCmd.Name() != ShellCompRequestCmd || len(cmdArgs) <= 1 || cmdArgs[0] != compCmdName) {
|
||||
// The completion command is not being called or being completed so we remove it.
|
||||
c.RemoveCommand(completionCmd)
|
||||
return
|
||||
|
|
|
@ -1297,7 +1297,7 @@ func TestValidArgsFuncCmdContext(t *testing.T) {
|
|||
}
|
||||
rootCmd.AddCommand(childCmd)
|
||||
|
||||
//nolint:golint,staticcheck // We can safely use a basic type as key in tests.
|
||||
//nolint:staticcheck // We can safely use a basic type as key in tests.
|
||||
ctx := context.WithValue(context.Background(), "testKey", "123")
|
||||
|
||||
// Test completing an empty string on the childCmd
|
||||
|
@ -2899,7 +2899,7 @@ func TestCompletionFuncCompatibility(t *testing.T) {
|
|||
var userComp func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
|
||||
|
||||
// check against new signature
|
||||
var _ CompletionFunc = userComp
|
||||
var _ CompletionFunc = userComp //nolint:staticcheck // LHS type is needed for this use case
|
||||
|
||||
// check Command accepts
|
||||
cmd := Command{
|
||||
|
@ -2913,8 +2913,7 @@ func TestCompletionFuncCompatibility(t *testing.T) {
|
|||
var userComp func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective)
|
||||
|
||||
// check against new signature
|
||||
var _ CompletionFunc = userComp
|
||||
|
||||
var _ CompletionFunc = userComp //nolint:staticcheck // LHS type is needed for this use case
|
||||
// check Command accepts
|
||||
cmd := Command{
|
||||
ValidArgsFunction: userComp,
|
||||
|
@ -2927,8 +2926,8 @@ func TestCompletionFuncCompatibility(t *testing.T) {
|
|||
var userComp CompletionFunc
|
||||
|
||||
// check helper against old signature
|
||||
var _ func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) = userComp
|
||||
var _ func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) = userComp
|
||||
var _ func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) = userComp //nolint:staticcheck // LHS type is needed for this use case
|
||||
var _ func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) = userComp //nolint:staticcheck // LHS type is needed for this use case
|
||||
|
||||
// check Command accepts
|
||||
cmd := Command{
|
||||
|
@ -2967,7 +2966,7 @@ func TestCompletionFuncCompatibility(t *testing.T) {
|
|||
var userComp UserCompletionTypeAliasHelper
|
||||
|
||||
// Here we are validating the existing type validates the CompletionFunc type
|
||||
var _ CompletionFunc = userComp
|
||||
var _ CompletionFunc = userComp //nolint:staticcheck // LHS type is needed for this use case
|
||||
|
||||
cmd := Command{
|
||||
ValidArgsFunction: userComp,
|
||||
|
@ -4016,3 +4015,60 @@ func TestInitDefaultCompletionCmd(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomDefaultShellCompDirective(t *testing.T) {
|
||||
rootCmd := &Command{Use: "root", Run: emptyRun}
|
||||
rootCmd.PersistentFlags().String("string", "", "test string flag")
|
||||
// use ShellCompDirectiveNoFileComp instead of the default, which is ShellCompDirectiveDefault.
|
||||
rootCmd.CompletionOptions.SetDefaultShellCompDirective(ShellCompDirectiveNoFileComp)
|
||||
|
||||
// child1 inherits the custom DefaultShellCompDirective.
|
||||
childCmd1 := &Command{Use: "child1", Run: emptyRun}
|
||||
// child2 resets the custom DefaultShellCompDirective to the default value.
|
||||
childCmd2 := &Command{Use: "child2", Run: emptyRun}
|
||||
childCmd2.CompletionOptions.SetDefaultShellCompDirective(ShellCompDirectiveDefault)
|
||||
|
||||
rootCmd.AddCommand(childCmd1, childCmd2)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
expectedDirective string
|
||||
}{
|
||||
{
|
||||
"flag completion on root command with custom DefaultShellCompDirective",
|
||||
[]string{"--string", ""},
|
||||
"ShellCompDirectiveNoFileComp",
|
||||
},
|
||||
{
|
||||
"flag completion on subcommand with inherited custom DefaultShellCompDirective",
|
||||
[]string{"child1", "--string", ""},
|
||||
"ShellCompDirectiveNoFileComp",
|
||||
},
|
||||
{
|
||||
"flag completion on subcommand with reset DefaultShellCompDirective",
|
||||
[]string{"child2", "--string", ""},
|
||||
"ShellCompDirectiveDefault",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
args := []string{ShellCompNoDescRequestCmd}
|
||||
args = append(args, tc.args...)
|
||||
|
||||
output, err := executeCommand(rootCmd, args...)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
outputWords := strings.Split(strings.TrimSpace(output), " ")
|
||||
directive := outputWords[len(outputWords)-1]
|
||||
|
||||
if directive != tc.expectedDirective {
|
||||
t.Errorf("expected: %q, got: %q", tc.expectedDirective, directive)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
|
|||
manPrintOptions(buf, cmd)
|
||||
if len(cmd.Example) > 0 {
|
||||
buf.WriteString("# EXAMPLE\n")
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n", cmd.Example))
|
||||
fmt.Fprintf(buf, "```\n%s\n```\n", cmd.Example)
|
||||
}
|
||||
if hasSeeAlso(cmd) {
|
||||
buf.WriteString("# SEE ALSO\n")
|
||||
|
@ -240,7 +240,7 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
|
|||
buf.WriteString(strings.Join(seealsos, ", ") + "\n")
|
||||
}
|
||||
if !cmd.DisableAutoGenTag {
|
||||
buf.WriteString(fmt.Sprintf("# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006")))
|
||||
fmt.Fprintf(buf, "# HISTORY\n%s Auto generated by spf13/cobra\n", header.Date.Format("2-Jan-2006"))
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
|
|
@ -69,12 +69,12 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
|
|||
}
|
||||
|
||||
if cmd.Runnable() {
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
|
||||
fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.UseLine())
|
||||
}
|
||||
|
||||
if len(cmd.Example) > 0 {
|
||||
buf.WriteString("### Examples\n\n")
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
|
||||
fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.Example)
|
||||
}
|
||||
|
||||
if err := printOptions(buf, cmd, name); err != nil {
|
||||
|
@ -87,7 +87,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
|
|||
pname := parent.CommandPath()
|
||||
link := pname + markdownExtension
|
||||
link = strings.ReplaceAll(link, " ", "_")
|
||||
buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short))
|
||||
fmt.Fprintf(buf, "* [%s](%s)\t - %s\n", pname, linkHandler(link), parent.Short)
|
||||
cmd.VisitParents(func(c *cobra.Command) {
|
||||
if c.DisableAutoGenTag {
|
||||
cmd.DisableAutoGenTag = c.DisableAutoGenTag
|
||||
|
@ -105,7 +105,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
|
|||
cname := name + " " + child.Name()
|
||||
link := cname + markdownExtension
|
||||
link = strings.ReplaceAll(link, " ", "_")
|
||||
buf.WriteString(fmt.Sprintf("* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short))
|
||||
fmt.Fprintf(buf, "* [%s](%s)\t - %s\n", cname, linkHandler(link), child.Short)
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
|
|
@ -82,13 +82,13 @@ func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, str
|
|||
buf.WriteString("\n" + long + "\n\n")
|
||||
|
||||
if cmd.Runnable() {
|
||||
buf.WriteString(fmt.Sprintf("::\n\n %s\n\n", cmd.UseLine()))
|
||||
fmt.Fprintf(buf, "::\n\n %s\n\n", cmd.UseLine())
|
||||
}
|
||||
|
||||
if len(cmd.Example) > 0 {
|
||||
buf.WriteString("Examples\n")
|
||||
buf.WriteString("~~~~~~~~\n\n")
|
||||
buf.WriteString(fmt.Sprintf("::\n\n%s\n\n", indentString(cmd.Example, " ")))
|
||||
fmt.Fprintf(buf, "::\n\n%s\n\n", indentString(cmd.Example, " "))
|
||||
}
|
||||
|
||||
if err := printOptionsReST(buf, cmd, name); err != nil {
|
||||
|
@ -101,7 +101,7 @@ func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, str
|
|||
parent := cmd.Parent()
|
||||
pname := parent.CommandPath()
|
||||
ref = strings.ReplaceAll(pname, " ", "_")
|
||||
buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(pname, ref), parent.Short))
|
||||
fmt.Fprintf(buf, "* %s \t - %s\n", linkHandler(pname, ref), parent.Short)
|
||||
cmd.VisitParents(func(c *cobra.Command) {
|
||||
if c.DisableAutoGenTag {
|
||||
cmd.DisableAutoGenTag = c.DisableAutoGenTag
|
||||
|
@ -118,7 +118,7 @@ func GenReSTCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string, str
|
|||
}
|
||||
cname := name + " " + child.Name()
|
||||
ref = strings.ReplaceAll(cname, " ", "_")
|
||||
buf.WriteString(fmt.Sprintf("* %s \t - %s\n", linkHandler(cname, ref), child.Short))
|
||||
fmt.Fprintf(buf, "* %s \t - %s\n", linkHandler(cname, ref), child.Short)
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ func genFlagResult(flags *pflag.FlagSet) []cmdOption {
|
|||
// Todo, when we mark a shorthand is deprecated, but specify an empty message.
|
||||
// The flag.ShorthandDeprecated is empty as the shorthand is deprecated.
|
||||
// Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok.
|
||||
if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 {
|
||||
if len(flag.ShorthandDeprecated) == 0 && len(flag.Shorthand) > 0 {
|
||||
opt := cmdOption{
|
||||
flag.Name,
|
||||
flag.Shorthand,
|
||||
|
|
|
@ -260,7 +260,7 @@ Calling the `__complete` command directly allows you to run the Go debugger to t
|
|||
```go
|
||||
// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
|
||||
// is set to a file path) and optionally prints to stderr.
|
||||
cobra.CompDebug(msg string, printToStdErr bool) {
|
||||
cobra.CompDebug(msg string, printToStdErr bool)
|
||||
cobra.CompDebugln(msg string, printToStdErr bool)
|
||||
|
||||
// Prints to the completion script debug file (if BASH_COMP_DEBUG_FILE
|
||||
|
@ -305,6 +305,36 @@ $ helm status --output [tab][tab]
|
|||
json table yaml
|
||||
```
|
||||
|
||||
#### Change the default ShellCompDirective
|
||||
|
||||
When no completion function is registered for a leaf command or for a flag, Cobra will
|
||||
automatically use `ShellCompDirectiveDefault`, which will invoke the shell's filename completion.
|
||||
This implies that when file completion does not apply to a leaf command or to a flag (the command
|
||||
or flag does not operate on a filename), turning off file completion requires you to register a
|
||||
completion function for that command/flag.
|
||||
For example:
|
||||
|
||||
```go
|
||||
cmd.RegisterFlagCompletionFunc("flag-name", cobra.NoFileCompletions)
|
||||
```
|
||||
|
||||
If you find that there are more situations where file completion should be turned off than
|
||||
when it is applicable, you can recursively change the default `ShellCompDirective` for a command
|
||||
and its subcommands to `ShellCompDirectiveNoFileComp`:
|
||||
|
||||
```go
|
||||
cmd.CompletionOptions.SetDefaultShellCompDirective(ShellCompDirectiveNoFileComp)
|
||||
```
|
||||
|
||||
If doing so, keep in mind that you should instead register a completion function for leaf commands or
|
||||
flags where file completion is applicable. For example:
|
||||
|
||||
```go
|
||||
cmd.RegisterFlagCompletionFunc("flag-name", cobra.FixedCompletions(nil, ShellCompDirectiveDefault))
|
||||
```
|
||||
|
||||
To change the default directive for the entire program, set the DefaultShellCompDirective on the root command.
|
||||
|
||||
#### Debugging
|
||||
|
||||
You can also easily debug your Go completion code for flags:
|
||||
|
|
Loading…
Add table
Reference in a new issue