mirror of
https://github.com/thegeeklab/git-sv.git
synced 2024-11-23 14:50:39 +00:00
174 lines
4.0 KiB
Go
174 lines
4.0 KiB
Go
package commands
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"regexp"
|
|
|
|
"github.com/manifoldco/promptui"
|
|
)
|
|
|
|
type commitType struct {
|
|
Type string
|
|
Description string
|
|
Example string
|
|
}
|
|
|
|
var errInvalidValue = errors.New("invalid value")
|
|
|
|
func promptType(types []string) (commitType, error) {
|
|
defaultTypes := map[string]commitType{
|
|
"build": {
|
|
Type: "build",
|
|
Description: "changes that affect the build system or external dependencies",
|
|
Example: "gradle, maven, go mod, npm",
|
|
},
|
|
"ci": {
|
|
Type: "ci",
|
|
Description: "changes to our CI configuration files and scripts",
|
|
Example: "Circle, BrowserStack, SauceLabs",
|
|
},
|
|
"chore": {
|
|
Type: "chore",
|
|
Description: "update something without impacting the user",
|
|
Example: "gitignore",
|
|
},
|
|
"docs": {
|
|
Type: "docs",
|
|
Description: "documentation only changes",
|
|
},
|
|
"feat": {
|
|
Type: "feat",
|
|
Description: "a new feature",
|
|
},
|
|
"fix": {
|
|
Type: "fix",
|
|
Description: "a bug fix",
|
|
},
|
|
"perf": {
|
|
Type: "perf",
|
|
Description: "a code change that improves performance",
|
|
},
|
|
"refactor": {
|
|
Type: "refactor",
|
|
Description: "a code change that neither fixes a bug nor adds a feature",
|
|
},
|
|
"style": {
|
|
Type: "style",
|
|
Description: "changes that do not affect the meaning of the code",
|
|
Example: "white-space, formatting, missing semi-colons, etc",
|
|
},
|
|
"test": {
|
|
Type: "test",
|
|
Description: "adding missing tests or correcting existing tests",
|
|
},
|
|
"revert": {
|
|
Type: "revert",
|
|
Description: "revert a single commit",
|
|
},
|
|
}
|
|
|
|
var items []commitType
|
|
|
|
for _, t := range types {
|
|
if v, exists := defaultTypes[t]; exists {
|
|
items = append(items, v)
|
|
} else {
|
|
items = append(items, commitType{Type: t})
|
|
}
|
|
}
|
|
|
|
template := &promptui.SelectTemplates{
|
|
Label: "{{ . }}",
|
|
Active: "> {{ .Type | white }} - {{ .Description | faint }}",
|
|
Inactive: " {{ .Type | white }} - {{ .Description | faint }}",
|
|
Selected: `{{ "type:" | faint }} {{ .Type | white }}`,
|
|
Details: `
|
|
{{ "Type:" | faint }} {{ .Type }}
|
|
{{ "Description:" | faint }} {{ .Description }}
|
|
{{ "Example:" | faint }} {{ .Example }}`,
|
|
}
|
|
|
|
i, err := promptSelect("type", items, template)
|
|
if err != nil {
|
|
return commitType{}, err
|
|
}
|
|
|
|
return items[i], nil
|
|
}
|
|
|
|
func promptScope(values []string) (string, error) {
|
|
if len(values) > 0 {
|
|
selected, err := promptSelect("scope", values, nil)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return values[selected], nil
|
|
}
|
|
|
|
return promptText("scope", "^[a-z0-9-]*$", "")
|
|
}
|
|
|
|
func promptSubject() (string, error) {
|
|
return promptText("subject", "^[a-z].+$", "")
|
|
}
|
|
|
|
func promptBody() (string, error) {
|
|
return promptText("body (leave empty to finish)", "^.*$", "")
|
|
}
|
|
|
|
func promptIssueID(issueLabel, issueRegex, defaultValue string) (string, error) {
|
|
return promptText(issueLabel, "^("+issueRegex+")?$", defaultValue)
|
|
}
|
|
|
|
func promptBreakingChanges() (string, error) {
|
|
return promptText("Breaking change description", "[a-z].+", "")
|
|
}
|
|
|
|
func promptSelect(label string, items interface{}, template *promptui.SelectTemplates) (int, error) {
|
|
if items == nil || reflect.TypeOf(items).Kind() != reflect.Slice {
|
|
return 0, fmt.Errorf("%w: %v is not a slice", errInvalidValue, items)
|
|
}
|
|
|
|
prompt := promptui.Select{
|
|
Label: label,
|
|
Size: reflect.ValueOf(items).Len(),
|
|
Items: items,
|
|
Templates: template,
|
|
}
|
|
|
|
index, _, err := prompt.Run()
|
|
|
|
return index, err
|
|
}
|
|
|
|
func promptText(label, regex, defaultValue string) (string, error) {
|
|
validate := func(input string) error {
|
|
regex := regexp.MustCompile(regex)
|
|
if !regex.MatchString(input) {
|
|
return fmt.Errorf("%w, expected: %s", errInvalidValue, regex)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
prompt := promptui.Prompt{
|
|
Label: label,
|
|
Default: defaultValue,
|
|
Validate: validate,
|
|
}
|
|
|
|
return prompt.Run()
|
|
}
|
|
|
|
func promptConfirm(label string) (bool, error) {
|
|
r, err := promptText(label+" [y/n]", "^y|n$", "")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return r == "y", nil
|
|
}
|