Skip to content

Commit

Permalink
feat(parameters): refactor parameters and validators (#62)
Browse files Browse the repository at this point in the history
* <no value>: <no value>

* feat(parameters): add parameters and validators

* feat(template): update default template
  • Loading branch information
shipengqi authored Apr 26, 2024
1 parent 30512db commit 85fc6af
Show file tree
Hide file tree
Showing 26 changed files with 995 additions and 285 deletions.
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ go 1.22

require (
github.com/charmbracelet/huh v0.3.0
github.com/mitchellh/mapstructure v1.5.0
github.com/onsi/ginkgo/v2 v2.17.1
github.com/onsi/gomega v1.33.0
github.com/shipengqi/component-base v0.2.9
github.com/shipengqi/golib v0.2.12
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v3 v3.0.1
)

Expand All @@ -22,6 +24,7 @@ require (
github.com/charmbracelet/bubbletea v0.25.0 // indirect
github.com/charmbracelet/lipgloss v0.10.0 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
Expand All @@ -40,6 +43,7 @@ require (
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.6.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
Expand Down
30 changes: 17 additions & 13 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ import (
"gopkg.in/yaml.v3"

"github.com/shipengqi/commitizen/internal/options"
"github.com/shipengqi/commitizen/internal/render"
"github.com/shipengqi/commitizen/internal/templates"
)

const (
RCFilename = ".git-czrc"
RCFilename = ".czrc"
ReservedDefaultName = "default"
FieldKeyTemplateSelect = "template-select"
)

type Config struct {
defaultTmpl *render.Template
more []*render.Template
defaultTmpl *templates.Template
more []*templates.Template
}

func New() *Config {
Expand Down Expand Up @@ -81,7 +81,7 @@ func (c *Config) initialize() error {
return nil
}

func (c *Config) Run(opts *options.Options) (*render.Template, error) {
func (c *Config) Run(opts *options.Options) (*templates.Template, error) {
err := c.initialize()
if err != nil {
return nil, err
Expand Down Expand Up @@ -124,7 +124,7 @@ func (c *Config) Run(opts *options.Options) (*render.Template, error) {

func (c *Config) createTemplatesSelect(label string) *huh.Form {
var choices []string
var all []*render.Template
var all []*templates.Template
all = append(all, c.more...)
all = append(all, c.defaultTmpl)
// list custom templates and default templates
Expand All @@ -141,7 +141,7 @@ func (c *Config) createTemplatesSelect(label string) *huh.Form {
)
}

func LoadTemplates(file string) ([]*render.Template, error) {
func LoadTemplates(file string) ([]*templates.Template, error) {
if len(file) == 0 {
return nil, nil
}
Expand All @@ -153,24 +153,28 @@ func LoadTemplates(file string) ([]*render.Template, error) {
return load(fd)
}

func Load(data []byte) ([]*render.Template, error) {
func Load(data []byte) ([]*templates.Template, error) {
return load(bytes.NewReader(data))
}

func load(reader io.Reader) ([]*render.Template, error) {
var templates []*render.Template
func load(reader io.Reader) ([]*templates.Template, error) {
var tmpls []*templates.Template
d := yaml.NewDecoder(reader)
for {
tmpl := new(render.Template)
tmpl := new(templates.Template)
err := d.Decode(tmpl)
if err != nil {
if errors.Is(err, io.EOF) {
break
}
return nil, err
}
templates = append(templates, tmpl)
err = tmpl.Initialize()
if err != nil {
return nil, err
}
tmpls = append(tmpls, tmpl)
}

return templates, nil
return tmpls, nil
}
62 changes: 34 additions & 28 deletions internal/config/default.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
package config

const DefaultCommitTemplate = `---
version: v2
name: default
default: true
items:
- name: type
desc: "Select the type of change that you're committing:"
type: select
group: page1
label: "Select the type of change that you're committing:"
type: list
options:
- name: feat
desc: "A new feature"
- name: fix
desc: "A bug fix"
- name: docs
desc: "Documentation only changes"
- name: test
desc: "Adding missing or correcting existing tests"
- name: chore
desc: "Changes to the build process or auxiliary tools and\n libraries such as documentation generation"
- name: style
desc: "Changes that do not affect the meaning of the code\n (white-space, formatting, missing semi-colons, etc)"
- name: refactor
desc: "A code change that neither fixes a bug nor adds a feature"
- name: perf
desc: "A code change that improves performance"
- name: revert
desc: "Reverts a previous commit"
- value: feat
key: "feat: A new feature"
- value: fix
key: "fix: A bug fix"
- value: docs
key: "docs: Documentation only changes"
- value: test
key: "test: Adding missing or correcting existing tests"
- value: chore
key: "chore: Changes to the build process or auxiliary tools and\n libraries such as documentation generation"
- value: style
key: "style: Changes that do not affect the meaning of the code\n (white-space, formatting, missing semi-colons, etc)"
- value: refactor
key: "refactor: A code change that neither fixes a bug nor adds a feature"
- value: perf
key: "perf: A code change that improves performance"
- value: revert
key: "revert: Reverts a previous commit"
- name: scope
desc: "Scope. What is the scope of this change? (class or file name):"
type: input
group: page2
label: "Scope. What is the scope of this change? (class or file name):"
type: string
- name: subject
desc: "Subject. Write a short and imperative summary of the code change (lower case and no period):"
type: input
group: page2
label: "Subject. Write a short and imperative summary of the code change (lower case and no period):"
type: string
required: true
- name: body
desc: "Body. Provide additional contextual information about the code changes:"
type: textarea
group: page3
label: "Body. Provide additional contextual information about the code changes:"
type: text
- name: footer
desc: "Footer. Information about Breaking Changes and reference issues that this commit closes:"
type: textarea
group: page3
label: "Footer. Information about Breaking Changes and reference issues that this commit closes:"
type: text
format: "{{.type}}{{with .scope}}({{.}}){{end}}: {{.subject}}{{with .body}}\n\n{{.}}{{end}}{{with .footer}}\n\n{{.}}{{end}}"`
7 changes: 7 additions & 0 deletions internal/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package errors

import "errors"

var (
ErrType = errors.New("type error")
)
17 changes: 17 additions & 0 deletions internal/errors/required.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package errors

import (
"fmt"
)

type RequiredErr struct {
field string
}

func (e RequiredErr) Error() string {
return fmt.Sprintf("%s is required", e.field)
}

func NewRequiredErr(field string) error {
return RequiredErr{field: field}
}
26 changes: 26 additions & 0 deletions internal/parameter/boolean/bool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package boolean

import (
"github.com/charmbracelet/huh"

"github.com/shipengqi/commitizen/internal/parameter"
)

type Param struct {
parameter.Parameter `mapstructure:",squash"`

DefaultValue bool `yaml:"default_value" json:"default_value" mapstructure:"default_value"`
}

func (p Param) Render() huh.Field {
param := huh.NewConfirm().Key(p.Name).
Title(p.Label)

if len(p.Description) > 0 {
param.Description(p.Description)
}

param.Value(&p.DefaultValue)

return param
}
44 changes: 44 additions & 0 deletions internal/parameter/integer/int.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package integer

import (
"github.com/charmbracelet/huh"

"github.com/shipengqi/commitizen/internal/parameter"
"github.com/shipengqi/commitizen/internal/parameter/validators"
)

type Param struct {
parameter.Parameter `mapstructure:",squash"`

DefaultValue string `yaml:"default_value" json:"default_value" mapstructure:"default_value"`
Required bool `yaml:"required" json:"required" mapstructure:"required"`
Min *int `yaml:"min" json:"min" mapstructure:"min"`
Max *int `yaml:"max" json:"max" mapstructure:"max"`
}

func (p Param) Render() huh.Field {
param := huh.NewInput().Key(p.Name).
Title(p.Label)

if len(p.Description) > 0 {
param.Description(p.Description)
}

param.Value(&p.DefaultValue)

var group []validators.Validator
if p.Required {
group = append(group, validators.Required(p.Name, true))
}
if p.Min != nil {
group = append(group, validators.Min(*p.Min))
}
if p.Max != nil {
group = append(group, validators.Max(*p.Max))
}

if len(group) > 0 {
param.Validate(validators.Group(group...))
}
return param
}
46 changes: 46 additions & 0 deletions internal/parameter/list/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package list

import (
"github.com/charmbracelet/huh"

"github.com/shipengqi/commitizen/internal/errors"
"github.com/shipengqi/commitizen/internal/parameter"
"github.com/shipengqi/commitizen/internal/parameter/validators"
)

type Param struct {
parameter.Parameter `mapstructure:",squash"`

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"`
}

func (p Param) Validate() []error {
errs := p.Parameter.Validate()
if len(p.Options) < 1 {
errs = append(errs, errors.NewRequiredErr("parameter.options"))
}
return errs
}

func (p Param) Render() huh.Field {
param := huh.NewSelect[string]().Key(p.Name).
Options(p.Options...).
Title(p.Label)
if len(p.Description) > 0 {
param.Description(p.Description)
}

param.Value(&p.DefaultValue)

var group []validators.Validator
if p.Required {
group = append(group, validators.Required(p.Name, false))
}

if len(group) > 0 {
param.Validate(validators.Group(group...))
}
return param
}
42 changes: 42 additions & 0 deletions internal/parameter/multilist/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package multilist

import (
"github.com/charmbracelet/huh"

"github.com/shipengqi/commitizen/internal/errors"
"github.com/shipengqi/commitizen/internal/parameter"
"github.com/shipengqi/commitizen/internal/parameter/validators"
)

type Param struct {
parameter.Parameter `mapstructure:",squash"`

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"`
}

func (p Param) Validate() []error {
errs := p.Parameter.Validate()
if len(p.Options) < 1 {
errs = append(errs, errors.NewRequiredErr("parameter.options"))
}
return errs
}

func (p Param) Render() huh.Field {
param := huh.NewMultiSelect[string]().Key(p.Name).
Options(p.Options...).
Title(p.Label)
if len(p.Description) > 0 {
param.Description(p.Description)
}

param.Value(&p.DefaultValue)

if p.Required {
param.Validate(validators.MultiRequired(p.Name))
}

return param
}
Loading

0 comments on commit 85fc6af

Please sign in to comment.