Skip to content

Commit f1f5ec6

Browse files
add external plugin arg filter funcs
change test of bindSpecificFlags from bindAllFlags Co-authored-by: Bryce Palmer <[email protected]>
1 parent 51e15c2 commit f1f5ec6

File tree

2 files changed

+147
-22
lines changed

2 files changed

+147
-22
lines changed

pkg/plugins/external/external_test.go

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,10 @@ func (m *mockValidMEOutputGetter) GetExecOutput(req []byte, path string) ([]byte
100100
return json.Marshal(response)
101101
}
102102

103-
const externalPlugin = "myexternalplugin.sh"
104-
const floatVal = "float"
103+
const (
104+
externalPlugin = "myexternalplugin.sh"
105+
floatVal = "float"
106+
)
105107

106108
var _ = Describe("Run external plugin using Scaffold", func() {
107109
Context("with valid mock values", func() {
@@ -136,7 +138,6 @@ var _ = Describe("Run external plugin using Scaffold", func() {
136138
Expect(err).To(BeNil())
137139

138140
args = []string{"--domain", "example.com"}
139-
140141
})
141142

142143
AfterEach(func() {
@@ -185,7 +186,6 @@ var _ = Describe("Run external plugin using Scaffold", func() {
185186
err = c.Scaffold(fs)
186187
Expect(err).To(BeNil())
187188
})
188-
189189
})
190190

191191
Context("with invalid mock values of GetExecOutput() and GetCurrentDir()", func() {
@@ -204,7 +204,6 @@ var _ = Describe("Run external plugin using Scaffold", func() {
204204

205205
pluginFileName = externalPlugin
206206
args = []string{"--domain", "example.com"}
207-
208207
})
209208

210209
It("should return error upon running init subcommand on the external plugin", func() {
@@ -241,7 +240,6 @@ var _ = Describe("Run external plugin using Scaffold", func() {
241240
err = e.Scaffold(fs)
242241
Expect(err).NotTo(BeNil())
243242
Expect(err.Error()).To(ContainSubstring("error getting current directory"))
244-
245243
})
246244

247245
It("should return error upon running create api subcommand on the external plugin", func() {
@@ -278,7 +276,6 @@ var _ = Describe("Run external plugin using Scaffold", func() {
278276
err = c.Scaffold(fs)
279277
Expect(err).NotTo(BeNil())
280278
Expect(err.Error()).To(ContainSubstring("error getting current directory"))
281-
282279
})
283280
})
284281

@@ -437,14 +434,50 @@ var _ = Describe("Run external plugin using Scaffold", func() {
437434

438435
checkFlagset()
439436
})
437+
})
440438

439+
Context("Flag Parsing Filter Functions", func() {
440+
It("gvk(Arg/Flag)Filter should filter out (--)group, (--)version, (--)kind", func() {
441+
for _, toBeFiltered := range []string{
442+
"group", "version", "kind",
443+
} {
444+
Expect(gvkArgFilter("--" + toBeFiltered)).To(BeFalse())
445+
Expect(gvkArgFilter(toBeFiltered)).To(BeFalse())
446+
Expect(gvkFlagFilter(external.Flag{Name: "--" + toBeFiltered})).To(BeFalse())
447+
Expect(gvkFlagFilter(external.Flag{Name: "--" + toBeFiltered})).To(BeFalse())
448+
}
449+
Expect(gvkArgFilter("somerandomflag")).To(BeTrue())
450+
Expect(gvkFlagFilter(external.Flag{Name: "somerandomflag"})).To(BeTrue())
451+
})
452+
453+
It("helpArgFilter should filter out (--)help", func() {
454+
Expect(helpArgFilter("--help")).To(BeFalse())
455+
Expect(helpArgFilter("help")).To(BeFalse())
456+
Expect(helpArgFilter("somerandomflag")).To(BeTrue())
457+
Expect(helpFlagFilter(external.Flag{Name: "--help"})).To(BeFalse())
458+
Expect(helpFlagFilter(external.Flag{Name: "help"})).To(BeFalse())
459+
Expect(helpFlagFilter(external.Flag{Name: "somerandomflag"})).To(BeTrue())
460+
})
441461
})
442462

443463
Context("Flag Parsing Helper Functions", func() {
444464
var (
445-
fs *pflag.FlagSet
446-
args = []string{"--domain", "something.com", "--boolean", "--another", "flag", "--help"}
447-
flags []external.Flag
465+
fs *pflag.FlagSet
466+
args = []string{
467+
"--domain", "something.com",
468+
"--boolean",
469+
"--another", "flag",
470+
"--help",
471+
"--group", "somegroup",
472+
"--kind", "somekind",
473+
"--version", "someversion",
474+
}
475+
forbidden = []string{
476+
"help", "group", "kind", "version",
477+
}
478+
flags []external.Flag
479+
argFilters []argFilterFunc
480+
externalFlagFilters []externalFlagFilterFunc
448481
)
449482

450483
BeforeEach(func() {
@@ -454,6 +487,13 @@ var _ = Describe("Run external plugin using Scaffold", func() {
454487

455488
flags = make([]external.Flag, len(flagsToAppend))
456489
copy(flags, flagsToAppend)
490+
491+
argFilters = []argFilterFunc{
492+
gvkArgFilter, helpArgFilter,
493+
}
494+
externalFlagFilters = []externalFlagFilterFunc{
495+
gvkFlagFilter, helpFlagFilter,
496+
}
457497
})
458498

459499
It("isBooleanFlag should return true if boolean flag provided at index", func() {
@@ -464,11 +504,11 @@ var _ = Describe("Run external plugin using Scaffold", func() {
464504
Expect(isBooleanFlag(0, args)).To(BeFalse())
465505
})
466506

467-
It("bindAllFlags should bind all flags except for `--help`", func() {
507+
It("bindAllFlags should bind all flags", func() {
468508
usage := "Kubebuilder could not validate this flag with the external plugin. " +
469509
"Consult the external plugin documentation for more information."
470510

471-
bindAllFlags(fs, args)
511+
bindAllFlags(fs, filterArgs(args, argFilters))
472512
Expect(fs.HasFlags()).To(BeTrue())
473513
Expect(fs.Lookup("domain")).NotTo(BeNil())
474514
Expect(fs.Lookup("domain").Value.Type()).To(Equal("string"))
@@ -479,15 +519,20 @@ var _ = Describe("Run external plugin using Scaffold", func() {
479519
Expect(fs.Lookup("another")).NotTo(BeNil())
480520
Expect(fs.Lookup("another").Value.Type()).To(Equal("string"))
481521
Expect(fs.Lookup("another").Usage).To(Equal(usage))
482-
Expect(fs.Lookup("help")).To(BeNil())
522+
523+
By("bindAllFlags not have bound any forbidden flag after filtering")
524+
for i := range forbidden {
525+
Expect(fs.Lookup(forbidden[i])).To(BeNil())
526+
}
483527
})
484528

485529
It("bindSpecificFlags should bind all flags in given []Flag", func() {
486-
bindSpecificFlags(fs, flags)
530+
filteredFlags := filterFlags(flags, externalFlagFilters)
531+
bindSpecificFlags(fs, filteredFlags)
487532

488533
Expect(fs.HasFlags()).To(BeTrue())
489534

490-
for _, flag := range flags {
535+
for _, flag := range filteredFlags {
491536
Expect(fs.Lookup(flag.Name)).NotTo(BeNil())
492537
// we parse floats as float64 Go type so this check will account for that
493538
if flag.Type != floatVal {
@@ -498,6 +543,11 @@ var _ = Describe("Run external plugin using Scaffold", func() {
498543
Expect(fs.Lookup(flag.Name).Usage).To(Equal(flag.Usage))
499544
Expect(fs.Lookup(flag.Name).DefValue).To(Equal(flag.Default))
500545
}
546+
547+
By("bindSpecificFlags not have bound any forbidden flag after filtering")
548+
for i := range forbidden {
549+
Expect(fs.Lookup(forbidden[i])).To(BeNil())
550+
}
501551
})
502552
})
503553

@@ -629,7 +679,6 @@ var _ = Describe("Run external plugin using Scaffold", func() {
629679
checkMetadata()
630680
})
631681
})
632-
633682
})
634683

635684
func getFlags() []external.Flag {

pkg/plugins/external/helpers.go

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,7 @@ func bindAllFlags(fs *pflag.FlagSet, args []string) {
166166
flag := strings.Replace(args[i], "--", "", 1)
167167
// Check if the flag is a boolean flag
168168
if isBooleanFlag(i, args) {
169-
// --help is already a defined flag in the kubebuilder commands and has a description so we skip parsing it again
170-
if flag != "help" {
171-
_ = fs.Bool(flag, false, defaultFlagDescription)
172-
}
169+
_ = fs.Bool(flag, false, defaultFlagDescription)
173170
} else {
174171
_ = fs.String(flag, "", defaultFlagDescription)
175172
}
@@ -197,6 +194,75 @@ func bindSpecificFlags(fs *pflag.FlagSet, flags []external.Flag) {
197194
}
198195
}
199196

197+
func filterFlags(flags []external.Flag, externalFlagFilters []externalFlagFilterFunc) []external.Flag {
198+
filteredFlags := []external.Flag{}
199+
for _, flag := range flags {
200+
ok := true
201+
for _, filter := range externalFlagFilters {
202+
if !filter(flag) {
203+
ok = false
204+
break
205+
}
206+
}
207+
if ok {
208+
filteredFlags = append(filteredFlags, flag)
209+
}
210+
}
211+
return filteredFlags
212+
}
213+
214+
func filterArgs(args []string, argFilters []argFilterFunc) []string {
215+
filteredArgs := []string{}
216+
for _, arg := range args {
217+
ok := true
218+
for _, filter := range argFilters {
219+
if !filter(arg) {
220+
ok = false
221+
break
222+
}
223+
}
224+
if ok {
225+
filteredArgs = append(filteredArgs, arg)
226+
}
227+
}
228+
return filteredArgs
229+
}
230+
231+
type (
232+
externalFlagFilterFunc func(flag external.Flag) bool
233+
argFilterFunc func(arg string) bool
234+
)
235+
236+
var (
237+
// see gvkArgFilter
238+
gvkFlagFilter = func(flag external.Flag) bool {
239+
return gvkArgFilter(flag.Name)
240+
}
241+
// gvkFlagFilter filters out any flag named "group", "version", "kind" as
242+
// they are already bound by kubebuilder
243+
gvkArgFilter = func(arg string) bool {
244+
arg = strings.Replace(arg, "--", "", 1)
245+
for _, invalidFlagName := range []string{
246+
"group", "version", "kind",
247+
} {
248+
if arg == invalidFlagName {
249+
return false
250+
}
251+
}
252+
return true
253+
}
254+
255+
// see helpArgFilter
256+
helpFlagFilter = func(flag external.Flag) bool {
257+
return helpArgFilter(flag.Name)
258+
}
259+
// helpArgFilter filters out any flag named "help" as its already bound
260+
helpArgFilter = func(arg string) bool {
261+
arg = strings.Replace(arg, "--", "", 1)
262+
return !(arg == "help")
263+
}
264+
)
265+
200266
func bindExternalPluginFlags(fs *pflag.FlagSet, subcommand string, path string, args []string) {
201267
req := external.PluginRequest{
202268
APIVersion: defaultAPIVersion,
@@ -208,10 +274,20 @@ func bindExternalPluginFlags(fs *pflag.FlagSet, subcommand string, path string,
208274
// If it returns an error, parse all flags passed by the user and let
209275
// the external plugin return an unknown flag error.
210276
flags, err := getExternalPluginFlags(req, path)
277+
278+
// Filter Flags based on a set of filters that we do not want.
279+
// can be used to filter out non-overridable flags or other
280+
// criteria by creating your own filterFlagFunc
211281
if err != nil {
212-
bindAllFlags(fs, args)
282+
bindAllFlags(fs, filterArgs(args, []argFilterFunc{
283+
gvkArgFilter,
284+
helpArgFilter,
285+
}))
213286
} else {
214-
bindSpecificFlags(fs, flags)
287+
bindSpecificFlags(fs, filterFlags(flags, []externalFlagFilterFunc{
288+
gvkFlagFilter,
289+
helpFlagFilter,
290+
}))
215291
}
216292
}
217293

0 commit comments

Comments
 (0)