From b48c53a0f693e984793992129012d876d3091188 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Thu, 23 Jan 2025 13:34:06 -0500 Subject: [PATCH 1/9] add config list-keys command --- cmd/config/config.go | 5 +- cmd/config/list_keys.go | 43 +++++++ cmd/config/list_keys_test.go | 37 ++++++ internal/commands/config/get_internal_test.go | 2 +- .../commands/config/list_keys_internal.go | 106 ++++++++++++++++++ .../config/list_keys_internal_test.go | 16 +++ internal/commands/config/set_internal_test.go | 2 +- .../commands/config/unset_internal_test.go | 2 +- .../configuration/config/list_keys_yaml.go | 35 ++++++ internal/configuration/configuration.go | 9 +- internal/configuration/configuration_test.go | 8 +- internal/configuration/options/options.go | 3 + 12 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 cmd/config/list_keys.go create mode 100644 cmd/config/list_keys_test.go create mode 100644 internal/commands/config/list_keys_internal.go create mode 100644 internal/commands/config/list_keys_internal_test.go create mode 100644 internal/configuration/config/list_keys_yaml.go diff --git a/cmd/config/config.go b/cmd/config/config.go index 89815d3e..d63b1c3a 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -23,12 +23,13 @@ func NewConfigCommand() *cobra.Command { cmd.AddCommand( NewConfigAddProfileCommand(), NewConfigDeleteProfileCommand(), - NewConfigViewProfileCommand(), + NewConfigGetCommand(), + NewConfigListKeysCommand(), NewConfigListProfilesCommand(), NewConfigSetActiveProfileCommand(), - NewConfigGetCommand(), NewConfigSetCommand(), NewConfigUnsetCommand(), + NewConfigViewProfileCommand(), ) return cmd diff --git a/cmd/config/list_keys.go b/cmd/config/list_keys.go new file mode 100644 index 00000000..e84bdc08 --- /dev/null +++ b/cmd/config/list_keys.go @@ -0,0 +1,43 @@ +package config + +import ( + "github.com/pingidentity/pingcli/cmd/common" + config_internal "github.com/pingidentity/pingcli/internal/commands/config" + "github.com/pingidentity/pingcli/internal/configuration/options" + "github.com/pingidentity/pingcli/internal/logger" + "github.com/spf13/cobra" +) + +const ( + listKeysCommandExamples = ` pingcli config list-keys + pingcli config list-keys --yaml` +) + +func NewConfigListKeysCommand() *cobra.Command { + cmd := &cobra.Command{ + Args: common.ExactArgs(0), + DisableFlagsInUseLine: true, // We write our own flags in @Use attribute + Example: listKeysCommandExamples, + Long: "\n" + `View the complete list of available configuration options. These attributes can be saved via the set and unset config subcommands or stored in a profile within the config file. +For details on the configuration options visit: https://github.com/pingidentity/pingcli/blob/main/docs/tool-configuration/configuration-key.md`, + RunE: configListKeysRunE, + Short: "List all keys.", + Use: "list-keys [flags]", + } + + cmd.Flags().AddFlag(options.ConfigListKeysYamlOption.Flag) + + return cmd +} + +func configListKeysRunE(cmd *cobra.Command, args []string) error { + l := logger.Get() + l.Debug().Msgf("Config list-keys Subcommand Called.") + + err := config_internal.RunInternalConfigListKeys() + if err != nil { + return err + } + + return nil +} diff --git a/cmd/config/list_keys_test.go b/cmd/config/list_keys_test.go new file mode 100644 index 00000000..2ba4497c --- /dev/null +++ b/cmd/config/list_keys_test.go @@ -0,0 +1,37 @@ +package config_test + +import ( + "testing" + + "github.com/pingidentity/pingcli/internal/configuration/options" + "github.com/pingidentity/pingcli/internal/testing/testutils" + "github.com/pingidentity/pingcli/internal/testing/testutils_cobra" +) + +// Test Config List Keys Command Executes without issue +func TestConfigListKeysCmd_Execute(t *testing.T) { + err := testutils_cobra.ExecutePingcli(t, "config", "list-keys") + testutils.CheckExpectedError(t, err, nil) +} + +// Test Config List Keys Command With YAML Flag Executes without issue +func TestConfigListKeysYAMLCmd_Execute(t *testing.T) { + err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", options.ConfigListKeysYamlOption.ViperKey) + testutils.CheckExpectedError(t, err, nil) +} + +// Test Config List Keys Command --help, -h flag +func TestConfigListKeysCmd_HelpFlag(t *testing.T) { + err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", "--help") + testutils.CheckExpectedError(t, err, nil) + + err = testutils_cobra.ExecutePingcli(t, "config", "list-keys", "-h") + testutils.CheckExpectedError(t, err, nil) +} + +// Test Config List Keys Command fails when provided too many arguments +func TestConfigListKeysCmd_TooManyArgs(t *testing.T) { + expectedErrorPattern := `^failed to execute 'pingcli config get': command accepts 0 arg\(s\), received 1$` + err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", options.RootColorOption.ViperKey) + testutils.CheckExpectedError(t, err, &expectedErrorPattern) +} diff --git a/internal/commands/config/get_internal_test.go b/internal/commands/config/get_internal_test.go index ddc5ef02..8cd5d3f7 100644 --- a/internal/commands/config/get_internal_test.go +++ b/internal/commands/config/get_internal_test.go @@ -23,7 +23,7 @@ func Test_RunInternalConfigGet(t *testing.T) { func Test_RunInternalConfigGet_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := RunInternalConfigGet("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/list_keys_internal.go b/internal/commands/config/list_keys_internal.go new file mode 100644 index 00000000..83d144f1 --- /dev/null +++ b/internal/commands/config/list_keys_internal.go @@ -0,0 +1,106 @@ +package config_internal + +import ( + "strings" + + "github.com/pingidentity/pingcli/internal/configuration" + "github.com/pingidentity/pingcli/internal/configuration/options" + "github.com/pingidentity/pingcli/internal/logger" + "github.com/pingidentity/pingcli/internal/output" + "github.com/pingidentity/pingcli/internal/profiles" + "gopkg.in/yaml.v3" +) + +func returnKeysYamlString() string { + inputString := returnKeysString("", " ") + // Split the input by spaces + parts := strings.Fields(inputString) + + // Create a nested map based on the period (.) separator + result := make(map[string]interface{}) + + // Flag to indicate if activeProfile is processed + activeProfileFound := false + + // Iterate through each part + for _, part := range parts { + keys := strings.Split(part, ".") + + // Only treat the first occurrence of activeProfile as the root key + if keys[0] == "activeProfile" && !activeProfileFound { + // Set activeProfile as the top-level key and initialize it as an empty string + result["activeProfile"] = "" + activeProfileFound = true + continue // Skip further processing for the "activeProfile" key itself + } + + // Now handle nested elements only under activeProfile + if activeProfileFound { + // Ensure we create a map for the activeProfile if it's not already created + if _, exists := result["activeProfile"].(map[string]interface{}); !exists { + result["activeProfile"] = make(map[string]interface{}) + } + + // Get the map for activeProfile + current := result["activeProfile"].(map[string]interface{}) + + // Process each key in the current part + for i, key := range keys { + if i == len(keys)-1 { + // Set the value for the last key, which should be an empty string + current[key] = "" + } else { + // Create intermediate maps for nested keys + if _, exists := current[key]; !exists { + current[key] = make(map[string]interface{}) + } + // Move deeper into the nested map + current = current[key].(map[string]interface{}) + } + } + } + } + + // Marshal the result into YAML + yamlData, err := yaml.Marshal(result) + if err != nil { + output.Warn("Error marshaling keys to YAML format", nil) + return "" + } + + return string(yamlData) +} + +func returnKeysString(stringPrefix, keyPrefix string) string { + var err error + l := logger.Get() + validKeys := configuration.ViperKeys() + + validKeysJoined := strings.Join(validKeys, keyPrefix) + + if len(validKeys) == 0 { + l.Err(err).Msg("Unable to retrieve valid keys.") + return "" + } else { + return stringPrefix + validKeysJoined + } +} + +func RunInternalConfigListKeys() (err error) { + l := logger.Get() + var outputMessageString string + if yamlStr, err := profiles.GetOptionValue(options.ConfigListKeysYamlOption); yamlStr == "true" { + if err != nil { + l.Err(err).Msg("Unable to get list keys option.") + } + // Output the YAML data as a string + outputMessageString = returnKeysYamlString() + } else { + listKeysStr := "Valid Keys:\n- " + outputMessageString = returnKeysString(listKeysStr, "\n- ") + } + + output.Message(outputMessageString, nil) + + return nil +} diff --git a/internal/commands/config/list_keys_internal_test.go b/internal/commands/config/list_keys_internal_test.go new file mode 100644 index 00000000..1b4119a5 --- /dev/null +++ b/internal/commands/config/list_keys_internal_test.go @@ -0,0 +1,16 @@ +package config_internal + +import ( + "testing" + + "github.com/pingidentity/pingcli/internal/testing/testutils" + "github.com/pingidentity/pingcli/internal/testing/testutils_viper" +) + +// Test RunInternalConfigListKeys function +func Test_RunInternalConfigListKeys(t *testing.T) { + testutils_viper.InitVipers(t) + + err := RunInternalConfigListKeys() + testutils.CheckExpectedError(t, err, nil) +} diff --git a/internal/commands/config/set_internal_test.go b/internal/commands/config/set_internal_test.go index 3d6da9d6..6393a79c 100644 --- a/internal/commands/config/set_internal_test.go +++ b/internal/commands/config/set_internal_test.go @@ -23,7 +23,7 @@ func Test_RunInternalConfigSet(t *testing.T) { func Test_RunInternalConfigSet_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^failed to set configuration: key '.*' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `^failed to set configuration: key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := RunInternalConfigSet("invalid-key=false") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/unset_internal_test.go b/internal/commands/config/unset_internal_test.go index 2dab8f94..a31b508d 100644 --- a/internal/commands/config/unset_internal_test.go +++ b/internal/commands/config/unset_internal_test.go @@ -23,7 +23,7 @@ func Test_RunInternalConfigUnset(t *testing.T) { func Test_RunInternalConfigUnset_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^failed to unset configuration: key '.*' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `^failed to unset configuration: key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := RunInternalConfigUnset("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/configuration/config/list_keys_yaml.go b/internal/configuration/config/list_keys_yaml.go new file mode 100644 index 00000000..bc2f540c --- /dev/null +++ b/internal/configuration/config/list_keys_yaml.go @@ -0,0 +1,35 @@ +package configuration_config + +import ( + "github.com/pingidentity/pingcli/internal/configuration/options" + "github.com/pingidentity/pingcli/internal/customtypes" + "github.com/spf13/pflag" +) + +func InitConfigListKeyOptions() { + initConfigListKeysYAMLOption() +} + +func initConfigListKeysYAMLOption() { + cobraParamName := "yaml" + cobraValue := new(customtypes.Bool) + defaultValue := customtypes.Bool(false) + + options.ConfigListKeysYamlOption = options.Option{ + CobraParamName: cobraParamName, + CobraParamValue: cobraValue, + DefaultValue: &defaultValue, + EnvVar: "", // No environment variable + Flag: &pflag.Flag{ + Name: cobraParamName, + Shorthand: "y", + Usage: "Output configuration keys in YAML format. " + + "(default false)", + Value: cobraValue, + NoOptDefVal: "true", // Make this flag a boolean flag + }, + Sensitive: false, + Type: options.ENUM_BOOL, + ViperKey: "", // No viper key + } +} diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go index fd9ad30f..a82eb1ce 100644 --- a/internal/configuration/configuration.go +++ b/internal/configuration/configuration.go @@ -33,8 +33,8 @@ func ValidateViperKey(viperKey string) error { } } - validKeysStr := strings.Join(validKeys, ", ") - return fmt.Errorf("key '%s' is not recognized as a valid configuration key. Valid keys: %s", viperKey, validKeysStr) + // validKeysStr := strings.Join(validKeys, ", ") + return fmt.Errorf("key '%s' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys", viperKey) } // Return a list of all viper keys from Options @@ -67,8 +67,8 @@ func ValidateParentViperKey(viperKey string) error { } } - validKeysStr := "\n- " + strings.Join(validKeys, "\n- ") - return fmt.Errorf("key '%s' is not recognized as a valid configuration key. Valid keys: %s", viperKey, validKeysStr) + // validKeysStr := "\n- " + strings.Join(validKeys, "\n- ") + return fmt.Errorf("key '%s' is not recognized as a valid configuration key.\nUse 'pingcli config list-keys' to view all available keys", viperKey) } func OptionFromViperKey(viperKey string) (opt options.Option, err error) { @@ -83,6 +83,7 @@ func OptionFromViperKey(viperKey string) (opt options.Option, err error) { func InitAllOptions() { configuration_config.InitConfigAddProfileOptions() configuration_config.InitConfigDeleteProfileOptions() + configuration_config.InitConfigListKeyOptions() configuration_platform.InitPlatformExportOptions() diff --git a/internal/configuration/configuration_test.go b/internal/configuration/configuration_test.go index 08862b67..6e8b956b 100644 --- a/internal/configuration/configuration_test.go +++ b/internal/configuration/configuration_test.go @@ -22,7 +22,7 @@ func Test_ValidateViperKey(t *testing.T) { func Test_ValidateViperKey_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := configuration.ValidateViperKey("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -31,7 +31,7 @@ func Test_ValidateViperKey_InvalidKey(t *testing.T) { func Test_ValidateViperKey_EmptyKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^key '' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `^key '' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := configuration.ValidateViperKey("") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -50,7 +50,7 @@ func Test_ValidateParentViperKey(t *testing.T) { func Test_ValidateParentViperKey_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^key '.*' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `(?s)^key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := configuration.ValidateParentViperKey("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -59,7 +59,7 @@ func Test_ValidateParentViperKey_InvalidKey(t *testing.T) { func Test_ValidateParentViperKey_EmptyKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^key '' is not recognized as a valid configuration key. Valid keys: .*$` + expectedErrorPattern := `(?s)^key '' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` err := configuration.ValidateParentViperKey("") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/configuration/options/options.go b/internal/configuration/options/options.go index 2afeaa85..fa57bb59 100644 --- a/internal/configuration/options/options.go +++ b/internal/configuration/options/options.go @@ -77,6 +77,7 @@ func Options() []Option { ConfigAddProfileNameOption, ConfigAddProfileSetActiveOption, ConfigDeleteAutoAcceptOption, + ConfigListKeysYamlOption, RequestDataOption, RequestHTTPMethodOption, @@ -126,6 +127,8 @@ var ( ConfigAddProfileNameOption Option ConfigAddProfileSetActiveOption Option + ConfigListKeysYamlOption Option + ConfigDeleteAutoAcceptOption Option ) From bd67fc172937ef8719d83fe5d3db380e66b3c35a Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Thu, 23 Jan 2025 16:11:18 -0500 Subject: [PATCH 2/9] update test regex --- cmd/config/get_test.go | 2 +- cmd/config/unset_test.go | 2 +- internal/commands/config/get_internal_test.go | 3 ++- internal/commands/config/set_internal_test.go | 4 ++-- internal/commands/config/unset_internal_test.go | 2 +- internal/configuration/configuration.go | 2 +- internal/configuration/configuration_test.go | 8 ++++---- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/cmd/config/get_test.go b/cmd/config/get_test.go index 0d4da6dd..d61db0c5 100644 --- a/cmd/config/get_test.go +++ b/cmd/config/get_test.go @@ -35,7 +35,7 @@ func TestConfigGetCmd_PartialKey(t *testing.T) { // Test Config Get Command fails when provided an invalid key func TestConfigGetCmd_InvalidKey(t *testing.T) { - expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key\. Valid keys: .*$` + expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := testutils_cobra.ExecutePingcli(t, "config", "get", "pingcli.invalid") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/cmd/config/unset_test.go b/cmd/config/unset_test.go index eefd3b5d..a6a9f088 100644 --- a/cmd/config/unset_test.go +++ b/cmd/config/unset_test.go @@ -32,7 +32,7 @@ func TestConfigUnsetCmd_TooManyArgs(t *testing.T) { // Test Config Unset Command Fails when an invalid key is provided func TestConfigUnsetCmd_InvalidKey(t *testing.T) { - expectedErrorPattern := `^failed to unset configuration: key '.*' is not recognized as a valid configuration key\. Valid keys: [A-Za-z\.\s,]+$` + expectedErrorPattern := `^failed to unset configuration: key '.*' is not recognized as a valid configuration key\.\s*Use 'pingcli config list-keys' to view all available keys` err := testutils_cobra.ExecutePingcli(t, "config", "unset", "pingcli.invalid") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/get_internal_test.go b/internal/commands/config/get_internal_test.go index 8cd5d3f7..c2ab66d8 100644 --- a/internal/commands/config/get_internal_test.go +++ b/internal/commands/config/get_internal_test.go @@ -23,7 +23,8 @@ func Test_RunInternalConfigGet(t *testing.T) { func Test_RunInternalConfigGet_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key. +Use 'pingcli config list-keys' to view all available keys` err := RunInternalConfigGet("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/set_internal_test.go b/internal/commands/config/set_internal_test.go index 6393a79c..56b6c57a 100644 --- a/internal/commands/config/set_internal_test.go +++ b/internal/commands/config/set_internal_test.go @@ -23,7 +23,7 @@ func Test_RunInternalConfigSet(t *testing.T) { func Test_RunInternalConfigSet_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^failed to set configuration: key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `(?s)^failed to set configuration: key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := RunInternalConfigSet("invalid-key=false") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -32,7 +32,7 @@ func Test_RunInternalConfigSet_InvalidKey(t *testing.T) { func Test_RunInternalConfigSet_InvalidValue(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^failed to set configuration: value for key '.*' must be a boolean. Allowed .*: strconv.ParseBool: parsing ".*": invalid syntax$` + expectedErrorPattern := `(?s)^failed to set configuration: value for key '.*' must be a boolean. Allowed .*: strconv.ParseBool: parsing ".*": invalid syntax$` err := RunInternalConfigSet("noColor=invalid") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/unset_internal_test.go b/internal/commands/config/unset_internal_test.go index a31b508d..7c73a38d 100644 --- a/internal/commands/config/unset_internal_test.go +++ b/internal/commands/config/unset_internal_test.go @@ -23,7 +23,7 @@ func Test_RunInternalConfigUnset(t *testing.T) { func Test_RunInternalConfigUnset_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^failed to unset configuration: key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `^failed to unset configuration: key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := RunInternalConfigUnset("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go index a82eb1ce..8fb58977 100644 --- a/internal/configuration/configuration.go +++ b/internal/configuration/configuration.go @@ -34,7 +34,7 @@ func ValidateViperKey(viperKey string) error { } // validKeysStr := strings.Join(validKeys, ", ") - return fmt.Errorf("key '%s' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys", viperKey) + return fmt.Errorf("key '%s' is not recognized as a valid configuration key.\nUse 'pingcli config list-keys' to view all available keys", viperKey) } // Return a list of all viper keys from Options diff --git a/internal/configuration/configuration_test.go b/internal/configuration/configuration_test.go index 6e8b956b..d2d3c52f 100644 --- a/internal/configuration/configuration_test.go +++ b/internal/configuration/configuration_test.go @@ -22,7 +22,7 @@ func Test_ValidateViperKey(t *testing.T) { func Test_ValidateViperKey_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := configuration.ValidateViperKey("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -31,7 +31,7 @@ func Test_ValidateViperKey_InvalidKey(t *testing.T) { func Test_ValidateViperKey_EmptyKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `^key '' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `^key '' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := configuration.ValidateViperKey("") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -50,7 +50,7 @@ func Test_ValidateParentViperKey(t *testing.T) { func Test_ValidateParentViperKey_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^key '.*' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := configuration.ValidateParentViperKey("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } @@ -59,7 +59,7 @@ func Test_ValidateParentViperKey_InvalidKey(t *testing.T) { func Test_ValidateParentViperKey_EmptyKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^key '' is not recognized as a valid configuration key. \nUse 'pingcli config list-keys' to view all available keys.*$` + expectedErrorPattern := `^key '' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := configuration.ValidateParentViperKey("") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } From d8acb291a7dc32e68cceefefec96bf1c3b009f8c Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Thu, 23 Jan 2025 16:31:09 -0500 Subject: [PATCH 3/9] update tests --- cmd/config/get_test.go | 2 +- cmd/config/list_keys_test.go | 11 +++++++---- cmd/config/set_test.go | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/cmd/config/get_test.go b/cmd/config/get_test.go index d61db0c5..62f43ca1 100644 --- a/cmd/config/get_test.go +++ b/cmd/config/get_test.go @@ -35,7 +35,7 @@ func TestConfigGetCmd_PartialKey(t *testing.T) { // Test Config Get Command fails when provided an invalid key func TestConfigGetCmd_InvalidKey(t *testing.T) { - expectedErrorPattern := `^key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` + expectedErrorPattern := `^failed to get configuration: key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := testutils_cobra.ExecutePingcli(t, "config", "get", "pingcli.invalid") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/cmd/config/list_keys_test.go b/cmd/config/list_keys_test.go index 2ba4497c..84cadd50 100644 --- a/cmd/config/list_keys_test.go +++ b/cmd/config/list_keys_test.go @@ -14,9 +14,12 @@ func TestConfigListKeysCmd_Execute(t *testing.T) { testutils.CheckExpectedError(t, err, nil) } -// Test Config List Keys Command With YAML Flag Executes without issue -func TestConfigListKeysYAMLCmd_Execute(t *testing.T) { - err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", options.ConfigListKeysYamlOption.ViperKey) +// Test Config List Keys YAML Command --help, -h flag +func TestConfigListKeysCmd_YAMLFlag(t *testing.T) { + err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", "--yaml") + testutils.CheckExpectedError(t, err, nil) + + err = testutils_cobra.ExecutePingcli(t, "config", "list-keys", "-y") testutils.CheckExpectedError(t, err, nil) } @@ -31,7 +34,7 @@ func TestConfigListKeysCmd_HelpFlag(t *testing.T) { // Test Config List Keys Command fails when provided too many arguments func TestConfigListKeysCmd_TooManyArgs(t *testing.T) { - expectedErrorPattern := `^failed to execute 'pingcli config get': command accepts 0 arg\(s\), received 1$` + expectedErrorPattern := `^failed to execute 'pingcli config list-keys': command accepts 0 arg\(s\), received 1$` err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", options.RootColorOption.ViperKey) testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/cmd/config/set_test.go b/cmd/config/set_test.go index 3c787b38..b60d98b0 100644 --- a/cmd/config/set_test.go +++ b/cmd/config/set_test.go @@ -32,7 +32,7 @@ func TestConfigSetCmd_TooManyArgs(t *testing.T) { // Test Config Set Command Fails when an invalid key is provided func TestConfigSetCmd_InvalidKey(t *testing.T) { - expectedErrorPattern := `^failed to set configuration: key 'pingcli\.invalid' is not recognized as a valid configuration key\. Valid keys: [A-Za-z\.\s,]+$` + expectedErrorPattern := `^failed to set configuration: key 'pingcli\.invalid' is not recognized as a valid configuration key\.\s*Use 'pingcli config list-keys' to view all available keys` err := testutils_cobra.ExecutePingcli(t, "config", "set", "pingcli.invalid=true") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } From 00fd652456bb24cafbe1fe56b640c9851797c0bb Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Thu, 23 Jan 2025 16:47:21 -0500 Subject: [PATCH 4/9] match other test formatting --- internal/commands/config/get_internal_test.go | 3 +-- internal/commands/config/set_internal_test.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/commands/config/get_internal_test.go b/internal/commands/config/get_internal_test.go index c2ab66d8..69cfc0eb 100644 --- a/internal/commands/config/get_internal_test.go +++ b/internal/commands/config/get_internal_test.go @@ -23,8 +23,7 @@ func Test_RunInternalConfigGet(t *testing.T) { func Test_RunInternalConfigGet_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key. -Use 'pingcli config list-keys' to view all available keys` + expectedErrorPattern := `(?s)^failed to get configuration: key '.*' is not recognized as a valid configuration key\.\s*Use 'pingcli config list-keys' to view all available keys` err := RunInternalConfigGet("invalid-key") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } diff --git a/internal/commands/config/set_internal_test.go b/internal/commands/config/set_internal_test.go index 56b6c57a..2b4e882b 100644 --- a/internal/commands/config/set_internal_test.go +++ b/internal/commands/config/set_internal_test.go @@ -32,7 +32,7 @@ func Test_RunInternalConfigSet_InvalidKey(t *testing.T) { func Test_RunInternalConfigSet_InvalidValue(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^failed to set configuration: value for key '.*' must be a boolean. Allowed .*: strconv.ParseBool: parsing ".*": invalid syntax$` + expectedErrorPattern := `^failed to set configuration: value for key '.*' must be a boolean. Allowed .*: strconv.ParseBool: parsing ".*": invalid syntax$` err := RunInternalConfigSet("noColor=invalid") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } From 2e5c911870b4dcb0a065d0a960e76af73041f3c7 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Fri, 24 Jan 2025 12:13:23 -0500 Subject: [PATCH 5/9] remove activeProfile on output, update error handling, add output tests, edit existing tests --- cmd/config/list_keys.go | 6 +- cmd/config/list_keys_test.go | 92 ++++++++++++++- .../commands/config/list_keys_internal.go | 105 ++++++++---------- internal/commands/config/set_internal_test.go | 2 +- 4 files changed, 143 insertions(+), 62 deletions(-) diff --git a/cmd/config/list_keys.go b/cmd/config/list_keys.go index e84bdc08..bb7f1a7d 100644 --- a/cmd/config/list_keys.go +++ b/cmd/config/list_keys.go @@ -9,7 +9,7 @@ import ( ) const ( - listKeysCommandExamples = ` pingcli config list-keys + listKeysCommandExamples = ` List all configuration keys stored in the CLI configuration file. pingcli config list-keys --yaml` ) @@ -18,10 +18,10 @@ func NewConfigListKeysCommand() *cobra.Command { Args: common.ExactArgs(0), DisableFlagsInUseLine: true, // We write our own flags in @Use attribute Example: listKeysCommandExamples, - Long: "\n" + `View the complete list of available configuration options. These attributes can be saved via the set and unset config subcommands or stored in a profile within the config file. + Long: `View the complete list of available configuration options. These attributes can be saved via the set and unset config subcommands or stored in a profile within the config file. For details on the configuration options visit: https://github.com/pingidentity/pingcli/blob/main/docs/tool-configuration/configuration-key.md`, RunE: configListKeysRunE, - Short: "List all keys.", + Short: "List all configuration keys.", Use: "list-keys [flags]", } diff --git a/cmd/config/list_keys_test.go b/cmd/config/list_keys_test.go index 84cadd50..3f26475d 100644 --- a/cmd/config/list_keys_test.go +++ b/cmd/config/list_keys_test.go @@ -14,7 +14,7 @@ func TestConfigListKeysCmd_Execute(t *testing.T) { testutils.CheckExpectedError(t, err, nil) } -// Test Config List Keys YAML Command --help, -h flag +// Test Config List Keys YAML Command --yaml, -y flag func TestConfigListKeysCmd_YAMLFlag(t *testing.T) { err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", "--yaml") testutils.CheckExpectedError(t, err, nil) @@ -38,3 +38,93 @@ func TestConfigListKeysCmd_TooManyArgs(t *testing.T) { err := testutils_cobra.ExecutePingcli(t, "config", "list-keys", options.RootColorOption.ViperKey) testutils.CheckExpectedError(t, err, &expectedErrorPattern) } + +// https://pkg.go.dev/testing#hdr-Examples +func Example_listKeysValue() { + t := testing.T{} + _ = testutils_cobra.ExecutePingcli(&t, "config", "list-keys") + + // Output: + // Valid Keys: + // - activeProfile + // - description + // - export.format + // - export.outputDirectory + // - export.overwrite + // - export.pingone.environmentID + // - export.services + // - noColor + // - outputFormat + // - request.accessToken + // - request.accessTokenExpiry + // - request.fail + // - request.service + // - service.pingfederate.adminAPIPath + // - service.pingfederate.authentication.accessTokenAuth.accessToken + // - service.pingfederate.authentication.basicAuth.password + // - service.pingfederate.authentication.basicAuth.username + // - service.pingfederate.authentication.clientCredentialsAuth.clientID + // - service.pingfederate.authentication.clientCredentialsAuth.clientSecret + // - service.pingfederate.authentication.clientCredentialsAuth.scopes + // - service.pingfederate.authentication.clientCredentialsAuth.tokenURL + // - service.pingfederate.authentication.type + // - service.pingfederate.caCertificatePemFiles + // - service.pingfederate.httpsHost + // - service.pingfederate.insecureTrustAllTLS + // - service.pingfederate.xBypassExternalValidationHeader + // - service.pingone.authentication.type + // - service.pingone.authentication.worker.clientID + // - service.pingone.authentication.worker.clientSecret + // - service.pingone.authentication.worker.environmentID + // - service.pingone.regionCode +} + +// https://pkg.go.dev/testing#hdr-Examples +func Example_listKeysYAMLValue() { + t := testing.T{} + _ = testutils_cobra.ExecutePingcli(&t, "config", "list-keys", "--yaml") + + // Output: + // description: "" + // export: + // format: "" + // outputDirectory: "" + // overwrite: "" + // pingone: + // environmentID: "" + // services: "" + // noColor: "" + // outputFormat: "" + // request: + // accessToken: "" + // accessTokenExpiry: "" + // fail: "" + // service: "" + // service: + // pingfederate: + // adminAPIPath: "" + // authentication: + // accessTokenAuth: + // accessToken: "" + // basicAuth: + // password: "" + // username: "" + // clientCredentialsAuth: + // clientID: "" + // clientSecret: "" + // scopes: "" + // tokenURL: "" + // type: "" + // caCertificatePemFiles: "" + // httpsHost: "" + // insecureTrustAllTLS: "" + // xBypassExternalValidationHeader: "" + // pingone: + // authentication: + // type: "" + // worker: + // clientID: "" + // clientSecret: "" + // environmentID: "" + // regionCode: "" +} diff --git a/internal/commands/config/list_keys_internal.go b/internal/commands/config/list_keys_internal.go index 83d144f1..54ec9a42 100644 --- a/internal/commands/config/list_keys_internal.go +++ b/internal/commands/config/list_keys_internal.go @@ -1,62 +1,50 @@ package config_internal import ( + "fmt" "strings" "github.com/pingidentity/pingcli/internal/configuration" "github.com/pingidentity/pingcli/internal/configuration/options" - "github.com/pingidentity/pingcli/internal/logger" "github.com/pingidentity/pingcli/internal/output" "github.com/pingidentity/pingcli/internal/profiles" "gopkg.in/yaml.v3" ) -func returnKeysYamlString() string { - inputString := returnKeysString("", " ") - // Split the input by spaces - parts := strings.Fields(inputString) +func returnKeysYamlString() (string, error) { + var err error + validKeys := configuration.ViperKeys() - // Create a nested map based on the period (.) separator - result := make(map[string]interface{}) + validKeysJoined := strings.Join(validKeys, " ") + + if len(validKeys) == 0 { + return "", fmt.Errorf("unable to retrieve valid keys") + } - // Flag to indicate if activeProfile is processed - activeProfileFound := false + // Split the input string into individual keys + parts := strings.Split(validKeysJoined, " ") + result := make(map[string]interface{}) - // Iterate through each part + // Iterate over each part for _, part := range parts { - keys := strings.Split(part, ".") - - // Only treat the first occurrence of activeProfile as the root key - if keys[0] == "activeProfile" && !activeProfileFound { - // Set activeProfile as the top-level key and initialize it as an empty string - result["activeProfile"] = "" - activeProfileFound = true - continue // Skip further processing for the "activeProfile" key itself + // Skip the "activeProfile" key + if part == "activeProfile" { + continue } - // Now handle nested elements only under activeProfile - if activeProfileFound { - // Ensure we create a map for the activeProfile if it's not already created - if _, exists := result["activeProfile"].(map[string]interface{}); !exists { - result["activeProfile"] = make(map[string]interface{}) - } - - // Get the map for activeProfile - current := result["activeProfile"].(map[string]interface{}) - - // Process each key in the current part - for i, key := range keys { - if i == len(keys)-1 { - // Set the value for the last key, which should be an empty string - current[key] = "" - } else { - // Create intermediate maps for nested keys - if _, exists := current[key]; !exists { - current[key] = make(map[string]interface{}) - } - // Move deeper into the nested map - current = current[key].(map[string]interface{}) + // Create a nested map for each part + currentMap := result + keys := strings.Split(part, ".") + for i, key := range keys { + // If it's the last key, set an empty map + if i == len(keys)-1 { + currentMap[key] = "" + } else { + // Otherwise, create or navigate to the next level + if _, exists := currentMap[key]; !exists { + currentMap[key] = make(map[string]interface{}) } + currentMap = currentMap[key].(map[string]interface{}) } } } @@ -64,40 +52,43 @@ func returnKeysYamlString() string { // Marshal the result into YAML yamlData, err := yaml.Marshal(result) if err != nil { - output.Warn("Error marshaling keys to YAML format", nil) - return "" + return "", fmt.Errorf("error marshaling keys to YAML format") } - return string(yamlData) + return string(yamlData), nil } -func returnKeysString(stringPrefix, keyPrefix string) string { - var err error - l := logger.Get() +func returnKeysString() (string, error) { + // var err error validKeys := configuration.ViperKeys() - validKeysJoined := strings.Join(validKeys, keyPrefix) + validKeysJoined := strings.Join(validKeys, "\n- ") if len(validKeys) == 0 { - l.Err(err).Msg("Unable to retrieve valid keys.") - return "" + return "", fmt.Errorf("unable to retrieve valid keys") } else { - return stringPrefix + validKeysJoined + return "Valid Keys:\n- " + validKeysJoined, nil } } func RunInternalConfigListKeys() (err error) { - l := logger.Get() var outputMessageString string - if yamlStr, err := profiles.GetOptionValue(options.ConfigListKeysYamlOption); yamlStr == "true" { + yamlFlagStr, err := profiles.GetOptionValue(options.ConfigListKeysYamlOption) + if err != nil { + return err + } + if yamlFlagStr == "true" { + // Output the YAML data as a string + outputMessageString, err = returnKeysYamlString() if err != nil { - l.Err(err).Msg("Unable to get list keys option.") + return err } - // Output the YAML data as a string - outputMessageString = returnKeysYamlString() } else { - listKeysStr := "Valid Keys:\n- " - outputMessageString = returnKeysString(listKeysStr, "\n- ") + // Output data list string + outputMessageString, err = returnKeysString() + if err != nil { + return err + } } output.Message(outputMessageString, nil) diff --git a/internal/commands/config/set_internal_test.go b/internal/commands/config/set_internal_test.go index 2b4e882b..e8743d73 100644 --- a/internal/commands/config/set_internal_test.go +++ b/internal/commands/config/set_internal_test.go @@ -23,7 +23,7 @@ func Test_RunInternalConfigSet(t *testing.T) { func Test_RunInternalConfigSet_InvalidKey(t *testing.T) { testutils_viper.InitVipers(t) - expectedErrorPattern := `(?s)^failed to set configuration: key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` + expectedErrorPattern := `^failed to set configuration: key '.*' is not recognized as a valid configuration key.\s*Use 'pingcli config list-keys' to view all available keys` err := RunInternalConfigSet("invalid-key=false") testutils.CheckExpectedError(t, err, &expectedErrorPattern) } From abae9a2b9196c45c3dd69435f59a66bfefb945b2 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Fri, 24 Jan 2025 12:27:16 -0500 Subject: [PATCH 6/9] check key length before running function, remove unneeded comment lines, update test spacing --- cmd/config/list_keys_test.go | 70 +++++++++---------- .../commands/config/list_keys_internal.go | 6 +- internal/configuration/configuration.go | 2 - 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/cmd/config/list_keys_test.go b/cmd/config/list_keys_test.go index 3f26475d..42e55dac 100644 --- a/cmd/config/list_keys_test.go +++ b/cmd/config/list_keys_test.go @@ -87,44 +87,44 @@ func Example_listKeysYAMLValue() { // Output: // description: "" // export: - // format: "" - // outputDirectory: "" - // overwrite: "" - // pingone: - // environmentID: "" - // services: "" + // format: "" + // outputDirectory: "" + // overwrite: "" + // pingone: + // environmentID: "" + // services: "" // noColor: "" // outputFormat: "" // request: - // accessToken: "" - // accessTokenExpiry: "" - // fail: "" - // service: "" + // accessToken: "" + // accessTokenExpiry: "" + // fail: "" + // service: "" // service: - // pingfederate: - // adminAPIPath: "" - // authentication: - // accessTokenAuth: - // accessToken: "" - // basicAuth: - // password: "" - // username: "" - // clientCredentialsAuth: - // clientID: "" - // clientSecret: "" - // scopes: "" - // tokenURL: "" - // type: "" - // caCertificatePemFiles: "" - // httpsHost: "" - // insecureTrustAllTLS: "" - // xBypassExternalValidationHeader: "" + // pingfederate: + // adminAPIPath: "" + // authentication: + // accessTokenAuth: + // accessToken: "" + // basicAuth: + // password: "" + // username: "" + // clientCredentialsAuth: + // clientID: "" + // clientSecret: "" + // scopes: "" + // tokenURL: "" + // type: "" + // caCertificatePemFiles: "" + // httpsHost: "" + // insecureTrustAllTLS: "" + // xBypassExternalValidationHeader: "" // pingone: - // authentication: - // type: "" - // worker: - // clientID: "" - // clientSecret: "" - // environmentID: "" - // regionCode: "" + // authentication: + // type: "" + // worker: + // clientID: "" + // clientSecret: "" + // environmentID: "" + // regionCode: "" } diff --git a/internal/commands/config/list_keys_internal.go b/internal/commands/config/list_keys_internal.go index 54ec9a42..b998ddec 100644 --- a/internal/commands/config/list_keys_internal.go +++ b/internal/commands/config/list_keys_internal.go @@ -15,12 +15,11 @@ func returnKeysYamlString() (string, error) { var err error validKeys := configuration.ViperKeys() - validKeysJoined := strings.Join(validKeys, " ") - if len(validKeys) == 0 { return "", fmt.Errorf("unable to retrieve valid keys") } + validKeysJoined := strings.Join(validKeys, " ") // Split the input string into individual keys parts := strings.Split(validKeysJoined, " ") result := make(map[string]interface{}) @@ -62,11 +61,10 @@ func returnKeysString() (string, error) { // var err error validKeys := configuration.ViperKeys() - validKeysJoined := strings.Join(validKeys, "\n- ") - if len(validKeys) == 0 { return "", fmt.Errorf("unable to retrieve valid keys") } else { + validKeysJoined := strings.Join(validKeys, "\n- ") return "Valid Keys:\n- " + validKeysJoined, nil } } diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go index 8fb58977..26390eb1 100644 --- a/internal/configuration/configuration.go +++ b/internal/configuration/configuration.go @@ -33,7 +33,6 @@ func ValidateViperKey(viperKey string) error { } } - // validKeysStr := strings.Join(validKeys, ", ") return fmt.Errorf("key '%s' is not recognized as a valid configuration key.\nUse 'pingcli config list-keys' to view all available keys", viperKey) } @@ -67,7 +66,6 @@ func ValidateParentViperKey(viperKey string) error { } } - // validKeysStr := "\n- " + strings.Join(validKeys, "\n- ") return fmt.Errorf("key '%s' is not recognized as a valid configuration key.\nUse 'pingcli config list-keys' to view all available keys", viperKey) } From 352c74d56760c6a035a527903c6728a19a406df2 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Fri, 24 Jan 2025 13:33:23 -0500 Subject: [PATCH 7/9] adjust spacing in test --- cmd/config/list_keys_test.go | 60 ++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/cmd/config/list_keys_test.go b/cmd/config/list_keys_test.go index 42e55dac..61ebf048 100644 --- a/cmd/config/list_keys_test.go +++ b/cmd/config/list_keys_test.go @@ -89,42 +89,42 @@ func Example_listKeysYAMLValue() { // export: // format: "" // outputDirectory: "" - // overwrite: "" - // pingone: - // environmentID: "" - // services: "" + // overwrite: "" + // pingone: + // environmentID: "" + // services: "" // noColor: "" // outputFormat: "" // request: // accessToken: "" // accessTokenExpiry: "" // fail: "" - // service: "" + // service: "" // service: // pingfederate: - // adminAPIPath: "" - // authentication: - // accessTokenAuth: - // accessToken: "" - // basicAuth: - // password: "" - // username: "" - // clientCredentialsAuth: - // clientID: "" - // clientSecret: "" - // scopes: "" - // tokenURL: "" - // type: "" - // caCertificatePemFiles: "" - // httpsHost: "" - // insecureTrustAllTLS: "" - // xBypassExternalValidationHeader: "" - // pingone: - // authentication: - // type: "" - // worker: - // clientID: "" - // clientSecret: "" - // environmentID: "" - // regionCode: "" + // adminAPIPath: "" + // authentication: + // accessTokenAuth: + // accessToken: "" + // basicAuth: + // password: "" + // username: "" + // clientCredentialsAuth: + // clientID: "" + // clientSecret: "" + // scopes: "" + // tokenURL: "" + // type: "" + // caCertificatePemFiles: "" + // httpsHost: "" + // insecureTrustAllTLS: "" + // xBypassExternalValidationHeader: "" + // pingone: + // authentication: + // type: "" + // worker: + // clientID: "" + // clientSecret: "" + // environmentID: "" + // regionCode: "" } From 1eba4c2420cb158a48b68cbbd9b94d57e471ad65 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Fri, 24 Jan 2025 14:04:00 -0500 Subject: [PATCH 8/9] remove yaml test --- cmd/config/list_keys_test.go | 50 ------------------------------------ 1 file changed, 50 deletions(-) diff --git a/cmd/config/list_keys_test.go b/cmd/config/list_keys_test.go index 61ebf048..be4bf0a8 100644 --- a/cmd/config/list_keys_test.go +++ b/cmd/config/list_keys_test.go @@ -78,53 +78,3 @@ func Example_listKeysValue() { // - service.pingone.authentication.worker.environmentID // - service.pingone.regionCode } - -// https://pkg.go.dev/testing#hdr-Examples -func Example_listKeysYAMLValue() { - t := testing.T{} - _ = testutils_cobra.ExecutePingcli(&t, "config", "list-keys", "--yaml") - - // Output: - // description: "" - // export: - // format: "" - // outputDirectory: "" - // overwrite: "" - // pingone: - // environmentID: "" - // services: "" - // noColor: "" - // outputFormat: "" - // request: - // accessToken: "" - // accessTokenExpiry: "" - // fail: "" - // service: "" - // service: - // pingfederate: - // adminAPIPath: "" - // authentication: - // accessTokenAuth: - // accessToken: "" - // basicAuth: - // password: "" - // username: "" - // clientCredentialsAuth: - // clientID: "" - // clientSecret: "" - // scopes: "" - // tokenURL: "" - // type: "" - // caCertificatePemFiles: "" - // httpsHost: "" - // insecureTrustAllTLS: "" - // xBypassExternalValidationHeader: "" - // pingone: - // authentication: - // type: "" - // worker: - // clientID: "" - // clientSecret: "" - // environmentID: "" - // regionCode: "" -} From 9130db80fb12801ab5ce71b553c66997dfbfd373 Mon Sep 17 00:00:00 2001 From: wesleymccollam Date: Fri, 24 Jan 2025 15:05:14 -0500 Subject: [PATCH 9/9] add command example, update logic and readability --- cmd/config/list_keys.go | 3 +- .../commands/config/list_keys_internal.go | 36 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/cmd/config/list_keys.go b/cmd/config/list_keys.go index bb7f1a7d..5777c44c 100644 --- a/cmd/config/list_keys.go +++ b/cmd/config/list_keys.go @@ -10,7 +10,8 @@ import ( const ( listKeysCommandExamples = ` List all configuration keys stored in the CLI configuration file. - pingcli config list-keys --yaml` + pingcli config list-keys + pingcli config list-keys --yaml` ) func NewConfigListKeysCommand() *cobra.Command { diff --git a/internal/commands/config/list_keys_internal.go b/internal/commands/config/list_keys_internal.go index b998ddec..5c04167f 100644 --- a/internal/commands/config/list_keys_internal.go +++ b/internal/commands/config/list_keys_internal.go @@ -13,43 +13,41 @@ import ( func returnKeysYamlString() (string, error) { var err error - validKeys := configuration.ViperKeys() + viperKeys := configuration.ViperKeys() - if len(validKeys) == 0 { + if len(viperKeys) == 0 { return "", fmt.Errorf("unable to retrieve valid keys") } - validKeysJoined := strings.Join(validKeys, " ") // Split the input string into individual keys - parts := strings.Split(validKeysJoined, " ") - result := make(map[string]interface{}) + keyMap := make(map[string]interface{}) - // Iterate over each part - for _, part := range parts { + // Iterate over each viper key + for _, viperKey := range viperKeys { // Skip the "activeProfile" key - if part == "activeProfile" { + if viperKey == "activeProfile" { continue } - // Create a nested map for each part - currentMap := result - keys := strings.Split(part, ".") - for i, key := range keys { - // If it's the last key, set an empty map - if i == len(keys)-1 { - currentMap[key] = "" + // Create a nested map for each yaml key + currentMap := keyMap + yamlKeys := strings.Split(viperKey, ".") + for i, k := range yamlKeys { + // If it's the last yaml key, set an empty map + if i == len(yamlKeys)-1 { + currentMap[k] = "" } else { // Otherwise, create or navigate to the next level - if _, exists := currentMap[key]; !exists { - currentMap[key] = make(map[string]interface{}) + if _, exists := currentMap[k]; !exists { + currentMap[k] = make(map[string]interface{}) } - currentMap = currentMap[key].(map[string]interface{}) + currentMap = currentMap[k].(map[string]interface{}) } } } // Marshal the result into YAML - yamlData, err := yaml.Marshal(result) + yamlData, err := yaml.Marshal(keyMap) if err != nil { return "", fmt.Errorf("error marshaling keys to YAML format") }