mirror of
https://github.com/vbatts/git-validation.git
synced 2025-04-18 12:54:55 +00:00
validate: prep for rules that have a value
where needed, some rules may need to pass in a value like for a reguler expression. Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
cc3ab48288
commit
d9bf419b44
2 changed files with 117 additions and 13 deletions
|
@ -1,24 +1,30 @@
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/vbatts/git-validation/git"
|
"github.com/vbatts/git-validation/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// RegisteredRules are the standard validation to perform on git commits
|
// RegisteredRules are the standard validation to perform on git commits
|
||||||
RegisteredRules = []Rule{}
|
RegisteredRules = []Rule{}
|
||||||
|
registerRuleLock = sync.Mutex{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterRule includes the Rule in the avaible set to use
|
// RegisterRule includes the Rule in the avaible set to use
|
||||||
func RegisterRule(vr Rule) {
|
func RegisterRule(vr Rule) {
|
||||||
|
registerRuleLock.Lock()
|
||||||
|
defer registerRuleLock.Unlock()
|
||||||
RegisteredRules = append(RegisteredRules, vr)
|
RegisteredRules = append(RegisteredRules, vr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rule will operate over a provided git.CommitEntry, and return a result.
|
// Rule will operate over a provided git.CommitEntry, and return a result.
|
||||||
type Rule struct {
|
type Rule struct {
|
||||||
Name string // short name for reference in in the `-run=...` flag
|
Name string // short name for reference in in the `-run=...` flag
|
||||||
|
Value string // value to configure for the rule (i.e. a regexp to check for in the commit message)
|
||||||
Description string // longer Description for readability
|
Description string // longer Description for readability
|
||||||
Run func(git.CommitEntry) Result
|
Run func(git.CommitEntry) Result
|
||||||
}
|
}
|
||||||
|
@ -54,28 +60,74 @@ func (vr Results) PassFail() (pass int, fail int) {
|
||||||
return pass, fail
|
return pass, fail
|
||||||
}
|
}
|
||||||
|
|
||||||
// SanitizeFilters takes a comma delimited list and returns the cleaned items in the list
|
// SanitizeFilters takes a comma delimited list and returns the trimmend and
|
||||||
func SanitizeFilters(filt string) (excludes []string) {
|
// split (on ",") items in the list
|
||||||
|
func SanitizeFilters(filtStr string) (filters []string) {
|
||||||
for _, item := range strings.Split(filt, ",") {
|
for _, item := range strings.Split(filtStr, ",") {
|
||||||
excludes = append(excludes, strings.TrimSpace(item))
|
filters = append(filters, strings.TrimSpace(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterRules takes a set of rules and a list of short names to exclude, and returns the reduced set.
|
// FilterRules takes a set of rules and a list of short names to include, and
|
||||||
// The comparison is case insensitive.
|
// returns the reduced set. The comparison is case insensitive.
|
||||||
func FilterRules(rules []Rule, excludes []string) []Rule {
|
//
|
||||||
|
// Some `includes` rules have values assigned to them.
|
||||||
|
// i.e. -run "dco,message_regexp='^JIRA-[0-9]+ [A-Z].*$'"
|
||||||
|
//
|
||||||
|
func FilterRules(rules []Rule, includes []string) []Rule {
|
||||||
ret := []Rule{}
|
ret := []Rule{}
|
||||||
|
|
||||||
for _, r := range rules {
|
for _, r := range rules {
|
||||||
for _, e := range excludes {
|
for i := range includes {
|
||||||
if strings.ToLower(r.Name) == strings.ToLower(e) {
|
if strings.Contains(includes[i], "=") {
|
||||||
ret = append(ret, r)
|
chunks := strings.SplitN(includes[i], "=", 2)
|
||||||
|
if strings.ToLower(r.Name) == strings.ToLower(chunks[0]) {
|
||||||
|
// for these rules, the Name won't be unique per se. There may be
|
||||||
|
// multiple "regexp=" with different values. We'll need to set the
|
||||||
|
// .Value = chunk[1] and ensure r is dup'ed so they don't clobber
|
||||||
|
// each other.
|
||||||
|
newR := Rule(r)
|
||||||
|
newR.Value = chunks[1]
|
||||||
|
ret = append(ret, newR)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if strings.ToLower(r.Name) == strings.ToLower(includes[i]) {
|
||||||
|
ret = append(ret, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringsSliceEqual compares two string arrays for equality
|
||||||
|
func StringsSliceEqual(a, b []string) bool {
|
||||||
|
if !sort.StringsAreSorted(a) {
|
||||||
|
sort.Strings(a)
|
||||||
|
}
|
||||||
|
if !sort.StringsAreSorted(b) {
|
||||||
|
sort.Strings(b)
|
||||||
|
}
|
||||||
|
for i := range b {
|
||||||
|
if !StringsSliceContains(a, b[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if !StringsSliceContains(b, a[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringsSliceContains checks for the presence of a word in string array
|
||||||
|
func StringsSliceContains(a []string, b string) bool {
|
||||||
|
if !sort.StringsAreSorted(a) {
|
||||||
|
sort.Strings(a)
|
||||||
|
}
|
||||||
|
i := sort.SearchStrings(a, b)
|
||||||
|
return i < len(a) && a[i] == b
|
||||||
|
}
|
||||||
|
|
52
validate/rules_test.go
Normal file
52
validate/rules_test.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package validate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSanitizeRules(t *testing.T) {
|
||||||
|
set := []struct {
|
||||||
|
input string
|
||||||
|
output []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "apples, oranges , bananas",
|
||||||
|
output: []string{"apples", "oranges", "bananas"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "apples, oranges , bananas, peaches='with cream'",
|
||||||
|
output: []string{"apples", "oranges", "bananas", "peaches='with cream'"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range set {
|
||||||
|
filt := SanitizeFilters(set[i].input)
|
||||||
|
if !StringsSliceEqual(filt, set[i].output) {
|
||||||
|
t.Errorf("expected output like %v, but got %v", set[i].output, filt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSliceHelpers(t *testing.T) {
|
||||||
|
set := []struct {
|
||||||
|
A, B []string
|
||||||
|
Equal bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
A: []string{"apples", "bananas", "oranges", "mango"},
|
||||||
|
B: []string{"oranges", "bananas", "apples", "mango"},
|
||||||
|
Equal: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
A: []string{"apples", "bananas", "oranges", "mango"},
|
||||||
|
B: []string{"waffles"},
|
||||||
|
Equal: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := range set {
|
||||||
|
got := StringsSliceEqual(set[i].A, set[i].B)
|
||||||
|
if got != set[i].Equal {
|
||||||
|
t.Errorf("expected %d A and B comparison to be %q, but got %q", i, set[i].Equal, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue