Skip to content

Commit ffa0ffb

Browse files
v3.0 (feat): add template runner and it dependency prompt wrapper to load and parse cmf yaml file
1 parent 2050263 commit ffa0ffb

File tree

5 files changed

+480
-0
lines changed

5 files changed

+480
-0
lines changed

mocks/templaterunner.go

Lines changed: 100 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

prompt/prompt.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package prompt
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/mritd/promptx"
8+
)
9+
10+
// SelectItem a default item struct
11+
type SelectItem struct {
12+
Title string
13+
Description string
14+
Value string
15+
}
16+
17+
// SelectConfiguration a complete configuration select options
18+
type SelectConfiguration struct {
19+
ActiveTpl string
20+
InactiveTpl string
21+
SelectPrompt string
22+
SelectedTpl string
23+
DetailsTpl string
24+
}
25+
26+
// Select Returns a selected item
27+
func Select(items []SelectItem, config SelectConfiguration) SelectItem {
28+
configuration := &promptx.SelectConfig{
29+
ActiveTpl: config.ActiveTpl,
30+
InactiveTpl: config.InactiveTpl,
31+
SelectPrompt: config.SelectPrompt,
32+
SelectedTpl: config.SelectedTpl,
33+
DisPlaySize: 9,
34+
DetailsTpl: config.DetailsTpl,
35+
}
36+
37+
selector := &promptx.Select{
38+
Items: items,
39+
Config: configuration,
40+
}
41+
42+
return items[selector.Run()]
43+
}
44+
45+
// Input return a simple user input
46+
func Input(title string, errorMessage string, defaultValue string) string {
47+
input := promptx.NewDefaultPrompt(func(line []rune) error {
48+
if strings.TrimSpace(string(line)) == "" && defaultValue == "" {
49+
return errors.New(errorMessage)
50+
}
51+
52+
return nil
53+
}, title)
54+
55+
value := input.Run()
56+
57+
if value == "" && defaultValue != "" {
58+
return defaultValue
59+
}
60+
61+
return value
62+
}

promptxWrapper/promptxwrapper.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package promptxwrapper
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/mritd/promptx"
8+
"github.com/walmartdigital/commit-message-formatter/prompt"
9+
"github.com/walmartdigital/commit-message-formatter/templaterunner"
10+
)
11+
12+
// PromptxWrapper promptx wrapper object
13+
type PromptxWrapper struct{}
14+
15+
// NewPromptxWrapper return a new instance of promptxWrapper
16+
func NewPromptxWrapper() *PromptxWrapper {
17+
return &PromptxWrapper{}
18+
}
19+
20+
// ReadValue return a value from user single input
21+
func (pw *PromptxWrapper) ReadValue(title string, errorMessage string, defaultValue string) string {
22+
input := promptx.NewDefaultPrompt(func(line []rune) error {
23+
if strings.TrimSpace(string(line)) == "" && defaultValue == "" {
24+
return errors.New(errorMessage)
25+
}
26+
27+
return nil
28+
}, title)
29+
30+
value := input.Run()
31+
32+
if value == "" && defaultValue != "" {
33+
return defaultValue
34+
}
35+
36+
return value
37+
}
38+
39+
// ReadValueFromList return a value from user multi select input
40+
func (pw *PromptxWrapper) ReadValueFromList(title string, options []templaterunner.Options) string {
41+
configuration := &promptx.SelectConfig{
42+
ActiveTpl: "\U0001F449 {{ .Title | cyan | bold }}",
43+
InactiveTpl: " {{ .Title | white }}",
44+
SelectPrompt: title,
45+
SelectedTpl: "\U0001F44D {{ \"" + title + "\" | cyan }} {{ .Title | cyan | bold }}",
46+
DetailsTpl: `-------------------------------
47+
{{ .Title | white | bold }} {{ .Description | white | bold }}`,
48+
}
49+
50+
var items []prompt.SelectItem
51+
for _, option := range options {
52+
items = append(items, prompt.SelectItem{Title: option.Value, Value: option.Value, Description: option.Description})
53+
}
54+
55+
selector := &promptx.Select{
56+
Items: items,
57+
Config: configuration,
58+
}
59+
60+
return items[selector.Run()].Value
61+
}

