2020-03-18 22:35:32 +00:00
|
|
|
package accessctl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/bmatcuk/doublestar"
|
|
|
|
)
|
|
|
|
|
|
|
|
// StringMatcher is used to match against a string. It can use one of several
|
|
|
|
// methods to match. Only one field should be filled at a time.
|
|
|
|
type StringMatcher struct {
|
|
|
|
// Pattern, if set, indicates that the Match method should succeed if this
|
|
|
|
// doublestar pattern matches against the string.
|
|
|
|
Pattern string `yaml:"pattern,omitempty"`
|
|
|
|
|
|
|
|
// Patterns, if set, indicates that the Match method should succeed if at
|
|
|
|
// least one of these doublestar patterns matches against the string.
|
|
|
|
Patterns []string `yaml:"patterns,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func doublestarMatch(pattern, str string) (bool, error) {
|
|
|
|
ok, err := doublestar.Match(pattern, str)
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("matching %q on pattern %q: %w",
|
|
|
|
str, pattern, err)
|
|
|
|
}
|
|
|
|
return ok, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Match operates similarly to the Match method of the FilterInterface, except
|
|
|
|
// it only takes in strings.
|
|
|
|
func (m StringMatcher) Match(str string) error {
|
|
|
|
switch {
|
|
|
|
case m.Pattern != "":
|
|
|
|
if ok, err := doublestarMatch(m.Pattern, str); err != nil {
|
|
|
|
return err
|
|
|
|
} else if !ok {
|
|
|
|
return ErrFilterNoMatch{
|
|
|
|
Err: fmt.Errorf("pattern %q does not match %q", m.Pattern, str),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
|
|
|
|
case len(m.Patterns) > 0:
|
|
|
|
for _, pattern := range m.Patterns {
|
|
|
|
if ok, err := doublestarMatch(pattern, str); err != nil {
|
|
|
|
return err
|
|
|
|
} else if ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ErrFilterNoMatch{
|
|
|
|
Err: fmt.Errorf("no patterns in %+v match %q", m.Patterns, str),
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return errors.New(`one of the following fields must be set: "pattern", "patterns"`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FilterBranch matches a CommitRequest's Branch field using a double-star
|
|
|
|
// pattern.
|
|
|
|
type FilterBranch struct {
|
|
|
|
StringMatcher StringMatcher `yaml:",inline"`
|
|
|
|
}
|
|
|
|
|
2020-04-26 20:23:03 +00:00
|
|
|
var _ Filter = FilterBranch{}
|
2020-03-18 22:35:32 +00:00
|
|
|
|
|
|
|
// MatchCommit implements the method for FilterInterface.
|
|
|
|
func (f FilterBranch) MatchCommit(req CommitRequest) error {
|
|
|
|
return f.StringMatcher.Match(req.Branch)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FilterFilesChanged matches a CommitRequest's FilesChanged field using a
|
|
|
|
// double-star pattern. It only matches if all of the CommitRequest's
|
|
|
|
// FilesChanged match.
|
|
|
|
type FilterFilesChanged struct {
|
|
|
|
StringMatcher StringMatcher `yaml:",inline"`
|
|
|
|
}
|
|
|
|
|
2020-04-26 20:23:03 +00:00
|
|
|
var _ Filter = FilterFilesChanged{}
|
2020-03-18 22:35:32 +00:00
|
|
|
|
|
|
|
// MatchCommit implements the method for FilterInterface.
|
|
|
|
func (f FilterFilesChanged) MatchCommit(req CommitRequest) error {
|
|
|
|
for _, path := range req.FilesChanged {
|
2020-05-10 00:00:00 +00:00
|
|
|
if err := f.StringMatcher.Match(path); errors.As(err, new(ErrFilterNoMatch)) {
|
|
|
|
continue
|
|
|
|
} else if err != nil {
|
2020-03-18 22:35:32 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-05-10 00:00:00 +00:00
|
|
|
return nil
|
2020-03-18 22:35:32 +00:00
|
|
|
}
|
2020-05-10 00:00:00 +00:00
|
|
|
|
|
|
|
return ErrFilterNoMatch{Err: errors.New("no paths matched")}
|
2020-03-18 22:35:32 +00:00
|
|
|
}
|