Skip to content

Commit

Permalink
Updated to array of paths
Browse files Browse the repository at this point in the history
Signed-off-by: Luke Massa <lukefrederickmassa@gmail.com>
  • Loading branch information
lukemassa committed Jan 20, 2025
1 parent e8c7bd1 commit 23f773f
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 61 deletions.
5 changes: 3 additions & 2 deletions runatlantis.io/docs/repo-level-atlantis-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,11 @@ it's still desirable for Atlantis to plan/apply for projects not enumerated in t
```yaml
autodiscover:
mode: "enabled"
ignore: /dir.*/
ignore_paths:
- /dir.*/
```

Autodiscover can be configured to skip over directories that match a regex.
Autodiscover can also be configured to skip over directories that match any of a list of regexes.

### Custom Backend Config

Expand Down
3 changes: 2 additions & 1 deletion runatlantis.io/docs/server-side-repo-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ repos:
autodiscover:
mode: auto
# Optionally ignore some paths for autodiscovery by regex
ignore: /foo.*/
ignore_paths:
- /foo.*/

# id can also be an exact match.
- id: github.com/myorg/specific-repo
Expand Down
43 changes: 25 additions & 18 deletions server/core/config/raw/autodiscover.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
var DefaultAutoDiscoverMode = valid.AutoDiscoverAutoMode

type AutoDiscover struct {
Mode *valid.AutoDiscoverMode `yaml:"mode,omitempty"`
Ignore *string `yaml:"ignore,omitempty"`
Mode *valid.AutoDiscoverMode `yaml:"mode,omitempty"`
IgnorePaths []string `yaml:"ignore_paths,omitempty"`
}

