diff --git a/docs/module-definition.md b/docs/module-definition.md index b59cb30c..53eca7a0 100644 --- a/docs/module-definition.md +++ b/docs/module-definition.md @@ -47,12 +47,12 @@ Note: Default is supplied as the starting point of the user's manual input (Not |-----------------------|-----------------|---------------------------------------------------------------------------------------------------------------------------| | `field` | string | key to store result for project definition | | `label` | string | displayed name for the prompt | -| `options` | list(string) | A list of values for users to pick from | +| `options` | map | A map of `value: display name` pairs for users to pick from | | `default` | string | Defaults to this value during prompt | | `value` | string | Skips prompt entirely when set | | `info` | string | Displays during prompt as extra information guiding user's input | | `fieldValidation` | Validation | Validations for the prompt value | -| `type` | enum(string) | Built in custom prompts: currently supports [`AWSProfilePicker`] | +| `type` | enum(string) | Built in custom prompts: currently supports [`AWSProfilePicker`] | | `execute` | string | executes commands and takes stdout as prompt result | | `omitFromProjectFile` | bool | Field is skipped from adding to project definition | | `conditions` | list(Condition) | Conditions for prompt to run, if supplied all conditions must pass | diff --git a/internal/config/moduleconfig/module_config.go b/internal/config/moduleconfig/module_config.go index d6ba8e40..58bc13fd 100644 --- a/internal/config/moduleconfig/module_config.go +++ b/internal/config/moduleconfig/module_config.go @@ -27,17 +27,17 @@ type ModuleConfig struct { type Parameter struct { Field string - Label string `yaml:"label,omitempty"` - Options []string `yaml:"options,omitempty"` - Execute string `yaml:"execute,omitempty"` - Value string `yaml:"value,omitempty"` - Default string `yaml:"default,omitempty"` - Info string `yaml:"info,omitempty"` - FieldValidation Validate `yaml:"fieldValidation,omitempty"` - Type string `yaml:"type,omitempty"` - OmitFromProjectFile bool `yaml:"omitFromProjectFile,omitempty"` - Conditions []Condition `yaml:"conditions,omitempty"` - EnvVarName string `yaml:"envVarName,omitempty"` + Label string `yaml:"label,omitempty"` + Options yaml.MapSlice `yaml:"options,omitempty"` + Execute string `yaml:"execute,omitempty"` + Value string `yaml:"value,omitempty"` + Default string `yaml:"default,omitempty"` + Info string `yaml:"info,omitempty"` + FieldValidation Validate `yaml:"fieldValidation,omitempty"` + Type string `yaml:"type,omitempty"` + OmitFromProjectFile bool `yaml:"omitFromProjectFile,omitempty"` + Conditions []Condition `yaml:"conditions,omitempty"` + EnvVarName string `yaml:"envVarName,omitempty"` } type Condition struct { diff --git a/internal/init/custom-prompts.go b/internal/init/custom-prompts.go index 73a43115..2afdcd3f 100644 --- a/internal/init/custom-prompts.go +++ b/internal/init/custom-prompts.go @@ -36,7 +36,7 @@ func promptAWSProfilePicker(params map[string]string) error { Parameter: moduleconfig.Parameter{ Field: "aws_profile", Label: "Select AWS Profile", - Options: profiles, + Options: listToPromptOptions(profiles), }, Condition: NoCondition, Validate: NoValidation, diff --git a/internal/init/prompts.go b/internal/init/prompts.go index b02752b1..083b0c60 100644 --- a/internal/init/prompts.go +++ b/internal/init/prompts.go @@ -15,11 +15,11 @@ import ( "github.com/commitdev/zero/pkg/util/exit" "github.com/commitdev/zero/pkg/util/flog" "github.com/manifoldco/promptui" + "gopkg.in/yaml.v2" ) -// Constant to maintain prompt orders so users can have the same flow, -// modules get downloaded asynchronously therefore its easier to just hardcode an order -var AvailableVendorOrders = []string{"aws", "github", "circleci"} +const cyanArrow = "\033[36m\U000025B6\033[0m" +const greenCheckMark = "\033[32m\U00002714\033[0m" const awsPickProfile = "Existing AWS Profiles" const awsManualInputCredentials = "Enter my own AWS credentials" @@ -152,12 +152,24 @@ func promptParameter(prompt PromptHandler) (error, string) { var err error var result string if len(param.Options) > 0 { + var selectedIndex int + // Scope of selected does not have the label data, so we need a dynamic + // template with string format to put in the label in `selected` + optionTemplate := &promptui.SelectTemplates{ + Label: `{{ . }}`, + Active: fmt.Sprintf("%s {{ .Value | cyan }}", cyanArrow), + Inactive: " {{ .Value }}", + Selected: fmt.Sprintf("%s %s: {{ .Value }}", greenCheckMark, label), + } + prompt := promptui.Select{ - Label: label, - Items: param.Options, + Label: label, + Items: param.Options, + Templates: optionTemplate, } - _, result, err = prompt.Run() + selectedIndex, _, err = prompt.Run() + result = param.Options[selectedIndex].Key.(string) } else { prompt := promptui.Prompt{ Label: label, @@ -168,7 +180,7 @@ func promptParameter(prompt PromptHandler) (error, string) { result, err = prompt.Run() } if err != nil { - exit.Fatal("Exiting prompt: %v\n", err) + return err, "" } return nil, result @@ -287,3 +299,14 @@ func appendToSet(set []string, toAppend []string) []string { } return set } + +func listToPromptOptions(list []string) yaml.MapSlice { + mapSlice := make(yaml.MapSlice, len(list)) + for i := 0; i < len(list); i++ { + mapSlice[i] = yaml.MapItem{ + Key: list[i], + Value: list[i], + } + } + return mapSlice +} diff --git a/tests/test_data/modules/ci/zero-module.yml b/tests/test_data/modules/ci/zero-module.yml index a9f0f38b..d96d1741 100644 --- a/tests/test_data/modules/ci/zero-module.yml +++ b/tests/test_data/modules/ci/zero-module.yml @@ -29,8 +29,8 @@ parameters: label: CI Platform # default: github options: - - github - - circlci + github: Github + circleci: Circle CI - field: circleci_api_key label: "Circle CI API Key to setup your CI/CD for repositories" conditions: @@ -40,8 +40,8 @@ parameters: - field: useExistingAwsProfile label: "Use credentials from an existing AWS profile?" options: - - "yes" - - "no" + "yes": "Yes" + "no": "No" omitFromProjectFile: yes - field: profilePicker omitFromProjectFile: yes