From ac2cfd7813ba00ff8a7a4763043b94ce364e9ddf Mon Sep 17 00:00:00 2001 From: Luc DUZAN Date: Mon, 3 Feb 2025 15:18:01 +0100 Subject: [PATCH] improve flags regeneration --- cmd/get.go | 7 ++- cmd/multiple_flags.go | 86 ++++++++++++++++++++++++++++++ cmd/multiple_flags_test.go | 104 +++++++++++++++++++++++++++++++++++++ cmd/run.go | 12 ++--- cmd/utils.go | 84 ------------------------------ cmd/utils_test.go | 53 ------------------- 6 files changed, 199 insertions(+), 147 deletions(-) create mode 100644 cmd/multiple_flags.go create mode 100644 cmd/multiple_flags_test.go delete mode 100644 cmd/utils.go delete mode 100644 cmd/utils_test.go diff --git a/cmd/get.go b/cmd/get.go index 772b679..b433bd7 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -146,10 +146,9 @@ func initGet(kinds schema.KindCatalog) { } parentFlags := kind.GetParentFlag() parentQueryFlags := kind.GetParentQueryFlag() - listFlags := kind.GetListFlag() parentFlagValue := make([]*string, len(parentFlags)) parentQueryFlagValue := make([]*string, len(parentQueryFlags)) - listFlagValue := make(map[string]interface{}, len(listFlags)) + var multipleFlags *MultipleFlags kindCmd := &cobra.Command{ Use: use, Short: "Get resource of kind " + name, @@ -159,7 +158,7 @@ func initGet(kinds schema.KindCatalog) { Run: func(cmd *cobra.Command, args []string) { parentValue := make([]string, len(parentFlagValue)) parentQueryValue := make([]string, len(parentQueryFlagValue)) - queryParams := extractFlagValueForQueryParam(listFlagValue) + queryParams := multipleFlags.ExtractFlagValueForQueryParam() for i, v := range parentFlagValue { parentValue[i] = *v } @@ -207,7 +206,7 @@ func initGet(kinds schema.KindCatalog) { for i, flag := range parentQueryFlags { parentQueryFlagValue[i] = kindCmd.Flags().String(flag, "", "Parent "+flag) } - buildFlag(kindCmd, listFlags, listFlagValue) + multipleFlags = NewMultipleFlags(kindCmd, kind.GetListFlag()) kindCmd.Flags().VarP(enumflag.New(&format, "output", OutputFormatIds, enumflag.EnumCaseInsensitive), "output", "o", "Output format. One of: json|yaml|name") getCmd.AddCommand(kindCmd) } diff --git a/cmd/multiple_flags.go b/cmd/multiple_flags.go new file mode 100644 index 0000000..243a81b --- /dev/null +++ b/cmd/multiple_flags.go @@ -0,0 +1,86 @@ +package cmd + +import ( + "github.com/conduktor/ctl/schema" + "github.com/conduktor/ctl/utils" + "github.com/spf13/cobra" + "strconv" +) + +type MultipleFlags struct { + result map[string]interface{} + flagParams map[string]schema.FlagParameterOption + command *cobra.Command +} + +func NewMultipleFlags(command *cobra.Command, flagParams map[string]schema.FlagParameterOption) *MultipleFlags { + result := make(map[string]interface{}, len(flagParams)) + usage := "" + for key, flag := range flagParams { + var isFlagSet bool + if flag.Type == "string" { + isFlagSet = true + defaultValue := "" + result[key] = command.Flags().String(flag.FlagName, defaultValue, usage) + } else if flag.Type == "boolean" { + isFlagSet = true + defaultValue := false + result[key] = command.Flags().Bool(flag.FlagName, defaultValue, usage) + } else if flag.Type == "integer" { + isFlagSet = true + defaultValue := 0 + result[key] = command.Flags().Int(flag.FlagName, defaultValue, usage) + } else if utils.CdkDebug() { + println("Unknown flag type: " + flag.Type) + } + if isFlagSet && flag.Required { + command.MarkFlagRequired(flag.FlagName) + } + } + + return &MultipleFlags{ + result, + flagParams, + command, + } +} + +func (m *MultipleFlags) ExtractFlagValueForBodyParam() map[string]interface{} { + bodyParams := make(map[string]interface{}) + for key, value := range m.result { + if value != nil && m.flagSetByUser(key) { + bodyParams[key] = value + } + } + return bodyParams +} + +func (m *MultipleFlags) ExtractFlagValueForQueryParam() map[string]string { + queryParams := make(map[string]string) + for key, value := range m.result { + if value != nil && m.flagSetByUser(key) { + str, strOk := value.(*string) + boolValue, boolOk := value.(*bool) + intValue, intOk := value.(*int) + + if strOk { + queryParams[key] = *str + } else if boolOk { + queryParams[key] = strconv.FormatBool(*boolValue) + } else if intOk { + queryParams[key] = strconv.Itoa(*intValue) + } else { + panic("Unknown query flag type") + } + } + } + return queryParams +} + +func (m *MultipleFlags) flagSetByUser(flagKey string) bool { + flag, present := m.flagParams[flagKey] + if !present { + panic("Flag " + flagKey + " not found in flagParams") + } + return m.command.Flags().Changed(flag.FlagName) +} diff --git a/cmd/multiple_flags_test.go b/cmd/multiple_flags_test.go new file mode 100644 index 0000000..7b27640 --- /dev/null +++ b/cmd/multiple_flags_test.go @@ -0,0 +1,104 @@ +package cmd + +import ( + "github.com/conduktor/ctl/schema" + "github.com/davecgh/go-spew/spew" + "github.com/spf13/cobra" + "reflect" + "strconv" + "testing" +) + +func TestExtractFlagValueForQueryParam(t *testing.T) { + command := &cobra.Command{} + multipleFlags := NewMultipleFlags(command, map[string]schema.FlagParameterOption{ + "stringParam": {FlagName: "stringParam", Type: "string"}, + "notSetString": {FlagName: "notSetStrign", Type: "string"}, + "emptyString": {FlagName: "emptyString", Type: "string"}, + "boolParam": {FlagName: "boolParam", Type: "boolean"}, + "boolParamFalse": {FlagName: "boolParamFalse", Type: "boolean"}, + "notSetBoolean": {FlagName: "notSetBoolean", Type: "boolean"}, + "intParam": {FlagName: "intParam", Type: "integer"}, + "notSetInt": {FlagName: "notSetInt", Type: "integer"}, + "zeroParam": {FlagName: "zeroParam", Type: "integer"}, + }) + multipleFlags.result = map[string]interface{}{ + "stringParam": func() *string { s := "test"; return &s }(), + "notSetString": func() *string { s := ""; return &s }(), + "emptyString": func() *string { s := ""; return &s }(), + "boolParam": func() *bool { b := true; return &b }(), + "boolParamFalse": func() *bool { b := false; return &b }(), + "notSetBoolean": func() *bool { b := false; return &b }(), + "intParam": func() *int { i := 123; return &i }(), + "notSetInt": func() *int { i := 0; return &i }(), + "zeroParam": func() *int { i := 0; return &i }(), + } + + expected := map[string]string{ + "stringParam": "test", + "boolParam": strconv.FormatBool(true), + "intParam": strconv.Itoa(123), + "zeroParam": strconv.Itoa(0), + "emptyString": "", + "boolParamFalse": strconv.FormatBool(false), + } + + command.Flags().Lookup("stringParam").Changed = true + command.Flags().Lookup("boolParam").Changed = true + command.Flags().Lookup("boolParamFalse").Changed = true + command.Flags().Lookup("intParam").Changed = true + command.Flags().Lookup("zeroParam").Changed = true + command.Flags().Lookup("emptyString").Changed = true + result := multipleFlags.ExtractFlagValueForQueryParam() + + if !reflect.DeepEqual(result, expected) { + t.Error(spew.Printf("got %v, want %v", result, expected)) + } +} + +func TestExtractFlagValueForBodyParam(t *testing.T) { + command := &cobra.Command{} + multipleFlags := NewMultipleFlags(command, map[string]schema.FlagParameterOption{ + "stringParam": {FlagName: "stringParam", Type: "string"}, + "notSetString": {FlagName: "notSetStrign", Type: "string"}, + "emptyString": {FlagName: "emptyString", Type: "string"}, + "boolParam": {FlagName: "boolParam", Type: "boolean"}, + "boolParamFalse": {FlagName: "boolParamFalse", Type: "boolean"}, + "notSetBoolean": {FlagName: "notSetBoolean", Type: "boolean"}, + "intParam": {FlagName: "intParam", Type: "integer"}, + "notSetInt": {FlagName: "notSetInt", Type: "integer"}, + "zeroParam": {FlagName: "zeroParam", Type: "integer"}, + }) + multipleFlags.result = map[string]interface{}{ + "stringParam": func() *string { s := "test"; return &s }(), + "notSetString": func() *string { s := ""; return &s }(), + "emptyString": func() *string { s := ""; return &s }(), + "boolParam": func() *bool { b := true; return &b }(), + "boolParamFalse": func() *bool { b := false; return &b }(), + "notSetBoolean": func() *bool { b := false; return &b }(), + "intParam": func() *int { i := 123; return &i }(), + "notSetInt": func() *int { i := 0; return &i }(), + "zeroParam": func() *int { i := 0; return &i }(), + } + + expected := map[string]interface{}{ + "stringParam": func() *string { s := "test"; return &s }(), + "emptyString": func() *string { s := ""; return &s }(), + "boolParam": func() *bool { b := true; return &b }(), + "boolParamFalse": func() *bool { b := false; return &b }(), + "intParam": func() *int { i := 123; return &i }(), + "zeroParam": func() *int { i := 0; return &i }(), + } + + command.Flags().Lookup("stringParam").Changed = true + command.Flags().Lookup("boolParam").Changed = true + command.Flags().Lookup("boolParamFalse").Changed = true + command.Flags().Lookup("intParam").Changed = true + command.Flags().Lookup("zeroParam").Changed = true + command.Flags().Lookup("emptyString").Changed = true + result := multipleFlags.ExtractFlagValueForBodyParam() + + if !reflect.DeepEqual(result, expected) { + t.Error(spew.Printf("got %v, want %v", result, expected)) + } +} diff --git a/cmd/run.go b/cmd/run.go index a45ae42..149776e 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -51,8 +51,8 @@ func initRun(runs schema.RunCatalog) { pathFlagValues := make([]*string, len(pathFlags)) queryFlags := run.QueryParameter bodyFlags := run.BodyFields - queryFlagValues := make(map[string]interface{}, len(queryFlags)) - bodyFlagValues := make(map[string]interface{}, len(bodyFlags)) + var multipleFlagsForQuery *MultipleFlags + var multipleFlagsForBody *MultipleFlags subRunCmd := &cobra.Command{ Use: name, Short: run.Doc, @@ -60,8 +60,8 @@ func initRun(runs schema.RunCatalog) { Aliases: buildAlias(name), Run: func(cmd *cobra.Command, args []string) { pathValues := make([]string, len(pathFlagValues)) - queryParams := extractFlagValueForQueryParam(queryFlagValues) - body := extractFlagValueForBodyParam(bodyFlagValues) + queryParams := multipleFlagsForQuery.ExtractFlagValueForQueryParam() + body := multipleFlagsForBody.ExtractFlagValueForBodyParam() for i, v := range pathFlagValues { pathValues[i] = *v } @@ -93,8 +93,8 @@ func initRun(runs schema.RunCatalog) { panic(err) } } - buildFlag(subRunCmd, queryFlags, queryFlagValues) - buildFlag(subRunCmd, bodyFlags, bodyFlagValues) + multipleFlagsForQuery = NewMultipleFlags(subRunCmd, queryFlags) + multipleFlagsForBody = NewMultipleFlags(subRunCmd, bodyFlags) runCmd.AddCommand(subRunCmd) } diff --git a/cmd/utils.go b/cmd/utils.go deleted file mode 100644 index 124ceb0..0000000 --- a/cmd/utils.go +++ /dev/null @@ -1,84 +0,0 @@ -package cmd - -import ( - "github.com/conduktor/ctl/schema" - "github.com/spf13/cobra" - "strconv" -) - -// used to detect when flag wasn't used -const unprobableInt = -23871 - -// for string it's "" -// for bool we will keep default false value - -func extractFlagValueForQueryParam(params map[string]interface{}) map[string]string { - queryParams := make(map[string]string) - for key, value := range params { - if value != nil { - str, strOk := value.(*string) - boolValue, boolOk := value.(*bool) - intValue, intOk := value.(*int) - - if strOk { - if *str != "" { - queryParams[key] = *str - } - } else if boolOk { - queryParams[key] = strconv.FormatBool(*boolValue) - } else if intOk { - if *intValue != unprobableInt { - queryParams[key] = strconv.Itoa(*intValue) - } - } else { - panic("Unknown query flag type") - } - } - } - return queryParams -} - -func extractFlagValueForBodyParam(params map[string]interface{}) map[string]interface{} { - bodyParams := make(map[string]interface{}) - for key, value := range params { - if value != nil { - str, strOk := value.(*string) - boolValue, boolOk := value.(*bool) - intValue, intOk := value.(*int) - - if strOk { - if *str != "" { - bodyParams[key] = str - } - } else if boolOk { - bodyParams[key] = boolValue - } else if intOk { - if *intValue != unprobableInt { - bodyParams[key] = *intValue - } - } else { - bodyParams[key] = value - } - } - } - return bodyParams -} - -func buildFlag(command *cobra.Command, flagParams map[string]schema.FlagParameterOption, flagResult map[string]interface{}) { - for key, flag := range flagParams { - var isFlagSet bool - if flag.Type == "string" { - isFlagSet = true - flagResult[key] = command.Flags().String(flag.FlagName, "", "") - } else if flag.Type == "boolean" { - isFlagSet = true - flagResult[key] = command.Flags().Bool(flag.FlagName, false, "") - } else if flag.Type == "integer" { - isFlagSet = true - flagResult[key] = command.Flags().Int(flag.FlagName, unprobableInt, "") - } - if isFlagSet && flag.Required { - command.MarkFlagRequired(flag.FlagName) - } - } -} diff --git a/cmd/utils_test.go b/cmd/utils_test.go deleted file mode 100644 index 097d5b0..0000000 --- a/cmd/utils_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package cmd - -import ( - "github.com/davecgh/go-spew/spew" - "reflect" - "strconv" - "testing" -) - -func TestExtractFlagValueForQueryParam(t *testing.T) { - params := map[string]interface{}{ - "stringParam": func() *string { s := "test"; return &s }(), - "emptyString": func() *string { s := ""; return &s }(), - "boolParam": func() *bool { b := true; return &b }(), - "intParam": func() *int { i := 123; return &i }(), - "unprobableInt": func() *int { i := unprobableInt; return &i }(), - } - - expected := map[string]string{ - "stringParam": "test", - "boolParam": strconv.FormatBool(true), - "intParam": strconv.Itoa(123), - } - - result := extractFlagValueForQueryParam(params) - - if !reflect.DeepEqual(result, expected) { - t.Error(spew.Printf("got %v, want %v", result, expected)) - } -} - -func TestExtractFlagValueForBodyParam(t *testing.T) { - params := map[string]interface{}{ - "stringParam": func() *string { s := "test"; return &s }(), - "emptyString": func() *string { s := ""; return &s }(), - "boolParam": func() *bool { b := true; return &b }(), - "intParam": func() *int { i := 123; return &i }(), - "unprobableInt": func() *int { i := unprobableInt; return &i }(), - "otherParam": "otherValue", - } - - expected := map[string]interface{}{ - "stringParam": func() *string { s := "test"; return &s }(), - "boolParam": func() *bool { b := true; return &b }(), - "intParam": 123, - "otherParam": "otherValue", - } - - result := extractFlagValueForBodyParam(params) - if !reflect.DeepEqual(result, expected) { - t.Error(spew.Printf("got %v, want %v", result, expected)) - } -}