From 23e022af84323bc05cb094719101ea3a8c52cba6 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Thu, 1 Jul 2021 16:07:54 +0530 Subject: [PATCH 01/12] fix: rule config overriding --- go.mod | 1 + go.sum | 2 ++ validator/rules/executor.go | 39 +++++++++++++++++-------------------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index be74727..d40a322 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/BurntSushi/toml v0.3.1 + github.com/imdario/mergo v0.3.12 github.com/nicksnyder/go-i18n/v2 v2.1.2 github.com/spf13/cobra v1.1.3 golang.org/x/text v0.3.3 diff --git a/go.sum b/go.sum index 60a8706..83c9c26 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 80c8d18..7ddd5e8 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -1,15 +1,17 @@ package rules import ( - "encoding/json" "fmt" "log" "os" "github.com/aerogear/charmil/validator" + "github.com/imdario/mergo" "github.com/spf13/cobra" ) +// Rules is an interface that is implemented +// by every rule defined in rules package type Rules interface { Validate() []validator.ValidationError } @@ -84,6 +86,7 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog &MustExistHelper{cmd: cmd, config: config}, } + // traverse all rules and validate for _, rule := range rules { validationErrors := rule.Validate() info.TotalErrors += len(validationErrors) @@ -113,28 +116,22 @@ func (config *RuleConfig) initDefaultRules() { }, } - // Check verbose input from user - var verbose bool - if config != nil && config.Verbose { - verbose = true + if err := mergo.Merge(&config.Length, defaultConfig.Length); err != nil { + log.Fatal(err) } + config.Fields = append(config.Fields, defaultConfig.Fields...) + config.Fields = removeDuplicates(config.Fields) +} - // Set Config to defaultConfig - *config = *defaultConfig - config.Verbose = verbose - - // Merge the defaultConfig and Config given by user - if config.Length.Limits != nil && config.MustExist.Fields != nil { - out, err := json.Marshal(config) - if err != nil { - log.Fatal(err) - } - data := []byte(out) - - errr := json.Unmarshal(data, &defaultConfig) - if errr != nil { - log.Fatal(errr) +// remove duplicates from slice +func removeDuplicates(input []string) []string { + keys := make(map[string]bool) + list := []string{} + for _, entry := range input { + if _, value := keys[entry]; !value { + keys[entry] = true + list = append(list, entry) } } - + return list } From 4c61aef4be1faaf88767a345fa36f754a7ef6f54 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Sat, 3 Jul 2021 11:39:20 +0530 Subject: [PATCH 02/12] refactor: rules as slice --- go.mod | 1 - go.sum | 2 - validator/example/cmd_test.go | 9 ++++- validator/rules/executor.go | 70 ++++++++++++----------------------- validator/rules/length.go | 26 ++++++------- validator/rules/must_exist.go | 18 ++++----- 6 files changed, 48 insertions(+), 78 deletions(-) diff --git a/go.mod b/go.mod index d40a322..be74727 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.16 require ( github.com/BurntSushi/toml v0.3.1 - github.com/imdario/mergo v0.3.12 github.com/nicksnyder/go-i18n/v2 v2.1.2 github.com/spf13/cobra v1.1.3 golang.org/x/text v0.3.3 diff --git a/go.sum b/go.sum index 83c9c26..60a8706 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index 436a25a..d0f97da 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -11,7 +11,12 @@ func Test_ExecuteCommand(t *testing.T) { // Testing cobra commands with default recommended config // default config can also be overrided - var vali rules.RuleConfig + var vali rules.RuleConfig = rules.RuleConfig{ + Rules: []rules.Rules{ + &rules.Length{Verbose: true, Limits: map[string]rules.Limit{"Use": {Min: 100}}}, + }, + } + validationErr := vali.ExecuteRules(cmd) if len(validationErr) != 0 { t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) @@ -19,7 +24,7 @@ func Test_ExecuteCommand(t *testing.T) { for _, errs := range validationErr { if errs.Err != nil { - t.Fatalf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) + t.Errorf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) } } diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 7ddd5e8..4292304 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -2,26 +2,22 @@ package rules import ( "fmt" - "log" "os" "github.com/aerogear/charmil/validator" - "github.com/imdario/mergo" "github.com/spf13/cobra" ) // Rules is an interface that is implemented // by every rule defined in rules package type Rules interface { - Validate() []validator.ValidationError + Validate(cmd *cobra.Command) []validator.ValidationError } // RuleConfig is the struct that stores // configuration of rules type RuleConfig struct { - Verbose bool - Length - MustExist + Rules []Rules } // ExecuteRules executes all the rules @@ -31,7 +27,7 @@ func (config *RuleConfig) ExecuteRules(cmd *cobra.Command) []validator.Validatio info := validator.StatusLog{TotalTested: 0, TotalErrors: 0, Errors: errors} // initialize default rules - config.initDefaultRules() + config.initDefaultRules(cmd) // validate the root command config.validate(cmd, &info) @@ -51,7 +47,7 @@ func (config *RuleConfig) executeHelper(cmd *cobra.Command, info *validator.Stat // executeRecursive recursively traverse over all the subcommands // and validate using executeRulesChildren function func (config *RuleConfig) executeRecursive(cmd *cobra.Command, info *validator.StatusLog) []validator.ValidationError { - + // fmt.Println(cmd.CommandPath()) for _, child := range cmd.Commands() { // base case if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { @@ -81,14 +77,11 @@ func (config *RuleConfig) executeRulesChildren(cmd *cobra.Command, info *validat // validate returns validation errors by executing the rules func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog) { - rules := []Rules{ - &LengthHelper{cmd: cmd, config: config}, - &MustExistHelper{cmd: cmd, config: config}, - } - // traverse all rules and validate - for _, rule := range rules { - validationErrors := rule.Validate() + for _, rule := range config.Rules { + // fmt.Println(reflect.TypeOf(rule)) + + validationErrors := rule.Validate(cmd) info.TotalErrors += len(validationErrors) info.Errors = append(info.Errors, validationErrors...) info.TotalTested++ @@ -98,40 +91,23 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user -func (config *RuleConfig) initDefaultRules() { - - // default config for rules - var defaultConfig = &RuleConfig{ - Verbose: false, - Length: Length{ - Limits: map[string]Limit{ - "Use": {Min: 2}, - "Short": {Min: 15}, - "Long": {Min: 50}, - "Example": {Min: 50}, - }, - }, - MustExist: MustExist{ - Fields: []string{"Use", "Short", "Long", "Example"}, +func (config *RuleConfig) initDefaultRules(cmd *cobra.Command) { + + defaultConfig := RuleConfig{ + Rules: []Rules{ + &Length{ + Verbose: false, + Limits: map[string]Limit{ + "Use": {Min: 2}, + "Short": {Min: 15}, + "Long": {Min: 50}, + "Example": {Min: 50}, + }}, + &MustExist{Verbose: false, Fields: []string{"Use", "Short", "Long", "Example"}}, }, } - if err := mergo.Merge(&config.Length, defaultConfig.Length); err != nil { - log.Fatal(err) - } - config.Fields = append(config.Fields, defaultConfig.Fields...) - config.Fields = removeDuplicates(config.Fields) -} + // TODO: Override default configuration -// remove duplicates from slice -func removeDuplicates(input []string) []string { - keys := make(map[string]bool) - list := []string{} - for _, entry := range input { - if _, value := keys[entry]; !value { - keys[entry] = true - list = append(list, entry) - } - } - return list + *config = defaultConfig } diff --git a/validator/rules/length.go b/validator/rules/length.go index 15b90e4..cd5f4f5 100644 --- a/validator/rules/length.go +++ b/validator/rules/length.go @@ -22,31 +22,27 @@ var ( var LengthRule = "LENGTH_RULE" -// Length is a struct that provides a map -// with key as attribute for which length is controlled -// and value limit as Limit struct -type Length struct { - Limits map[string]Limit -} - // Limit defines min, max length of string type Limit struct { Min, Max int } -type LengthHelper struct { - cmd *cobra.Command - config *RuleConfig +// Length is a struct that provides a map +// with key as attribute for which length is controlled +// and value limit as Limit struct +type Length struct { + Verbose bool + Limits map[string]Limit } -func (l *LengthHelper) Validate() []validator.ValidationError { - return validateLength(l.cmd, l.config) +func (l *Length) Validate(cmd *cobra.Command) []validator.ValidationError { + return l.validateLength(cmd) } -func validateLength(cmd *cobra.Command, config *RuleConfig) []validator.ValidationError { +func (l *Length) validateLength(cmd *cobra.Command) []validator.ValidationError { var errors []validator.ValidationError - for fieldName, limits := range config.Length.Limits { + for fieldName, limits := range l.Limits { // reflects the fieldName in cobra.Command struct reflectValue := reflect.ValueOf(cmd).Elem().FieldByName(fieldName) @@ -57,7 +53,7 @@ func validateLength(cmd *cobra.Command, config *RuleConfig) []validator.Validati } // validate fieldName - err := validateField(cmd, limits, reflectValue.String(), cmd.CommandPath(), fieldName, config.Verbose) + err := validateField(cmd, limits, reflectValue.String(), cmd.CommandPath(), fieldName, l.Verbose) if err.Err != nil { errors = append(errors, err) } diff --git a/validator/rules/must_exist.go b/validator/rules/must_exist.go index 0af5502..efdafca 100644 --- a/validator/rules/must_exist.go +++ b/validator/rules/must_exist.go @@ -21,22 +21,18 @@ var MustExistRule = "MUST_EXIST_RULE" // MustExist is a struct that provides // Fields defined for MustExist validation type MustExist struct { - Fields []string + Verbose bool + Fields []string } -type MustExistHelper struct { - cmd *cobra.Command - config *RuleConfig +func (m *MustExist) Validate(cmd *cobra.Command) []validator.ValidationError { + return m.validateMustExist(cmd) } -func (m *MustExistHelper) Validate() []validator.ValidationError { - return validateMustExist(m.cmd, m.config) -} - -func validateMustExist(cmd *cobra.Command, config *RuleConfig) []validator.ValidationError { +func (m *MustExist) validateMustExist(cmd *cobra.Command) []validator.ValidationError { var errors []validator.ValidationError - for _, field := range config.MustExist.Fields { + for _, field := range m.Fields { // reflects the field in cobra.Command struct reflectValue := reflect.ValueOf(cmd).Elem().FieldByName(field) @@ -47,7 +43,7 @@ func validateMustExist(cmd *cobra.Command, config *RuleConfig) []validator.Valid } // validate field and append errors - errors = append(errors, validateByType(cmd, &reflectValue, field, cmd.CommandPath(), config.Verbose)...) + errors = append(errors, validateByType(cmd, &reflectValue, field, cmd.CommandPath(), m.Verbose)...) } return errors } From 6e53b377c5275f6d29b4286a066c4f851fc0b7fc Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Sat, 3 Jul 2021 13:26:50 +0530 Subject: [PATCH 03/12] fix: override length field --- go.mod | 1 + go.sum | 22 ++-------------------- validator/example/cmd_test.go | 5 +++-- validator/rules/executor.go | 20 ++++++++++++++------ 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index be74727..d40a322 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/BurntSushi/toml v0.3.1 + github.com/imdario/mergo v0.3.12 github.com/nicksnyder/go-i18n/v2 v2.1.2 github.com/spf13/cobra v1.1.3 golang.org/x/text v0.3.3 diff --git a/go.sum b/go.sum index 60a8706..0b1f1c2 100644 --- a/go.sum +++ b/go.sum @@ -33,12 +33,10 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -66,7 +64,6 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -87,18 +84,18 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -110,7 +107,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -118,13 +114,11 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -133,11 +127,9 @@ github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61C github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -156,31 +148,23 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -247,7 +231,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -300,7 +283,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index d0f97da..b87f467 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -13,7 +13,8 @@ func Test_ExecuteCommand(t *testing.T) { // default config can also be overrided var vali rules.RuleConfig = rules.RuleConfig{ Rules: []rules.Rules{ - &rules.Length{Verbose: true, Limits: map[string]rules.Limit{"Use": {Min: 100}}}, + &rules.Length{Verbose: false, Limits: map[string]rules.Limit{"Use": {Min: 100}}}, + &rules.MustExist{Verbose: false, Fields: []string{"Args", "yo"}}, }, } @@ -21,7 +22,7 @@ func Test_ExecuteCommand(t *testing.T) { if len(validationErr) != 0 { t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) } - + t.Error() for _, errs := range validationErr { if errs.Err != nil { t.Errorf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 4292304..6005d30 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -2,9 +2,11 @@ package rules import ( "fmt" + "log" "os" "github.com/aerogear/charmil/validator" + "github.com/imdario/mergo" "github.com/spf13/cobra" ) @@ -17,7 +19,8 @@ type Rules interface { // RuleConfig is the struct that stores // configuration of rules type RuleConfig struct { - Rules []Rules + Verbose bool + Rules []Rules } // ExecuteRules executes all the rules @@ -92,22 +95,27 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user func (config *RuleConfig) initDefaultRules(cmd *cobra.Command) { - + defaultVerbose := false defaultConfig := RuleConfig{ + Verbose: defaultVerbose, Rules: []Rules{ &Length{ - Verbose: false, + Verbose: defaultVerbose, Limits: map[string]Limit{ "Use": {Min: 2}, "Short": {Min: 15}, "Long": {Min: 50}, "Example": {Min: 50}, }}, - &MustExist{Verbose: false, Fields: []string{"Use", "Short", "Long", "Example"}}, + &MustExist{Verbose: defaultVerbose, Fields: []string{"Use", "Short", "Long", "Example"}}, }, } - // TODO: Override default configuration - + fmt.Println("User Input", config.Rules[0]) + if err := mergo.Merge(&defaultConfig, config, mergo.WithSliceDeepCopy); err != nil { + log.Fatal(err) + } *config = defaultConfig + fmt.Println("After Merging", config.Rules[0]) + } From 4f466eb7bc673722b3ad19b9fc655c32648cc5c0 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Sat, 3 Jul 2021 14:06:29 +0530 Subject: [PATCH 04/12] fix: mustExist rule overriding --- validator/example/cmd_test.go | 7 ++++--- validator/rules/executor.go | 11 +++++------ validator/rules/length.go | 4 ++-- validator/rules/must_exist.go | 12 +++++++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index b87f467..631f7b5 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -12,9 +12,10 @@ func Test_ExecuteCommand(t *testing.T) { // Testing cobra commands with default recommended config // default config can also be overrided var vali rules.RuleConfig = rules.RuleConfig{ + Verbose: true, Rules: []rules.Rules{ - &rules.Length{Verbose: false, Limits: map[string]rules.Limit{"Use": {Min: 100}}}, - &rules.MustExist{Verbose: false, Fields: []string{"Args", "yo"}}, + &rules.Length{Verbose: false, Limits: map[string]rules.Limit{"Use": {Min: 1000}}}, + &rules.MustExist{Verbose: false, Fields: map[string]bool{"Long": true}}, }, } @@ -22,7 +23,7 @@ func Test_ExecuteCommand(t *testing.T) { if len(validationErr) != 0 { t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) } - t.Error() + for _, errs := range validationErr { if errs.Err != nil { t.Errorf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 6005d30..0a3b405 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -95,27 +95,26 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user func (config *RuleConfig) initDefaultRules(cmd *cobra.Command) { - defaultVerbose := false defaultConfig := RuleConfig{ - Verbose: defaultVerbose, + Verbose: false, Rules: []Rules{ &Length{ - Verbose: defaultVerbose, + Verbose: false, Limits: map[string]Limit{ "Use": {Min: 2}, "Short": {Min: 15}, "Long": {Min: 50}, "Example": {Min: 50}, }}, - &MustExist{Verbose: defaultVerbose, Fields: []string{"Use", "Short", "Long", "Example"}}, + &MustExist{Verbose: false, Fields: map[string]bool{"Use": true, "Short": true, "Long": true, "Example": true}}, }, } - fmt.Println("User Input", config.Rules[0]) + fmt.Println("User Input", config) if err := mergo.Merge(&defaultConfig, config, mergo.WithSliceDeepCopy); err != nil { log.Fatal(err) } *config = defaultConfig - fmt.Println("After Merging", config.Rules[0]) + fmt.Println("After Merging", config) } diff --git a/validator/rules/length.go b/validator/rules/length.go index cd5f4f5..42c673f 100644 --- a/validator/rules/length.go +++ b/validator/rules/length.go @@ -3,7 +3,7 @@ package rules import ( "errors" "fmt" - "log" + "os" "reflect" "github.com/aerogear/charmil/validator" @@ -74,7 +74,7 @@ func validateField(cmd *cobra.Command, limit Limit, value string, path string, f // prints additional info in debug mode if verbose { - log.Printf("%s Command %s -> %s: %v\n", LengthRule, path, value, limit) + fmt.Fprintf(os.Stderr, "%s Command %s -> %s: %v\n", LengthRule, path, value, limit) } if length < limit.Min { diff --git a/validator/rules/must_exist.go b/validator/rules/must_exist.go index efdafca..9b832a8 100644 --- a/validator/rules/must_exist.go +++ b/validator/rules/must_exist.go @@ -3,7 +3,7 @@ package rules import ( "errors" "fmt" - "log" + "os" "reflect" "github.com/aerogear/charmil/validator" @@ -22,7 +22,7 @@ var MustExistRule = "MUST_EXIST_RULE" // Fields defined for MustExist validation type MustExist struct { Verbose bool - Fields []string + Fields map[string]bool } func (m *MustExist) Validate(cmd *cobra.Command) []validator.ValidationError { @@ -32,7 +32,7 @@ func (m *MustExist) Validate(cmd *cobra.Command) []validator.ValidationError { func (m *MustExist) validateMustExist(cmd *cobra.Command) []validator.ValidationError { var errors []validator.ValidationError - for _, field := range m.Fields { + for field, isTrue := range m.Fields { // reflects the field in cobra.Command struct reflectValue := reflect.ValueOf(cmd).Elem().FieldByName(field) @@ -43,7 +43,9 @@ func (m *MustExist) validateMustExist(cmd *cobra.Command) []validator.Validation } // validate field and append errors - errors = append(errors, validateByType(cmd, &reflectValue, field, cmd.CommandPath(), m.Verbose)...) + if isTrue { + errors = append(errors, validateByType(cmd, &reflectValue, field, cmd.CommandPath(), m.Verbose)...) + } } return errors } @@ -55,7 +57,7 @@ func validateByType(cmd *cobra.Command, reflectValue *reflect.Value, field strin // prints additional info in debug mode if verbose { - log.Printf("%s Command %s -> %s: %v\n", MustExistRule, path, reflectValue.String(), field) + fmt.Fprintf(os.Stderr, "%s Command %s -> %s: %v\n", MustExistRule, path, reflectValue.String(), field) } // handle types From 8a43148ebde7c9580effa40324ac2c609bf34015 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Sat, 3 Jul 2021 14:30:43 +0530 Subject: [PATCH 05/12] chore: remove unused param in initDefaultRules --- validator/example/cmd_test.go | 6 +++--- validator/rules/executor.go | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index 631f7b5..833cbc0 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -12,10 +12,10 @@ func Test_ExecuteCommand(t *testing.T) { // Testing cobra commands with default recommended config // default config can also be overrided var vali rules.RuleConfig = rules.RuleConfig{ - Verbose: true, + Verbose: false, Rules: []rules.Rules{ - &rules.Length{Verbose: false, Limits: map[string]rules.Limit{"Use": {Min: 1000}}}, - &rules.MustExist{Verbose: false, Fields: map[string]bool{"Long": true}}, + &rules.Length{Limits: map[string]rules.Limit{"Use": {Min: 2}}}, + &rules.MustExist{Fields: map[string]bool{"Long": false}}, }, } diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 0a3b405..bdeb709 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -30,7 +30,7 @@ func (config *RuleConfig) ExecuteRules(cmd *cobra.Command) []validator.Validatio info := validator.StatusLog{TotalTested: 0, TotalErrors: 0, Errors: errors} // initialize default rules - config.initDefaultRules(cmd) + config.initDefaultRules() // validate the root command config.validate(cmd, &info) @@ -50,7 +50,6 @@ func (config *RuleConfig) executeHelper(cmd *cobra.Command, info *validator.Stat // executeRecursive recursively traverse over all the subcommands // and validate using executeRulesChildren function func (config *RuleConfig) executeRecursive(cmd *cobra.Command, info *validator.StatusLog) []validator.ValidationError { - // fmt.Println(cmd.CommandPath()) for _, child := range cmd.Commands() { // base case if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { @@ -94,27 +93,26 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user -func (config *RuleConfig) initDefaultRules(cmd *cobra.Command) { +func (config *RuleConfig) initDefaultRules() { + defaultVerbose := config.Verbose + defaultConfig := RuleConfig{ - Verbose: false, + Verbose: defaultVerbose, Rules: []Rules{ &Length{ - Verbose: false, + Verbose: defaultVerbose, Limits: map[string]Limit{ "Use": {Min: 2}, "Short": {Min: 15}, "Long": {Min: 50}, "Example": {Min: 50}, }}, - &MustExist{Verbose: false, Fields: map[string]bool{"Use": true, "Short": true, "Long": true, "Example": true}}, + &MustExist{Verbose: defaultVerbose, Fields: map[string]bool{"Use": true, "Short": true, "Long": true, "Example": true}}, }, } - fmt.Println("User Input", config) if err := mergo.Merge(&defaultConfig, config, mergo.WithSliceDeepCopy); err != nil { log.Fatal(err) } *config = defaultConfig - fmt.Println("After Merging", config) - } From 5abd7a8434935d9275731703f4ea78d32e04de60 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 15:26:15 +0530 Subject: [PATCH 06/12] refactor: separate user API from ruleConfig --- validator/example/cmd_test.go | 17 ++++++---- validator/rules/config.go | 64 +++++++++++++++++++++++++++++++++++ validator/rules/executor.go | 40 +++++----------------- validator/rules/length.go | 7 ++-- validator/rules/must_exist.go | 4 +-- 5 files changed, 88 insertions(+), 44 deletions(-) create mode 100644 validator/rules/config.go diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index 833cbc0..1bbc6b8 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -11,19 +11,22 @@ func Test_ExecuteCommand(t *testing.T) { // Testing cobra commands with default recommended config // default config can also be overrided - var vali rules.RuleConfig = rules.RuleConfig{ - Verbose: false, - Rules: []rules.Rules{ - &rules.Length{Limits: map[string]rules.Limit{"Use": {Min: 2}}}, - &rules.MustExist{Fields: map[string]bool{"Long": false}}, + ruleCfg := rules.ValidatorConfig{ + Options: rules.Options{Verbose: false}, + ValidatorRules: rules.ValidatorRules{ + Length: rules.Length{ + Limits: map[string]rules.Limit{ + "Use": {Min: 100}, + }, + }, }, } - validationErr := vali.ExecuteRules(cmd) + validationErr := ruleCfg.ExecuteRules(cmd) if len(validationErr) != 0 { t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) } - + t.Error() for _, errs := range validationErr { if errs.Err != nil { t.Errorf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) diff --git a/validator/rules/config.go b/validator/rules/config.go new file mode 100644 index 0000000..46742f7 --- /dev/null +++ b/validator/rules/config.go @@ -0,0 +1,64 @@ +package rules + +import ( + "encoding/json" + + "github.com/aerogear/charmil/validator" + "github.com/imdario/mergo" + "github.com/spf13/cobra" +) + +// ValidatorConfig is provided to user for overriding default rules +type ValidatorConfig struct { + Options `json:"Options"` + ValidatorRules `json:"ValidatorRules"` +} +type Options struct { + Verbose bool `json:"Verbose"` +} +type ValidatorRules struct { + Length `json:"Length"` + MustExist `json:"MustExist"` +} + +// ExecuteRules executes all the rules +// provided by validatorConfig +func (validatorConfig *ValidatorConfig) ExecuteRules(cmd *cobra.Command) []validator.ValidationError { + var ruleConfig RuleConfig + return ruleConfig.ExecuteRulesInternal(cmd, validatorConfig) +} + +func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *RuleConfig) { + + defaultConfigJson := `{ + "Options": { + "Verbose": false + }, + "ValidatorRules": { + "Length": { + "Limits": { + "Use": {"Min": 2}, + "Short": {"Min": 15}, + "Long": {"Min": 50}, + "Example": {"Min": 50} + } + }, + "MustExist": { + "Fields": {"Use": true, "Short": true, "Long": true, "Example": true} + } + } + }` + + // unmarshal defaultConfigJson in configHelper + var configHelper ValidatorConfig + json.Unmarshal([]byte(defaultConfigJson), &configHelper) + + // Merge user provided config into configHelper + mergo.Merge(&configHelper, validatorConfig, mergo.WithSliceDeepCopy) + validatorConfig = &configHelper + + // append rules to execute + ruleConfig.Verbose = validatorConfig.Verbose + ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.Length) + ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.MustExist) +} diff --git a/validator/rules/executor.go b/validator/rules/executor.go index bdeb709..8767c82 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -2,11 +2,9 @@ package rules import ( "fmt" - "log" "os" "github.com/aerogear/charmil/validator" - "github.com/imdario/mergo" "github.com/spf13/cobra" ) @@ -23,19 +21,19 @@ type RuleConfig struct { Rules []Rules } -// ExecuteRules executes all the rules -// according to the RuleConfig provided -func (config *RuleConfig) ExecuteRules(cmd *cobra.Command) []validator.ValidationError { +// ExecuteRulesInternal executes all the rules +// provided by ruleConfig +func (ruleConfig *RuleConfig) ExecuteRulesInternal(cmd *cobra.Command, userValidatorConfig *ValidatorConfig) []validator.ValidationError { var errors []validator.ValidationError info := validator.StatusLog{TotalTested: 0, TotalErrors: 0, Errors: errors} // initialize default rules - config.initDefaultRules() + ruleConfig.initDefaultRules(userValidatorConfig) // validate the root command - config.validate(cmd, &info) + ruleConfig.validate(cmd, &info) - return config.executeHelper(cmd, &info) + return ruleConfig.executeHelper(cmd, &info) } func (config *RuleConfig) executeHelper(cmd *cobra.Command, info *validator.StatusLog) []validator.ValidationError { @@ -81,8 +79,6 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // traverse all rules and validate for _, rule := range config.Rules { - // fmt.Println(reflect.TypeOf(rule)) - validationErrors := rule.Validate(cmd) info.TotalErrors += len(validationErrors) info.Errors = append(info.Errors, validationErrors...) @@ -93,26 +89,6 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user -func (config *RuleConfig) initDefaultRules() { - defaultVerbose := config.Verbose - - defaultConfig := RuleConfig{ - Verbose: defaultVerbose, - Rules: []Rules{ - &Length{ - Verbose: defaultVerbose, - Limits: map[string]Limit{ - "Use": {Min: 2}, - "Short": {Min: 15}, - "Long": {Min: 50}, - "Example": {Min: 50}, - }}, - &MustExist{Verbose: defaultVerbose, Fields: map[string]bool{"Use": true, "Short": true, "Long": true, "Example": true}}, - }, - } - - if err := mergo.Merge(&defaultConfig, config, mergo.WithSliceDeepCopy); err != nil { - log.Fatal(err) - } - *config = defaultConfig +func (config *RuleConfig) initDefaultRules(testCfg *ValidatorConfig) { + ValidatorConfigToRuleConfig(testCfg, config) } diff --git a/validator/rules/length.go b/validator/rules/length.go index 42c673f..da82d79 100644 --- a/validator/rules/length.go +++ b/validator/rules/length.go @@ -24,15 +24,16 @@ var LengthRule = "LENGTH_RULE" // Limit defines min, max length of string type Limit struct { - Min, Max int + Min int `json:"Min"` + Max int `json:"Max"` } // Length is a struct that provides a map // with key as attribute for which length is controlled // and value limit as Limit struct type Length struct { - Verbose bool - Limits map[string]Limit + Verbose bool `json:"Verbose"` + Limits map[string]Limit `json:"Limits"` } func (l *Length) Validate(cmd *cobra.Command) []validator.ValidationError { diff --git a/validator/rules/must_exist.go b/validator/rules/must_exist.go index 9b832a8..5dfb225 100644 --- a/validator/rules/must_exist.go +++ b/validator/rules/must_exist.go @@ -21,8 +21,8 @@ var MustExistRule = "MUST_EXIST_RULE" // MustExist is a struct that provides // Fields defined for MustExist validation type MustExist struct { - Verbose bool - Fields map[string]bool + Verbose bool `json:"Verbose"` + Fields map[string]bool `json:"Fields"` } func (m *MustExist) Validate(cmd *cobra.Command) []validator.ValidationError { From 399d6c65e78efd47c3725d7a15c1957930bfb51a Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 15:29:22 +0530 Subject: [PATCH 07/12] fix: check mergo, unmarshal for err --- validator/example/cmd_test.go | 3 +-- validator/rules/config.go | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index 1bbc6b8..14572ec 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -16,7 +16,7 @@ func Test_ExecuteCommand(t *testing.T) { ValidatorRules: rules.ValidatorRules{ Length: rules.Length{ Limits: map[string]rules.Limit{ - "Use": {Min: 100}, + "Use": {Min: 1}, }, }, }, @@ -26,7 +26,6 @@ func Test_ExecuteCommand(t *testing.T) { if len(validationErr) != 0 { t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) } - t.Error() for _, errs := range validationErr { if errs.Err != nil { t.Errorf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) diff --git a/validator/rules/config.go b/validator/rules/config.go index 46742f7..408b612 100644 --- a/validator/rules/config.go +++ b/validator/rules/config.go @@ -2,6 +2,7 @@ package rules import ( "encoding/json" + "log" "github.com/aerogear/charmil/validator" "github.com/imdario/mergo" @@ -51,10 +52,14 @@ func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *R // unmarshal defaultConfigJson in configHelper var configHelper ValidatorConfig - json.Unmarshal([]byte(defaultConfigJson), &configHelper) + if err := json.Unmarshal([]byte(defaultConfigJson), &configHelper); err != nil { + log.Fatal(err) + } // Merge user provided config into configHelper - mergo.Merge(&configHelper, validatorConfig, mergo.WithSliceDeepCopy) + if err := mergo.Merge(&configHelper, validatorConfig, mergo.WithSliceDeepCopy); err != nil { + log.Fatal(err) + } validatorConfig = &configHelper // append rules to execute From fbdaf5d12ce45eff84d728c9340633ac7187ead8 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 16:04:16 +0530 Subject: [PATCH 08/12] fix: global verbose & rename options --- validator/example/cmd_test.go | 4 ++-- validator/rules/config.go | 13 ++++++++----- validator/rules/executor.go | 7 +++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index 14572ec..db60077 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -12,11 +12,11 @@ func Test_ExecuteCommand(t *testing.T) { // Testing cobra commands with default recommended config // default config can also be overrided ruleCfg := rules.ValidatorConfig{ - Options: rules.Options{Verbose: false}, + ValidatorOptions: rules.ValidatorOptions{Verbose: false}, ValidatorRules: rules.ValidatorRules{ Length: rules.Length{ Limits: map[string]rules.Limit{ - "Use": {Min: 1}, + "Use": {Min: 100}, }, }, }, diff --git a/validator/rules/config.go b/validator/rules/config.go index 408b612..eca49d8 100644 --- a/validator/rules/config.go +++ b/validator/rules/config.go @@ -11,10 +11,10 @@ import ( // ValidatorConfig is provided to user for overriding default rules type ValidatorConfig struct { - Options `json:"Options"` - ValidatorRules `json:"ValidatorRules"` + ValidatorOptions `json:"ValidatorOptions"` + ValidatorRules `json:"ValidatorRules"` } -type Options struct { +type ValidatorOptions struct { Verbose bool `json:"Verbose"` } type ValidatorRules struct { @@ -30,9 +30,10 @@ func (validatorConfig *ValidatorConfig) ExecuteRules(cmd *cobra.Command) []valid } func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *RuleConfig) { + defaultVerbose := validatorConfig.ValidatorOptions.Verbose defaultConfigJson := `{ - "Options": { + "ValidatorOptions": { "Verbose": false }, "ValidatorRules": { @@ -56,6 +57,9 @@ func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *R log.Fatal(err) } + configHelper.Length.Verbose = defaultVerbose + configHelper.MustExist.Verbose = defaultVerbose + // Merge user provided config into configHelper if err := mergo.Merge(&configHelper, validatorConfig, mergo.WithSliceDeepCopy); err != nil { log.Fatal(err) @@ -63,7 +67,6 @@ func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *R validatorConfig = &configHelper // append rules to execute - ruleConfig.Verbose = validatorConfig.Verbose ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.Length) ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.MustExist) } diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 8767c82..3a18682 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -17,8 +17,7 @@ type Rules interface { // RuleConfig is the struct that stores // configuration of rules type RuleConfig struct { - Verbose bool - Rules []Rules + Rules []Rules } // ExecuteRulesInternal executes all the rules @@ -89,6 +88,6 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user -func (config *RuleConfig) initDefaultRules(testCfg *ValidatorConfig) { - ValidatorConfigToRuleConfig(testCfg, config) +func (config *RuleConfig) initDefaultRules(validatorConfig *ValidatorConfig) { + ValidatorConfigToRuleConfig(validatorConfig, config) } From a5ed19c35c60c975b05c44b197ac21bb75383468 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 16:30:47 +0530 Subject: [PATCH 09/12] chore: run gofmt & provide docs --- core/commands/charmil.go | 6 +++--- core/commands/disable_commands.go | 2 +- core/commands/enable_commands.go | 2 +- examples/host/main.go | 2 +- validator/rules/config.go | 8 ++++++++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core/commands/charmil.go b/core/commands/charmil.go index 7f28c21..7d48d3b 100644 --- a/core/commands/charmil.go +++ b/core/commands/charmil.go @@ -10,10 +10,10 @@ func AttachCharmilCommands(hostRoot *cobra.Command) error { return nil } - // Placeholder command. To be replaced later by actual commands + // Placeholder command. To be replaced later by actual commands cmd := &cobra.Command{ - Use: "charmil", - Short: "built in charmil commands", + Use: "charmil", + Short: "built in charmil commands", SilenceUsage: false, } diff --git a/core/commands/disable_commands.go b/core/commands/disable_commands.go index 1d4fdd1..0c286f4 100644 --- a/core/commands/disable_commands.go +++ b/core/commands/disable_commands.go @@ -2,4 +2,4 @@ package commands -const inDev = false \ No newline at end of file +const inDev = false diff --git a/core/commands/enable_commands.go b/core/commands/enable_commands.go index adf7fd2..a843095 100644 --- a/core/commands/enable_commands.go +++ b/core/commands/enable_commands.go @@ -2,4 +2,4 @@ package commands -const inDev = true \ No newline at end of file +const inDev = true diff --git a/examples/host/main.go b/examples/host/main.go index af1788c..aae2148 100644 --- a/examples/host/main.go +++ b/examples/host/main.go @@ -29,4 +29,4 @@ func main() { if err := root.Execute(); err != nil { log.Fatal(err) } -} \ No newline at end of file +} diff --git a/validator/rules/config.go b/validator/rules/config.go index eca49d8..03f2371 100644 --- a/validator/rules/config.go +++ b/validator/rules/config.go @@ -14,9 +14,15 @@ type ValidatorConfig struct { ValidatorOptions `json:"ValidatorOptions"` ValidatorRules `json:"ValidatorRules"` } + +// ValidatorOptions provide additional configurations +// to the rules type ValidatorOptions struct { Verbose bool `json:"Verbose"` } + +// ValidatorRules consists of all the rules +// present in validator type ValidatorRules struct { Length `json:"Length"` MustExist `json:"MustExist"` @@ -29,6 +35,8 @@ func (validatorConfig *ValidatorConfig) ExecuteRules(cmd *cobra.Command) []valid return ruleConfig.ExecuteRulesInternal(cmd, validatorConfig) } +// ValidatorConfigToRuleConfig intializes the default config +// and overrides default with user provided config func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *RuleConfig) { defaultVerbose := validatorConfig.ValidatorOptions.Verbose From 013122baa1396b5af0d719109e051de2efee2ca8 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 17:52:29 +0530 Subject: [PATCH 10/12] chore: address review comments --- validator/example/cmd_test.go | 4 +-- validator/rules/config.go | 47 +++++++++++++++-------------------- validator/rules/executor.go | 30 +++++++++++----------- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index db60077..c4bc4a0 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -16,13 +16,13 @@ func Test_ExecuteCommand(t *testing.T) { ValidatorRules: rules.ValidatorRules{ Length: rules.Length{ Limits: map[string]rules.Limit{ - "Use": {Min: 100}, + "Use": {Min: 1}, }, }, }, } - validationErr := ruleCfg.ExecuteRules(cmd) + validationErr := rules.ExecuteRules(cmd, &ruleCfg) if len(validationErr) != 0 { t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) } diff --git a/validator/rules/config.go b/validator/rules/config.go index 03f2371..7446cb3 100644 --- a/validator/rules/config.go +++ b/validator/rules/config.go @@ -1,7 +1,6 @@ package rules import ( - "encoding/json" "log" "github.com/aerogear/charmil/validator" @@ -30,9 +29,9 @@ type ValidatorRules struct { // ExecuteRules executes all the rules // provided by validatorConfig -func (validatorConfig *ValidatorConfig) ExecuteRules(cmd *cobra.Command) []validator.ValidationError { +func ExecuteRules(cmd *cobra.Command, validatorConfig *ValidatorConfig) []validator.ValidationError { var ruleConfig RuleConfig - return ruleConfig.ExecuteRulesInternal(cmd, validatorConfig) + return ExecuteRulesInternal(cmd, &ruleConfig, validatorConfig) } // ValidatorConfigToRuleConfig intializes the default config @@ -40,34 +39,28 @@ func (validatorConfig *ValidatorConfig) ExecuteRules(cmd *cobra.Command) []valid func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *RuleConfig) { defaultVerbose := validatorConfig.ValidatorOptions.Verbose - defaultConfigJson := `{ - "ValidatorOptions": { - "Verbose": false + // unmarshal defaultConfigJson in configHelper + var configHelper ValidatorConfig = ValidatorConfig{ + ValidatorOptions: ValidatorOptions{ + Verbose: defaultVerbose, }, - "ValidatorRules": { - "Length": { - "Limits": { - "Use": {"Min": 2}, - "Short": {"Min": 15}, - "Long": {"Min": 50}, - "Example": {"Min": 50} - } + ValidatorRules: ValidatorRules{ + Length: Length{ + Verbose: defaultVerbose, + Limits: map[string]Limit{ + "Use": {Min: 2}, + "Short": {Min: 15}, + "Long": {Min: 50}, + "Example": {Min: 50}, + }, }, - "MustExist": { - "Fields": {"Use": true, "Short": true, "Long": true, "Example": true} - } - } - }` - - // unmarshal defaultConfigJson in configHelper - var configHelper ValidatorConfig - if err := json.Unmarshal([]byte(defaultConfigJson), &configHelper); err != nil { - log.Fatal(err) + MustExist: MustExist{ + Verbose: defaultVerbose, + Fields: map[string]bool{"Use": true, "Short": true, "Long": true, "Example": true}, + }, + }, } - configHelper.Length.Verbose = defaultVerbose - configHelper.MustExist.Verbose = defaultVerbose - // Merge user provided config into configHelper if err := mergo.Merge(&configHelper, validatorConfig, mergo.WithSliceDeepCopy); err != nil { log.Fatal(err) diff --git a/validator/rules/executor.go b/validator/rules/executor.go index 3a18682..5bc28a7 100644 --- a/validator/rules/executor.go +++ b/validator/rules/executor.go @@ -22,21 +22,21 @@ type RuleConfig struct { // ExecuteRulesInternal executes all the rules // provided by ruleConfig -func (ruleConfig *RuleConfig) ExecuteRulesInternal(cmd *cobra.Command, userValidatorConfig *ValidatorConfig) []validator.ValidationError { +func ExecuteRulesInternal(cmd *cobra.Command, ruleConfig *RuleConfig, userValidatorConfig *ValidatorConfig) []validator.ValidationError { var errors []validator.ValidationError info := validator.StatusLog{TotalTested: 0, TotalErrors: 0, Errors: errors} // initialize default rules - ruleConfig.initDefaultRules(userValidatorConfig) + initDefaultRules(userValidatorConfig, ruleConfig) // validate the root command - ruleConfig.validate(cmd, &info) + validate(cmd, &info, ruleConfig) - return ruleConfig.executeHelper(cmd, &info) + return executeHelper(cmd, &info, ruleConfig) } -func (config *RuleConfig) executeHelper(cmd *cobra.Command, info *validator.StatusLog) []validator.ValidationError { - info.Errors = config.executeRecursive(cmd, info) +func executeHelper(cmd *cobra.Command, info *validator.StatusLog, ruleConfig *RuleConfig) []validator.ValidationError { + info.Errors = executeRecursive(cmd, info, ruleConfig) // prints additional info for the checks fmt.Fprintf(os.Stderr, "commands checked: %d\nchecks failed: %d\n", info.TotalTested, info.TotalErrors) @@ -46,38 +46,38 @@ func (config *RuleConfig) executeHelper(cmd *cobra.Command, info *validator.Stat // executeRecursive recursively traverse over all the subcommands // and validate using executeRulesChildren function -func (config *RuleConfig) executeRecursive(cmd *cobra.Command, info *validator.StatusLog) []validator.ValidationError { +func executeRecursive(cmd *cobra.Command, info *validator.StatusLog, ruleConfig *RuleConfig) []validator.ValidationError { for _, child := range cmd.Commands() { // base case if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } // recursive call - info.Errors = config.executeRecursive(child, info) + info.Errors = executeRecursive(child, info, ruleConfig) } - info.Errors = config.executeRulesChildren(cmd, info) + info.Errors = executeRulesChildren(cmd, info, ruleConfig) return info.Errors } // executeRulesChildren execute rules on children of cmd -func (config *RuleConfig) executeRulesChildren(cmd *cobra.Command, info *validator.StatusLog) []validator.ValidationError { +func executeRulesChildren(cmd *cobra.Command, info *validator.StatusLog, ruleConfig *RuleConfig) []validator.ValidationError { children := cmd.Commands() for _, child := range children { if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } - config.validate(child, info) + validate(child, info, ruleConfig) } return info.Errors } // validate returns validation errors by executing the rules -func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog) { +func validate(cmd *cobra.Command, info *validator.StatusLog, ruleConfig *RuleConfig) { // traverse all rules and validate - for _, rule := range config.Rules { + for _, rule := range ruleConfig.Rules { validationErrors := rule.Validate(cmd) info.TotalErrors += len(validationErrors) info.Errors = append(info.Errors, validationErrors...) @@ -88,6 +88,6 @@ func (config *RuleConfig) validate(cmd *cobra.Command, info *validator.StatusLog // initDefaultRules initialize default rules // and overrides the default rules if RuleConfig is provided by the user -func (config *RuleConfig) initDefaultRules(validatorConfig *ValidatorConfig) { - ValidatorConfigToRuleConfig(validatorConfig, config) +func initDefaultRules(validatorConfig *ValidatorConfig, ruleConfig *RuleConfig) { + ValidatorConfigToRuleConfig(validatorConfig, ruleConfig) } From 88910357cb3fbf7b1421b4bfcd01f0c9a49c916b Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 19:47:48 +0530 Subject: [PATCH 11/12] chore: pass golangci-lint --- core/localize/i18n.go | 4 ++-- validator/rules/config.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/localize/i18n.go b/core/localize/i18n.go index 8e083d2..d5a3ac9 100644 --- a/core/localize/i18n.go +++ b/core/localize/i18n.go @@ -32,7 +32,7 @@ type Config struct { // LocalizeByID helps in localizing by passing id present in local file // pass dynamic value using template entries -func (I *GoI18n) LocalizeByID(messageId string, template ...*TemplateEntry) string { +func (i *GoI18n) LocalizeByID(messageId string, template ...*TemplateEntry) string { // Putting back templateEntry into desired format // required by go-i18n @@ -42,7 +42,7 @@ func (I *GoI18n) LocalizeByID(messageId string, template ...*TemplateEntry) stri } localizeConfig := &i18n.LocalizeConfig{MessageID: messageId, PluralCount: 1, TemplateData: templateData} - res := I.Localizer.MustLocalize(localizeConfig) + res := i.Localizer.MustLocalize(localizeConfig) return res } diff --git a/validator/rules/config.go b/validator/rules/config.go index 7446cb3..eda9b8b 100644 --- a/validator/rules/config.go +++ b/validator/rules/config.go @@ -68,6 +68,5 @@ func ValidatorConfigToRuleConfig(validatorConfig *ValidatorConfig, ruleConfig *R validatorConfig = &configHelper // append rules to execute - ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.Length) - ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.MustExist) + ruleConfig.Rules = append(ruleConfig.Rules, &validatorConfig.Length, &validatorConfig.MustExist) } From 4635e1fceafdc8ec38fd10dc8ff7f8d37dccfc06 Mon Sep 17 00:00:00 2001 From: Ankit Hans Date: Mon, 5 Jul 2021 21:27:28 +0530 Subject: [PATCH 12/12] docs: update validator docs --- cmd/main.go | 1 - docs/src/validator/validator.md | 25 +++++++++++-------- examples/host/main.go | 13 ++++++---- .../{plugins/date/main.go => plugin/echo.go} | 23 ++++++++--------- examples/plugin/locales/en/en.yaml | 12 +++++++++ examples/plugins/date/locales/en/en.yaml | 12 --------- validator/example/cmd_test.go | 1 - 7 files changed, 44 insertions(+), 43 deletions(-) delete mode 100644 cmd/main.go rename examples/{plugins/date/main.go => plugin/echo.go} (65%) create mode 100644 examples/plugin/locales/en/en.yaml delete mode 100644 examples/plugins/date/locales/en/en.yaml diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 1d619dd..0000000 --- a/cmd/main.go +++ /dev/null @@ -1 +0,0 @@ -package cmd diff --git a/docs/src/validator/validator.md b/docs/src/validator/validator.md index 1cdf200..2a0bcfa 100644 --- a/docs/src/validator/validator.md +++ b/docs/src/validator/validator.md @@ -2,33 +2,36 @@ Validator can be used for testing and controlling many aspects of cobra commands. It provides many rules out of the box for validating the commands. ## Rules provided by validator -- [LengthRule](validator_length_rule.md) -- [MustExistRule](validator_must_exist_rule.md) -- UseMatches +- LengthRule +- MustExistRule +- UseMatchesRule > We are working on the validator library to provide more rules ## How to use It is recommended to use the validator while writing unit tests for cobra commands. -1. Create a validator of type `rules.RuleConfig`. You can provide your own RulesConfig or use the default one by leaving it empty +1. Create a configuration of type `rules.ValidatorConfig`. You can provide your own ValidatorConfig or use the default one by leaving it empty ```go -var vali rules.RuleConfig +var ruleCfg rules.ValidatorConfig ``` or overriding default config ```go -vali := rules.RuleConfig{ - Verbose: true, - MustExist: rules.MustExist{ - Fields: []string{"Args"}, +ruleCfg := rules.ValidatorConfig{ + ValidatorRules: rules.ValidatorRules{ + Length: rules.Length{Limits: map[string]rules.Limit{"Use": {Min: 1}}}, + MustExist: rules.MustExist{Fields: map[string]bool{"Args": true}}, }, } ``` -2. Generate the validation errors by using `ExecuteRules` function over the config +2. Generate the validation errors by using `ExecuteRules` function over the ruleCfg ```go -validationErr := vali.ExecuteRules(cmd) +validationErr := rules.ExecuteRules(cmd, &ruleCfg) ``` `ExecuteRules` function will return a slice of `ValidationError` object, which can be efficiently used for testing purposes. ```go +if len(validationErr) != 0 { + t.Errorf("validationErr was not empty, got length: %d; want %d", len(validationErr), 0) +} for _, errs := range validationErr { if errs.Err != nil { t.Errorf("%s: cmd %s: %s", errs.Rule, errs.Cmd.CommandPath(), errs.Name) diff --git a/examples/host/main.go b/examples/host/main.go index aae2148..91ce2d6 100644 --- a/examples/host/main.go +++ b/examples/host/main.go @@ -1,10 +1,11 @@ package main import ( + "log" + "github.com/aerogear/charmil/core/commands" - "github.com/aerogear/charmil/examples/plugins/date" + echo "github.com/aerogear/charmil/examples/plugin" "github.com/spf13/cobra" - "log" ) func main() { @@ -14,18 +15,20 @@ func main() { SilenceUsage: true, } - dateCmd, err := date.DateCommand() + // Add plugin CLI into host + echoCmd, err := echo.EchoCommand() if err != nil { log.Fatal(err) } + root.AddCommand(echoCmd) - root.AddCommand(dateCmd) - + // Add Charmil commands into host err = commands.AttachCharmilCommands(root) if err != nil { log.Fatal(err) } + // Execute root command if err := root.Execute(); err != nil { log.Fatal(err) } diff --git a/examples/plugins/date/main.go b/examples/plugin/echo.go similarity index 65% rename from examples/plugins/date/main.go rename to examples/plugin/echo.go index ed24c04..62965c5 100644 --- a/examples/plugins/date/main.go +++ b/examples/plugin/echo.go @@ -1,8 +1,6 @@ -package date +package echo import ( - "time" - "github.com/aerogear/charmil/core/factory" "github.com/aerogear/charmil/core/localize" "github.com/aerogear/charmil/core/logging" @@ -18,10 +16,10 @@ type Options struct { } // Date Command -func DateCommand() (*cobra.Command, error) { +func EchoCommand() (*cobra.Command, error) { // Initialize localizer providing the language, locals and format of locals file - loc, err := localize.InitLocalizer(localize.Config{Language: language.English, Path: "examples/plugins/date/locales/en/en.yaml", Format: "yaml"}) + loc, err := localize.InitLocalizer(localize.Config{Language: language.English, Path: "examples/plugin/locales/en/en.yaml", Format: "yaml"}) if err != nil { return nil, err } @@ -33,19 +31,18 @@ func DateCommand() (*cobra.Command, error) { Localize: newFactory.Localizer, } - // creating new command + // creating new echo command // using localizer to access default text by ID provided in locals cmd := &cobra.Command{ - Use: opts.Localize.LocalizeByID("date.cmd.use"), - Short: opts.Localize.LocalizeByID("date.cmd.short"), - Long: opts.Localize.LocalizeByID("date.cmd.long"), - Example: opts.Localize.LocalizeByID("date.cmd.example"), - Args: cobra.ExactArgs(0), - // SilenceUsage: true, + Use: opts.Localize.LocalizeByID("echo.cmd.use"), + Short: opts.Localize.LocalizeByID("echo.cmd.short"), + Long: opts.Localize.LocalizeByID("echo.cmd.long"), + Example: opts.Localize.LocalizeByID("echo.cmd.example"), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { // Using logger for output - opts.Logger.Infof("Date Time is %s", time.Now()) + opts.Logger.Info(args[0]) return nil }, diff --git a/examples/plugin/locales/en/en.yaml b/examples/plugin/locales/en/en.yaml new file mode 100644 index 0000000..090d835 --- /dev/null +++ b/examples/plugin/locales/en/en.yaml @@ -0,0 +1,12 @@ +echo.cmd.use: + description: "echo command use" + one: "echo [string to echo]" +echo.cmd.short: + description: "echo command short description" + one: "Echo anything to the screen" +echo.cmd.long: + description: "echo command long description" + one: "Echo can utter any string to the screen" +echo.cmd.example: + description: "echo command examples" + one: "$ host echo" diff --git a/examples/plugins/date/locales/en/en.yaml b/examples/plugins/date/locales/en/en.yaml deleted file mode 100644 index 82daea5..0000000 --- a/examples/plugins/date/locales/en/en.yaml +++ /dev/null @@ -1,12 +0,0 @@ -date.cmd.use: - description: "Use of date" - one: "date" -date.cmd.short: - description: "short description of date command" - one: "tell date" -date.cmd.example: - description: "Examples of date command" - one: "$ host date" -date.cmd.long: - description: "Long description of date command" - one: "This is very Long" diff --git a/validator/example/cmd_test.go b/validator/example/cmd_test.go index c4bc4a0..f61f80a 100644 --- a/validator/example/cmd_test.go +++ b/validator/example/cmd_test.go @@ -12,7 +12,6 @@ func Test_ExecuteCommand(t *testing.T) { // Testing cobra commands with default recommended config // default config can also be overrided ruleCfg := rules.ValidatorConfig{ - ValidatorOptions: rules.ValidatorOptions{Verbose: false}, ValidatorRules: rules.ValidatorRules{ Length: rules.Length{ Limits: map[string]rules.Limit{