diff options
Diffstat (limited to 'test/tools/vendor/github.com/vbatts/git-validation/validate')
-rw-r--r-- | test/tools/vendor/github.com/vbatts/git-validation/validate/rules.go | 134 | ||||
-rw-r--r-- | test/tools/vendor/github.com/vbatts/git-validation/validate/runner.go | 109 |
2 files changed, 243 insertions, 0 deletions
diff --git a/test/tools/vendor/github.com/vbatts/git-validation/validate/rules.go b/test/tools/vendor/github.com/vbatts/git-validation/validate/rules.go new file mode 100644 index 000000000..38126a4f0 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/validate/rules.go @@ -0,0 +1,134 @@ +package validate + +import ( + "sort" + "strings" + "sync" + + "github.com/vbatts/git-validation/git" +) + +var ( + // RegisteredRules are the avaible validation to perform on git commits + RegisteredRules = []Rule{} + registerRuleLock = sync.Mutex{} +) + +// RegisterRule includes the Rule in the avaible set to use +func RegisterRule(vr Rule) { + registerRuleLock.Lock() + defer registerRuleLock.Unlock() + RegisteredRules = append(RegisteredRules, vr) +} + +// Rule will operate over a provided git.CommitEntry, and return a result. +type Rule struct { + 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 + Run func(Rule, git.CommitEntry) Result + Default bool // whether the registered rule is run by default +} + +// Commit processes the given rules on the provided commit, and returns the result set. +func Commit(c git.CommitEntry, rules []Rule) Results { + results := Results{} + for _, r := range rules { + results = append(results, r.Run(r, c)) + } + return results +} + +// Result is the result for a single validation of a commit. +type Result struct { + CommitEntry git.CommitEntry + Pass bool + Msg string +} + +// Results is a set of results. This is type makes it easy for the following function. +type Results []Result + +// PassFail gives a quick over/under of passes and failures of the results in this set +func (vr Results) PassFail() (pass int, fail int) { + for _, res := range vr { + if res.Pass { + pass++ + } else { + fail++ + } + } + return pass, fail +} + +// SanitizeFilters takes a comma delimited list and returns the trimmend and +// split (on ",") items in the list +func SanitizeFilters(filtStr string) (filters []string) { + for _, item := range strings.Split(filtStr, ",") { + filters = append(filters, strings.TrimSpace(item)) + } + return +} + +// FilterRules takes a set of rules and a list of short names to include, and +// returns the reduced set. The comparison is case insensitive. +// +// 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{} + + for _, r := range rules { + for i := range includes { + if strings.Contains(includes[i], "=") { + 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 +} + +// 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 +} diff --git a/test/tools/vendor/github.com/vbatts/git-validation/validate/runner.go b/test/tools/vendor/github.com/vbatts/git-validation/validate/runner.go new file mode 100644 index 000000000..eea61fba1 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/validate/runner.go @@ -0,0 +1,109 @@ +package validate + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/vbatts/git-validation/git" +) + +// Runner is the for processing a set of rules against a range of commits +type Runner struct { + Root string + Rules []Rule + Results Results + Verbose bool + CommitRange string // if this is empty, then it will default to FETCH_HEAD, then HEAD +} + +// NewRunner returns an initiallized Runner. +func NewRunner(root string, rules []Rule, commitrange string, verbose bool) (*Runner, error) { + newroot, err := filepath.Abs(root) + if err != nil { + return nil, fmt.Errorf("failed to get absolute path of %q: %s", root, err) + } + if commitrange == "" { + var err error + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + defer os.Chdir(cwd) + + if err := os.Chdir(newroot); err != nil { + return nil, err + } + commitrange, err = git.FetchHeadCommit() + if err != nil { + commitrange, err = git.HeadCommit() + if err != nil { + return nil, err + } + } + } + return &Runner{ + Root: newroot, + Rules: rules, + CommitRange: commitrange, + Verbose: verbose, + }, nil +} + +// Run processes the rules for each commit in the range provided +func (r *Runner) Run() error { + cwd, err := os.Getwd() + if err != nil { + return err + } + defer os.Chdir(cwd) + + if err := os.Chdir(r.Root); err != nil { + return err + } + + // collect the entries + c, err := git.Commits(r.CommitRange) + if err != nil { + return err + } + + // run them and show results + for _, commit := range c { + if os.Getenv("QUIET") == "" { + fmt.Printf(" * %s %q ... ", commit["abbreviated_commit"], commit["subject"]) + } + vr := Commit(commit, r.Rules) + r.Results = append(r.Results, vr...) + _, fail := vr.PassFail() + if os.Getenv("QUIET") != "" { + if fail != 0 { + for _, res := range vr { + if !res.Pass { + fmt.Printf(" %s - FAIL - %s\n", commit["abbreviated_commit"], res.Msg) + } + } + } + // everything else in the loop is printing output. + // If we're quiet, then just continue + continue + } + if fail == 0 { + fmt.Println("PASS") + } else { + fmt.Println("FAIL") + } + for _, res := range vr { + if r.Verbose { + if res.Pass { + fmt.Printf(" - PASS - %s\n", res.Msg) + } else { + fmt.Printf(" - FAIL - %s\n", res.Msg) + } + } else if !res.Pass { + fmt.Printf(" - FAIL - %s\n", res.Msg) + } + } + } + return nil +} |