func (a AutoDiscover) ToValid() *valid.AutoDiscover {
Expand All @@ -25,11 +25,14 @@ func (a AutoDiscover) ToValid() *valid.AutoDiscover {
v.Mode = DefaultAutoDiscoverMode
}

if a.Ignore != nil {
ignore := *a.Ignore
withoutSlashes := ignore[1 : len(ignore)-1]
// Safe to use MustCompile because we test it in Validate().
v.Ignore = regexp.MustCompile(withoutSlashes)
var ignorePaths []*regexp.Regexp
if a.IgnorePaths != nil {
for _, ignore := range a.IgnorePaths {
withoutSlashes := ignore[1 : len(ignore)-1]
// Safe to use MustCompile because we test it in Validate().
ignorePaths = append(ignorePaths, regexp.MustCompile(withoutSlashes))
}
v.IgnorePaths = ignorePaths
}

return &v
Expand All @@ -38,30 +41,34 @@ func (a AutoDiscover) ToValid() *valid.AutoDiscover {
func (a AutoDiscover) Validate() error {

ignoreValid := func(value interface{}) error {
strPtr := value.(*string)
if strPtr == nil {
strSlice := value.([]string)
if strSlice == nil {
return nil
}
ignore := *strPtr
if !strings.HasPrefix(ignore, "/") || !strings.HasSuffix(ignore, "/") {
return errors.New("regex must begin and end with a slash '/'")
for _, ignore := range strSlice {
if !strings.HasPrefix(ignore, "/") || !strings.HasSuffix(ignore, "/") {
return errors.New("regex must begin and end with a slash '/'")
}
withoutSlashes := ignore[1 : len(ignore)-1]
_, err := regexp.Compile(withoutSlashes)
if err != nil {
return errors.Wrapf(err, "parsing: %s", ignore)
}
}
withoutSlashes := ignore[1 : len(ignore)-1]
_, err := regexp.Compile(withoutSlashes)
return errors.Wrapf(err, "parsing: %s", ignore)
return nil
}

res := validation.ValidateStruct(&a,
// If a.Mode is nil, this should still pass validation.
validation.Field(&a.Mode, validation.In(valid.AutoDiscoverAutoMode, valid.AutoDiscoverDisabledMode, valid.AutoDiscoverEnabledMode)),
validation.Field(&a.Ignore, validation.By(ignoreValid)),
validation.Field(&a.IgnorePaths, validation.By(ignoreValid)),
)
return res
}

func DefaultAutoDiscover() *valid.AutoDiscover {
return &valid.AutoDiscover{
Mode: DefaultAutoDiscoverMode,
Ignore: nil,
Mode: DefaultAutoDiscoverMode,
IgnorePaths: nil,
}
}
71 changes: 45 additions & 26 deletions server/core/config/raw/autodiscover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

func TestAutoDiscover_UnmarshalYAML(t *testing.T) {
autoDiscoverEnabled := valid.AutoDiscoverEnabledMode
ignoreString := "foobar"
cases := []struct {
description string
input string
Expand All @@ -21,19 +20,20 @@ func TestAutoDiscover_UnmarshalYAML(t *testing.T) {
description: "omit unset fields",
input: "",
exp: raw.AutoDiscover{
Mode: nil,
Ignore: nil,
Mode: nil,
IgnorePaths: nil,
},
},
{
description: "all fields set",
input: `
mode: enabled
ignore: foobar
ignore_paths:
- foobar
`,
exp: raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
Ignore: &ignoreString,
Mode: &autoDiscoverEnabled,
IgnorePaths: []string{"foobar"},
},
},
}
Expand All @@ -53,10 +53,6 @@ func TestAutoDiscover_Validate(t *testing.T) {
autoDiscoverEnabled := valid.AutoDiscoverEnabledMode
autoDiscoverDisabled := valid.AutoDiscoverDisabledMode
randomString := valid.AutoDiscoverMode("random_string")
regexWithoutSlahes := ".*"
invalidRegexString := "/***/"
validRegexString := "/.*/"
validRegexPath := `/some\/path\//`
cases := []struct {
description string
input raw.AutoDiscover
Expand Down Expand Up @@ -98,35 +94,54 @@ func TestAutoDiscover_Validate(t *testing.T) {
{
description: "ignore set to regex without slashes",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
Ignore: &regexWithoutSlahes,
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
".*",
},
},
errContains: String("regex must begin and end with a slash '/'"),
},
{
description: "ignore set to broken regex",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
Ignore: &invalidRegexString,
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"/***/",
},
},
errContains: String("error parsing regexp: missing argument to repetition operator: `*`"),
},
{
description: "ignore set to valid regex",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
Ignore: &validRegexString,
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"/.*/",
},
},
errContains: nil,
},
{
description: "ignore set to valid regex path",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
Ignore: &validRegexPath,
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
`/some\/path\//`,
},
},
errContains: nil,
},
{
description: "ignore set to one valid and one invalid regex",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"/foo/",
"foo",
},
},
errContains: String("regex must begin and end with a slash '/'"),
},
}
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
Expand All @@ -141,8 +156,6 @@ func TestAutoDiscover_Validate(t *testing.T) {

func TestAutoDiscover_ToValid(t *testing.T) {
autoDiscoverEnabled := valid.AutoDiscoverEnabledMode
ignoreString := ".*"
ignoreRegex := regexp.MustCompile(".*")
cases := []struct {
description string
input raw.AutoDiscover
Expand All @@ -152,19 +165,25 @@ func TestAutoDiscover_ToValid(t *testing.T) {
description: "nothing set",
input: raw.AutoDiscover{},
exp: &valid.AutoDiscover{
Mode: valid.AutoDiscoverAutoMode,
Ignore: nil,
Mode: valid.AutoDiscoverAutoMode,
IgnorePaths: nil,
},
},
{
description: "value set",
input: raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
Ignore: &ignoreString,
Mode: &autoDiscoverEnabled,
IgnorePaths: []string{
"/foo/",
"/bar.*/",
},
},
exp: &valid.AutoDiscover{
Mode: valid.AutoDiscoverEnabledMode,
Ignore: ignoreRegex,
Mode: valid.AutoDiscoverEnabledMode,
IgnorePaths: []*regexp.Regexp{
regexp.MustCompile("foo"),
regexp.MustCompile("bar.*"),
},
},
},
}
Expand Down
10 changes: 7 additions & 3 deletions server/core/config/raw/repo_cfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ version: 3
automerge: true
autodiscover:
mode: enabled
ignore: /foo.*/
ignore_paths:
- /foo.*/
parallel_apply: true
parallel_plan: false
repo_locks:
Expand Down Expand Up @@ -158,8 +159,11 @@ allowed_regexp_prefixes:
- dev/
- staging/`,
exp: raw.RepoCfg{
Version: Int(3),
AutoDiscover: &raw.AutoDiscover{Mode: &autoDiscoverEnabled},
Version: Int(3),
AutoDiscover: &raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
IgnorePaths: []string{"/foo.*/"},
},
Automerge: Bool(true),
ParallelApply: Bool(true),
ParallelPlan: Bool(false),
Expand Down
4 changes: 2 additions & 2 deletions server/core/config/valid/autodiscover.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ const (
)

type AutoDiscover struct {
Mode AutoDiscoverMode
Ignore *regexp.Regexp
Mode AutoDiscoverMode
IgnorePaths []*regexp.Regexp
}
9 changes: 7 additions & 2 deletions server/core/config/valid/repo_cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,15 @@ func (r RepoCfg) AutoDiscoverEnabled(defaultAutoDiscoverMode AutoDiscoverMode) b
}

func (r RepoCfg) IsPathIgnoredForAutoDiscover(path string) bool {
if r.AutoDiscover == nil || r.AutoDiscover.Ignore == nil {
if r.AutoDiscover == nil || r.AutoDiscover.IgnorePaths == nil {
return false
}
return r.AutoDiscover.Ignore.MatchString(path)
for i := 0; i < len(r.AutoDiscover.IgnorePaths); i++ {
if r.AutoDiscover.IgnorePaths[i].MatchString(path) {
return true
}
}
return false
}

// validateWorkspaceAllowed returns an error if repoCfg defines projects in
Expand Down
27 changes: 22 additions & 5 deletions server/core/config/valid/repo_cfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,12 @@ func TestConfig_IsPathIgnoredForAutoDiscover(t *testing.T) {
expIgnored: false,
},
{
description: "path does not match regex",
description: "paths do not match regex",
repoCfg: valid.RepoCfg{
AutoDiscover: &valid.AutoDiscover{
Ignore: regexp.MustCompile("bar"),
IgnorePaths: []*regexp.Regexp{
regexp.MustCompile("bar"),
},
},
},
path: "foo",
Expand All @@ -362,8 +364,21 @@ func TestConfig_IsPathIgnoredForAutoDiscover(t *testing.T) {
description: "path does match regex",
repoCfg: valid.RepoCfg{
AutoDiscover: &valid.AutoDiscover{
Ignore: regexp.MustCompile("fo.*"),
},
IgnorePaths: []*regexp.Regexp{
regexp.MustCompile("fo.*"),
}},
},
path: "foo",
expIgnored: true,
},
{
description: "one path matches regex, another doesn't",
repoCfg: valid.RepoCfg{
AutoDiscover: &valid.AutoDiscover{
IgnorePaths: []*regexp.Regexp{
regexp.MustCompile("fo.*"),
regexp.MustCompile("ba.*"),
}},
},
path: "foo",
expIgnored: true,
Expand All @@ -372,7 +387,9 @@ func TestConfig_IsPathIgnoredForAutoDiscover(t *testing.T) {
description: "long path does match regex",
repoCfg: valid.RepoCfg{
AutoDiscover: &valid.AutoDiscover{
Ignore: regexp.MustCompile(`foo\/.*\/baz`),
IgnorePaths: []*regexp.Regexp{
regexp.MustCompile(`foo\/.*\/baz`),
},
},
},
path: "foo/bar/baz",
Expand Down
6 changes: 4 additions & 2 deletions server/events/project_command_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,8 @@ projects:
AtlantisYAML: `version: 3
autodiscover:
mode: enabled
ignore: /project3/
ignore_paths:
- /project3/
projects:
- name: project1-custom-name
dir: project1`,
Expand Down Expand Up @@ -1128,7 +1129,8 @@ projects:
AtlantisYAML: `version: 3
autodiscover:
mode: enabled
ignore: /project1/
ignore_paths:
- /project1/
projects:
- name: project1-custom-name
dir: project1`,
Expand Down

0 comments on commit 23f773f

Please sign in to comment.