diff options
Diffstat (limited to 'test/tools/vendor/github.com/vbatts/git-validation')
14 files changed, 911 insertions, 0 deletions
diff --git a/test/tools/vendor/github.com/vbatts/git-validation/.gitignore b/test/tools/vendor/github.com/vbatts/git-validation/.gitignore new file mode 100644 index 000000000..265db6acb --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/.gitignore @@ -0,0 +1,2 @@ +*~ +git-validation diff --git a/test/tools/vendor/github.com/vbatts/git-validation/.travis.yml b/test/tools/vendor/github.com/vbatts/git-validation/.travis.yml new file mode 100644 index 000000000..27cd83c47 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/.travis.yml @@ -0,0 +1,37 @@ +language: go + +go_import_path: github.com/vbatts/git-validation + +go: + - "tip" + - "1.x" + - "1.11.x" + - "1.10.x" + - "1.9.x" + +env: + +matrix: + +sudo: false + +install: true + +notifications: + email: + on_success: change + on_failure: always + +before_script: + - env + +before_install: + - go get ./... + - if [[ "$(go version |awk '{ print $3 }')" =~ ^go1\.11\. ]] ; then go get -u golang.org/x/lint/golint ; fi + +script: + - if [[ "$(go version |awk '{ print $3 }')" =~ ^go1\.11\. ]] ; then golint -set_exit_status ./... ; fi + - go vet -x ./... + - go build . + - go test -v ./... + - ./git-validation -run DCO,short-subject,dangling-whitespace -v diff --git a/test/tools/vendor/github.com/vbatts/git-validation/LICENSE b/test/tools/vendor/github.com/vbatts/git-validation/LICENSE new file mode 100644 index 000000000..8efd59c71 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Vincent Batts + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/test/tools/vendor/github.com/vbatts/git-validation/README.md b/test/tools/vendor/github.com/vbatts/git-validation/README.md new file mode 100644 index 000000000..354276e02 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/README.md @@ -0,0 +1,106 @@ +# git-validation + +A way to do validation on git commits. +[![Build Status](https://travis-ci.org/vbatts/git-validation.svg?branch=master)](https://travis-ci.org/vbatts/git-validation) + +## install + +```console +vbatts@valse ~ (master) $ go get -u github.com/vbatts/git-validation +``` + +## usage + +The flags +```console +vbatts@valse ~/src/vb/git-validation (master *) $ git-validation -h +Usage of git-validation: + -D debug output + -d string + git directory to validate from (default ".") + -list-rules + list the rules registered + -range string + use this commit range instead + -run string + comma delimited list of rules to run. Defaults to all. + -v verbose +``` + +The entire default rule set is run by default: +```console +vbatts@valse ~/src/vb/git-validation (master) $ git-validation -list-rules +"dangling-whitespace" -- checking the presence of dangling whitespaces on line endings +"DCO" -- makes sure the commits are signed +"message_regexp" -- checks the commit message for a user provided regular expression +"short-subject" -- commit subjects are strictly less than 90 (github ellipsis length) +``` + +Or, specify comma-delimited rules to run: +```console +vbatts@valse ~/src/vb/git-validation (master) $ git-validation -run DCO,short-subject + * b243ca4 "README: adding install and usage" ... PASS + * d614ccf "*: run tests in a runner" ... PASS + * b9413c6 "shortsubject: add a subject length check" ... PASS + * 5e74abd "*: comments and golint" ... PASS + * 07a982f "git: add verbose output of the commands run" ... PASS + * 03bda4b "main: add filtering of rules to run" ... PASS + * c10ba9c "Initial commit" ... PASS +``` + +Verbosity shows each rule's output: +```console +vbatts@valse ~/src/vb/git-validation (master) $ git-validation -v + * d614ccf "*: run tests in a runner" ... PASS + - PASS - has a valid DCO + - PASS - commit subject is 72 characters or less! *yay* + * b9413c6 "shortsubject: add a subject length check" ... PASS + - PASS - has a valid DCO + - PASS - commit subject is 72 characters or less! *yay* + * 5e74abd "*: comments and golint" ... PASS + - PASS - has a valid DCO + - PASS - commit subject is 72 characters or less! *yay* + * 07a982f "git: add verbose output of the commands run" ... PASS + - PASS - has a valid DCO + - PASS - commit subject is 72 characters or less! *yay* + * 03bda4b "main: add filtering of rules to run" ... PASS + - PASS - has a valid DCO + - PASS - commit subject is 72 characters or less! *yay* + * c10ba9c "Initial commit" ... PASS + - PASS - has a valid DCO + - PASS - commit subject is 72 characters or less! *yay* +``` + +Here's a failure: +```console +vbatts@valse ~/src/vb/git-validation (master) $ git-validation + * 49f51a8 "README: adding install and usage" ... FAIL + - FAIL - does not have a valid DCO + * d614ccf "*: run tests in a runner" ... PASS + * b9413c6 "shortsubject: add a subject length check" ... PASS + * 5e74abd "*: comments and golint" ... PASS + * 07a982f "git: add verbose output of the commands run" ... PASS + * 03bda4b "main: add filtering of rules to run" ... PASS + * c10ba9c "Initial commit" ... PASS +1 issues to fix +vbatts@valse ~/src/vb/git-validation (master) $ echo $? +1 +``` + +Excluding paths that are out of the scope of your project: +```console +vbatts@valse ~/src/vb/git-validation (master) $ GIT_CHECK_EXCLUDE="./vendor:./git/testdata" git-validation -q -run dangling-whitespace +... +``` +using the `GIT_CHECK_EXCLUDE` environment variable. Multiple paths should be separated by colon(`:`) + + +## Rules + +Default rules are added by registering them to the `validate` package. +Usually by putting them in their own package. +See [`./rules/`](./rules/). +Feel free to contribute more. + +Otherwise, by using `validate` package API directly, rules can be handed directly to the `validate.Runner`. + diff --git a/test/tools/vendor/github.com/vbatts/git-validation/git/commits.go b/test/tools/vendor/github.com/vbatts/git-validation/git/commits.go new file mode 100644 index 000000000..52af99789 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/git/commits.go @@ -0,0 +1,192 @@ +package git + +import ( + "fmt" + "os" + "os/exec" + "strings" + + version "github.com/hashicorp/go-version" + "github.com/sirupsen/logrus" +) + +// Commits returns a set of commits. +// If commitrange is a git still range 12345...54321, then it will be isolated set of commits. +// If commitrange is a single commit, all ancestor commits up through the hash provided. +// If commitrange is an empty commit range, then nil is returned. +func Commits(commitrange string) ([]CommitEntry, error) { + cmdArgs := []string{"git", "--no-pager", "log", `--pretty=format:%H`, commitrange} + if debug() { + logrus.Infof("[git] cmd: %q", strings.Join(cmdArgs, " ")) + } + output, err := exec.Command(cmdArgs[0], cmdArgs[1:]...).Output() + if err != nil { + logrus.Errorf("mm[git] cmd: %q", strings.Join(cmdArgs, " ")) + return nil, err + } + if len(output) == 0 { + return nil, nil + } + commitHashes := strings.Split(strings.TrimSpace(string(output)), "\n") + commits := make([]CommitEntry, len(commitHashes)) + for i, commitHash := range commitHashes { + c, err := LogCommit(commitHash) + if err != nil { + return commits, err + } + commits[i] = *c + } + return commits, nil +} + +// FieldNames are for the formating and rendering of the CommitEntry structs. +// Keys here are from git log pretty format "format:..." +var FieldNames = map[string]string{ + "%h": "abbreviated_commit", + "%p": "abbreviated_parent", + "%t": "abbreviated_tree", + "%aD": "author_date", + "%aE": "author_email", + "%aN": "author_name", + "%b": "body", + "%H": "commit", + "%N": "commit_notes", + "%cD": "committer_date", + "%cE": "committer_email", + "%cN": "committer_name", + "%e": "encoding", + "%P": "parent", + "%D": "refs", + "%f": "sanitized_subject_line", + "%GS": "signer", + "%GK": "signer_key", + "%s": "subject", + "%G?": "verification_flag", +} + +func gitVersion() (string, error) { + cmd := exec.Command("git", "version") + cmd.Stderr = os.Stderr + buf, err := cmd.Output() + if err != nil { + return "", err + } + return strings.Fields(string(buf))[2], nil +} + +// https://github.com/vbatts/git-validation/issues/37 +var versionWithExcludes = "1.9.5" + +func gitVersionNewerThan(otherV string) (bool, error) { + gv, err := gitVersion() + if err != nil { + return false, err + } + v1, err := version.NewVersion(gv) + if err != nil { + return false, err + } + v2, err := version.NewVersion(otherV) + if err != nil { + return false, err + } + return v2.Equal(v1) || v2.LessThan(v1), nil +} + +// Check warns if changes introduce whitespace errors. +// Returns non-zero if any issues are found. +func Check(commit string) ([]byte, error) { + args := []string{ + "--no-pager", "log", "--check", + fmt.Sprintf("%s^..%s", commit, commit), + } + if excludeEnvList := os.Getenv("GIT_CHECK_EXCLUDE"); excludeEnvList != "" { + gitNewEnough, err := gitVersionNewerThan(versionWithExcludes) + if err != nil { + return nil, err + } + if gitNewEnough { + excludeList := strings.Split(excludeEnvList, ":") + for _, exclude := range excludeList { + if exclude == "" { + continue + } + args = append(args, "--", ".", fmt.Sprintf(":(exclude)%s", exclude)) + } + } + } + cmd := exec.Command("git", args...) + if debug() { + logrus.Infof("[git] cmd: %q", strings.Join(cmd.Args, " ")) + } + cmd.Stderr = os.Stderr + return cmd.Output() +} + +// Show returns the diff of a commit. +// +// NOTE: This could be expensive for very large commits. +func Show(commit string) ([]byte, error) { + cmd := exec.Command("git", "--no-pager", "show", commit) + if debug() { + logrus.Infof("[git] cmd: %q", strings.Join(cmd.Args, " ")) + } + cmd.Stderr = os.Stderr + return cmd.Output() +} + +// CommitEntry represents a single commit's information from `git`. +// See also FieldNames +type CommitEntry map[string]string + +// LogCommit assembles the full information on a commit from its commit hash +func LogCommit(commit string) (*CommitEntry, error) { + c := CommitEntry{} + for k, v := range FieldNames { + cmd := exec.Command("git", "--no-pager", "log", "-1", `--pretty=format:`+k+``, commit) + if debug() { + logrus.Infof("[git] cmd: %q", strings.Join(cmd.Args, " ")) + } + cmd.Stderr = os.Stderr + out, err := cmd.Output() + if err != nil { + logrus.Errorf("[git] cmd: %q", strings.Join(cmd.Args, " ")) + return nil, err + } + c[v] = strings.TrimSpace(string(out)) + } + + return &c, nil +} + +func debug() bool { + return len(os.Getenv("DEBUG")) > 0 +} + +// FetchHeadCommit returns the hash of FETCH_HEAD +func FetchHeadCommit() (string, error) { + cmdArgs := []string{"git", "--no-pager", "rev-parse", "--verify", "FETCH_HEAD"} + if debug() { + logrus.Infof("[git] cmd: %q", strings.Join(cmdArgs, " ")) + } + output, err := exec.Command(cmdArgs[0], cmdArgs[1:]...).Output() + if err != nil { + logrus.Errorf("[git] cmd: %q", strings.Join(cmdArgs, " ")) + return "", err + } + return strings.TrimSpace(string(output)), nil +} + +// HeadCommit returns the hash of HEAD +func HeadCommit() (string, error) { + cmdArgs := []string{"git", "--no-pager", "rev-parse", "--verify", "HEAD"} + if debug() { + logrus.Infof("[git] cmd: %q", strings.Join(cmdArgs, " ")) + } + output, err := exec.Command(cmdArgs[0], cmdArgs[1:]...).Output() + if err != nil { + logrus.Errorf("[git] cmd: %q", strings.Join(cmdArgs, " ")) + return "", err + } + return strings.TrimSpace(string(output)), nil +} diff --git a/test/tools/vendor/github.com/vbatts/git-validation/go.mod b/test/tools/vendor/github.com/vbatts/git-validation/go.mod new file mode 100644 index 000000000..14b7069e7 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/go.mod @@ -0,0 +1,8 @@ +module github.com/vbatts/git-validation + +go 1.12 + +require ( + github.com/hashicorp/go-version v1.2.0 + github.com/sirupsen/logrus v1.4.1 +) diff --git a/test/tools/vendor/github.com/vbatts/git-validation/go.sum b/test/tools/vendor/github.com/vbatts/git-validation/go.sum new file mode 100644 index 000000000..265941fe3 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/test/tools/vendor/github.com/vbatts/git-validation/main.go b/test/tools/vendor/github.com/vbatts/git-validation/main.go new file mode 100644 index 000000000..cd5f271a4 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/main.go @@ -0,0 +1,92 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "strings" + + _ "github.com/vbatts/git-validation/rules/danglingwhitespace" + _ "github.com/vbatts/git-validation/rules/dco" + _ "github.com/vbatts/git-validation/rules/messageregexp" + _ "github.com/vbatts/git-validation/rules/shortsubject" + "github.com/vbatts/git-validation/validate" +) + +var ( + flCommitRange = flag.String("range", "", "use this commit range instead (implies -no-travis)") + flListRules = flag.Bool("list-rules", false, "list the rules registered") + flRun = flag.String("run", "", "comma delimited list of rules to run. Defaults to all.") + flVerbose = flag.Bool("v", false, "verbose") + flDebug = flag.Bool("D", false, "debug output") + flQuiet = flag.Bool("q", false, "less output") + flDir = flag.String("d", ".", "git directory to validate from") + flNoTravis = flag.Bool("no-travis", false, "disables travis environment checks (when env TRAVIS=true is set)") + flTravisPROnly = flag.Bool("travis-pr-only", true, "when on travis, only run validations if the CI-Build is checking pull-request build") +) + +func main() { + flag.Parse() + + if *flDebug { + os.Setenv("DEBUG", "1") + } + if *flQuiet { + os.Setenv("QUIET", "1") + } + + if *flListRules { + for _, r := range validate.RegisteredRules { + fmt.Printf("%q -- %s\n", r.Name, r.Description) + } + return + } + + if *flTravisPROnly && strings.ToLower(os.Getenv("TRAVIS_PULL_REQUEST")) == "false" { + fmt.Printf("only to check travis PR builds and this not a PR build. yielding.\n") + return + } + + // rules to be used + var rules []validate.Rule + for _, r := range validate.RegisteredRules { + // only those that are Default + if r.Default { + rules = append(rules, r) + } + } + // or reduce the set being run to what the user provided + if *flRun != "" { + rules = validate.FilterRules(validate.RegisteredRules, validate.SanitizeFilters(*flRun)) + } + if os.Getenv("DEBUG") != "" { + log.Printf("%#v", rules) // XXX maybe reduce this list + } + + var commitRange = *flCommitRange + if commitRange == "" { + if strings.ToLower(os.Getenv("TRAVIS")) == "true" && !*flNoTravis { + if os.Getenv("TRAVIS_COMMIT_RANGE") != "" { + commitRange = strings.Replace(os.Getenv("TRAVIS_COMMIT_RANGE"), "...", "..", 1) + } else if os.Getenv("TRAVIS_COMMIT") != "" { + commitRange = os.Getenv("TRAVIS_COMMIT") + } + } + } + + runner, err := validate.NewRunner(*flDir, rules, commitRange, *flVerbose) + if err != nil { + log.Fatal(err) + } + + if err := runner.Run(); err != nil { + log.Fatal(err) + } + _, fail := runner.Results.PassFail() + if fail > 0 { + fmt.Printf("%d commits to fix\n", fail) + os.Exit(1) + } + +} diff --git a/test/tools/vendor/github.com/vbatts/git-validation/rules/danglingwhitespace/rule.go b/test/tools/vendor/github.com/vbatts/git-validation/rules/danglingwhitespace/rule.go new file mode 100644 index 000000000..dab3a984b --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/rules/danglingwhitespace/rule.go @@ -0,0 +1,39 @@ +package danglingwhitespace + +import ( + "github.com/vbatts/git-validation/git" + "github.com/vbatts/git-validation/validate" +) + +var ( + // DanglingWhitespace is the rule for checking the presence of dangling + // whitespaces on line endings. + DanglingWhitespace = validate.Rule{ + Name: "dangling-whitespace", + Description: "checking the presence of dangling whitespaces on line endings", + Run: ValidateDanglingWhitespace, + Default: true, + } +) + +func init() { + validate.RegisterRule(DanglingWhitespace) +} + +// ValidateDanglingWhitespace runs Git's check to look for whitespace errors. +func ValidateDanglingWhitespace(r validate.Rule, c git.CommitEntry) (vr validate.Result) { + vr.CommitEntry = c + vr.Msg = "commit does not have any whitespace errors" + vr.Pass = true + + _, err := git.Check(c["commit"]) + if err != nil { + vr.Pass = false + if err.Error() == "exit status 2" { + vr.Msg = "has whitespace errors. See `git show --check " + c["commit"] + "`." + } else { + vr.Msg = "errored with: " + err.Error() + } + } + return +} diff --git a/test/tools/vendor/github.com/vbatts/git-validation/rules/dco/dco.go b/test/tools/vendor/github.com/vbatts/git-validation/rules/dco/dco.go new file mode 100644 index 000000000..a42ea06ac --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/rules/dco/dco.go @@ -0,0 +1,51 @@ +package dco + +import ( + "regexp" + "strings" + + "github.com/vbatts/git-validation/git" + "github.com/vbatts/git-validation/validate" +) + +func init() { + validate.RegisterRule(DcoRule) +} + +var ( + // ValidDCO is the regexp for signed off DCO + ValidDCO = regexp.MustCompile(`^Signed-off-by: ([^<]+) <([^<>@]+@[^<>]+)>$`) + // DcoRule is the rule being registered + DcoRule = validate.Rule{ + Name: "DCO", + Description: "makes sure the commits are signed", + Run: ValidateDCO, + Default: true, + } +) + +// ValidateDCO checks that the commit has been signed off, per the DCO process +func ValidateDCO(r validate.Rule, c git.CommitEntry) (vr validate.Result) { + vr.CommitEntry = c + if len(strings.Split(c["parent"], " ")) > 1 { + vr.Pass = true + vr.Msg = "merge commits do not require DCO" + return vr + } + + hasValid := false + for _, line := range strings.Split(c["body"], "\n") { + if ValidDCO.MatchString(line) { + hasValid = true + } + } + if !hasValid { + vr.Pass = false + vr.Msg = "does not have a valid DCO" + } else { + vr.Pass = true + vr.Msg = "has a valid DCO" + } + + return vr +} diff --git a/test/tools/vendor/github.com/vbatts/git-validation/rules/messageregexp/rule.go b/test/tools/vendor/github.com/vbatts/git-validation/rules/messageregexp/rule.go new file mode 100644 index 000000000..98587f262 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/rules/messageregexp/rule.go @@ -0,0 +1,61 @@ +package messageregexp + +import ( + "fmt" + "regexp" + "strings" + + "github.com/vbatts/git-validation/git" + "github.com/vbatts/git-validation/validate" +) + +func init() { + validate.RegisterRule(RegexpRule) +} + +var ( + // RegexpRule for validating a user provided regex on the commit messages + RegexpRule = validate.Rule{ + Name: "message_regexp", + Description: "checks the commit message for a user provided regular expression", + Run: ValidateMessageRegexp, + Default: false, // only for users specifically calling it through -run ... + } +) + +// ValidateMessageRegexp is the message regex func to run +func ValidateMessageRegexp(r validate.Rule, c git.CommitEntry) (vr validate.Result) { + if r.Value == "" { + vr.Pass = true + vr.Msg = "noop: message_regexp value is blank" + return vr + } + + re := regexp.MustCompile(r.Value) + vr.CommitEntry = c + if len(strings.Split(c["parent"], " ")) > 1 { + vr.Pass = true + vr.Msg = "merge commits are not checked for message_regexp" + return vr + } + + hasValid := false + for _, line := range strings.Split(c["subject"], "\n") { + if re.MatchString(line) { + hasValid = true + } + } + for _, line := range strings.Split(c["body"], "\n") { + if re.MatchString(line) { + hasValid = true + } + } + if !hasValid { + vr.Pass = false + vr.Msg = fmt.Sprintf("commit message does not match %q", r.Value) + } else { + vr.Pass = true + vr.Msg = fmt.Sprintf("commit message matches %q", r.Value) + } + return vr +} diff --git a/test/tools/vendor/github.com/vbatts/git-validation/rules/shortsubject/shortsubject.go b/test/tools/vendor/github.com/vbatts/git-validation/rules/shortsubject/shortsubject.go new file mode 100644 index 000000000..8fd033601 --- /dev/null +++ b/test/tools/vendor/github.com/vbatts/git-validation/rules/shortsubject/shortsubject.go @@ -0,0 +1,44 @@ +package shortsubject + +import ( + "strings" + + "github.com/vbatts/git-validation/git" + "github.com/vbatts/git-validation/validate" +) + +var ( + // ShortSubjectRule is the rule being registered + ShortSubjectRule = validate.Rule{ + Name: "short-subject", + Description: "commit subjects are strictly less than 90 (github ellipsis length)", + Run: ValidateShortSubject, + Default: true, + } +) + +func init() { + validate.RegisterRule(ShortSubjectRule) +} + +// ValidateShortSubject checks that the commit's subject is strictly less than +// 90 characters (preferably not more than 72 chars). +func ValidateShortSubject(r validate.Rule, c git.CommitEntry) (vr validate.Result) { + if len(strings.Split(c["parent"], " ")) > 1 { + vr.Pass = true + vr.Msg = "merge commits do not require length check" + return vr + } + if len(c["subject"]) >= 90 { + vr.Pass = false + vr.Msg = "commit subject exceeds 90 characters" + return + } + vr.Pass = true + if len(c["subject"]) > 72 { + vr.Msg = "commit subject is under 90 characters, but is still more than 72 chars" + } else { + vr.Msg = "commit subject is 72 characters or less! *yay*" + } + return +} 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 +} |