Skip to content

Commit

Permalink
Add ignore path to autodiscover using glob
Browse files Browse the repository at this point in the history
  • Loading branch information
lukemassa committed Jan 23, 2025
1 parent 33be84b commit 6a408f3
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 10 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bmatcuk/doublestar/v4 v4.8.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.3.9 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/bmatcuk/doublestar/v4 v4.8.0 h1:DSXtrypQddoug1459viM9X9D3dp1Z7993fw36I2kNcQ=
github.com/bmatcuk/doublestar/v4 v4.8.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bradleyfalzon/ghinstallation/v2 v2.13.0 h1:5FhjW93/YLQJDmPdeyMPw7IjAPzqsr+0jHPfrPz0sZI=
github.com/bradleyfalzon/ghinstallation/v2 v2.13.0/go.mod h1:EJ6fgedVEHa2kUyBTTvslJCXJafS/mhJNNKEOCspZXQ=
github.com/briandowns/spinner v1.23.1 h1:t5fDPmScwUjozhDj4FA46p5acZWIPXYE30qW2Ptu650=
Expand Down
11 changes: 11 additions & 0 deletions runatlantis.io/docs/repo-level-atlantis-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ version: 3
automerge: true
autodiscover:
mode: auto
ignore_paths:
- some/path
delete_source_branch_on_merge: true
parallel_plan: true
parallel_apply: true
Expand Down Expand Up @@ -405,6 +407,15 @@ the manual configuration will take precedence.
Use this feature when some projects require specific configuration in a repo with many projects yet
it's still desirable for Atlantis to plan/apply for projects not enumerated in the config.

```yaml
autodiscover:
mode: "enabled"
ignore_paths:
- dir/*
```

