podman
133 строки · 3.5 Кб
1package validate
2
3import (
4"sort"
5"strings"
6"sync"
7
8"github.com/vbatts/git-validation/git"
9)
10
11var (
12// RegisteredRules are the avaible validation to perform on git commits
13RegisteredRules = []Rule{}
14registerRuleLock = sync.Mutex{}
15)
16
17// RegisterRule includes the Rule in the avaible set to use
18func RegisterRule(vr Rule) {
19registerRuleLock.Lock()
20defer registerRuleLock.Unlock()
21RegisteredRules = append(RegisteredRules, vr)
22}
23
24// Rule will operate over a provided git.CommitEntry, and return a result.
25type Rule struct {
26Name string // short name for reference in in the `-run=...` flag
27Value string // value to configure for the rule (i.e. a regexp to check for in the commit message)
28Description string // longer Description for readability
29Run func(Rule, git.CommitEntry) Result
30Default bool // whether the registered rule is run by default
31}
32
33// Commit processes the given rules on the provided commit, and returns the result set.
34func Commit(c git.CommitEntry, rules []Rule) Results {
35results := Results{}
36for _, r := range rules {
37results = append(results, r.Run(r, c))
38}
39return results
40}
41
42// Result is the result for a single validation of a commit.
43type Result struct {
44CommitEntry git.CommitEntry
45Pass bool
46Msg string
47}
48
49// Results is a set of results. This is type makes it easy for the following function.
50type Results []Result
51
52// PassFail gives a quick over/under of passes and failures of the results in this set
53func (vr Results) PassFail() (pass int, fail int) {
54for _, res := range vr {
55if res.Pass {
56pass++
57} else {
58fail++
59}
60}
61return pass, fail
62}
63
64// SanitizeFilters takes a comma delimited list and returns the trimmend and
65// split (on ",") items in the list
66func SanitizeFilters(filtStr string) (filters []string) {
67for _, item := range strings.Split(filtStr, ",") {
68filters = append(filters, strings.TrimSpace(item))
69}
70return
71}
72
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].*$'"
78func FilterRules(rules []Rule, includes []string) []Rule {
79ret := []Rule{}
80
81for _, r := range rules {
82for i := range includes {
83if strings.Contains(includes[i], "=") {
84chunks := strings.SplitN(includes[i], "=", 2)
85if strings.EqualFold(r.Name, 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.
90newR := Rule(r)
91newR.Value = chunks[1]
92ret = append(ret, newR)
93}
94} else {
95if strings.EqualFold(r.Name, includes[i]) {
96ret = append(ret, r)
97}
98}
99}
100}
101
102return ret
103}
104
105// StringsSliceEqual compares two string arrays for equality
106func StringsSliceEqual(a, b []string) bool {
107if !sort.StringsAreSorted(a) {
108sort.Strings(a)
109}
110if !sort.StringsAreSorted(b) {
111sort.Strings(b)
112}
113for i := range b {
114if !StringsSliceContains(a, b[i]) {
115return false
116}
117}
118for i := range a {
119if !StringsSliceContains(b, a[i]) {
120return false
121}
122}
123return true
124}
125
126// StringsSliceContains checks for the presence of a word in string array
127func StringsSliceContains(a []string, b string) bool {
128if !sort.StringsAreSorted(a) {
129sort.Strings(a)
130}
131i := sort.SearchStrings(a, b)
132return i < len(a) && a[i] == b
133}
134