Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: conventional commit validator #1228

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 22 additions & 1 deletion baked_in.go
Expand Up @@ -23,6 +23,8 @@ import (
"golang.org/x/text/language"

"github.com/gabriel-vasile/mimetype"
"github.com/leodido/go-conventionalcommits"
cc "github.com/leodido/go-conventionalcommits/parser"
urn "github.com/leodido/go-urn"
)

Expand Down Expand Up @@ -130,7 +132,8 @@ var (
"url": isURL,
"http_url": isHttpURL,
"uri": isURI,
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"conventionalcommit": isConventionalCommit, // Conventional Commit v1.0 spec
"file": isFile,
"filepath": isFilePath,
"base64": isBase64,
Expand Down Expand Up @@ -1522,6 +1525,24 @@ func isUrnRFC2141(fl FieldLevel) bool {
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}

// isConventionalCommit is the validation function for validating if the current field's value is a valid conventional commit as per Conventional Commits v1.0 spec.
func isConventionalCommit(fl FieldLevel) bool {
field := fl.Field()

switch field.Kind() {
case reflect.String:

str := field.String()

parser := cc.NewMachine(conventionalcommits.WithTypes(conventionalcommits.TypesConventional))
_, err := parser.Parse([]byte(str))

return err == nil
}

panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}

// isFile is the validation function for validating if the current field's value is a valid existing file path.
func isFile(fl FieldLevel) bool {
field := fl.Field()
Expand Down
7 changes: 7 additions & 0 deletions doc.go
Expand Up @@ -916,6 +916,13 @@ according to the RFC 2141 spec.

Usage: urn_rfc2141

# Conventional Commits v1.0 String

This validataes that a string value contains a valid conventional commit
according to the Conventional Commits v1.0 spec.

Usage: conventionalcommit

# Base64 String

This validates that a string value contains a valid base64 value.
Expand Down
4 changes: 3 additions & 1 deletion go.mod
@@ -1,18 +1,20 @@
module github.com/go-playground/validator/v10

go 1.18
go 1.21

require (
github.com/gabriel-vasile/mimetype v1.4.3
github.com/go-playground/assert/v2 v2.2.0
github.com/go-playground/locales v0.14.1
github.com/go-playground/universal-translator v0.18.1
github.com/leodido/go-conventionalcommits v0.12.0
github.com/leodido/go-urn v1.4.0
golang.org/x/crypto v0.19.0
golang.org/x/text v0.14.0
)

require (
github.com/sirupsen/logrus v1.9.3 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
)
14 changes: 14 additions & 0 deletions go.sum
@@ -1,4 +1,6 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
Expand All @@ -7,16 +9,28 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/leodido/go-conventionalcommits v0.12.0 h1:pG01rl8Ze+mxnSSVB2wPdGASXyyU25EGwLUc0bWrmKc=
github.com/leodido/go-conventionalcommits v0.12.0/go.mod h1:DW+n8pQb5w/c7Vba7iGOMS3rkbPqykVlnrDykGjlsJM=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
87 changes: 87 additions & 0 deletions validator_test.go
Expand Up @@ -8134,6 +8134,93 @@ func TestUrnRFC2141(t *testing.T) {
PanicMatches(t, func() { _ = validate.Var(i, tag) }, "Bad field type int")
}

func TestConventionalCommit(t *testing.T) {
tests := []struct {
param string
expected bool
}{
{"feat: allow provided config object to extend other configs", true},
{"refactor: move code around", true},
{"perf: my parser is so fast", true},
{"build: makefiles yay!", true},
{
`feat: allow provided config object to extend other configs

BREAKING CHANGE: extends key in config file is now used for extending other config files`,
true,
},
{"feat!: send an email to the customer when a product is shipped", true},
{"feat(api)!: send an email to the customer when a product is shipped", true},
{
`chore!: drop support for Node 6

BREAKING CHANGE: use JavaScript features not available in Node 6.`, true},
{"docs: correct spelling of CHANGELOG", true},
{"feat(lang): add Polish language", true},
{
`fix: prevent racing of requests

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

Remove timeouts which were used to mitigate the racing issue but are
obsolete now.

Reviewed-by: Z
Refs: #123`,
true,
},
{"fix: x", true},
{"fix(): bbb", true},
{
`fix: only footer

Fixes #3
Signed-off-by: Leo`,
true,
},
{"fix", false},
{"fi:", false},
{"feat(az)(", false},
{"fix((", false},
{"feat(az)!: bla\x0A", false},
{"feat(az)!: bla\x0Al", false},
{"feat(az): new\x0Aline", false},
{"fix(scope)!: ", false},
{"fix:a", false},
{"fix(scope)", false},
{"feat?", false},
{"fix>", false},
}

tag := "conventionalcommit"

validate := New()

for i, test := range tests {

errs := validate.Var(test.param, tag)

if test.expected {
if !IsEqual(errs, nil) {
t.Fatalf("Index: %d conventionalcommit failed Error: %s", i, errs)
}
} else {
if IsEqual(errs, nil) {
t.Fatalf("Index: %d conventionalcommit failed Error: %s", i, errs)
} else {
val := getError(errs, "", "")
if val.Tag() != tag {
t.Fatalf("Index: %d conventionalcommit failed Error: %s", i, errs)
}
}
}
}

i := 1
PanicMatches(t, func() { _ = validate.Var(i, tag) }, "Bad field type int")
}

func TestUrl(t *testing.T) {
tests := []struct {
param string
Expand Down