diff --git a/internal/errors/missing.go b/internal/errors/missing.go new file mode 100644 index 0000000..e75e356 --- /dev/null +++ b/internal/errors/missing.go @@ -0,0 +1,23 @@ +package errors + +import "fmt" + +type MissingErr struct { + name string + field string +} + +func (e MissingErr) Error() string { + if e.name == "" { + return fmt.Sprintf("missing required field `%s`", e.field) + } + return fmt.Sprintf("'%s' missing required field: %s", e.name, e.field) +} + +func NewMissingErr(field string, name ...string) error { + err := MissingErr{field: field} + if len(name) > 0 { + err.name = name[0] + } + return err +} diff --git a/internal/parameter/integer/int.go b/internal/parameter/integer/int.go index 37070ec..4b744f7 100644 --- a/internal/parameter/integer/int.go +++ b/internal/parameter/integer/int.go @@ -26,7 +26,7 @@ func (p Param) Render() huh.Field { param.Value(&p.DefaultValue) - var group []validators.Validator + var group []validators.Validator[string] if p.Required { group = append(group, validators.Required(p.Name, true)) } diff --git a/internal/parameter/list/list.go b/internal/parameter/list/list.go index 3597e60..2cb198e 100644 --- a/internal/parameter/list/list.go +++ b/internal/parameter/list/list.go @@ -19,7 +19,7 @@ type Param struct { func (p Param) Validate() []error { errs := p.Parameter.Validate() if len(p.Options) < 1 { - errs = append(errs, errors.NewRequiredErr("parameter.options")) + errs = append(errs, errors.NewMissingErr("options", p.Name)) } return errs } @@ -34,7 +34,7 @@ func (p Param) Render() huh.Field { param.Value(&p.DefaultValue) - var group []validators.Validator + var group []validators.Validator[string] if p.Required { group = append(group, validators.Required(p.Name, false)) } diff --git a/internal/parameter/multilist/list.go b/internal/parameter/multilist/list.go index 48b226f..6ca2c1d 100644 --- a/internal/parameter/multilist/list.go +++ b/internal/parameter/multilist/list.go @@ -14,12 +14,13 @@ type Param struct { Options []huh.Option[string] `yaml:"options" json:"options" mapstructure:"options"` DefaultValue []string `yaml:"default_value" json:"default_value" mapstructure:"default_value"` Required bool `yaml:"required" json:"required" mapstructure:"required"` + Limit *int `yaml:"limit" json:"limit" mapstructure:"limit"` } func (p Param) Validate() []error { errs := p.Parameter.Validate() if len(p.Options) < 1 { - errs = append(errs, errors.NewRequiredErr("parameter.options")) + errs = append(errs, errors.NewMissingErr("options", p.Name)) } return errs } @@ -32,10 +33,18 @@ func (p Param) Render() huh.Field { param.Description(p.Description) } + if p.Limit != nil { + param.Limit(*p.Limit) + } param.Value(&p.DefaultValue) + var group []validators.Validator[[]string] + if p.Required { + group = append(group, validators.MultiRequired(p.Name)) + } + if p.Required { - param.Validate(validators.MultiRequired(p.Name)) + param.Validate(validators.Group(group...)) } return param diff --git a/internal/parameter/param.go b/internal/parameter/param.go index 9208e27..72ea6ae 100644 --- a/internal/parameter/param.go +++ b/internal/parameter/param.go @@ -33,13 +33,13 @@ func (p Parameter) Render() huh.Field { func (p Parameter) Validate() []error { var errs []error if strutil.IsEmpty(p.Name) { - errs = append(errs, errors.NewRequiredErr("parameter.name")) + errs = append(errs, errors.NewMissingErr("parameter.name")) } if strutil.IsEmpty(p.Label) { - errs = append(errs, errors.NewRequiredErr("parameter.label")) + errs = append(errs, errors.NewMissingErr("label", p.Name)) } if strutil.IsEmpty(p.Type) { - errs = append(errs, errors.NewRequiredErr("parameter.type")) + errs = append(errs, errors.NewMissingErr("type", p.Name)) } return errs } diff --git a/internal/parameter/str/str.go b/internal/parameter/str/str.go index fbd5ad4..889565a 100644 --- a/internal/parameter/str/str.go +++ b/internal/parameter/str/str.go @@ -35,7 +35,7 @@ func (p Param) RenderInput() *huh.Input { param.Value(&p.DefaultValue) - var group []validators.Validator + var group []validators.Validator[string] if p.Required { group = append(group, validators.Required(p.Name, p.Trim)) } diff --git a/internal/parameter/text/text.go b/internal/parameter/text/text.go index 5a1e4b1..95eb8fa 100644 --- a/internal/parameter/text/text.go +++ b/internal/parameter/text/text.go @@ -16,19 +16,24 @@ type Param struct { RegexMessage string `yaml:"regex_message" json:"regex_message" mapstructure:"regex_message"` MinLength *int `yaml:"min_length" json:"min_length" mapstructure:"min_length"` MaxLength *int `yaml:"max_length" json:"max_length" mapstructure:"max_length"` + Height *int `yaml:"height" json:"height" mapstructure:"height"` } func (p Param) Render() huh.Field { param := huh.NewText().Key(p.Name). Title(p.Label) + if p.Height != nil { + param.Lines(*p.Height) + } + if len(p.Description) > 0 { param.Description(p.Description) } param.Value(&p.DefaultValue) - var group []validators.Validator + var group []validators.Validator[string] if p.Required { group = append(group, validators.Required(p.Name, false)) } diff --git a/internal/parameter/validators/required.go b/internal/parameter/validators/required.go index 8fc8d03..1d9be01 100644 --- a/internal/parameter/validators/required.go +++ b/internal/parameter/validators/required.go @@ -3,8 +3,6 @@ package validators import ( "fmt" "strings" - - "github.com/shipengqi/commitizen/internal/errors" ) func Required(name string, trim bool) func(string) error { @@ -18,12 +16,3 @@ func Required(name string, trim bool) func(string) error { return nil } } - -func MultiRequired(name string) func([]string) error { - return func(strs []string) error { - if len(strs) == 0 { - return errors.NewRequiredErr(name) - } - return nil - } -} diff --git a/internal/parameter/validators/slice.go b/internal/parameter/validators/slice.go new file mode 100644 index 0000000..9c06e7a --- /dev/null +++ b/internal/parameter/validators/slice.go @@ -0,0 +1,12 @@ +package validators + +import "github.com/shipengqi/commitizen/internal/errors" + +func MultiRequired(name string) func([]string) error { + return func(vals []string) error { + if len(vals) == 0 { + return errors.NewRequiredErr(name) + } + return nil + } +} diff --git a/internal/parameter/validators/validators.go b/internal/parameter/validators/validators.go index b3a7026..35536aa 100644 --- a/internal/parameter/validators/validators.go +++ b/internal/parameter/validators/validators.go @@ -1,11 +1,11 @@ package validators -type Validator func(string) error +type Validator[T string | []string] func(T) error -func Group(validators ...Validator) Validator { - return func(str string) error { +func Group[T string | []string](validators ...Validator[T]) Validator[T] { + return func(t T) error { for _, validator := range validators { - if err := validator(str); err != nil { + if err := validator(t); err != nil { return err } } diff --git a/internal/templates/template.go b/internal/templates/template.go index ec6576b..48d8093 100644 --- a/internal/templates/template.go +++ b/internal/templates/template.go @@ -2,8 +2,8 @@ package templates import ( "bytes" + standarderrs "errors" "fmt" - "strings" "text/template" "github.com/charmbracelet/huh" @@ -23,23 +23,6 @@ import ( const UnknownGroup = "unknown" -type Option struct { - Name string - Desc string -} - -func (o *Option) String() string { - var b strings.Builder - ml := len(o.Name) - pl := 12 - ml - 2 - padding := strings.Repeat(" ", pl) - b.WriteString(o.Name) - b.WriteString(": ") - b.WriteString(padding) - b.WriteString(o.Desc) - return b.String() -} - type Template struct { Name string Desc string @@ -52,7 +35,7 @@ type Template struct { func (t *Template) Initialize() error { if strutil.IsEmpty(t.Format) { - return errors.NewRequiredErr("format") + return errors.NewMissingErr("format") } groups := NewSortedGroupMap() @@ -105,6 +88,10 @@ func (t *Template) Initialize() error { if err != nil { return err } + errs := param.Validate() + if len(errs) > 0 { + return standarderrs.Join(errs...) + } group = param.GetGroup() field = param.Render() t.fields = append(t.fields, field) @@ -165,7 +152,7 @@ func GetValueFromYAML[T any](data map[string]interface{}, key string) (T, error) v, ok = data[key] if !ok { - return res, errors.NewRequiredErr(key) + return res, errors.NewMissingErr(key) } res, ok = v.(T) if !ok {