templaterunner/templaterunner.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package templaterunner
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"gopkg.in/yaml.v2"
8+
)
9+
10+
type templateRunner struct {
11+
promptManager PromptManager
12+
}
13+
14+
// PromptManager ...
15+
type PromptManager interface {
16+
ReadValue(title string, errorMessage string, defaultValue string) string
17+
ReadValueFromList(title string, options []Options) string
18+
}
19+
20+
// TemplateRunner main template interface
21+
type TemplateRunner interface {
22+
Run(yamlData string, injectedVariables map[string]string) (message string, err error)
23+
}
24+
25+
// Template main template struct
26+
type Template struct {
27+
Prompt []PromptItem `yaml:"PROMPT"`
28+
Template string `yaml:"TEMPLATE"`
29+
}
30+
31+
//PromptItem ...
32+
type PromptItem struct {
33+
Key string `yaml:"KEY"`
34+
Label string `yaml:"LABEL"`
35+
ErrorLabel string `yaml:"ERROR_LABEL"`
36+
DefaultValue string `yaml:"DEFAULT_VALUE"`
37+
Options []Options `yaml:"OPTIONS"`
38+
}
39+
40+
// Options multiselect option struct
41+
type Options struct {
42+
Value string `yaml:"VALUE"`
43+
Description string `yaml:"DESC"`
44+
}
45+
46+
type keyValue struct {
47+
Key string
48+
Value string
49+
}
50+
51+
// NewTemplateRunner return a bluetnew instance of template
52+
func NewTemplateRunner(promptManager PromptManager) TemplateRunner {
53+
return &templateRunner{
54+
promptManager: promptManager,
55+
}
56+
}
57+
58+
func (tr *templateRunner) parseYaml(yamlData string) (Template, error) {
59+
template := Template{}
60+
err := yaml.Unmarshal([]byte(yamlData), &template)
61+
62+
if err != nil {
63+
return Template{}, errors.New("parsing yaml error")
64+
}
65+
66+
return template, nil
67+
}
68+
69+
// Run return the result of run the template
70+
func (tr *templateRunner) Run(yamlData string, injectedVariables map[string]string) (string, error) {
71+
template, err := tr.parseYaml(yamlData)
72+
if err != nil {
73+
return "", err
74+
}
75+
76+
variables := tr.prompt(template)
77+
for k, v := range injectedVariables {
78+
variables = append(variables, keyValue{Key: k, Value: v})
79+
}
80+
81+
message := tr.parseTemplate(template.Template, variables)
82+
83+
return message, err
84+
}
85+
86+
func (tr *templateRunner) parseTemplate(template string, variables []keyValue) string {
87+
for _, v := range variables {
88+
template = strings.Replace(template, "{{"+v.Key+"}}", v.Value, -1)
89+
}
90+
91+
return template
92+
}
93+
94+
func (tr *templateRunner) prompt(template Template) []keyValue {
95+
variables := []keyValue{}
96+
for _, step := range template.Prompt {
97+
result := ""
98+
var errorMessage = "empty value"
99+
100+
if step.ErrorLabel != "" {
101+
errorMessage = step.ErrorLabel
102+
}
103+
104+
if step.Options == nil {
105+
var labelMessage = step.Label
106+
107+
if step.DefaultValue != "" {
108+
labelMessage += " (" + step.DefaultValue + ")"
109+
}
110+
111+
labelMessage += ":"
112+
113+
result = tr.promptManager.ReadValue(labelMessage, errorMessage, step.DefaultValue)
114+
} else {
115+
result = tr.promptManager.ReadValueFromList(step.Label, step.Options)
116+
}
117+
118+
variables = append(variables, keyValue{
119+
Key: step.Key,
120+
Value: result,
121+
})
122+
}
123+
124+
return variables
125+
}

0 commit comments

Comments
 (0)