11package validate
22
33import (
4+ "sort"
45 "strings"
6+ "sync"
57
68 "github.com/vbatts/git-validation/git"
79)
810
911var (
10- // RegisteredRules are the standard validation to perform on git commits
11- RegisteredRules = []Rule {}
12+ // RegisteredRules are the avaible validation to perform on git commits
13+ RegisteredRules = []Rule {}
14+ registerRuleLock = sync.Mutex {}
1215)
1316
1417// RegisterRule includes the Rule in the avaible set to use
1518func RegisterRule (vr Rule ) {
19+ registerRuleLock .Lock ()
20+ defer registerRuleLock .Unlock ()
1621 RegisteredRules = append (RegisteredRules , vr )
1722}
1823
1924// Rule will operate over a provided git.CommitEntry, and return a result.
2025type Rule struct {
2126 Name string // short name for reference in in the `-run=...` flag
27+ Value string // value to configure for the rule (i.e. a regexp to check for in the commit message)
2228 Description string // longer Description for readability
23- Run func (git.CommitEntry ) Result
29+ Run func (Rule , git.CommitEntry ) Result
30+ Default bool // whether the registered rule is run by default
2431}
2532
2633// Commit processes the given rules on the provided commit, and returns the result set.
2734func Commit (c git.CommitEntry , rules []Rule ) Results {
2835 results := Results {}
2936 for _ , r := range rules {
30- results = append (results , r .Run (c ))
37+ results = append (results , r .Run (r , c ))
3138 }
3239 return results
3340}
@@ -54,28 +61,74 @@ func (vr Results) PassFail() (pass int, fail int) {
5461 return pass , fail
5562}
5663
57- // SanitizeFilters takes a comma delimited list and returns the cleaned items in the list
58- func SanitizeFilters ( filt string ) ( excludes [] string ) {
59-
60- for _ , item := range strings .Split (filt , "," ) {
61- excludes = append (excludes , strings .TrimSpace (item ))
64+ // SanitizeFilters takes a comma delimited list and returns the trimmend and
65+ // split (on ",") items in the list
66+ func SanitizeFilters ( filtStr string ) ( filters [] string ) {
67+ for _ , item := range strings .Split (filtStr , "," ) {
68+ filters = append (filters , strings .TrimSpace (item ))
6269 }
63-
6470 return
6571}
6672
67- // FilterRules takes a set of rules and a list of short names to exclude, and returns the reduced set.
68- // The comparison is case insensitive.
69- func FilterRules (rules []Rule , excludes []string ) []Rule {
73+ // FilterRules takes a set of rules and a list of short names to include, and
74+ // returns the reduced set. The comparison is case insensitive.
75+ //
76+ // Some `includes` rules have values assigned to them.
77+ // i.e. -run "dco,message_regexp='^JIRA-[0-9]+ [A-Z].*$'"
78+ //
79+ func FilterRules (rules []Rule , includes []string ) []Rule {
7080 ret := []Rule {}
7181
7282 for _ , r := range rules {
73- for _ , e := range excludes {
74- if strings .ToLower (r .Name ) == strings .ToLower (e ) {
75- ret = append (ret , r )
83+ for i := range includes {
84+ if strings .Contains (includes [i ], "=" ) {
85+ chunks := strings .SplitN (includes [i ], "=" , 2 )
86+ if strings .ToLower (r .Name ) == strings .ToLower (chunks [0 ]) {
87+ // for these rules, the Name won't be unique per se. There may be
88+ // multiple "regexp=" with different values. We'll need to set the
89+ // .Value = chunk[1] and ensure r is dup'ed so they don't clobber
90+ // each other.
91+ newR := Rule (r )
92+ newR .Value = chunks [1 ]
93+ ret = append (ret , newR )
94+ }
95+ } else {
96+ if strings .ToLower (r .Name ) == strings .ToLower (includes [i ]) {
97+ ret = append (ret , r )
98+ }
7699 }
77100 }
78101 }
79102
80103 return ret
81104}
105+
106+ // StringsSliceEqual compares two string arrays for equality
107+ func StringsSliceEqual (a , b []string ) bool {
108+ if ! sort .StringsAreSorted (a ) {
109+ sort .Strings (a )
110+ }
111+ if ! sort .StringsAreSorted (b ) {
112+ sort .Strings (b )
113+ }
114+ for i := range b {
115+ if ! StringsSliceContains (a , b [i ]) {
116+ return false
117+ }
118+ }
119+ for i := range a {
120+ if ! StringsSliceContains (b , a [i ]) {
121+ return false
122+ }
123+ }
124+ return true
125+ }
126+
127+ // StringsSliceContains checks for the presence of a word in string array
128+ func StringsSliceContains (a []string , b string ) bool {
129+ if ! sort .StringsAreSorted (a ) {
130+ sort .Strings (a )
131+ }
132+ i := sort .SearchStrings (a , b )
133+ return i < len (a ) && a [i ] == b
134+ }
0 commit comments