Autodiscover can also be configured to skip over directories that match a path glob (as defined [here](https://pkg.go.dev/github.com/bmatcuk/doublestar/v4))

### Custom Backend Config

See [Custom Workflow Use Cases: Custom Backend Config](custom-workflows.md#custom-backend-config)
Expand Down
3 changes: 3 additions & 0 deletions runatlantis.io/docs/server-side-repo-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ repos:
# autodiscover defines how atlantis should automatically discover projects in this repository.
autodiscover:
mode: auto
# Optionally ignore some paths for autodiscovery by a glob path
ignore_paths:
- foo/*

# id can also be an exact match.
- id: github.com/myorg/specific-repo
Expand Down
35 changes: 33 additions & 2 deletions server/core/config/raw/autodiscover.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package raw

import (
"fmt"
"strings"

"github.com/bmatcuk/doublestar/v4"
validation "github.com/go-ozzo/ozzo-validation"
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/core/config/valid"
)

var DefaultAutoDiscoverMode = valid.AutoDiscoverAutoMode

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

func (a AutoDiscover) ToValid() *valid.AutoDiscover {
Expand All @@ -20,19 +26,44 @@ func (a AutoDiscover) ToValid() *valid.AutoDiscover {
v.Mode = DefaultAutoDiscoverMode
}

v.IgnorePaths = a.IgnorePaths

return &v
}

func (a AutoDiscover) Validate() error {

ignoreValid := func(value interface{}) error {
strSlice := value.([]string)
if strSlice == nil {
return nil
}
for _, ignore := range strSlice {
// A beginning slash isn't necessary since they are specifying a relative path, not an absolute one.
// Rejecting `/...` also allows us to potentially use `/.*/` as regexes in the future
if strings.HasPrefix(ignore, "/") {
return errors.New("pattern must not begin with a slash '/'")
}

if !doublestar.ValidatePattern(ignore) {
return fmt.Errorf("invalid pattern: %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.IgnorePaths, validation.By(ignoreValid)),
)
return res
}

func DefaultAutoDiscover() *valid.AutoDiscover {
return &valid.AutoDiscover{
Mode: DefaultAutoDiscoverMode,
Mode: DefaultAutoDiscoverMode,
IgnorePaths: nil,
}
}
80 changes: 77 additions & 3 deletions server/core/config/raw/autodiscover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ func TestAutoDiscover_UnmarshalYAML(t *testing.T) {
description: "omit unset fields",
input: "",
exp: raw.AutoDiscover{
Mode: nil,
Mode: nil,
IgnorePaths: nil,
},
},
{
description: "all fields set",
input: `
mode: enabled
ignore_paths:
- foobar
`,
exp: raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
Mode: &autoDiscoverEnabled,
IgnorePaths: []string{"foobar"},
},
},
}
Expand Down Expand Up @@ -86,6 +90,67 @@ func TestAutoDiscover_Validate(t *testing.T) {
},
errContains: String("valid value"),
},
{
description: "ignore set with leading slash",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"/foo",
},
},
errContains: String("pattern must not begin with a slash '/'"),
},
{
description: `ignore set to broken pattern \`,
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
`\`,
},
},
errContains: String(`invalid pattern: \`),
},
{
description: "ignore set to broken pattern [-]",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"[",
},
},
errContains: String("invalid pattern: ["),
},
{
description: "ignore set to valid pattern",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"foo*",
},
},
errContains: nil,
},
{
description: "ignore set to long pattern",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"foo/**/bar/baz/??",
},
},
errContains: nil,
},
{
description: "ignore set to one valid and one invalid pattern",
input: raw.AutoDiscover{
Mode: &autoDiscoverAuto,
IgnorePaths: []string{
"/foo",
"foo",
},
},
errContains: String("pattern must not begin with a slash '/'"),
},
}
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
Expand All @@ -109,16 +174,25 @@ func TestAutoDiscover_ToValid(t *testing.T) {
description: "nothing set",
input: raw.AutoDiscover{},
exp: &valid.AutoDiscover{
Mode: valid.AutoDiscoverAutoMode,
Mode: valid.AutoDiscoverAutoMode,
IgnorePaths: nil,
},
},
{
description: "value set",
input: raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
IgnorePaths: []string{
"foo",
"bar/*",
},
},
exp: &valid.AutoDiscover{
Mode: valid.AutoDiscoverEnabledMode,
IgnorePaths: []string{
"foo",
"bar/*",
},
},
},
}
Expand Down
9 changes: 7 additions & 2 deletions server/core/config/raw/repo_cfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ version: 3
automerge: true
autodiscover:
mode: enabled
ignore_paths:
- foo/*
parallel_apply: true
parallel_plan: false
repo_locks:
Expand Down Expand Up @@ -157,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
3 changes: 2 additions & 1 deletion server/core/config/valid/autodiscover.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ const (
)

type AutoDiscover struct {
Mode AutoDiscoverMode
Mode AutoDiscoverMode
IgnorePaths []string
}
21 changes: 21 additions & 0 deletions server/core/config/valid/repo_cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"regexp"
"strings"

"github.com/bmatcuk/doublestar/v4"
version "github.com/hashicorp/go-version"
"github.com/pkg/errors"
)

// RepoCfg is the atlantis.yaml config after it's been parsed and validated.
Expand Down Expand Up @@ -111,6 +113,25 @@ func (r RepoCfg) AutoDiscoverEnabled(defaultAutoDiscoverMode AutoDiscoverMode) b
return autoDiscoverMode == AutoDiscoverEnabledMode
}

func (r RepoCfg) IsPathIgnoredForAutoDiscover(path string) (bool, error) {
if r.AutoDiscover == nil || r.AutoDiscover.IgnorePaths == nil {
return false, nil
}
for i := 0; i < len(r.AutoDiscover.IgnorePaths); i++ {
matches, err := doublestar.Match(r.AutoDiscover.IgnorePaths[i], path)
if err != nil {
// Per documentation https://pkg.go.dev/github.com/bmatcuk/doublestar, this only
// occurs if the pattern itself is invalid, and we already checked this when
// parsing raw config
return false, errors.Wrap(err, "unexpectedly found invalid ignore pattern (this is a bug, should have been validated at startup)")
}
if matches {
return true, nil
}
}
return false, nil
}

// validateWorkspaceAllowed returns an error if repoCfg defines projects in
// repoRelDir but none of them use workspace. We want this to be an error
// because if users have gone to the trouble of defining projects in repoRelDir
Expand Down
Loading

0 comments on commit 6a408f3

Please sign in to comment.