Skip to content

Commit

Permalink
Set default value for --autoplan-file-list and add terragrunt.hcl
Browse files Browse the repository at this point in the history
… to the list.
  • Loading branch information
Omicron7 committed Mar 31, 2021
1 parent ffd713d commit 91e0d48
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 82 deletions.
14 changes: 12 additions & 2 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"path/filepath"
"strings"

"github.com/docker/docker/pkg/fileutils"
homedir "github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server"
Expand Down Expand Up @@ -102,6 +103,7 @@ const (
// NOTE: Must manually set these as defaults in the setDefaults function.
DefaultADBasicUser = ""
DefaultADBasicPassword = ""
DefaultAutoplanFileList = "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl"
DefaultCheckoutStrategy = "branch"
DefaultBitbucketBaseURL = bitbucketcloud.BaseURL
DefaultDataDir = "~/.atlantis"
Expand Down Expand Up @@ -140,9 +142,9 @@ var stringFlags = map[string]stringFlag{
AutoplanFileListFlag: {
description: "Comma separated list of file patterns that Atlantis will use to check if a directory contains modified files that should trigger project planning." +
" Patterns use the dockerignore (https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax." +
" Use single quotes to avoid shell expansion of '*'. Defaults to '**/*.tf,**/*.tfvars,**/*.tfvars.json'." +
" Use single quotes to avoid shell expansion of '*'. Defaults to '" + DefaultAutoplanFileList + "'." +
" A custom Workflow that uses autoplan 'when_modified' will ignore this value.",
defaultValue: "",
defaultValue: DefaultAutoplanFileList,
},
BitbucketUserFlag: {
description: "Bitbucket username of API user.",
Expand Down Expand Up @@ -572,6 +574,9 @@ func (s *ServerCmd) run() error {
}

func (s *ServerCmd) setDefaults(c *server.UserConfig) {
if c.AutoplanFileList == "" {
c.AutoplanFileList = DefaultAutoplanFileList
}
if c.CheckoutStrategy == "" {
c.CheckoutStrategy = DefaultCheckoutStrategy
}
Expand Down Expand Up @@ -689,6 +694,11 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
return fmt.Errorf("if setting --%s, must set --%s", TFEHostnameFlag, TFETokenFlag)
}

_, patternErr := fileutils.NewPatternMatcher(strings.Split(userConfig.AutoplanFileList, ","))
if patternErr != nil {
return errors.Wrapf(patternErr, "invalid pattern in --%s, %s", AutoplanFileListFlag, userConfig.AutoplanFileList)
}

return nil
}

Expand Down
47 changes: 47 additions & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,53 @@ func TestExecute_RepoWhitelistDeprecation(t *testing.T) {
Equals(t, "*", passedConfig.RepoAllowlist)
}

func TestExecute_AutoplanFileList(t *testing.T) {
cases := []struct {
description string
flags map[string]interface{}
expectErr string
}{
{
"default value",
map[string]interface{}{
AutoplanFileListFlag: DefaultAutoplanFileList,
},
"",
},
{
"valid value",
map[string]interface{}{
AutoplanFileListFlag: "**/*.tf",
},
"",
},
{
"invalid exclusion pattern",
map[string]interface{}{
AutoplanFileListFlag: "**/*.yml,!",
},
"invalid pattern in --autoplan-file-list, **/*.yml,!: illegal exclusion pattern: \"!\"",
},
{
"invalid pattern",
map[string]interface{}{
AutoplanFileListFlag: "?[",
},
"invalid pattern in --autoplan-file-list, ?[: syntax error in pattern",
},
}
for _, testCase := range cases {
t.Log("Should validate autoplan file list when " + testCase.description)
c := setupWithDefaults(testCase.flags)
err := c.Execute()
if testCase.expectErr != "" {
ErrEquals(t, testCase.expectErr, err)
} else {
Ok(t, err)
}
}
}

func setup(flags map[string]interface{}) *cobra.Command {
vipr := viper.New()
for k, v := range flags {
Expand Down
3 changes: 2 additions & 1 deletion runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ Values are chosen in this order:
* Accepts a comma separated list, ex. `pattern1,pattern2`.
* Patterns use the [`.dockerignore` syntax](https://docs.docker.com/engine/reference/builder/#dockerignore-file)
* List of file patterns will be used by both automatic and manually run plans.
* When not set, defaults to all `.tf`, `.tfvars` and `.tfvars.json` files (`--autoplan-file-list='**/*.tf,**/*.tfvars,**/*.tfvars.json'`).
* When not set, defaults to all `.tf`, `.tfvars`, `.tfvars.json` and `terragrunt.hcl` files
(`--autoplan-file-list='**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl'`).
* Setting `--autoplan-file-list` will override the defaults. You **must** add `**/*.tf` and other defaults if you want to include them.
* A custom [Workflow](repo-level-atlantis-yaml.html#configuring-planning) that uses autoplan `when_modified` will ignore this value.

Expand Down
2 changes: 1 addition & 1 deletion server/events/project_command_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *CommandContext,
// If there is no config file, then we'll plan each project that
// our algorithm determines was modified.
ctx.Log.Info("found no %s file", yaml.AtlantisYAMLFilename)
modifiedProjects, err := p.ProjectFinder.DetermineProjects(ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir, p.AutoplanFileList)
modifiedProjects := p.ProjectFinder.DetermineProjects(ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir, p.AutoplanFileList)
if err != nil {
return nil, errors.Wrapf(err, "finding modified projects: %s", modifiedFiles)
}
Expand Down
6 changes: 3 additions & 3 deletions server/events/project_command_builder_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ projects:
&CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

// We run a test for each type of command.
Expand Down Expand Up @@ -775,7 +775,7 @@ projects:
&CommentParser{},
false,
true,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

// We run a test for each type of command, again specific projects
Expand Down Expand Up @@ -979,7 +979,7 @@ workflows:
&CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

cmd := models.PolicyCheckCommand
Expand Down
18 changes: 9 additions & 9 deletions server/events/project_command_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ projects:
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

ctxs, err := builder.BuildAutoplanCommands(&events.CommandContext{
Expand Down Expand Up @@ -373,7 +373,7 @@ projects:
&events.CommentParser{},
false,
true,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

var actCtxs []models.ProjectCommandContext
Expand Down Expand Up @@ -511,7 +511,7 @@ projects:
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

ctxs, err := builder.BuildPlanCommands(
Expand Down Expand Up @@ -587,7 +587,7 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) {
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

ctxs, err := builder.BuildApplyCommands(
Expand Down Expand Up @@ -658,7 +658,7 @@ projects:
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

ctx := &events.CommandContext{
Expand Down Expand Up @@ -724,7 +724,7 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) {
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

var actCtxs []models.ProjectCommandContext
Expand Down Expand Up @@ -892,7 +892,7 @@ projects:
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

actCtxs, err := builder.BuildPlanCommands(
Expand Down Expand Up @@ -944,7 +944,7 @@ projects:
&events.CommentParser{},
true,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

var actCtxs []models.ProjectCommandContext
Expand Down Expand Up @@ -986,7 +986,7 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman
&events.CommentParser{},
false,
false,
"",
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl",
)

ctxs, err := builder.BuildAutoplanCommands(&events.CommandContext{
Expand Down
26 changes: 10 additions & 16 deletions server/events/project_finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type ProjectFinder interface {
// DetermineProjects returns the list of projects that were modified based on
// the modifiedFiles. The list will be de-duplicated.
// absRepoDir is the path to the cloned repo on disk.
DetermineProjects(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string, absRepoDir string, autoplanFileList string) ([]models.Project, error)
DetermineProjects(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string, absRepoDir string, autoplanFileList string) []models.Project
// DetermineProjectsViaConfig returns the list of projects that were modified
// based on modifiedFiles and the repo's config.
// absRepoDir is the path to the cloned repo on disk.
Expand All @@ -47,16 +47,12 @@ var ignoredFilenameFragments = []string{"terraform.tfstate", "terraform.tfstate.
type DefaultProjectFinder struct{}

// See ProjectFinder.DetermineProjects.
func (p *DefaultProjectFinder) DetermineProjects(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string, absRepoDir string, autoplanFileList string) ([]models.Project, error) {
func (p *DefaultProjectFinder) DetermineProjects(log *logging.SimpleLogger, modifiedFiles []string, repoFullName string, absRepoDir string, autoplanFileList string) []models.Project {
var projects []models.Project

modifiedTerraformFiles, err := p.filterToFileList(log, modifiedFiles, autoplanFileList)
if err != nil {
return nil, errors.Wrapf(err, "filtering modified files by autoplanFileList: %s", autoplanFileList)
}

modifiedTerraformFiles := p.filterToFileList(log, modifiedFiles, autoplanFileList)
if len(modifiedTerraformFiles) == 0 {
return projects, nil
return projects
}
log.Info("filtered modified files to %d .tf or terragrunt.hcl files: %v",
len(modifiedTerraformFiles), modifiedTerraformFiles)
Expand All @@ -81,7 +77,7 @@ func (p *DefaultProjectFinder) DetermineProjects(log *logging.SimpleLogger, modi
}
log.Info("there are %d modified project(s) at path(s): %v",
len(projects), strings.Join(exists, ", "))
return projects, nil
return projects
}

// See ProjectFinder.DetermineProjectsViaConfig.
Expand Down Expand Up @@ -149,17 +145,15 @@ func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log *logging.SimpleLog
}

// filterToFileList filters out files not included in the file list
func (p *DefaultProjectFinder) filterToFileList(log *logging.SimpleLogger, files []string, fileList string) ([]string, error) {
func (p *DefaultProjectFinder) filterToFileList(log *logging.SimpleLogger, files []string, fileList string) []string {
var filtered []string
if fileList == "" {
fileList = "**/*.tf,**/*.tfvars,**/*.tfvars.json"
}

patterns := strings.Split(fileList, ",")
patternMatcher, err := fileutils.NewPatternMatcher(patterns)
if err != nil {
return nil, errors.Wrapf(err, "filtering modified files with patterns: %v", patterns)
}
// Ignore pattern matcher error here as it was checked for errors in server validation
patternMatcher, _ := fileutils.NewPatternMatcher(patterns)

for _, fileName := range files {
if p.shouldIgnore(fileName) {
Expand All @@ -170,12 +164,12 @@ func (p *DefaultProjectFinder) filterToFileList(log *logging.SimpleLogger, files
log.Debug("filter err for file %q: %s", fileName, err)
continue
}
if match || filepath.Base(fileName) == "terragrunt.hcl" {
if match {
filtered = append(filtered, fileName)
}
}

return filtered, nil
return filtered
}

// shouldIgnore returns true if we shouldn't trigger a plan on changes to this file.
Expand Down
Loading

0 comments on commit 91e0d48

Please sign in to comment.