Added a small utility method to display warnings when parsing command arguments. (#16441)

* Added a small utility method to display warnings when parsing command arguments

Will print warning if flag is passed after arguments e.g.
vault <command> -a b -c
In this example -c will be interpreted as an argument which may be misleading
This commit is contained in:
Max Coulombe 2022-07-27 14:00:03 -04:00 committed by GitHub
parent 1b1c6fe168
commit aa3e1c8a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 3 deletions

3
changelog/16441.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
cli: CLI commands will print a warning if flags will be ignored because they are passed after positional arguments.
```

View File

@ -549,6 +549,7 @@ type FlagSets struct {
mainSet *flag.FlagSet mainSet *flag.FlagSet
hiddens map[string]struct{} hiddens map[string]struct{}
completions complete.Flags completions complete.Flags
ui cli.Ui
} }
// NewFlagSets creates a new flag sets. // NewFlagSets creates a new flag sets.
@ -564,6 +565,7 @@ func NewFlagSets(ui cli.Ui) *FlagSets {
mainSet: mainSet, mainSet: mainSet,
hiddens: make(map[string]struct{}), hiddens: make(map[string]struct{}),
completions: complete.Flags{}, completions: complete.Flags{},
ui: ui,
} }
} }
@ -582,8 +584,16 @@ func (f *FlagSets) Completions() complete.Flags {
} }
// Parse parses the given flags, returning any errors. // Parse parses the given flags, returning any errors.
// Warnings, if any, regarding the arguments format are sent to stdout
func (f *FlagSets) Parse(args []string) error { func (f *FlagSets) Parse(args []string) error {
return f.mainSet.Parse(args) err := f.mainSet.Parse(args)
warnings := generateFlagWarnings(f.Args())
if warnings != "" {
f.ui.Warn(warnings)
}
return err
} }
// Parsed reports whether the command-line flags have been parsed. // Parsed reports whether the command-line flags have been parsed.
@ -603,10 +613,10 @@ func (f *FlagSets) Visit(fn func(*flag.Flag)) {
} }
// Help builds custom help for this command, grouping by flag set. // Help builds custom help for this command, grouping by flag set.
func (fs *FlagSets) Help() string { func (f *FlagSets) Help() string {
var out bytes.Buffer var out bytes.Buffer
for _, set := range fs.flagSets { for _, set := range f.flagSets {
printFlagTitle(&out, set.name+":") printFlagTitle(&out, set.name+":")
set.VisitAll(func(f *flag.Flag) { set.VisitAll(func(f *flag.Flag) {
// Skip any hidden flags // Skip any hidden flags

View File

@ -292,3 +292,19 @@ func parseFlagFile(raw string) (string, error) {
return raw, nil return raw, nil
} }
func generateFlagWarnings(args []string) string {
var trailingFlags []string
for _, arg := range args {
if strings.HasPrefix(arg, "-") {
trailingFlags = append(trailingFlags, arg)
}
}
if len(trailingFlags) > 0 {
return fmt.Sprintf("Flags must be provided before positional arguments. "+
"The following arguments will not be parsed as flags: [%s]", strings.Join(trailingFlags, ","))
} else {
return ""
}
}

View File

@ -5,6 +5,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"testing" "testing"
"time" "time"
) )
@ -209,3 +210,48 @@ func TestParseFlagFile(t *testing.T) {
}) })
} }
} }
func TestArgWarnings(t *testing.T) {
t.Parallel()
cases := []struct {
args []string
expected string
}{
{
[]string{"a", "b", "c"},
"",
},
{
[]string{"a", "-b"},
"-b",
},
{
[]string{"a", "--b"},
"--b",
},
{
[]string{"a-b", "-c"},
"-c",
},
{
[]string{"a", "-b-c"},
"-b-c",
},
{
[]string{"-a", "b"},
"-a",
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.expected, func(t *testing.T) {
warnings := generateFlagWarnings(tc.args)
if !strings.Contains(warnings, tc.expected) {
t.Fatalf("expected %s to contain %s", warnings, tc.expected)
}
})
}
}