add tagalign linter (#3709)
This commit is contained in:
parent
69f929b227
commit
134f2e0491
@ -1739,6 +1739,39 @@ linters-settings:
|
|||||||
# Default: ["200", "400", "404", "500"]
|
# Default: ["200", "400", "404", "500"]
|
||||||
http-status-code-whitelist: [ "200", "400", "404", "500" ]
|
http-status-code-whitelist: [ "200", "400", "404", "500" ]
|
||||||
|
|
||||||
|
tagalign:
|
||||||
|
# Align and sort can be used together or separately.
|
||||||
|
#
|
||||||
|
# Whether enable align. If true, the struct tags will be aligned.
|
||||||
|
# eg:
|
||||||
|
# type FooBar struct {
|
||||||
|
# Bar string `json:"bar" validate:"required"`
|
||||||
|
# FooFoo int8 `json:"foo_foo" validate:"required"`
|
||||||
|
# }
|
||||||
|
# will be formatted to:
|
||||||
|
# type FooBar struct {
|
||||||
|
# Bar string `json:"bar" validate:"required"`
|
||||||
|
# FooFoo int8 `json:"foo_foo" validate:"required"`
|
||||||
|
# }
|
||||||
|
# Default: true.
|
||||||
|
align: false
|
||||||
|
# Whether enable tags sort.
|
||||||
|
# If true, the tags will be sorted by name in ascending order.
|
||||||
|
# eg: `xml:"bar" json:"bar" validate:"required"` -> `json:"bar" validate:"required" xml:"bar"`
|
||||||
|
# Default: true
|
||||||
|
sort: false
|
||||||
|
# Specify the order of tags, the other tags will be sorted by name.
|
||||||
|
# This option will be ignored if `sort` is false.
|
||||||
|
# Default: []
|
||||||
|
order:
|
||||||
|
- json
|
||||||
|
- yaml
|
||||||
|
- yml
|
||||||
|
- toml
|
||||||
|
- mapstructure
|
||||||
|
- binding
|
||||||
|
- validate
|
||||||
|
|
||||||
tagliatelle:
|
tagliatelle:
|
||||||
# Check the struct tag name case.
|
# Check the struct tag name case.
|
||||||
case:
|
case:
|
||||||
@ -2118,6 +2151,7 @@ linters:
|
|||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
- structcheck
|
||||||
- stylecheck
|
- stylecheck
|
||||||
|
- tagalign
|
||||||
- tagliatelle
|
- tagliatelle
|
||||||
- tenv
|
- tenv
|
||||||
- testableexamples
|
- testableexamples
|
||||||
@ -2229,6 +2263,7 @@ linters:
|
|||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
- structcheck
|
||||||
- stylecheck
|
- stylecheck
|
||||||
|
- tagalign
|
||||||
- tagliatelle
|
- tagliatelle
|
||||||
- tenv
|
- tenv
|
||||||
- testableexamples
|
- testableexamples
|
||||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.19
|
|||||||
require (
|
require (
|
||||||
4d63.com/gocheckcompilerdirectives v1.2.1
|
4d63.com/gocheckcompilerdirectives v1.2.1
|
||||||
4d63.com/gochecknoglobals v0.2.1
|
4d63.com/gochecknoglobals v0.2.1
|
||||||
|
github.com/4meepo/tagalign v1.2.2
|
||||||
github.com/Abirdcfly/dupword v0.0.11
|
github.com/Abirdcfly/dupword v0.0.11
|
||||||
github.com/Antonboom/errname v0.1.9
|
github.com/Antonboom/errname v0.1.9
|
||||||
github.com/Antonboom/nilnil v0.1.3
|
github.com/Antonboom/nilnil v0.1.3
|
||||||
|
2
go.sum
generated
2
go.sum
generated
@ -40,6 +40,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
|||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
|
github.com/4meepo/tagalign v1.2.2 h1:kQeUTkFTaBRtd/7jm8OKJl9iHk0gAO+TDFPHGSna0aw=
|
||||||
|
github.com/4meepo/tagalign v1.2.2/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE=
|
||||||
github.com/Abirdcfly/dupword v0.0.11 h1:z6v8rMETchZXUIuHxYNmlUAuKuB21PeaSymTed16wgU=
|
github.com/Abirdcfly/dupword v0.0.11 h1:z6v8rMETchZXUIuHxYNmlUAuKuB21PeaSymTed16wgU=
|
||||||
github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU8d8rgeVYXA=
|
github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU8d8rgeVYXA=
|
||||||
github.com/Antonboom/errname v0.1.9 h1:BZDX4r3l4TBZxZ2o2LNrlGxSHran4d1u4veZdoORTT4=
|
github.com/Antonboom/errname v0.1.9 h1:BZDX4r3l4TBZxZ2o2LNrlGxSHran4d1u4veZdoORTT4=
|
||||||
|
@ -110,6 +110,11 @@ var defaultLintersSettings = LintersSettings{
|
|||||||
Ignore: "",
|
Ignore: "",
|
||||||
Qualified: false,
|
Qualified: false,
|
||||||
},
|
},
|
||||||
|
TagAlign: TagAlignSettings{
|
||||||
|
Align: true,
|
||||||
|
Sort: true,
|
||||||
|
Order: nil,
|
||||||
|
},
|
||||||
Testpackage: TestpackageSettings{
|
Testpackage: TestpackageSettings{
|
||||||
SkipRegexp: `(export|internal)_test\.go`,
|
SkipRegexp: `(export|internal)_test\.go`,
|
||||||
AllowPackages: []string{"main"},
|
AllowPackages: []string{"main"},
|
||||||
@ -203,6 +208,7 @@ type LintersSettings struct {
|
|||||||
Staticcheck StaticCheckSettings
|
Staticcheck StaticCheckSettings
|
||||||
Structcheck StructCheckSettings
|
Structcheck StructCheckSettings
|
||||||
Stylecheck StaticCheckSettings
|
Stylecheck StaticCheckSettings
|
||||||
|
TagAlign TagAlignSettings
|
||||||
Tagliatelle TagliatelleSettings
|
Tagliatelle TagliatelleSettings
|
||||||
Tenv TenvSettings
|
Tenv TenvSettings
|
||||||
Testpackage TestpackageSettings
|
Testpackage TestpackageSettings
|
||||||
@ -655,6 +661,12 @@ type StructCheckSettings struct {
|
|||||||
CheckExportedFields bool `mapstructure:"exported-fields"`
|
CheckExportedFields bool `mapstructure:"exported-fields"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagAlignSettings struct {
|
||||||
|
Align bool `mapstructure:"align"`
|
||||||
|
Sort bool `mapstructure:"sort"`
|
||||||
|
Order []string `mapstructure:"order"`
|
||||||
|
}
|
||||||
|
|
||||||
type TagliatelleSettings struct {
|
type TagliatelleSettings struct {
|
||||||
Case struct {
|
Case struct {
|
||||||
Rules map[string]string
|
Rules map[string]string
|
||||||
|
70
pkg/golinters/tagalign.go
Normal file
70
pkg/golinters/tagalign.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package golinters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/4meepo/tagalign"
|
||||||
|
"golang.org/x/tools/go/analysis"
|
||||||
|
|
||||||
|
"github.com/golangci/golangci-lint/pkg/config"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||||
|
"github.com/golangci/golangci-lint/pkg/result"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTagAlign(settings *config.TagAlignSettings) *goanalysis.Linter {
|
||||||
|
var mu sync.Mutex
|
||||||
|
var resIssues []goanalysis.Issue
|
||||||
|
|
||||||
|
options := []tagalign.Option{tagalign.WithMode(tagalign.GolangciLintMode)}
|
||||||
|
|
||||||
|
if settings != nil {
|
||||||
|
options = append(options, tagalign.WithAlign(settings.Align))
|
||||||
|
|
||||||
|
if settings.Sort || len(settings.Order) > 0 {
|
||||||
|
options = append(options, tagalign.WithSort(settings.Order...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
analyzer := tagalign.NewAnalyzer(options...)
|
||||||
|
analyzer.Run = func(pass *analysis.Pass) (any, error) {
|
||||||
|
taIssues := tagalign.Run(pass, options...)
|
||||||
|
|
||||||
|
issues := make([]goanalysis.Issue, len(taIssues))
|
||||||
|
for i, issue := range taIssues {
|
||||||
|
report := &result.Issue{
|
||||||
|
FromLinter: analyzer.Name,
|
||||||
|
Pos: issue.Pos,
|
||||||
|
Text: issue.Message,
|
||||||
|
Replacement: &result.Replacement{
|
||||||
|
Inline: &result.InlineFix{
|
||||||
|
StartCol: issue.InlineFix.StartCol,
|
||||||
|
Length: issue.InlineFix.Length,
|
||||||
|
NewString: issue.InlineFix.NewString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
issues[i] = goanalysis.NewIssue(report, pass)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(issues) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
resIssues = append(resIssues, issues...)
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return goanalysis.NewLinter(
|
||||||
|
analyzer.Name,
|
||||||
|
analyzer.Doc,
|
||||||
|
[]*analysis.Analyzer{analyzer},
|
||||||
|
nil,
|
||||||
|
).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||||
|
return resIssues
|
||||||
|
}).WithLoadMode(goanalysis.LoadModeSyntax)
|
||||||
|
}
|
@ -165,6 +165,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
staticcheckCfg *config.StaticCheckSettings
|
staticcheckCfg *config.StaticCheckSettings
|
||||||
structcheckCfg *config.StructCheckSettings
|
structcheckCfg *config.StructCheckSettings
|
||||||
stylecheckCfg *config.StaticCheckSettings
|
stylecheckCfg *config.StaticCheckSettings
|
||||||
|
tagalignCfg *config.TagAlignSettings
|
||||||
tagliatelleCfg *config.TagliatelleSettings
|
tagliatelleCfg *config.TagliatelleSettings
|
||||||
tenvCfg *config.TenvSettings
|
tenvCfg *config.TenvSettings
|
||||||
testpackageCfg *config.TestpackageSettings
|
testpackageCfg *config.TestpackageSettings
|
||||||
@ -244,6 +245,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
staticcheckCfg = &m.cfg.LintersSettings.Staticcheck
|
staticcheckCfg = &m.cfg.LintersSettings.Staticcheck
|
||||||
structcheckCfg = &m.cfg.LintersSettings.Structcheck
|
structcheckCfg = &m.cfg.LintersSettings.Structcheck
|
||||||
stylecheckCfg = &m.cfg.LintersSettings.Stylecheck
|
stylecheckCfg = &m.cfg.LintersSettings.Stylecheck
|
||||||
|
tagalignCfg = &m.cfg.LintersSettings.TagAlign
|
||||||
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
|
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
|
||||||
tenvCfg = &m.cfg.LintersSettings.Tenv
|
tenvCfg = &m.cfg.LintersSettings.Tenv
|
||||||
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
||||||
@ -777,6 +779,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
|||||||
WithPresets(linter.PresetStyle).
|
WithPresets(linter.PresetStyle).
|
||||||
WithURL("https://github.com/dominikh/go-tools/tree/master/stylecheck"),
|
WithURL("https://github.com/dominikh/go-tools/tree/master/stylecheck"),
|
||||||
|
|
||||||
|
linter.NewConfig(golinters.NewTagAlign(tagalignCfg)).
|
||||||
|
WithSince("v1.53.0").
|
||||||
|
WithPresets(linter.PresetStyle, linter.PresetFormatting).
|
||||||
|
WithAutoFix().
|
||||||
|
WithURL("https://github.com/4meepo/tagalign"),
|
||||||
|
|
||||||
linter.NewConfig(golinters.NewTagliatelle(tagliatelleCfg)).
|
linter.NewConfig(golinters.NewTagliatelle(tagliatelleCfg)).
|
||||||
WithSince("v1.40.0").
|
WithSince("v1.40.0").
|
||||||
WithPresets(linter.PresetStyle).
|
WithPresets(linter.PresetStyle).
|
||||||
|
3
test/testdata/configs/tagalign_align_only.yml
vendored
Normal file
3
test/testdata/configs/tagalign_align_only.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
linters-settings:
|
||||||
|
tagalign:
|
||||||
|
sort: false
|
7
test/testdata/configs/tagalign_order_only.yml
vendored
Normal file
7
test/testdata/configs/tagalign_order_only.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
linters-settings:
|
||||||
|
tagalign:
|
||||||
|
align: false
|
||||||
|
order:
|
||||||
|
- "xml"
|
||||||
|
- "json"
|
||||||
|
- "yaml"
|
4
test/testdata/configs/tagalign_sort_only.yml
vendored
Normal file
4
test/testdata/configs/tagalign_sort_only.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
linters-settings:
|
||||||
|
tagalign:
|
||||||
|
align: false
|
||||||
|
sort: true
|
15
test/testdata/tagalign.go
vendored
Normal file
15
test/testdata/tagalign.go
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//golangcitest:args -Etagalign
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TagAlignExampleAlignSort struct {
|
||||||
|
Foo time.Duration `json:"foo,omitempty" yaml:"foo" xml:"foo" binding:"required" gorm:"column:foo" zip:"foo" validate:"required"` // want `binding:"required" gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||||
|
Bar int `validate:"required" yaml:"bar" xml:"bar" binding:"required" json:"bar,omitempty" gorm:"column:bar" zip:"bar" ` // want `binding:"required" gorm:"column:bar" json:"bar,omitempty" validate:"required" xml:"bar" yaml:"bar" zip:"bar"`
|
||||||
|
FooBar int `gorm:"column:fooBar" validate:"required" xml:"fooBar" binding:"required" json:"fooBar,omitempty" zip:"fooBar" yaml:"fooBar"` // want `binding:"required" gorm:"column:fooBar" json:"fooBar,omitempty" validate:"required" xml:"fooBar" yaml:"fooBar" zip:"fooBar"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagAlignExampleAlignSort2 struct {
|
||||||
|
Foo int ` xml:"foo" json:"foo,omitempty" yaml:"foo" zip:"foo" binding:"required" gorm:"column:foo" validate:"required"` // want `binding:"required" gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||||
|
Bar int `validate:"required" gorm:"column:bar" yaml:"bar" xml:"bar" binding:"required" json:"bar" zip:"bar" ` // want `binding:"required" gorm:"column:bar" json:"bar" validate:"required" xml:"bar" yaml:"bar" zip:"bar"`
|
||||||
|
}
|
31
test/testdata/tagalign_align_only.go
vendored
Normal file
31
test/testdata/tagalign_align_only.go
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//golangcitest:args -Etagalign
|
||||||
|
//golangcitest:config_path testdata/configs/tagalign_align_only.yml
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TagAlignExampleAlignOnlyKO struct {
|
||||||
|
Foo time.Time `gorm:"column:foo" json:"foo,omitempty" xml:"foo" yaml:"foo" zip:"foo"` // want `gorm:"column:foo" json:"foo,omitempty" xml:"foo" yaml:"foo" zip:"foo"`
|
||||||
|
FooBar struct{} `gorm:"column:fooBar" zip:"fooBar" json:"fooBar,omitempty" xml:"fooBar" yaml:"fooBar"` // want `gorm:"column:fooBar" zip:"fooBar" json:"fooBar,omitempty" xml:"fooBar" yaml:"fooBar"`
|
||||||
|
FooFoo struct {
|
||||||
|
Foo int `json:"foo" yaml:"foo"` // want `json:"foo" yaml:"foo"`
|
||||||
|
Bar int `yaml:"bar" json:"bar"` // want `yaml:"bar" json:"bar"`
|
||||||
|
BarBar string `json:"barBar" yaml:"barBar"`
|
||||||
|
} `xml:"fooFoo" json:"fooFoo"`
|
||||||
|
NoTag struct{}
|
||||||
|
BarBar struct{} `json:"barBar,omitempty" gorm:"column:barBar" yaml:"barBar" xml:"barBar" zip:"barBar"`
|
||||||
|
Boo struct{} `gorm:"column:boo" json:"boo,omitempty" xml:"boo" yaml:"boo" zip:"boo"` // want `gorm:"column:boo" json:"boo,omitempty" xml:"boo" yaml:"boo" zip:"boo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagAlignExampleAlignOnlyOK struct {
|
||||||
|
Foo time.Time `gorm:"column:foo" json:"foo,omitempty" xml:"foo" yaml:"foo" zip:"foo"`
|
||||||
|
FooBar struct{} `gorm:"column:fooBar" zip:"fooBar" json:"fooBar,omitempty" xml:"fooBar" yaml:"fooBar"`
|
||||||
|
FooFoo struct {
|
||||||
|
Foo int `json:"foo" yaml:"foo"`
|
||||||
|
Bar int `yaml:"bar" json:"bar"`
|
||||||
|
BarBar string `json:"barBar" yaml:"barBar"`
|
||||||
|
} `xml:"fooFoo" json:"fooFoo"`
|
||||||
|
NoTag struct{}
|
||||||
|
BarBar struct{} `json:"barBar,omitempty" gorm:"column:barBar" yaml:"barBar" xml:"barBar" zip:"barBar"`
|
||||||
|
Boo struct{} `gorm:"column:boo" json:"boo,omitempty" xml:"boo" yaml:"boo" zip:"boo"`
|
||||||
|
}
|
15
test/testdata/tagalign_order_only.go
vendored
Normal file
15
test/testdata/tagalign_order_only.go
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//golangcitest:args -Etagalign
|
||||||
|
//golangcitest:config_path testdata/configs/tagalign_order_only.yml
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TagAlignExampleOrderOnlyKO struct {
|
||||||
|
Foo time.Time `xml:"foo" json:"foo,omitempty" yaml:"foo" zip:"foo" gorm:"column:foo" validate:"required"` // want `xml:"foo" json:"foo,omitempty" yaml:"foo" gorm:"column:foo" validate:"required" zip:"foo"`
|
||||||
|
FooBar struct{} `gorm:"column:fooBar" validate:"required" zip:"fooBar" xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar"` // want `xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar" gorm:"column:fooBar" validate:"required" zip:"fooBar"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagAlignExampleOrderOnlyOK struct {
|
||||||
|
Foo time.Time `xml:"foo" json:"foo,omitempty" yaml:"foo" gorm:"column:foo" validate:"required" zip:"foo"`
|
||||||
|
FooBar struct{} `xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar" gorm:"column:fooBar" validate:"required" zip:"fooBar"`
|
||||||
|
}
|
15
test/testdata/tagalign_sort_only.go
vendored
Normal file
15
test/testdata/tagalign_sort_only.go
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//golangcitest:args -Etagalign
|
||||||
|
//golangcitest:config_path testdata/configs/tagalign_sort_only.yml
|
||||||
|
package testdata
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type TagAlignExampleSortOnlyKO struct {
|
||||||
|
Foo time.Time `xml:"foo" json:"foo,omitempty" yaml:"foo" gorm:"column:foo" validate:"required" zip:"foo"` // want `gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||||
|
FooBar struct{} `gorm:"column:fooBar" validate:"required" zip:"fooBar" xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar"` // want `gorm:"column:fooBar" json:"fooBar,omitempty" validate:"required" xml:"fooBar" yaml:"fooBar" zip:"fooBar"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagAlignExampleSortOnlyOK struct {
|
||||||
|
Foo time.Time `gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||||
|
FooBar struct{} `gorm:"column:fooBar" json:"fooBar,omitempty" validate:"required" xml:"fooBar" yaml:"fooBar" zip:"fooBar"`
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user