|
1 | 1 | package validate |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "sort" |
4 | 5 | "strings" |
| 6 | + "sync" |
5 | 7 |
|
6 | 8 | "github.com/vbatts/git-validation/git" |
7 | 9 | ) |
8 | 10 |
|
9 | 11 | var ( |
10 | 12 | // RegisteredRules are the standard validation to perform on git commits |
11 | | - RegisteredRules = []Rule{} |
| 13 | + RegisteredRules = []Rule{} |
| 14 | + registerRuleLock = sync.Mutex{} |
12 | 15 | ) |
13 | 16 |
|
14 | 17 | // RegisterRule includes the Rule in the avaible set to use |
15 | 18 | func RegisterRule(vr Rule) { |
| 19 | + registerRuleLock.Lock() |
| 20 | + defer registerRuleLock.Unlock() |
16 | 21 | RegisteredRules = append(RegisteredRules, vr) |
17 | 22 | } |
18 | 23 |
|
19 | 24 | // Rule will operate over a provided git.CommitEntry, and return a result. |
20 | 25 | type Rule struct { |
21 | 26 | 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) |
22 | 28 | Description string // longer Description for readability |
23 | 29 | Run func(git.CommitEntry) Result |
24 | 30 | } |
@@ -54,28 +60,74 @@ func (vr Results) PassFail() (pass int, fail int) { |
54 | 60 | return pass, fail |
55 | 61 | } |
56 | 62 |
|
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)) |
| 63 | +// SanitizeFilters takes a comma delimited list and returns the trimmend and |
| 64 | +// split (on ",") items in the list |
| 65 | +func SanitizeFilters(filtStr string) (filters []string) { |
| 66 | + for _, item := range strings.Split(filtStr, ",") { |
| 67 | + filters = append(filters, strings.TrimSpace(item)) |
62 | 68 | } |
63 | | - |
64 | 69 | return |
65 | 70 | } |
66 | 71 |
|
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 { |
| 72 | +// FilterRules takes a set of rules and a list of short names to include, and |
| 73 | +// returns the reduced set. The comparison is case insensitive. |
| 74 | +// |
| 75 | +// Some `includes` rules have values assigned to them. |
| 76 | +// i.e. -run "dco,message_regexp='^JIRA-[0-9]+ [A-Z].*$'" |
| 77 | +// |
| 78 | +func FilterRules(rules []Rule, includes []string) []Rule { |
70 | 79 | ret := []Rule{} |
71 | 80 |
|
72 | 81 | for _, r := range rules { |
73 | | - for _, e := range excludes { |
74 | | - if strings.ToLower(r.Name) == strings.ToLower(e) { |
75 | | - ret = append(ret, r) |
| 82 | + for i := range includes { |
| 83 | + if strings.Contains(includes[i], "=") { |
| 84 | + chunks := strings.SplitN(includes[i], "=", 2) |
| 85 | + if strings.ToLower(r.Name) == strings.ToLower(chunks[0]) { |
| 86 | + // for these rules, the Name won't be unique per se. There may be |
| 87 | + // multiple "regexp=" with different values. We'll need to set the |
| 88 | + // .Value = chunk[1] and ensure r is dup'ed so they don't clobber |
| 89 | + // each other. |
| 90 | + newR := Rule(r) |
| 91 | + newR.Value = chunks[1] |
| 92 | + ret = append(ret, newR) |
| 93 | + } |
| 94 | + } else { |
| 95 | + if strings.ToLower(r.Name) == strings.ToLower(includes[i]) { |
| 96 | + ret = append(ret, r) |
| 97 | + } |
76 | 98 | } |
77 | 99 | } |
78 | 100 | } |
79 | 101 |
|
80 | 102 | return ret |
81 | 103 | } |
| 104 | + |
| 105 | +// StringsSliceEqual compares two string arrays for equality |
| 106 | +func StringsSliceEqual(a, b []string) bool { |
| 107 | + if !sort.StringsAreSorted(a) { |
| 108 | + sort.Strings(a) |
| 109 | + } |
| 110 | + if !sort.StringsAreSorted(b) { |
| 111 | + sort.Strings(b) |
| 112 | + } |
| 113 | + for i := range b { |
| 114 | + if !StringsSliceContains(a, b[i]) { |
| 115 | + return false |
| 116 | + } |
| 117 | + } |
| 118 | + for i := range a { |
| 119 | + if !StringsSliceContains(b, a[i]) { |
| 120 | + return false |
| 121 | + } |
| 122 | + } |
| 123 | + return true |
| 124 | +} |
| 125 | + |
| 126 | +// StringsSliceContains checks for the presence of a word in string array |
| 127 | +func StringsSliceContains(a []string, b string) bool { |
| 128 | + if !sort.StringsAreSorted(a) { |
| 129 | + sort.Strings(a) |
| 130 | + } |
| 131 | + i := sort.SearchStrings(a, b) |
| 132 | + return i < len(a) && a[i] == b |
| 133 | +} |
0 commit comments