Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support module-config default / value
- also adding support for project conditional prompts
- Loading branch information
1 parent
9d6372d
commit 544ab60
Showing
9 changed files
with
282 additions
and
164 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package context | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"os/exec" | ||
"regexp" | ||
|
||
"github.com/commitdev/zero/internal/config/moduleconfig" | ||
"github.com/commitdev/zero/pkg/util/exit" | ||
"github.com/manifoldco/promptui" | ||
) | ||
|
||
type PromptHandler struct { | ||
moduleconfig.Parameter | ||
Condition func(map[string]string) bool | ||
} | ||
|
||
func NoCondition(map[string]string) bool { | ||
return true | ||
} | ||
func KeyMatchCondition(key string, value string) func(map[string]string) bool { | ||
return func(param map[string]string) bool { | ||
return param[key] == value | ||
} | ||
} | ||
|
||
// TODO: validation / allow prompt retry ...etc | ||
func (p PromptHandler) GetParam(projectParams map[string]string) string { | ||
var err error | ||
var result string | ||
if p.Condition(projectParams) { | ||
// TODO: figure out scope of projectParams per project | ||
// potentially dangerous to have cross module env leaking | ||
// so if community module has an `execute: twitter tweet $ENV` | ||
// it wouldnt leak things the module shouldnt have access to | ||
if p.Parameter.Execute != "" { | ||
result = executeCmd(p.Parameter.Execute, projectParams) | ||
} else if p.Parameter.Value != "" { | ||
result = p.Parameter.Value | ||
} else { | ||
err, result = promptParameter(p.Parameter) | ||
} | ||
if err != nil { | ||
exit.Fatal("Exiting prompt: %v\n", err) | ||
} | ||
|
||
return sanitizeParameterValue(result) | ||
} | ||
return "" | ||
} | ||
|
||
func promptParameter(param moduleconfig.Parameter) (error, string) { | ||
label := param.Label | ||
if param.Label == "" { | ||
label = param.Field | ||
} | ||
defaultValue := param.Default | ||
|
||
var err error | ||
var result string | ||
if len(param.Options) > 0 { | ||
prompt := promptui.Select{ | ||
Label: label, | ||
Items: param.Options, | ||
} | ||
_, result, err = prompt.Run() | ||
|
||
} else { | ||
prompt := promptui.Prompt{ | ||
Label: label, | ||
Default: defaultValue, | ||
AllowEdit: true, | ||
} | ||
result, err = prompt.Run() | ||
} | ||
if err != nil { | ||
exit.Fatal("Exiting prompt: %v\n", err) | ||
} | ||
|
||
return nil, result | ||
} | ||
|
||
func executeCmd(command string, envVars map[string]string) string { | ||
cmd := exec.Command("bash", "-c", command) | ||
cmd.Env = appendProjectEnvToCmdEnv(envVars, os.Environ()) | ||
out, err := cmd.Output() | ||
|
||
if err != nil { | ||
log.Fatalf("Failed to execute %v\n", err) | ||
} | ||
return string(out) | ||
} | ||
|
||
// aws cli prints output with linebreak in them | ||
func sanitizeParameterValue(str string) string { | ||
re := regexp.MustCompile("\\n") | ||
return re.ReplaceAllString(str, "") | ||
} | ||
|
||
func appendProjectEnvToCmdEnv(envMap map[string]string, envList []string) []string { | ||
for key, val := range envMap { | ||
if val != "" { | ||
envList = append(envList, fmt.Sprintf("%s=%s", key, val)) | ||
} | ||
} | ||
return envList | ||
} | ||
|
||
// PromptParams renders series of prompt UI based on the config | ||
func PromptModuleParams(moduleConfig moduleconfig.ModuleConfig, parameters map[string]string) (map[string]string, error) { | ||
|
||
for _, promptConfig := range moduleConfig.Parameters { | ||
// deduplicate fields already prompted and received | ||
if _, isAlreadySet := parameters[promptConfig.Field]; isAlreadySet { | ||
continue | ||
} | ||
promptHandler := PromptHandler{ | ||
promptConfig, | ||
NoCondition, | ||
} | ||
result := promptHandler.GetParam(parameters) | ||
|
||
parameters[promptConfig.Field] = result | ||
} | ||
return parameters, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package context_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/commitdev/zero/internal/config/moduleconfig" | ||
"github.com/commitdev/zero/internal/context" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetParam(t *testing.T) { | ||
projectParams := map[string]string{} | ||
t.Run("Should execute params without prompt", func(t *testing.T) { | ||
param := moduleconfig.Parameter{ | ||
Field: "account-id", | ||
Execute: "echo \"my-acconut-id\"", | ||
} | ||
|
||
prompt := context.PromptHandler{ | ||
param, | ||
context.NoCondition, | ||
} | ||
|
||
result := prompt.GetParam(projectParams) | ||
assert.Equal(t, "my-acconut-id", result) | ||
}) | ||
|
||
t.Run("executes with project context", func(t *testing.T) { | ||
param := moduleconfig.Parameter{ | ||
Field: "myEnv", | ||
Execute: "echo $INJECTEDENV", | ||
} | ||
|
||
prompt := context.PromptHandler{ | ||
param, | ||
context.NoCondition, | ||
} | ||
|
||
result := prompt.GetParam(map[string]string{ | ||
"INJECTEDENV": "SOME_ENV_VAR_VALUE", | ||
}) | ||
assert.Equal(t, "SOME_ENV_VAR_VALUE", result) | ||
}) | ||
|
||
t.Run("Should return static value", func(t *testing.T) { | ||
param := moduleconfig.Parameter{ | ||
Field: "placeholder", | ||
Value: "lorem-ipsum", | ||
} | ||
|
||
prompt := context.PromptHandler{ | ||
param, | ||
context.NoCondition, | ||
} | ||
|
||
result := prompt.GetParam(projectParams) | ||
assert.Equal(t, "lorem-ipsum", result) | ||
}) | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.