feat: workflowpattern package (#1618)
* feat: workflowpattern package * nolint:gocyclo --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
4eba04b229
commit
05eaeaa528
|
@ -0,0 +1,18 @@
|
||||||
|
package workflowpattern
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type TraceWriter interface {
|
||||||
|
Info(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmptyTraceWriter struct{}
|
||||||
|
|
||||||
|
func (*EmptyTraceWriter) Info(string, ...interface{}) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type StdOutTraceWriter struct{}
|
||||||
|
|
||||||
|
func (*StdOutTraceWriter) Info(format string, args ...interface{}) {
|
||||||
|
fmt.Printf(format+"\n", args...)
|
||||||
|
}
|
|
@ -0,0 +1,196 @@
|
||||||
|
package workflowpattern
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WorkflowPattern struct {
|
||||||
|
Pattern string
|
||||||
|
Negative bool
|
||||||
|
Regex *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompilePattern(rawpattern string) (*WorkflowPattern, error) {
|
||||||
|
negative := false
|
||||||
|
pattern := rawpattern
|
||||||
|
if strings.HasPrefix(rawpattern, "!") {
|
||||||
|
negative = true
|
||||||
|
pattern = rawpattern[1:]
|
||||||
|
}
|
||||||
|
rpattern, err := PatternToRegex(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
regex, err := regexp.Compile(rpattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &WorkflowPattern{
|
||||||
|
Pattern: pattern,
|
||||||
|
Negative: negative,
|
||||||
|
Regex: regex,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gocyclo
|
||||||
|
func PatternToRegex(pattern string) (string, error) {
|
||||||
|
var rpattern strings.Builder
|
||||||
|
rpattern.WriteString("^")
|
||||||
|
pos := 0
|
||||||
|
errors := map[int]string{}
|
||||||
|
for pos < len(pattern) {
|
||||||
|
switch pattern[pos] {
|
||||||
|
case '*':
|
||||||
|
if pos+1 < len(pattern) && pattern[pos+1] == '*' {
|
||||||
|
if pos+2 < len(pattern) && pattern[pos+2] == '/' {
|
||||||
|
rpattern.WriteString("(.+/)?")
|
||||||
|
pos += 3
|
||||||
|
} else {
|
||||||
|
rpattern.WriteString(".*")
|
||||||
|
pos += 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rpattern.WriteString("[^/]*")
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
case '+', '?':
|
||||||
|
if pos > 0 {
|
||||||
|
rpattern.WriteByte(pattern[pos])
|
||||||
|
} else {
|
||||||
|
rpattern.WriteString(regexp.QuoteMeta(string([]byte{pattern[pos]})))
|
||||||
|
}
|
||||||
|
pos++
|
||||||
|
case '[':
|
||||||
|
rpattern.WriteByte(pattern[pos])
|
||||||
|
pos++
|
||||||
|
if pos < len(pattern) && pattern[pos] == ']' {
|
||||||
|
errors[pos] = "Unexpected empty brackets '[]'"
|
||||||
|
pos++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
validChar := func(a, b, test byte) bool {
|
||||||
|
return test >= a && test <= b
|
||||||
|
}
|
||||||
|
startPos := pos
|
||||||
|
for pos < len(pattern) && pattern[pos] != ']' {
|
||||||
|
switch pattern[pos] {
|
||||||
|
case '-':
|
||||||
|
if pos <= startPos || pos+1 >= len(pattern) {
|
||||||
|
errors[pos] = "Invalid range"
|
||||||
|
pos++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
validRange := func(a, b byte) bool {
|
||||||
|
return validChar(a, b, pattern[pos-1]) && validChar(a, b, pattern[pos+1]) && pattern[pos-1] <= pattern[pos+1]
|
||||||
|
}
|
||||||
|
if !validRange('A', 'z') && !validRange('0', '9') {
|
||||||
|
errors[pos] = "Ranges can only include a-z, A-Z, A-z, and 0-9"
|
||||||
|
pos++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rpattern.WriteString(pattern[pos : pos+2])
|
||||||
|
pos += 2
|
||||||
|
default:
|
||||||
|
if !validChar('A', 'z', pattern[pos]) && !validChar('0', '9', pattern[pos]) {
|
||||||
|
errors[pos] = "Ranges can only include a-z, A-Z and 0-9"
|
||||||
|
pos++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rpattern.WriteString(regexp.QuoteMeta(string([]byte{pattern[pos]})))
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pos >= len(pattern) || pattern[pos] != ']' {
|
||||||
|
errors[pos] = "Missing closing bracket ']' after '['"
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
rpattern.WriteString("]")
|
||||||
|
pos++
|
||||||
|
case '\\':
|
||||||
|
if pos+1 >= len(pattern) {
|
||||||
|
errors[pos] = "Missing symbol after \\"
|
||||||
|
pos++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rpattern.WriteString(regexp.QuoteMeta(string([]byte{pattern[pos+1]})))
|
||||||
|
pos += 2
|
||||||
|
default:
|
||||||
|
rpattern.WriteString(regexp.QuoteMeta(string([]byte{pattern[pos]})))
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errors) > 0 {
|
||||||
|
var errorMessage strings.Builder
|
||||||
|
for position, err := range errors {
|
||||||
|
if errorMessage.Len() > 0 {
|
||||||
|
errorMessage.WriteString(", ")
|
||||||
|
}
|
||||||
|
errorMessage.WriteString(fmt.Sprintf("Position: %d Error: %s", position, err))
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("invalid Pattern '%s': %s", pattern, errorMessage.String())
|
||||||
|
}
|
||||||
|
rpattern.WriteString("$")
|
||||||
|
return rpattern.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompilePatterns(patterns ...string) ([]*WorkflowPattern, error) {
|
||||||
|
ret := []*WorkflowPattern{}
|
||||||
|
for _, pattern := range patterns {
|
||||||
|
cp, err := CompilePattern(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret = append(ret, cp)
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the workflow should be skipped paths/branches
|
||||||
|
func Skip(sequence []*WorkflowPattern, input []string, traceWriter TraceWriter) bool {
|
||||||
|
if len(sequence) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, file := range input {
|
||||||
|
matched := false
|
||||||
|
for _, item := range sequence {
|
||||||
|
if item.Regex.MatchString(file) {
|
||||||
|
pattern := item.Pattern
|
||||||
|
if item.Negative {
|
||||||
|
matched = false
|
||||||
|
traceWriter.Info("%s excluded by pattern %s", file, pattern)
|
||||||
|
} else {
|
||||||
|
matched = true
|
||||||
|
traceWriter.Info("%s included by pattern %s", file, pattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the workflow should be skipped paths-ignore/branches-ignore
|
||||||
|
func Filter(sequence []*WorkflowPattern, input []string, traceWriter TraceWriter) bool {
|
||||||
|
if len(sequence) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, file := range input {
|
||||||
|
matched := false
|
||||||
|
for _, item := range sequence {
|
||||||
|
if item.Regex.MatchString(file) == !item.Negative {
|
||||||
|
pattern := item.Pattern
|
||||||
|
traceWriter.Info("%s ignored by pattern %s", file, pattern)
|
||||||
|
matched = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !matched {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,414 @@
|
||||||
|
package workflowpattern
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMatchPattern(t *testing.T) {
|
||||||
|
kases := []struct {
|
||||||
|
inputs []string
|
||||||
|
patterns []string
|
||||||
|
skipResult bool
|
||||||
|
filterResult bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
patterns: []string{"*"},
|
||||||
|
inputs: []string{"path/with/slash"},
|
||||||
|
skipResult: true,
|
||||||
|
filterResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"path/a", "path/b", "path/c"},
|
||||||
|
inputs: []string{"meta", "path/b", "otherfile"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"path/a", "path/b", "path/c"},
|
||||||
|
inputs: []string{"path/b"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"path/a", "path/b", "path/c"},
|
||||||
|
inputs: []string{"path/c", "path/b"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"path/a", "path/b", "path/c"},
|
||||||
|
inputs: []string{"path/c", "path/b", "path/a"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"path/a", "path/b", "path/c"},
|
||||||
|
inputs: []string{"path/c", "path/b", "path/d", "path/a"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{},
|
||||||
|
inputs: []string{},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"\\!file"},
|
||||||
|
inputs: []string{"!file"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"escape\\\\backslash"},
|
||||||
|
inputs: []string{"escape\\backslash"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{".yml"},
|
||||||
|
inputs: []string{"fyml"},
|
||||||
|
skipResult: true,
|
||||||
|
filterResult: false,
|
||||||
|
},
|
||||||
|
// https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#patterns-to-match-branches-and-tags
|
||||||
|
{
|
||||||
|
patterns: []string{"feature/*"},
|
||||||
|
inputs: []string{"feature/my-branch"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"feature/*"},
|
||||||
|
inputs: []string{"feature/your-branch"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"feature/**"},
|
||||||
|
inputs: []string{"feature/beta-a/my-branch"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"feature/**"},
|
||||||
|
inputs: []string{"feature/beta-a/my-branch"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"feature/**"},
|
||||||
|
inputs: []string{"feature/mona/the/octocat"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"main", "releases/mona-the-octocat"},
|
||||||
|
inputs: []string{"main"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"main", "releases/mona-the-octocat"},
|
||||||
|
inputs: []string{"releases/mona-the-octocat"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*"},
|
||||||
|
inputs: []string{"main"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*"},
|
||||||
|
inputs: []string{"releases"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**"},
|
||||||
|
inputs: []string{"all/the/branches"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**"},
|
||||||
|
inputs: []string{"every/tag"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*feature"},
|
||||||
|
inputs: []string{"mona-feature"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*feature"},
|
||||||
|
inputs: []string{"feature"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*feature"},
|
||||||
|
inputs: []string{"ver-10-feature"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"v2*"},
|
||||||
|
inputs: []string{"v2"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"v2*"},
|
||||||
|
inputs: []string{"v2.0"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"v2*"},
|
||||||
|
inputs: []string{"v2.9"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"v[12].[0-9]+.[0-9]+"},
|
||||||
|
inputs: []string{"v1.10.1"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"v[12].[0-9]+.[0-9]+"},
|
||||||
|
inputs: []string{"v2.0.0"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
// https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#patterns-to-match-file-paths
|
||||||
|
{
|
||||||
|
patterns: []string{"*"},
|
||||||
|
inputs: []string{"README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*"},
|
||||||
|
inputs: []string{"server.rb"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.jsx?"},
|
||||||
|
inputs: []string{"page.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.jsx?"},
|
||||||
|
inputs: []string{"page.jsx"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**"},
|
||||||
|
inputs: []string{"all/the/files.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.js"},
|
||||||
|
inputs: []string{"app.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.js"},
|
||||||
|
inputs: []string{"index.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**.js"},
|
||||||
|
inputs: []string{"index.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**.js"},
|
||||||
|
inputs: []string{"js/index.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**.js"},
|
||||||
|
inputs: []string{"src/js/app.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/*"},
|
||||||
|
inputs: []string{"docs/README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/*"},
|
||||||
|
inputs: []string{"docs/file.txt"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/**"},
|
||||||
|
inputs: []string{"docs/README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/**"},
|
||||||
|
inputs: []string{"docs/mona/octocat.txt"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/**/*.md"},
|
||||||
|
inputs: []string{"docs/README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/**/*.md"},
|
||||||
|
inputs: []string{"docs/mona/hello-world.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"docs/**/*.md"},
|
||||||
|
inputs: []string{"docs/a/markdown/file.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/docs/**"},
|
||||||
|
inputs: []string{"docs/hello.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/docs/**"},
|
||||||
|
inputs: []string{"dir/docs/my-file.txt"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/docs/**"},
|
||||||
|
inputs: []string{"space/docs/plan/space.doc"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/README.md"},
|
||||||
|
inputs: []string{"README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/README.md"},
|
||||||
|
inputs: []string{"js/README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/*src/**"},
|
||||||
|
inputs: []string{"a/src/app.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/*src/**"},
|
||||||
|
inputs: []string{"my-src/code/js/app.js"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/*-post.md"},
|
||||||
|
inputs: []string{"my-post.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/*-post.md"},
|
||||||
|
inputs: []string{"path/their-post.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/migrate-*.sql"},
|
||||||
|
inputs: []string{"migrate-10909.sql"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/migrate-*.sql"},
|
||||||
|
inputs: []string{"db/migrate-v1.0.sql"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"**/migrate-*.sql"},
|
||||||
|
inputs: []string{"db/sept/migrate-v1.sql"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.md", "!README.md"},
|
||||||
|
inputs: []string{"hello.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.md", "!README.md"},
|
||||||
|
inputs: []string{"README.md"},
|
||||||
|
skipResult: true,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.md", "!README.md"},
|
||||||
|
inputs: []string{"docs/hello.md"},
|
||||||
|
skipResult: true,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.md", "!README.md", "README*"},
|
||||||
|
inputs: []string{"hello.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.md", "!README.md", "README*"},
|
||||||
|
inputs: []string{"README.md"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
patterns: []string{"*.md", "!README.md", "README*"},
|
||||||
|
inputs: []string{"README.doc"},
|
||||||
|
skipResult: false,
|
||||||
|
filterResult: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, kase := range kases {
|
||||||
|
t.Run(strings.Join(kase.patterns, ","), func(t *testing.T) {
|
||||||
|
patterns, err := CompilePatterns(kase.patterns...)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.EqualValues(t, kase.skipResult, Skip(patterns, kase.inputs, &StdOutTraceWriter{}), "skipResult")
|
||||||
|
assert.EqualValues(t, kase.filterResult, Filter(patterns, kase.inputs, &StdOutTraceWriter{}), "filterResult")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue