From 1b9ca74f82c14ff9c63c5935730a6405dafd2af7 Mon Sep 17 00:00:00 2001 From: Marcelo Medeiros Date: Fri, 13 Oct 2023 13:04:56 +0200 Subject: [PATCH 1/8] add flag to allow the user disable the autodiscover --- .../events/events_controller_e2e_test.go | 1 + server/core/config/parser_validator_test.go | 63 ++++- server/core/config/raw/autodiscover.go | 32 +++ server/core/config/raw/autodiscover_test.go | 115 +++++++++ server/core/config/raw/repo_cfg.go | 11 + server/core/config/raw/repo_cfg_test.go | 46 +++- server/core/config/valid/repo_cfg.go | 6 + server/core/config/valid/valid.go | 1 + server/events/command/project_context.go | 3 + server/events/project_command_builder.go | 45 +++- .../project_command_builder_internal_test.go | 219 ++++++++++-------- server/events/project_command_builder_test.go | 72 +++++- .../events/project_command_context_builder.go | 18 +- .../project_command_context_builder_test.go | 8 +- server/server.go | 1 + server/user_config.go | 68 +++--- 16 files changed, 542 insertions(+), 167 deletions(-) create mode 100644 server/core/config/raw/autodiscover.go create mode 100644 server/core/config/raw/autodiscover_test.go diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go index 93c63df3bd..d585a6ac71 100644 --- a/server/controllers/events/events_controller_e2e_test.go +++ b/server/controllers/events/events_controller_e2e_test.go @@ -1319,6 +1319,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers false, false, false, + valid.Autodiscover{Enabled: true}, false, false, "", diff --git a/server/core/config/parser_validator_test.go b/server/core/config/parser_validator_test.go index 53caf9e539..afb5b83831 100644 --- a/server/core/config/parser_validator_test.go +++ b/server/core/config/parser_validator_test.go @@ -180,6 +180,7 @@ workflows: StateRm: valid.DefaultStateRmStage, }, }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, @@ -190,9 +191,10 @@ workflows: version: 3 projects:`, exp: valid.RepoCfg{ - Version: 3, - Projects: nil, - Workflows: map[string]valid.Workflow{}, + Version: 3, + Projects: nil, + Workflows: map[string]valid.Workflow{}, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -224,7 +226,8 @@ projects: ApplyRequirements: nil, }, }, - Workflows: map[string]valid.Workflow{}, + Workflows: map[string]valid.Workflow{}, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -246,7 +249,8 @@ projects: }, }, }, - Workflows: make(map[string]valid.Workflow), + Workflows: make(map[string]valid.Workflow), + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -270,7 +274,32 @@ projects: }, }, }, - Workflows: make(map[string]valid.Workflow), + Workflows: make(map[string]valid.Workflow), + Autodiscover: &valid.Autodiscover{Enabled: true}, + }, + }, + { + description: "autodiscover should be enabled by default", + input: ` +version: 3 +`, + exp: valid.RepoCfg{ + Version: 3, + Autodiscover: &valid.Autodiscover{Enabled: true}, + Workflows: make(map[string]valid.Workflow), + }, + }, + { + description: "disable autodiscover", + input: ` +version: 3 +autodiscover: + enabled: false +`, + exp: valid.RepoCfg{ + Version: 3, + Autodiscover: &valid.Autodiscover{Enabled: false}, + Workflows: make(map[string]valid.Workflow), }, }, { @@ -292,7 +321,8 @@ projects: }, }, }, - Workflows: make(map[string]valid.Workflow), + Workflows: make(map[string]valid.Workflow), + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -315,7 +345,8 @@ workflows: ~ }, }, }, - Workflows: make(map[string]valid.Workflow), + Workflows: make(map[string]valid.Workflow), + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -346,6 +377,7 @@ workflows: Workflows: map[string]valid.Workflow{ "default": defaultWorkflow("default"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -378,6 +410,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -412,6 +445,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -446,6 +480,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -480,6 +515,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -514,6 +550,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -548,6 +585,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -582,6 +620,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -616,6 +655,7 @@ workflows: Workflows: map[string]valid.Workflow{ "myworkflow": defaultWorkflow("myworkflow"), }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -731,7 +771,8 @@ projects: }, }, }, - Workflows: map[string]valid.Workflow{}, + Workflows: map[string]valid.Workflow{}, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -822,6 +863,7 @@ workflows: }, }, }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -925,6 +967,7 @@ workflows: }, }, }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -1008,6 +1051,7 @@ workflows: }, }, }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -1106,6 +1150,7 @@ workflows: }, }, }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, } diff --git a/server/core/config/raw/autodiscover.go b/server/core/config/raw/autodiscover.go new file mode 100644 index 0000000000..03f08ba15d --- /dev/null +++ b/server/core/config/raw/autodiscover.go @@ -0,0 +1,32 @@ +package raw + +import ( + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +type Autodiscover struct { + Enabled *bool `yaml:"enabled,omitempty"` +} + +func (a Autodiscover) ToValid() valid.Autodiscover { + var v valid.Autodiscover + + if a.Enabled == nil { + v.Enabled = true + } else { + v.Enabled = *a.Enabled + } + + return v +} + +func (a Autodiscover) Validate() error { + return nil +} + +// DefaultAutoDiscover returns the default autodiscover config. +func DefaultAutoDiscover() valid.Autodiscover { + return valid.Autodiscover{ + Enabled: valid.DefaultAutoDiscoverEnabled, + } +} diff --git a/server/core/config/raw/autodiscover_test.go b/server/core/config/raw/autodiscover_test.go new file mode 100644 index 0000000000..1805065798 --- /dev/null +++ b/server/core/config/raw/autodiscover_test.go @@ -0,0 +1,115 @@ +package raw_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" + yaml "gopkg.in/yaml.v2" +) + +func TestAutoDiscover_UnmarshalYAML(t *testing.T) { + cases := []struct { + description string + input string + exp raw.Autodiscover + }{ + { + description: "omit unset fields", + input: "", + exp: raw.Autodiscover{ + Enabled: nil, + }, + }, + { + description: "enabled true", + input: ` +enabled: true +`, + exp: raw.Autodiscover{ + Enabled: Bool(true), + }, + }, + { + description: "enabled false", + input: ` +enabled: false +`, + exp: raw.Autodiscover{ + Enabled: Bool(false), + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var a raw.Autodiscover + err := yaml.UnmarshalStrict([]byte(c.input), &a) + Ok(t, err) + Equals(t, c.exp, a) + }) + } +} + +func TestAutodiscover_Validate(t *testing.T) { + cases := []struct { + description string + input raw.Autodiscover + }{ + { + description: "nothing set", + input: raw.Autodiscover{}, + }, + { + description: "enabled false", + input: raw.Autodiscover{ + Enabled: Bool(false), + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Ok(t, c.input.Validate()) + }) + } +} + +func TestAutodiscover_ToValid(t *testing.T) { + cases := []struct { + description string + input raw.Autodiscover + exp valid.Autodiscover + }{ + { + description: "nothing set", + input: raw.Autodiscover{}, + exp: valid.Autodiscover{ + Enabled: true, + }, + }, + { + description: "enabled false", + input: raw.Autodiscover{ + Enabled: Bool(false), + }, + exp: valid.Autodiscover{ + Enabled: false, + }, + }, + { + description: "enabled true", + input: raw.Autodiscover{ + Enabled: Bool(true), + }, + exp: valid.Autodiscover{ + Enabled: true, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/core/config/raw/repo_cfg.go b/server/core/config/raw/repo_cfg.go index eb511b04aa..021575c43f 100644 --- a/server/core/config/raw/repo_cfg.go +++ b/server/core/config/raw/repo_cfg.go @@ -20,6 +20,7 @@ type RepoCfg struct { Workflows map[string]Workflow `yaml:"workflows,omitempty"` PolicySets PolicySets `yaml:"policies,omitempty"` Automerge *bool `yaml:"automerge,omitempty"` + Autodiscover *Autodiscover `yaml:"autodiscover,omitempty"` ParallelApply *bool `yaml:"parallel_apply,omitempty"` ParallelPlan *bool `yaml:"parallel_plan,omitempty"` DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty"` @@ -57,6 +58,15 @@ func (r RepoCfg) ToValid() valid.RepoCfg { validProjects = append(validProjects, p.ToValid()) } + var autodiscover *valid.Autodiscover + if r.Autodiscover == nil { + defaultAutoDiscover := DefaultAutoDiscover() + autodiscover = &defaultAutoDiscover + } else { + validAutoDiscover := r.Autodiscover.ToValid() + autodiscover = &validAutoDiscover + } + automerge := r.Automerge parallelApply := r.ParallelApply parallelPlan := r.ParallelPlan @@ -76,6 +86,7 @@ func (r RepoCfg) ToValid() valid.RepoCfg { Projects: validProjects, Workflows: validWorkflows, Automerge: automerge, + Autodiscover: autodiscover, ParallelApply: parallelApply, ParallelPlan: parallelPlan, ParallelPolicyCheck: parallelPlan, diff --git a/server/core/config/raw/repo_cfg_test.go b/server/core/config/raw/repo_cfg_test.go index 7b11655c13..783fe155b0 100644 --- a/server/core/config/raw/repo_cfg_test.go +++ b/server/core/config/raw/repo_cfg_test.go @@ -126,6 +126,8 @@ func TestConfig_UnmarshalYAML(t *testing.T) { input: ` version: 3 automerge: true +autodiscover: + enabled: true parallel_apply: true parallel_plan: false projects: @@ -149,8 +151,11 @@ allowed_regexp_prefixes: - dev/ - staging/`, exp: raw.RepoCfg{ - Version: Int(3), - Automerge: Bool(true), + Version: Int(3), + Automerge: Bool(true), + Autodiscover: &raw.Autodiscover{ + Enabled: Bool(true), + }, ParallelApply: Bool(true), ParallelPlan: Bool(false), Projects: []raw.Project{ @@ -241,21 +246,24 @@ func TestConfig_ToValid(t *testing.T) { description: "nothing set", input: raw.RepoCfg{Version: Int(2)}, exp: valid.RepoCfg{ - Version: 2, - Workflows: make(map[string]valid.Workflow), + Version: 2, + Workflows: make(map[string]valid.Workflow), + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { description: "set to empty", input: raw.RepoCfg{ - Version: Int(2), - Workflows: map[string]raw.Workflow{}, - Projects: []raw.Project{}, + Version: Int(2), + Workflows: map[string]raw.Workflow{}, + Projects: []raw.Project{}, + Autodiscover: &raw.Autodiscover{Enabled: Bool(true)}, }, exp: valid.RepoCfg{ - Version: 2, - Workflows: map[string]valid.Workflow{}, - Projects: nil, + Version: 2, + Workflows: map[string]valid.Workflow{}, + Projects: nil, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -269,6 +277,7 @@ func TestConfig_ToValid(t *testing.T) { ParallelApply: nil, AbortOnExcecutionOrderFail: false, Workflows: map[string]valid.Workflow{}, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -285,6 +294,7 @@ func TestConfig_ToValid(t *testing.T) { ParallelApply: Bool(true), AbortOnExcecutionOrderFail: true, Workflows: map[string]valid.Workflow{}, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -301,6 +311,19 @@ func TestConfig_ToValid(t *testing.T) { ParallelApply: Bool(false), AbortOnExcecutionOrderFail: false, Workflows: map[string]valid.Workflow{}, + Autodiscover: &valid.Autodiscover{Enabled: true}, + }, + }, + { + description: "autodiscover false", + input: raw.RepoCfg{ + Version: Int(2), + Autodiscover: &raw.Autodiscover{Enabled: Bool(false)}, + }, + exp: valid.RepoCfg{ + Version: 2, + Autodiscover: &valid.Autodiscover{Enabled: false}, + Workflows: map[string]valid.Workflow{}, }, }, { @@ -331,6 +354,7 @@ func TestConfig_ToValid(t *testing.T) { StateRm: valid.DefaultStateRmStage, }, }, + Autodiscover: &valid.Autodiscover{Enabled: true}, }, }, { @@ -338,6 +362,7 @@ func TestConfig_ToValid(t *testing.T) { input: raw.RepoCfg{ Version: Int(2), Automerge: Bool(true), + Autodiscover: &raw.Autodiscover{Enabled: Bool(true)}, ParallelApply: Bool(true), Workflows: map[string]raw.Workflow{ "myworkflow": { @@ -387,6 +412,7 @@ func TestConfig_ToValid(t *testing.T) { exp: valid.RepoCfg{ Version: 2, Automerge: Bool(true), + Autodiscover: &valid.Autodiscover{Enabled: true}, ParallelApply: Bool(true), Workflows: map[string]valid.Workflow{ "myworkflow": { diff --git a/server/core/config/valid/repo_cfg.go b/server/core/config/valid/repo_cfg.go index fe441f4d05..e2fdf5c04c 100644 --- a/server/core/config/valid/repo_cfg.go +++ b/server/core/config/valid/repo_cfg.go @@ -19,6 +19,7 @@ type RepoCfg struct { Workflows map[string]Workflow PolicySets PolicySets Automerge *bool + Autodiscover *Autodiscover ParallelApply *bool ParallelPlan *bool ParallelPolicyCheck *bool @@ -129,6 +130,7 @@ type Project struct { WorkflowName *string TerraformVersion *version.Version Autoplan Autoplan + Autodiscover Autodiscover PlanRequirements []string ApplyRequirements []string ImportRequirements []string @@ -148,6 +150,10 @@ func (p Project) GetName() string { return "" } +type Autodiscover struct { + Enabled bool +} + type Autoplan struct { WhenModified []string Enabled bool diff --git a/server/core/config/valid/valid.go b/server/core/config/valid/valid.go index 7fa35827a0..c638451f19 100644 --- a/server/core/config/valid/valid.go +++ b/server/core/config/valid/valid.go @@ -3,3 +3,4 @@ package valid const DefaultAutoPlanEnabled = true +const DefaultAutoDiscoverEnabled = true diff --git a/server/events/command/project_context.go b/server/events/command/project_context.go index 1e2521e38c..c75fa19d3e 100644 --- a/server/events/command/project_context.go +++ b/server/events/command/project_context.go @@ -38,6 +38,9 @@ type ProjectContext struct { // AutomergeEnabled is true if automerge is enabled for the repo that this // project is in. AutomergeEnabled bool + //AutodiscoverEnabled is true if autodiscover is enabled for the repo that this + // project is in. + AutodiscoverEnabled valid.Autodiscover // ParallelApplyEnabled is true if parallel apply is enabled for this project. ParallelApplyEnabled bool // ParallelPlanEnabled is true if parallel plan is enabled for this project. diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index 2347c9072a..34d88ec528 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -28,6 +28,14 @@ const ( // DefaultWorkspace is the default Terraform workspace we run commands in. // This is also Terraform's default workspace. DefaultWorkspace = "default" + // DefaultAutomergeEnabled is the default for the automerge setting. + DefaultAutomergeEnabled = false + // DefaultAutoDiscoverEnabled is the default for the auto discover setting. + DefaultAutoDiscoverEnabled = true + // DefaultParallelApplyEnabled is the default for the parallel apply setting. + DefaultParallelApplyEnabled = false + // DefaultParallelPlanEnabled is the default for the parallel plan setting. + DefaultParallelPlanEnabled = false // DefaultDeleteSourceBranchOnMerge being false is the default setting whether or not to remove a source branch on merge DefaultDeleteSourceBranchOnMerge = false // DefaultAbortOnExcecutionOrderFail being false is the default setting for abort on execution group failiures @@ -47,6 +55,7 @@ func NewInstrumentedProjectCommandBuilder( skipCloneNoChanges bool, EnableRegExpCmd bool, EnableAutoMerge bool, + EnableAutoDiscover valid.Autodiscover, EnableParallelPlan bool, EnableParallelApply bool, AutoDetectModuleFiles string, @@ -78,6 +87,7 @@ func NewInstrumentedProjectCommandBuilder( skipCloneNoChanges, EnableRegExpCmd, EnableAutoMerge, + EnableAutoDiscover, EnableParallelPlan, EnableParallelApply, AutoDetectModuleFiles, @@ -107,6 +117,7 @@ func NewProjectCommandBuilder( skipCloneNoChanges bool, EnableRegExpCmd bool, EnableAutoMerge bool, + EnableAutoDiscover valid.Autodiscover, EnableParallelPlan bool, EnableParallelApply bool, AutoDetectModuleFiles string, @@ -129,6 +140,7 @@ func NewProjectCommandBuilder( SkipCloneNoChanges: skipCloneNoChanges, EnableRegExpCmd: EnableRegExpCmd, EnableAutoMerge: EnableAutoMerge, + EnableAutoDiscover: EnableAutoDiscover, EnableParallelPlan: EnableParallelPlan, EnableParallelApply: EnableParallelApply, AutoDetectModuleFiles: AutoDetectModuleFiles, @@ -226,6 +238,8 @@ type DefaultProjectCommandBuilder struct { EnableRegExpCmd bool // User config option: Automatically merge pull requests after all plans have been successfully applied. EnableAutoMerge bool + // User config option: Enables auto-discovery of projects in a repository. + EnableAutoDiscover valid.Autodiscover // User config option: Whether to run plan operations in parallel. EnableParallelPlan bool // User config option: Whether to run apply operations in parallel. @@ -360,7 +374,11 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex return []command.ProjectContext{}, nil } } else { - ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", repoCfgFile) + if !repoCfg.Autodiscover.Enabled { + ctx.Log.Info("No projects are defined in %s. Auto discovery is disabled. Will skip automatic detection", repoCfgFile) + return []command.ProjectContext{}, nil + } + ctx.Log.Info("No projects are defined in %s. Auto discovery is enabled, will resume automatic detection", repoCfgFile) } // NOTE: We discard this work here and end up doing it again after // cloning to ensure all the return values are set properly with @@ -411,6 +429,7 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex ctx.Log.Debug("moduleInfo for %s (matching %q) = %v", repoDir, p.AutoDetectModuleFiles, moduleInfo) automerge := p.EnableAutoMerge + autodiscover := p.EnableAutoDiscover parallelApply := p.EnableParallelApply parallelPlan := p.EnableParallelPlan abortOnExcecutionOrderFail := DefaultAbortOnExcecutionOrderFail @@ -418,6 +437,11 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex if repoCfg.Automerge != nil { automerge = *repoCfg.Automerge } + if repoCfg.Autodiscover != nil { + autodiscover = *repoCfg.Autodiscover + } else { + autodiscover = valid.Autodiscover{Enabled: DefaultAutoDiscoverEnabled} + } if repoCfg.ParallelApply != nil { parallelApply = *repoCfg.ParallelApply } @@ -447,10 +471,11 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex commentFlags, repoDir, automerge, + autodiscover, parallelApply, parallelPlan, verbose, - repoCfg.AbortOnExcecutionOrderFail, + abortOnExcecutionOrderFail, p.TerraformExecutor, )...) } @@ -458,7 +483,11 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex // If there is no config file or it specified no projects, then we'll plan each project that // our algorithm determines was modified. if hasRepoCfg { - ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", repoCfgFile) + if !repoCfg.Autodiscover.Enabled { + ctx.Log.Info("No projects are defined in %s. Auto discovery is disabled. Will skip automatic detection", repoCfgFile) + return []command.ProjectContext{}, nil + } + ctx.Log.Info("No projects are defined in %s. Auto discovery is enabled, will resume automatic detection", repoCfgFile) } else { ctx.Log.Info("found no %s file", repoCfgFile) } @@ -483,6 +512,7 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex commentFlags, repoDir, automerge, + autodiscover, parallelApply, parallelPlan, verbose, @@ -772,7 +802,9 @@ func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *command.Conte } var projCtxs []command.ProjectContext var projCfg valid.MergedProjectCfg + automerge := p.EnableAutoMerge + autodiscover := p.EnableAutoDiscover parallelApply := p.EnableParallelApply parallelPlan := p.EnableParallelPlan abortOnExcecutionOrderFail := DefaultAbortOnExcecutionOrderFail @@ -780,6 +812,11 @@ func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *command.Conte if repoCfgPtr.Automerge != nil { automerge = *repoCfgPtr.Automerge } + if repoCfgPtr.Autodiscover != nil { + autodiscover = *repoCfgPtr.Autodiscover + } else { + autodiscover = valid.Autodiscover{Enabled: true} + } if repoCfgPtr.ParallelApply != nil { parallelApply = *repoCfgPtr.ParallelApply } @@ -808,6 +845,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *command.Conte commentFlags, repoDir, automerge, + autodiscover, parallelApply, parallelPlan, verbose, @@ -832,6 +870,7 @@ func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *command.Conte commentFlags, repoDir, automerge, + autodiscover, parallelApply, parallelPlan, verbose, diff --git a/server/events/project_command_builder_internal_test.go b/server/events/project_command_builder_internal_test.go index e8804c5142..18ee0f9890 100644 --- a/server/events/project_command_builder_internal_test.go +++ b/server/events/project_command_builder_internal_test.go @@ -61,15 +61,16 @@ workflows: - apply`, repoCfg: "", expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: false, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: false, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -118,15 +119,16 @@ projects: terraform_version: v10.0 `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -179,15 +181,16 @@ projects: terraform_version: v10.0 `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -248,15 +251,16 @@ projects: terraform_version: v10.0 `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -384,6 +388,8 @@ workflows: repoCfg: ` version: 3 automerge: true +autodiscover: + enabled: true projects: - dir: project1 workspace: myworkspace @@ -404,15 +410,16 @@ workflows: - apply `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -467,15 +474,16 @@ projects: workflow: custom `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -517,6 +525,8 @@ workflows: repoCfg: ` version: 3 automerge: true +autodiscover: + enabled: true projects: - dir: project1 workspace: myworkspace @@ -533,15 +543,16 @@ workflows: steps: [] `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -585,15 +596,16 @@ projects: workspace: myworkspace `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: false, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: false, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -666,6 +678,7 @@ projects: false, false, false, + valid.Autodiscover{Enabled: true}, false, false, "", @@ -802,15 +815,16 @@ projects: terraform_version: v10.0 `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -p myproject_1", - ApprovePoliciesCmd: "atlantis approve_policies -p myproject_1", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logging.NewNoopLogger(t), - Scope: statsScope, + ApplyCmd: "atlantis apply -p myproject_1", + ApprovePoliciesCmd: "atlantis approve_policies -p myproject_1", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logging.NewNoopLogger(t), + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -881,6 +895,7 @@ projects: false, true, false, + valid.Autodiscover{Enabled: true}, false, false, "", @@ -983,15 +998,16 @@ repos: `, repoCfg: "", expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: false, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: false, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -1029,6 +1045,8 @@ workflows: repoCfg: ` version: 3 automerge: true +autodiscover: + enabled: true projects: - dir: project1 workspace: myworkspace @@ -1045,15 +1063,16 @@ workflows: - policy_check `, expCtx: command.ProjectContext{ - ApplyCmd: "atlantis apply -d project1 -w myworkspace", - ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", - BaseRepo: baseRepo, - EscapedCommentArgs: []string{`\f\l\a\g`}, - AutomergeEnabled: true, - AutoplanEnabled: true, - HeadRepo: models.Repo{}, - Log: logger, - Scope: statsScope, + ApplyCmd: "atlantis apply -d project1 -w myworkspace", + ApprovePoliciesCmd: "atlantis approve_policies -d project1 -w myworkspace", + BaseRepo: baseRepo, + EscapedCommentArgs: []string{`\f\l\a\g`}, + AutomergeEnabled: true, + AutodiscoverEnabled: valid.Autodiscover{Enabled: true}, + AutoplanEnabled: true, + HeadRepo: models.Repo{}, + Log: logger, + Scope: statsScope, PullReqStatus: models.PullReqStatus{ Mergeable: true, }, @@ -1130,6 +1149,7 @@ workflows: false, false, false, + valid.Autodiscover{Enabled: true}, false, false, "", @@ -1286,6 +1306,7 @@ projects: false, false, false, + valid.Autodiscover{Enabled: true}, false, false, "", diff --git a/server/events/project_command_builder_test.go b/server/events/project_command_builder_test.go index 6a3e73798d..57d519a8b4 100644 --- a/server/events/project_command_builder_test.go +++ b/server/events/project_command_builder_test.go @@ -26,6 +26,7 @@ var defaultUserConfig = struct { SkipCloneNoChanges bool EnableRegExpCmd bool EnableAutoMerge bool + EnableAutoDiscover valid.Autodiscover EnableParallelPlan bool EnableParallelApply bool AutoDetectModuleFiles string @@ -187,6 +188,7 @@ projects: userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -232,6 +234,7 @@ func TestDefaultProjectCommandBuilder_BuildSinglePlanApplyCommand(t *testing.T) ExpErr string ExpApplyReqs []string EnableAutoMergeUserCfg bool + EnableAutoDiscoverUserCfg valid.Autodiscover EnableParallelPlanUserCfg bool EnableParallelApplyUserCfg bool ExpAutoMerge bool @@ -543,6 +546,7 @@ projects: userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, c.EnableAutoMergeUserCfg, + c.EnableAutoDiscoverUserCfg, c.EnableParallelPlanUserCfg, c.EnableParallelApplyUserCfg, userConfig.AutoDetectModuleFiles, @@ -732,6 +736,7 @@ projects: userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -770,6 +775,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands(t *testing.T) { RepoRelDir string Workspace string Automerge bool + Autodiscover valid.Autodiscover ExpParallelPlan bool ExpParallelApply bool } @@ -913,6 +919,60 @@ parallel_apply: false }, }, }, + "no projects and autodiscover is true in atlantis.yaml": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: ` +version: 3 +automerge: true +autodiscover: + enabled: true +parallel_plan: true +parallel_apply: true +`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: true, + Autodiscover: valid.Autodiscover{Enabled: true}, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: true, + Autodiscover: valid.Autodiscover{Enabled: true}, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + }, + }, + "no projects and the autodiscover is false atlantis.yaml": { + DirStructure: map[string]interface{}{ + "main.tf": nil, + }, + AtlantisYAML: ` +version: 3 +automerge: true +autodiscover: + enabled: false +parallel_plan: true +parallel_apply: true +`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{}, + }, "no modified files": { DirStructure: map[string]interface{}{ "main.tf": nil, @@ -1000,6 +1060,7 @@ projects: userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, c.ParallelPlanEnabledUserCfg, c.ParallelApplyEnabledUserCfg, userConfig.AutoDetectModuleFiles, @@ -1021,7 +1082,7 @@ projects: RepoRelDir: "", Flags: nil, Name: command.Plan, - Verbose: false, + Verbose: true, Workspace: "", ProjectName: "", }) @@ -1104,6 +1165,7 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1199,6 +1261,7 @@ projects: userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1289,6 +1352,7 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) { userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1460,6 +1524,7 @@ projects: userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1561,6 +1626,7 @@ parallel_plan: true`, userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1631,6 +1697,7 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1723,6 +1790,7 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) { userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1854,6 +1922,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands_Single_With_RestrictFile userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, @@ -1965,6 +2034,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands_with_IncludeGitUntracked userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.EnableAutoMerge, + userConfig.EnableAutoDiscover, userConfig.EnableParallelPlan, userConfig.EnableParallelApply, userConfig.AutoDetectModuleFiles, diff --git a/server/events/project_command_context_builder.go b/server/events/project_command_context_builder.go index 16714f841a..0bd4a4c712 100644 --- a/server/events/project_command_context_builder.go +++ b/server/events/project_command_context_builder.go @@ -38,7 +38,7 @@ type ProjectCommandContextBuilder interface { prjCfg valid.MergedProjectCfg, commentFlags []string, repoDir string, - automerge, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, terraformClient terraform.Client, + automerge bool, autodiscover valid.Autodiscover, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, terraformClient terraform.Client, ) []command.ProjectContext } @@ -58,13 +58,12 @@ func (cb *CommandScopedStatsProjectCommandContextBuilder) BuildProjectContext( prjCfg valid.MergedProjectCfg, commentFlags []string, repoDir string, - automerge, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, - terraformClient terraform.Client, + automerge bool, autodiscover valid.Autodiscover, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, terraformClient terraform.Client, ) (projectCmds []command.ProjectContext) { cb.ProjectCounter.Inc(1) cmds := cb.ProjectCommandContextBuilder.BuildProjectContext( - ctx, cmdName, subCmdName, prjCfg, commentFlags, repoDir, automerge, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail, terraformClient, + ctx, cmdName, subCmdName, prjCfg, commentFlags, repoDir, automerge, autodiscover, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail, terraformClient, ) projectCmds = []command.ProjectContext{} @@ -92,8 +91,7 @@ func (cb *DefaultProjectCommandContextBuilder) BuildProjectContext( prjCfg valid.MergedProjectCfg, commentFlags []string, repoDir string, - automerge, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, - terraformClient terraform.Client, + automerge bool, autodiscover valid.Autodiscover, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, terraformClient terraform.Client, ) (projectCmds []command.ProjectContext) { ctx.Log.Debug("Building project command context for %s", cmdName) @@ -138,6 +136,7 @@ func (cb *DefaultProjectCommandContextBuilder) BuildProjectContext( prjCfg.PolicySets, escapeArgs(commentFlags), automerge, + autodiscover, parallelApply, parallelPlan, verbose, @@ -163,8 +162,7 @@ func (cb *PolicyCheckProjectCommandContextBuilder) BuildProjectContext( prjCfg valid.MergedProjectCfg, commentFlags []string, repoDir string, - automerge, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, - terraformClient terraform.Client, + automerge bool, autodiscover valid.Autodiscover, parallelApply, parallelPlan, verbose, abortOnExcecutionOrderFail bool, terraformClient terraform.Client, ) (projectCmds []command.ProjectContext) { if prjCfg.PolicyCheck { ctx.Log.Debug("PolicyChecks are enabled") @@ -187,6 +185,7 @@ func (cb *PolicyCheckProjectCommandContextBuilder) BuildProjectContext( commentFlags, repoDir, automerge, + autodiscover, parallelApply, parallelPlan, verbose, @@ -209,6 +208,7 @@ func (cb *PolicyCheckProjectCommandContextBuilder) BuildProjectContext( prjCfg.PolicySets, escapeArgs(commentFlags), automerge, + autodiscover, parallelApply, parallelPlan, verbose, @@ -233,6 +233,7 @@ func newProjectCommandContext(ctx *command.Context, policySets valid.PolicySets, escapedCommentArgs []string, automergeEnabled bool, + autodiscoverEnabled valid.Autodiscover, parallelApplyEnabled bool, parallelPlanEnabled bool, verbose bool, @@ -269,6 +270,7 @@ func newProjectCommandContext(ctx *command.Context, BaseRepo: ctx.Pull.BaseRepo, EscapedCommentArgs: escapedCommentArgs, AutomergeEnabled: automergeEnabled, + AutodiscoverEnabled: autodiscoverEnabled, DeleteSourceBranchOnMerge: projCfg.DeleteSourceBranchOnMerge, RepoLocking: projCfg.RepoLocking, CustomPolicyCheck: projCfg.CustomPolicyCheck, diff --git a/server/events/project_command_context_builder_test.go b/server/events/project_command_context_builder_test.go index 8bee1d9fb0..859bcaa306 100644 --- a/server/events/project_command_context_builder_test.go +++ b/server/events/project_command_context_builder_test.go @@ -62,7 +62,7 @@ func TestProjectCommandContextBuilder_PullStatus(t *testing.T) { }, } - result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, false, false, false, false, terraformClient) + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, valid.Autodiscover{Enabled: true}, false, false, false, false, terraformClient) assert.Equal(t, models.ErroredPolicyCheckStatus, result[0].ProjectPlanStatus) }) @@ -81,7 +81,7 @@ func TestProjectCommandContextBuilder_PullStatus(t *testing.T) { }, } - result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, false, false, false, false, terraformClient) + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, valid.Autodiscover{Enabled: true}, false, false, false, false, terraformClient) assert.Equal(t, models.ErroredPolicyCheckStatus, result[0].ProjectPlanStatus) }) @@ -101,7 +101,7 @@ func TestProjectCommandContextBuilder_PullStatus(t *testing.T) { }, } - result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, true, false, false, false, terraformClient) + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, valid.Autodiscover{Enabled: true}, true, false, false, false, terraformClient) assert.True(t, result[0].ParallelApplyEnabled) assert.False(t, result[0].ParallelPlanEnabled) @@ -122,7 +122,7 @@ func TestProjectCommandContextBuilder_PullStatus(t *testing.T) { }, } - result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, false, false, false, true, terraformClient) + result := subject.BuildProjectContext(commandCtx, command.Plan, "", projCfg, []string{}, "some/dir", false, valid.Autodiscover{Enabled: true}, false, false, false, true, terraformClient) assert.True(t, result[0].AbortOnExcecutionOrderFail) }) diff --git a/server/server.go b/server/server.go index 6f80cb420f..bb62c6e261 100644 --- a/server/server.go +++ b/server/server.go @@ -590,6 +590,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, userConfig.Automerge, + userConfig.Autodiscover, userConfig.ParallelPlan, userConfig.ParallelApply, userConfig.AutoplanModulesFromProjects, diff --git a/server/user_config.go b/server/user_config.go index 49e3ed6fba..2c69b9abed 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -3,6 +3,7 @@ package server import ( "strings" + "github.com/runatlantis/atlantis/server/core/config/valid" "github.com/runatlantis/atlantis/server/events/command" "github.com/runatlantis/atlantis/server/logging" ) @@ -11,39 +12,40 @@ import ( // The mapstructure tags correspond to flags in cmd/server.go and are used when // the config is parsed from a YAML file. type UserConfig struct { - AllowForkPRs bool `mapstructure:"allow-fork-prs"` - AllowRepoConfig bool `mapstructure:"allow-repo-config"` - AllowCommands string `mapstructure:"allow-commands"` - AtlantisURL string `mapstructure:"atlantis-url"` - Automerge bool `mapstructure:"automerge"` - AutoplanFileList string `mapstructure:"autoplan-file-list"` - AutoplanModules bool `mapstructure:"autoplan-modules"` - AutoplanModulesFromProjects string `mapstructure:"autoplan-modules-from-projects"` - AzureDevopsToken string `mapstructure:"azuredevops-token"` - AzureDevopsUser string `mapstructure:"azuredevops-user"` - AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` - AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` - AzureDevOpsHostname string `mapstructure:"azuredevops-hostname"` - BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` - BitbucketToken string `mapstructure:"bitbucket-token"` - BitbucketUser string `mapstructure:"bitbucket-user"` - BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"` - CheckoutDepth int `mapstructure:"checkout-depth"` - CheckoutStrategy string `mapstructure:"checkout-strategy"` - DataDir string `mapstructure:"data-dir"` - DisableApplyAll bool `mapstructure:"disable-apply-all"` - DisableApply bool `mapstructure:"disable-apply"` - DisableAutoplan bool `mapstructure:"disable-autoplan"` - DisableAutoplanLabel string `mapstructure:"disable-autoplan-label"` - DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"` - DisableRepoLocking bool `mapstructure:"disable-repo-locking"` - DisableUnlockLabel string `mapstructure:"disable-unlock-label"` - DiscardApprovalOnPlanFlag bool `mapstructure:"discard-approval-on-plan"` - EmojiReaction string `mapstructure:"emoji-reaction"` - EnablePolicyChecksFlag bool `mapstructure:"enable-policy-checks"` - EnableRegExpCmd bool `mapstructure:"enable-regexp-cmd"` - EnableDiffMarkdownFormat bool `mapstructure:"enable-diff-markdown-format"` - ExecutableName string `mapstructure:"executable-name"` + AllowForkPRs bool `mapstructure:"allow-fork-prs"` + AllowRepoConfig bool `mapstructure:"allow-repo-config"` + AllowCommands string `mapstructure:"allow-commands"` + AtlantisURL string `mapstructure:"atlantis-url"` + Automerge bool `mapstructure:"automerge"` + Autodiscover valid.Autodiscover `mapstructure:"autodiscover"` + AutoplanFileList string `mapstructure:"autoplan-file-list"` + AutoplanModules bool `mapstructure:"autoplan-modules"` + AutoplanModulesFromProjects string `mapstructure:"autoplan-modules-from-projects"` + AzureDevopsToken string `mapstructure:"azuredevops-token"` + AzureDevopsUser string `mapstructure:"azuredevops-user"` + AzureDevopsWebhookPassword string `mapstructure:"azuredevops-webhook-password"` + AzureDevopsWebhookUser string `mapstructure:"azuredevops-webhook-user"` + AzureDevOpsHostname string `mapstructure:"azuredevops-hostname"` + BitbucketBaseURL string `mapstructure:"bitbucket-base-url"` + BitbucketToken string `mapstructure:"bitbucket-token"` + BitbucketUser string `mapstructure:"bitbucket-user"` + BitbucketWebhookSecret string `mapstructure:"bitbucket-webhook-secret"` + CheckoutDepth int `mapstructure:"checkout-depth"` + CheckoutStrategy string `mapstructure:"checkout-strategy"` + DataDir string `mapstructure:"data-dir"` + DisableApplyAll bool `mapstructure:"disable-apply-all"` + DisableApply bool `mapstructure:"disable-apply"` + DisableAutoplan bool `mapstructure:"disable-autoplan"` + DisableAutoplanLabel string `mapstructure:"disable-autoplan-label"` + DisableMarkdownFolding bool `mapstructure:"disable-markdown-folding"` + DisableRepoLocking bool `mapstructure:"disable-repo-locking"` + DisableUnlockLabel string `mapstructure:"disable-unlock-label"` + DiscardApprovalOnPlanFlag bool `mapstructure:"discard-approval-on-plan"` + EmojiReaction string `mapstructure:"emoji-reaction"` + EnablePolicyChecksFlag bool `mapstructure:"enable-policy-checks"` + EnableRegExpCmd bool `mapstructure:"enable-regexp-cmd"` + EnableDiffMarkdownFormat bool `mapstructure:"enable-diff-markdown-format"` + ExecutableName string `mapstructure:"executable-name"` // Fail and do not run the Atlantis command request if any of the pre workflow hooks error. FailOnPreWorkflowHookError bool `mapstructure:"fail-on-pre-workflow-hook-error"` HideUnchangedPlanComments bool `mapstructure:"hide-unchanged-plan-comments"` From 5e1f50b073efeaa88422ae5217055869973df94f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 01:32:56 +0000 Subject: [PATCH 2/8] chore(deps): update dependency node to v20.9.0 in .node-version (#3896) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .node-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.node-version b/.node-version index 6569dfa4f3..f3f52b42d3 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20.8.1 +20.9.0 From 3f640a75c3771467a0b5298d692e1ea1e88a6bf0 Mon Sep 17 00:00:00 2001 From: Marcelo Medeiros Date: Wed, 25 Oct 2023 22:58:46 +0200 Subject: [PATCH 3/8] add global config and doc --- cmd/server.go | 1 + runatlantis.io/docs/autodiscover.md | 92 +++++++++++++++++++ .../docs/repo-level-atlantis-yaml.md | 11 +++ .../docs/server-side-repo-config.md | 7 +- server/core/config/parser_validator_test.go | 25 ++++- server/core/config/raw/global_cfg.go | 49 ++++++---- server/core/config/valid/global_cfg.go | 26 +++++- server/core/config/valid/global_cfg_test.go | 31 ++++++- server/core/config/valid/repo_cfg.go | 2 +- server/user_config.go | 2 +- 10 files changed, 217 insertions(+), 29 deletions(-) create mode 100644 runatlantis.io/docs/autodiscover.md diff --git a/cmd/server.go b/cmd/server.go index d9e37a7c62..b18d87d39d 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -54,6 +54,7 @@ const ( AllowForkPRsFlag = "allow-fork-prs" AllowRepoConfigFlag = "allow-repo-config" AtlantisURLFlag = "atlantis-url" + AutoDiscover = "autodiscover" AutomergeFlag = "automerge" ParallelPlanFlag = "parallel-plan" ParallelApplyFlag = "parallel-apply" diff --git a/runatlantis.io/docs/autodiscover.md b/runatlantis.io/docs/autodiscover.md new file mode 100644 index 0000000000..4ddf5daec7 --- /dev/null +++ b/runatlantis.io/docs/autodiscover.md @@ -0,0 +1,92 @@ +# Autodiscover +Atlantis can be configured to automatically discover Terraform projects in a repository. + + +## How To Enable +By default the autodiscover is enabled, but you can "enforce it": +1. Server Side: + ```yaml + repo: + ... + autodiscover: + enabled: true + ... + ``` +1. Repo side `atlantis.yaml` file: + ```yaml + version: 3 + autodiscover: + enabled: true + projects: + - dir: . + ``` + :::tip NOTE + You need allow override in the server side configuration if you would like to disable it for a specific repo in the repo side configuration: + ```yaml + repo: + ... + allowed_overrides: [autodiscover] + ... + ``` + :::: + +## How to Disable +You can disable it globally for each repo in the server side. +1. Server Side: + ```yaml + repo: + ... + autodiscover: + enabled: false + ... + ``` +or for a specific repo in the repo side `atlantis.yaml` file: +1. Repo side `atlantis.yaml` file: + ```yaml + version: 3 + autodiscover: + enabled: false + projects: + - dir: . + ``` + :::tip NOTE + You need allow override in the server side configuration if you would like to disable it for a specific repo in the repo side configuration: + ```yaml + repo: + ... + allowed_overrides: [autodiscover] + ... + ``` + :::: +## Cases +### Multiple Projects +Atlantis will discover all Terraform projects in a repository. For example, if you have a repository with the following structure: +``` +|── prod +│ └── project1 +│ └── main.tf +| └── project2 +│ └── main.tf +``` +Atlantis will discover both `project1` and `project2` and create a plan for each one. + +### Multi Server +Image that you have a mono repository with multiples stages, and for each stage you have a different Atlantis server. You can configure each server to discover only the projects that are related to it. For example, if you have a repository with the following structure: +``` +|── prod +│ └── project1 +│ └── main.tf +|── stage +|── test +└── project1 +└── main.tf +``` +You can create the atlantis.yaml dynamically in each server to discover only the projects that are related to it. For example, the `prod` server side configuration will have the: +```yaml +repos: + - id: /.*/ + apply_requirements: [approved, mergeable] + repo_config_file: atlantis-prod.yaml +``` + +and you can use a [pre_workflow_hooks](./pre-workflow-hooks.md) to create the `atlantis-prod.yaml` file dynamically. \ No newline at end of file diff --git a/runatlantis.io/docs/repo-level-atlantis-yaml.md b/runatlantis.io/docs/repo-level-atlantis-yaml.md index 5484f26e34..ea9ba5461b 100644 --- a/runatlantis.io/docs/repo-level-atlantis-yaml.md +++ b/runatlantis.io/docs/repo-level-atlantis-yaml.md @@ -47,6 +47,8 @@ need to be defined. ```yaml version: 3 automerge: true +autodiscover: + enabled: true delete_source_branch_on_merge: true parallel_plan: true parallel_apply: true @@ -148,6 +150,15 @@ projects: This will stop Atlantis automatically running plan when `project1/` is updated in a pull request. +### Disabling Autodiscover +``` +version: 3 +autodiscover: + enabled: false +``` + +This will stop Atlantis automatically discovering projects in a repo. + ### Run plans and applies in parallel ```yaml diff --git a/runatlantis.io/docs/server-side-repo-config.md b/runatlantis.io/docs/server-side-repo-config.md index 01d8a175aa..106013cf60 100644 --- a/runatlantis.io/docs/server-side-repo-config.md +++ b/runatlantis.io/docs/server-side-repo-config.md @@ -54,7 +54,7 @@ repos: # allowed_overrides specifies which keys can be overridden by this repo in # its atlantis.yaml file. - allowed_overrides: [apply_requirements, workflow, delete_source_branch_on_merge, repo_locking, custom_policy_check] + allowed_overrides: [apply_requirements, workflow, delete_source_branch_on_merge, repo_locking, custom_policy_check, autodiscover] # allowed_workflows specifies which workflows the repos that match # are allowed to select. @@ -88,6 +88,10 @@ repos: # policy_check defines if policy checking should be enable on this repository. policy_check: false + # autodiscover defines if atlantis should automatically discover projects in this repository. + autodiscover: + enabled: true + # id can also be an exact match. - id: github.com/myorg/specific-repo @@ -496,6 +500,7 @@ If you set a workflow with the key `default`, it will override this. | repo_locking | bool | false | no | Whether or not to get a lock. | | policy_check | bool | false | no | Whether or not to run policy checks on this repository. | | custom_policy_check | bool | false | no | Whether or not to enable custom policy check tools outside of Conftest on this repository. | +| autodiscover | Autodiscover | true | no | Whether or not to enable autodiscover on this repository. | :::tip Notes diff --git a/server/core/config/parser_validator_test.go b/server/core/config/parser_validator_test.go index afb5b83831..f9a2939841 100644 --- a/server/core/config/parser_validator_test.go +++ b/server/core/config/parser_validator_test.go @@ -1354,7 +1354,7 @@ func TestParseGlobalCfg(t *testing.T) { input: `repos: - id: /.*/ allowed_overrides: [invalid]`, - expErr: "repos: (0: (allowed_overrides: \"invalid\" is not a valid override, only \"plan_requirements\", \"apply_requirements\", \"import_requirements\", \"workflow\", \"delete_source_branch_on_merge\", \"repo_locking\", \"policy_check\", and \"custom_policy_check\" are supported.).).", + expErr: "repos: (0: (allowed_overrides: \"invalid\" is not a valid override, only \"plan_requirements\", \"apply_requirements\", \"import_requirements\", \"workflow\", \"delete_source_branch_on_merge\", \"repo_locking\", \"policy_check\", \"custom_policy_check\", and \"auto_discover\" are supported.).).", }, "invalid plan_requirement": { input: `repos: @@ -1374,6 +1374,22 @@ func TestParseGlobalCfg(t *testing.T) { import_requirements: [invalid]`, expErr: "repos: (0: (import_requirements: \"invalid\" is not a valid import_requirement, only \"approved\", \"mergeable\" and \"undiverged\" are supported.).).", }, + "disable autodiscover": { + input: `repos: +- id: /.*/ + autodiscover: + enabled: false`, + exp: valid.GlobalCfg{ + Repos: []valid.Repo{ + defaultCfg.Repos[0], + { + IDRegex: regexp.MustCompile(".*"), + AutoDiscover: &valid.Autodiscover{Enabled: false}, + }, + }, + Workflows: defaultCfg.Workflows, + }, + }, "no workflows key": { input: `repos: []`, exp: defaultCfg, @@ -1449,6 +1465,8 @@ repos: allowed_overrides: [plan_requirements, apply_requirements, import_requirements, workflow, delete_source_branch_on_merge] allow_custom_workflows: true policy_check: true + autodiscover: + enabled: true - id: /.*/ branch: /(master|main)/ pre_workflow_hooks: @@ -1456,6 +1474,8 @@ repos: post_workflow_hooks: - run: custom workflow command policy_check: false + autodiscover: + enabled: false workflows: custom1: plan: @@ -1502,6 +1522,7 @@ policies: AllowedOverrides: []string{"plan_requirements", "apply_requirements", "import_requirements", "workflow", "delete_source_branch_on_merge"}, AllowCustomWorkflows: Bool(true), PolicyCheck: Bool(true), + AutoDiscover: &valid.Autodiscover{Enabled: true}, }, { IDRegex: regexp.MustCompile(".*"), @@ -1509,6 +1530,7 @@ policies: PreWorkflowHooks: preWorkflowHooks, PostWorkflowHooks: postWorkflowHooks, PolicyCheck: Bool(false), + AutoDiscover: &valid.Autodiscover{Enabled: false}, }, }, Workflows: map[string]valid.Workflow{ @@ -1619,6 +1641,7 @@ workflows: RepoLocking: Bool(true), PolicyCheck: Bool(false), CustomPolicyCheck: Bool(false), + AutoDiscover: &valid.Autodiscover{Enabled: true}, }, }, Workflows: map[string]valid.Workflow{ diff --git a/server/core/config/raw/global_cfg.go b/server/core/config/raw/global_cfg.go index 92a9ec29b6..74dd4f8c42 100644 --- a/server/core/config/raw/global_cfg.go +++ b/server/core/config/raw/global_cfg.go @@ -20,22 +20,23 @@ type GlobalCfg struct { // Repo is the raw schema for repos in the server-side repo config. type Repo struct { - ID string `yaml:"id" json:"id"` - Branch string `yaml:"branch" json:"branch"` - RepoConfigFile string `yaml:"repo_config_file" json:"repo_config_file"` - PlanRequirements []string `yaml:"plan_requirements" json:"plan_requirements"` - ApplyRequirements []string `yaml:"apply_requirements" json:"apply_requirements"` - ImportRequirements []string `yaml:"import_requirements" json:"import_requirements"` - PreWorkflowHooks []WorkflowHook `yaml:"pre_workflow_hooks" json:"pre_workflow_hooks"` - Workflow *string `yaml:"workflow,omitempty" json:"workflow,omitempty"` - PostWorkflowHooks []WorkflowHook `yaml:"post_workflow_hooks" json:"post_workflow_hooks"` - AllowedWorkflows []string `yaml:"allowed_workflows,omitempty" json:"allowed_workflows,omitempty"` - AllowedOverrides []string `yaml:"allowed_overrides" json:"allowed_overrides"` - AllowCustomWorkflows *bool `yaml:"allow_custom_workflows,omitempty" json:"allow_custom_workflows,omitempty"` - DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty" json:"delete_source_branch_on_merge,omitempty"` - RepoLocking *bool `yaml:"repo_locking,omitempty" json:"repo_locking,omitempty"` - PolicyCheck *bool `yaml:"policy_check,omitempty" json:"policy_check,omitempty"` - CustomPolicyCheck *bool `yaml:"custom_policy_check,omitempty" json:"custom_policy_check,omitempty"` + ID string `yaml:"id" json:"id"` + Branch string `yaml:"branch" json:"branch"` + RepoConfigFile string `yaml:"repo_config_file" json:"repo_config_file"` + PlanRequirements []string `yaml:"plan_requirements" json:"plan_requirements"` + ApplyRequirements []string `yaml:"apply_requirements" json:"apply_requirements"` + ImportRequirements []string `yaml:"import_requirements" json:"import_requirements"` + PreWorkflowHooks []WorkflowHook `yaml:"pre_workflow_hooks" json:"pre_workflow_hooks"` + Workflow *string `yaml:"workflow,omitempty" json:"workflow,omitempty"` + PostWorkflowHooks []WorkflowHook `yaml:"post_workflow_hooks" json:"post_workflow_hooks"` + AllowedWorkflows []string `yaml:"allowed_workflows,omitempty" json:"allowed_workflows,omitempty"` + AllowedOverrides []string `yaml:"allowed_overrides" json:"allowed_overrides"` + AllowCustomWorkflows *bool `yaml:"allow_custom_workflows,omitempty" json:"allow_custom_workflows,omitempty"` + DeleteSourceBranchOnMerge *bool `yaml:"delete_source_branch_on_merge,omitempty" json:"delete_source_branch_on_merge,omitempty"` + RepoLocking *bool `yaml:"repo_locking,omitempty" json:"repo_locking,omitempty"` + PolicyCheck *bool `yaml:"policy_check,omitempty" json:"policy_check,omitempty"` + CustomPolicyCheck *bool `yaml:"custom_policy_check,omitempty" json:"custom_policy_check,omitempty"` + Autodiscover *valid.Autodiscover `yaml:"autodiscover,omitempty" json:"autodiscover,omitempty"` } func (g GlobalCfg) Validate() error { @@ -193,8 +194,8 @@ func (r Repo) Validate() error { overridesValid := func(value interface{}) error { overrides := value.([]string) for _, o := range overrides { - if o != valid.PlanRequirementsKey && o != valid.ApplyRequirementsKey && o != valid.ImportRequirementsKey && o != valid.WorkflowKey && o != valid.DeleteSourceBranchOnMergeKey && o != valid.RepoLockingKey && o != valid.PolicyCheckKey && o != valid.CustomPolicyCheckKey { - return fmt.Errorf("%q is not a valid override, only %q, %q, %q, %q, %q, %q, %q, and %q are supported", o, valid.PlanRequirementsKey, valid.ApplyRequirementsKey, valid.ImportRequirementsKey, valid.WorkflowKey, valid.DeleteSourceBranchOnMergeKey, valid.RepoLockingKey, valid.PolicyCheckKey, valid.CustomPolicyCheckKey) + if o != valid.PlanRequirementsKey && o != valid.ApplyRequirementsKey && o != valid.ImportRequirementsKey && o != valid.WorkflowKey && o != valid.DeleteSourceBranchOnMergeKey && o != valid.RepoLockingKey && o != valid.PolicyCheckKey && o != valid.CustomPolicyCheckKey && o != valid.AutoDiscoverKey { + return fmt.Errorf("%q is not a valid override, only %q, %q, %q, %q, %q, %q, %q, %q, and %q are supported", o, valid.PlanRequirementsKey, valid.ApplyRequirementsKey, valid.ImportRequirementsKey, valid.WorkflowKey, valid.DeleteSourceBranchOnMergeKey, valid.RepoLockingKey, valid.PolicyCheckKey, valid.CustomPolicyCheckKey, valid.AutoDiscoverKey) } } return nil @@ -211,6 +212,16 @@ func (r Repo) Validate() error { return nil } + autoDiscoverValid := func(value interface{}) error { + // var autoDiscover interface{} = value + // if autoDiscover != nil { + // if _, ok := autoDiscover.(Autodiscover); !ok { + // return fmt.Errorf("autodiscover must be a map like : autodiscover: \\n enabled: true") + // } + // } + return nil + } + return validation.ValidateStruct(&r, validation.Field(&r.ID, validation.Required, validation.By(idValid)), validation.Field(&r.Branch, validation.By(branchValid)), @@ -221,6 +232,7 @@ func (r Repo) Validate() error { validation.Field(&r.ImportRequirements, validation.By(validImportReq)), validation.Field(&r.Workflow, validation.By(workflowExists)), validation.Field(&r.DeleteSourceBranchOnMerge, validation.By(deleteSourceBranchOnMergeValid)), + validation.Field(&r.Autodiscover, validation.By(autoDiscoverValid)), ) } @@ -333,5 +345,6 @@ OuterGlobalImportReqs: RepoLocking: r.RepoLocking, PolicyCheck: r.PolicyCheck, CustomPolicyCheck: r.CustomPolicyCheck, + AutoDiscover: r.Autodiscover, } } diff --git a/server/core/config/valid/global_cfg.go b/server/core/config/valid/global_cfg.go index 8aab42f67b..aabc13d51a 100644 --- a/server/core/config/valid/global_cfg.go +++ b/server/core/config/valid/global_cfg.go @@ -28,6 +28,7 @@ const DeleteSourceBranchOnMergeKey = "delete_source_branch_on_merge" const RepoLockingKey = "repo_locking" const PolicyCheckKey = "policy_check" const CustomPolicyCheckKey = "custom_policy_check" +const AutoDiscoverKey = "auto_discover" // DefaultAtlantisFile is the default name of the config file for each repo. const DefaultAtlantisFile = "atlantis.yaml" @@ -84,6 +85,7 @@ type Repo struct { RepoLocking *bool PolicyCheck *bool CustomPolicyCheck *bool + AutoDiscover *Autodiscover } type MergedProjectCfg struct { @@ -105,6 +107,7 @@ type MergedProjectCfg struct { RepoLocking bool PolicyCheck bool CustomPolicyCheck bool + AutoDiscover Autodiscover } // WorkflowHook is a map of custom run commands to run before or after workflows. @@ -210,6 +213,7 @@ type GlobalCfgArgs struct { PolicyCheckEnabled bool PreWorkflowHooks []*WorkflowHook PostWorkflowHooks []*WorkflowHook + AutoDiscover *Autodiscover } func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg { @@ -245,8 +249,9 @@ func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg { deleteSourceBranchOnMerge := false repoLockingKey := true customPolicyCheck := false + autoDiscover := Autodiscover{Enabled: true} if args.AllowRepoCfg { - allowedOverrides = []string{PlanRequirementsKey, ApplyRequirementsKey, ImportRequirementsKey, WorkflowKey, DeleteSourceBranchOnMergeKey, RepoLockingKey, PolicyCheckKey} + allowedOverrides = []string{PlanRequirementsKey, ApplyRequirementsKey, ImportRequirementsKey, WorkflowKey, DeleteSourceBranchOnMergeKey, RepoLockingKey, PolicyCheckKey, AutoDiscoverKey} allowCustomWorkflows = true } @@ -269,6 +274,7 @@ func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg { RepoLocking: &repoLockingKey, PolicyCheck: &policyCheck, CustomPolicyCheck: &customPolicyCheck, + AutoDiscover: &autoDiscover, }, }, Workflows: map[string]Workflow{ @@ -305,7 +311,7 @@ func (r Repo) IDString() string { // final config. It assumes that all configs have been validated. func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, proj Project, rCfg RepoCfg) MergedProjectCfg { log.Debug("MergeProjectCfg started") - planReqs, applyReqs, importReqs, workflow, allowedOverrides, allowCustomWorkflows, deleteSourceBranchOnMerge, repoLocking, policyCheck, customPolicyCheck := g.getMatchingCfg(log, repoID) + planReqs, applyReqs, importReqs, workflow, allowedOverrides, allowCustomWorkflows, deleteSourceBranchOnMerge, repoLocking, policyCheck, customPolicyCheck, autoDiscover := g.getMatchingCfg(log, repoID) // If repos are allowed to override certain keys then override them. for _, key := range allowedOverrides { @@ -376,6 +382,11 @@ func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, pro log.Debug("overriding server-defined %s with repo settings: [%t]", CustomPolicyCheckKey, *proj.CustomPolicyCheck) customPolicyCheck = *proj.CustomPolicyCheck } + case AutoDiscoverKey: + if proj.Autodiscover != nil { + log.Debug("overriding server-defined %s with repo settings: [%t]", AutoDiscoverKey, *proj.Autodiscover) + autoDiscover = *proj.Autodiscover + } } log.Debug("MergeProjectCfg completed") } @@ -400,6 +411,7 @@ func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, pro RepoLocking: repoLocking, PolicyCheck: policyCheck, CustomPolicyCheck: customPolicyCheck, + AutoDiscover: autoDiscover, } } @@ -407,7 +419,7 @@ func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, pro // repo with id repoID. It is used when there is no repo config. func (g GlobalCfg) DefaultProjCfg(log logging.SimpleLogging, repoID string, repoRelDir string, workspace string) MergedProjectCfg { log.Debug("building config based on server-side config") - planReqs, applyReqs, importReqs, workflow, _, _, deleteSourceBranchOnMerge, repoLocking, policyCheck, customPolicyCheck := g.getMatchingCfg(log, repoID) + planReqs, applyReqs, importReqs, workflow, _, _, deleteSourceBranchOnMerge, repoLocking, policyCheck, customPolicyCheck, autoDiscoverCheck := g.getMatchingCfg(log, repoID) return MergedProjectCfg{ PlanRequirements: planReqs, ApplyRequirements: applyReqs, @@ -423,6 +435,7 @@ func (g GlobalCfg) DefaultProjCfg(log logging.SimpleLogging, repoID string, repo RepoLocking: repoLocking, PolicyCheck: policyCheck, CustomPolicyCheck: customPolicyCheck, + AutoDiscover: autoDiscoverCheck, } } @@ -528,7 +541,7 @@ func (g GlobalCfg) ValidateRepoCfg(rCfg RepoCfg, repoID string) error { } // getMatchingCfg returns the key settings for repoID. -func (g GlobalCfg) getMatchingCfg(log logging.SimpleLogging, repoID string) (planReqs []string, applyReqs []string, importReqs []string, workflow Workflow, allowedOverrides []string, allowCustomWorkflows bool, deleteSourceBranchOnMerge bool, repoLocking bool, policyCheck bool, customPolicyCheck bool) { +func (g GlobalCfg) getMatchingCfg(log logging.SimpleLogging, repoID string) (planReqs []string, applyReqs []string, importReqs []string, workflow Workflow, allowedOverrides []string, allowCustomWorkflows bool, deleteSourceBranchOnMerge bool, repoLocking bool, policyCheck bool, customPolicyCheck bool, autoDiscover Autodiscover) { toLog := make(map[string]string) traceF := func(repoIdx int, repoID string, key string, val interface{}) string { from := "default server config" @@ -604,6 +617,11 @@ func (g GlobalCfg) getMatchingCfg(log logging.SimpleLogging, repoID string) (pla toLog[CustomPolicyCheckKey] = traceF(i, repo.IDString(), CustomPolicyCheckKey, *repo.CustomPolicyCheck) customPolicyCheck = *repo.CustomPolicyCheck } + case AutoDiscoverKey: + if repo.AutoDiscover != nil { + toLog[AutoDiscoverKey] = traceF(i, repo.IDString(), AutoDiscoverKey, *repo.AutoDiscover) + autoDiscover = *repo.AutoDiscover + } } } } diff --git a/server/core/config/valid/global_cfg_test.go b/server/core/config/valid/global_cfg_test.go index d778a9f12d..5cb27912e0 100644 --- a/server/core/config/valid/global_cfg_test.go +++ b/server/core/config/valid/global_cfg_test.go @@ -82,6 +82,7 @@ func TestNewGlobalCfg(t *testing.T) { RepoLocking: Bool(true), PolicyCheck: Bool(false), CustomPolicyCheck: Bool(false), + AutoDiscover: &valid.Autodiscover{Enabled: true}, }, }, Workflows: map[string]valid.Workflow{ @@ -95,6 +96,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq bool unDivergedReq bool policyCheckEnabled bool + autoDiscover *valid.Autodiscover }{ { allowRepoCfg: false, @@ -102,6 +104,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: false, unDivergedReq: false, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: true, @@ -109,6 +112,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: false, unDivergedReq: false, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: false, @@ -116,6 +120,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: false, unDivergedReq: false, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: false, @@ -123,6 +128,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: false, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: false, @@ -130,6 +136,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: false, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: true, @@ -137,6 +144,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: false, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: false, @@ -144,6 +152,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: false, unDivergedReq: true, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: true, @@ -151,6 +160,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: false, unDivergedReq: true, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: true}, }, { allowRepoCfg: false, @@ -158,6 +168,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: false, unDivergedReq: true, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: false, @@ -165,6 +176,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: true, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: false, @@ -172,6 +184,7 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: true, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: true, @@ -179,6 +192,15 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: true, policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: true}, + }, + { + allowRepoCfg: true, + approvedReq: true, + mergeableReq: true, + unDivergedReq: true, + policyCheckEnabled: false, + autoDiscover: &valid.Autodiscover{Enabled: false}, }, { allowRepoCfg: true, @@ -186,12 +208,13 @@ func TestNewGlobalCfg(t *testing.T) { mergeableReq: true, unDivergedReq: true, policyCheckEnabled: true, + autoDiscover: &valid.Autodiscover{Enabled: true}, }, } for _, c := range cases { - caseName := fmt.Sprintf("allow_repo: %t, approved: %t, mergeable: %t, undiverged: %t, policy_check: %t", - c.allowRepoCfg, c.approvedReq, c.mergeableReq, c.unDivergedReq, c.policyCheckEnabled) + caseName := fmt.Sprintf("allow_repo: %t, approved: %t, mergeable: %t, undiverged: %t, policy_check: %t, auto_discover: %t", + c.allowRepoCfg, c.approvedReq, c.mergeableReq, c.unDivergedReq, c.policyCheckEnabled, c.autoDiscover) t.Run(caseName, func(t *testing.T) { globalCfgArgs := valid.GlobalCfgArgs{ AllowRepoCfg: c.allowRepoCfg, @@ -199,6 +222,7 @@ func TestNewGlobalCfg(t *testing.T) { ApprovedReq: c.approvedReq, UnDivergedReq: c.unDivergedReq, PolicyCheckEnabled: c.policyCheckEnabled, + AutoDiscover: c.autoDiscover, } act := valid.NewGlobalCfgFromArgs(globalCfgArgs) @@ -209,7 +233,7 @@ func TestNewGlobalCfg(t *testing.T) { if c.allowRepoCfg { exp.Repos[0].AllowCustomWorkflows = Bool(true) - exp.Repos[0].AllowedOverrides = []string{"plan_requirements", "apply_requirements", "import_requirements", "workflow", "delete_source_branch_on_merge", "repo_locking", "policy_check"} + exp.Repos[0].AllowedOverrides = []string{"plan_requirements", "apply_requirements", "import_requirements", "workflow", "delete_source_branch_on_merge", "repo_locking", "policy_check", "auto_discover"} } if c.mergeableReq { exp.Repos[0].PlanRequirements = append(exp.Repos[0].PlanRequirements, "mergeable") @@ -677,6 +701,7 @@ policies: - name: good-policy source: local path: rel/path/to/source + `, repoID: "github.com/owner/repo", proj: valid.Project{ diff --git a/server/core/config/valid/repo_cfg.go b/server/core/config/valid/repo_cfg.go index e2fdf5c04c..e0fd52c496 100644 --- a/server/core/config/valid/repo_cfg.go +++ b/server/core/config/valid/repo_cfg.go @@ -130,7 +130,7 @@ type Project struct { WorkflowName *string TerraformVersion *version.Version Autoplan Autoplan - Autodiscover Autodiscover + Autodiscover *Autodiscover PlanRequirements []string ApplyRequirements []string ImportRequirements []string diff --git a/server/user_config.go b/server/user_config.go index 2c69b9abed..e0cf3d7a48 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -16,8 +16,8 @@ type UserConfig struct { AllowRepoConfig bool `mapstructure:"allow-repo-config"` AllowCommands string `mapstructure:"allow-commands"` AtlantisURL string `mapstructure:"atlantis-url"` - Automerge bool `mapstructure:"automerge"` Autodiscover valid.Autodiscover `mapstructure:"autodiscover"` + Automerge bool `mapstructure:"automerge"` AutoplanFileList string `mapstructure:"autoplan-file-list"` AutoplanModules bool `mapstructure:"autoplan-modules"` AutoplanModulesFromProjects string `mapstructure:"autoplan-modules-from-projects"` From 24863d8c86af4e5a306e7394b83c81a9e7a66222 Mon Sep 17 00:00:00 2001 From: CreatureKing Date: Tue, 24 Oct 2023 18:13:09 -0400 Subject: [PATCH 4/8] feat: Implement autodiscover.mode --- .../docs/repo-level-atlantis-yaml.md | 42 +++++- server/core/config/parser_validator_test.go | 67 ++++++--- server/core/config/raw/autodiscover.go | 38 +++++ server/core/config/raw/autodiscover_test.go | 131 ++++++++++++++++++ server/core/config/raw/repo_cfg.go | 7 + server/core/config/raw/repo_cfg_test.go | 68 +++++++-- server/core/config/valid/autodiscover.go | 14 ++ server/core/config/valid/repo_cfg.go | 10 ++ server/events/project_command_builder.go | 56 ++++++-- server/events/project_command_builder_test.go | 71 ++++++++++ 10 files changed, 453 insertions(+), 51 deletions(-) create mode 100644 server/core/config/raw/autodiscover.go create mode 100644 server/core/config/raw/autodiscover_test.go create mode 100644 server/core/config/valid/autodiscover.go diff --git a/runatlantis.io/docs/repo-level-atlantis-yaml.md b/runatlantis.io/docs/repo-level-atlantis-yaml.md index 5484f26e34..2ad348db07 100644 --- a/runatlantis.io/docs/repo-level-atlantis-yaml.md +++ b/runatlantis.io/docs/repo-level-atlantis-yaml.md @@ -34,12 +34,18 @@ By default, this is not allowed. ::: ::: warning -Once an `atlantis.yaml` file exists in a repo, Atlantis won't try to determine -where to run plan automatically. Instead it will just follow the project configuration. -This means that you'll need to define each project in your repo. +Once an `atlantis.yaml` file exists in a repo and one or more `projects` are configured, +Atlantis won't try to determine where to run plan automatically. Instead it will just +follow the project configuration. This means that you'll need to define each project +in your repo. If you have many directories with Terraform configuration, each directory will need to be defined. + +This behavior can be overriden by setting `autodiscover.mode` to +`enabled` in which case Atlantis will still try to discover projects which were not +explicitly configured. If the directory of any discovered project conflicts with a +manually configured project, the manually configured project will take precedence. ::: ## Example Using All Keys @@ -48,6 +54,8 @@ need to be defined. version: 3 automerge: true delete_source_branch_on_merge: true +autoplan: + mode: auto parallel_plan: true parallel_apply: true abort_on_execution_order_fail: true @@ -281,6 +289,34 @@ in each group one by one. If any plan/apply fails and `abort_on_execution_order_fail` is set to true on a repo level, all the following groups will be aborted. For this example, if project2 fails then project1 will not run. +### Autodiscovery Config +```yaml +autodiscover: + mode: "auto" +``` +The above is the default configuration for `autodiscover.mode`. When `autodiscover.mode` is auto, +projects will be discovered only if the repo has no `projects` configured. + +```yaml +autodiscover: + mode: "disabled" +``` +With the config above, Atlantis will never try to discover projects, even when there are no +`projects` configured. This is useful if dynamically generating Atlantis config in pre_workflow hooks. +See [Dynamic Repo Config Generation](pre-workflow-hooks.html#dynamic-repo-config-generation). + +```yaml +autodiscover: + mode: "enabled" +``` +With the config above, Atlantis will unconditionally try to discover projects based on modified_files, +even when the directory of the project is missing from the configured `projects` in the repo configuration. +If a discovered project has the same directory as a project which was manually configured in `projects`, +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. + ### Custom Backend Config See [Custom Workflow Use Cases: Custom Backend Config](custom-workflows.html#custom-backend-config) diff --git a/server/core/config/parser_validator_test.go b/server/core/config/parser_validator_test.go index 53caf9e539..e876989090 100644 --- a/server/core/config/parser_validator_test.go +++ b/server/core/config/parser_validator_test.go @@ -162,7 +162,8 @@ workflows: - run: old 'shell parsing' `, exp: valid.RepoCfg{ - Version: 2, + Version: 2, + AutoDiscover: raw.DefaultAutoDiscover(), Workflows: map[string]valid.Workflow{ "custom": { Name: "custom", @@ -190,9 +191,10 @@ workflows: version: 3 projects:`, exp: valid.RepoCfg{ - Version: 3, - Projects: nil, - Workflows: map[string]valid.Workflow{}, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), + Projects: nil, + Workflows: map[string]valid.Workflow{}, }, }, { @@ -210,7 +212,8 @@ version: 3 projects: - dir: .`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -235,7 +238,8 @@ projects: - dir: "." `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -259,7 +263,8 @@ projects: when_modified: ["**/*.tf*"] `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -281,7 +286,8 @@ projects: - dir: "." `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -304,7 +310,8 @@ projects: workflows: ~ `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -332,7 +339,8 @@ workflows: steps: `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -361,7 +369,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -395,7 +404,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -429,7 +439,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -463,7 +474,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -497,7 +509,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -531,7 +544,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -565,7 +579,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -599,7 +614,8 @@ projects: workflows: myworkflow: ~`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -710,7 +726,8 @@ projects: dir: . workspace: workspace`, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Name: String("myname"), @@ -762,7 +779,8 @@ workflows: - state_rm `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -861,7 +879,8 @@ workflows: extra_args: ["a", "b"] `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -952,7 +971,8 @@ workflows: - run: echo apply "arg 4" `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", @@ -1045,7 +1065,8 @@ workflows: value: env_value `, exp: valid.RepoCfg{ - Version: 3, + Version: 3, + AutoDiscover: raw.DefaultAutoDiscover(), Projects: []valid.Project{ { Dir: ".", diff --git a/server/core/config/raw/autodiscover.go b/server/core/config/raw/autodiscover.go new file mode 100644 index 0000000000..156128d271 --- /dev/null +++ b/server/core/config/raw/autodiscover.go @@ -0,0 +1,38 @@ +package raw + +import ( + validation "github.com/go-ozzo/ozzo-validation" + "github.com/runatlantis/atlantis/server/core/config/valid" +) + +var DefaultAutoDiscoverMode = valid.AutoDiscoverAutoMode + +type AutoDiscover struct { + Mode *valid.AutoDiscoverMode `yaml:"mode,omitempty"` +} + +func (a AutoDiscover) ToValid() *valid.AutoDiscover { + var v valid.AutoDiscover + + if a.Mode != nil { + v.Mode = *a.Mode + } else { + v.Mode = DefaultAutoDiscoverMode + } + + return &v +} + +func (a AutoDiscover) Validate() error { + 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)), + ) + return res +} + +func DefaultAutoDiscover() *valid.AutoDiscover { + return &valid.AutoDiscover{ + Mode: DefaultAutoDiscoverMode, + } +} diff --git a/server/core/config/raw/autodiscover_test.go b/server/core/config/raw/autodiscover_test.go new file mode 100644 index 0000000000..417257ad64 --- /dev/null +++ b/server/core/config/raw/autodiscover_test.go @@ -0,0 +1,131 @@ +package raw_test + +import ( + "testing" + + "github.com/runatlantis/atlantis/server/core/config/raw" + "github.com/runatlantis/atlantis/server/core/config/valid" + . "github.com/runatlantis/atlantis/testing" + yaml "gopkg.in/yaml.v2" +) + +func TestAutoDiscover_UnmarshalYAML(t *testing.T) { + auto_discover_enabled := valid.AutoDiscoverEnabledMode + cases := []struct { + description string + input string + exp raw.AutoDiscover + }{ + { + description: "omit unset fields", + input: "", + exp: raw.AutoDiscover{ + Mode: nil, + }, + }, + { + description: "all fields set", + input: ` +mode: enabled +`, + exp: raw.AutoDiscover{ + Mode: &auto_discover_enabled, + }, + }, + } + + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + var a raw.AutoDiscover + err := yaml.UnmarshalStrict([]byte(c.input), &a) + Ok(t, err) + Equals(t, c.exp, a) + }) + } +} + +func TestAutoDiscover_Validate(t *testing.T) { + auto_discover_auto := valid.AutoDiscoverAutoMode + auto_discover_enabled := valid.AutoDiscoverEnabledMode + auto_discover_disabled := valid.AutoDiscoverDisabledMode + random_string := valid.AutoDiscoverMode("random_string") + cases := []struct { + description string + input raw.AutoDiscover + errContains *string + }{ + { + description: "nothing set", + input: raw.AutoDiscover{}, + errContains: nil, + }, + { + description: "mode set to auto", + input: raw.AutoDiscover{ + Mode: &auto_discover_auto, + }, + errContains: nil, + }, + { + description: "mode set to disabled", + input: raw.AutoDiscover{ + Mode: &auto_discover_disabled, + }, + errContains: nil, + }, + { + description: "mode set to enabled", + input: raw.AutoDiscover{ + Mode: &auto_discover_enabled, + }, + errContains: nil, + }, + { + description: "mode set to random string", + input: raw.AutoDiscover{ + Mode: &random_string, + }, + errContains: String("valid value"), + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + if c.errContains == nil { + Ok(t, c.input.Validate()) + } else { + ErrContains(t, *c.errContains, c.input.Validate()) + } + }) + } +} + +func TestAutoDiscover_ToValid(t *testing.T) { + auto_discover_enabled := valid.AutoDiscoverEnabledMode + cases := []struct { + description string + input raw.AutoDiscover + exp *valid.AutoDiscover + }{ + { + description: "nothing set", + input: raw.AutoDiscover{}, + exp: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverAutoMode, + }, + }, + { + description: "value set", + input: raw.AutoDiscover{ + Mode: &auto_discover_enabled, + }, + exp: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverEnabledMode, + }, + }, + } + for _, c := range cases { + t.Run(c.description, func(t *testing.T) { + Equals(t, c.exp, c.input.ToValid()) + }) + } +} diff --git a/server/core/config/raw/repo_cfg.go b/server/core/config/raw/repo_cfg.go index eb511b04aa..53349fe3f3 100644 --- a/server/core/config/raw/repo_cfg.go +++ b/server/core/config/raw/repo_cfg.go @@ -19,6 +19,7 @@ type RepoCfg struct { Projects []Project `yaml:"projects,omitempty"` Workflows map[string]Workflow `yaml:"workflows,omitempty"` PolicySets PolicySets `yaml:"policies,omitempty"` + AutoDiscover *AutoDiscover `yaml:"autodiscover,omitempty"` Automerge *bool `yaml:"automerge,omitempty"` ParallelApply *bool `yaml:"parallel_apply,omitempty"` ParallelPlan *bool `yaml:"parallel_plan,omitempty"` @@ -71,10 +72,16 @@ func (r RepoCfg) ToValid() valid.RepoCfg { abortOnExcecutionOrderFail = *r.AbortOnExcecutionOrderFail } + autoDiscover := DefaultAutoDiscover() + if r.AutoDiscover != nil { + autoDiscover = r.AutoDiscover.ToValid() + } + return valid.RepoCfg{ Version: *r.Version, Projects: validProjects, Workflows: validWorkflows, + AutoDiscover: autoDiscover, Automerge: automerge, ParallelApply: parallelApply, ParallelPlan: parallelPlan, diff --git a/server/core/config/raw/repo_cfg_test.go b/server/core/config/raw/repo_cfg_test.go index 7b11655c13..563fc3b8d9 100644 --- a/server/core/config/raw/repo_cfg_test.go +++ b/server/core/config/raw/repo_cfg_test.go @@ -11,6 +11,7 @@ import ( ) func TestConfig_UnmarshalYAML(t *testing.T) { + auto_discover_enabled := valid.AutoDiscoverEnabledMode cases := []struct { description string input string @@ -128,6 +129,8 @@ version: 3 automerge: true parallel_apply: true parallel_plan: false +autodiscover: + mode: enabled projects: - dir: mydir workspace: myworkspace @@ -150,6 +153,7 @@ allowed_regexp_prefixes: - staging/`, exp: raw.RepoCfg{ Version: Int(3), + AutoDiscover: &raw.AutoDiscover{Mode: &auto_discover_enabled}, Automerge: Bool(true), ParallelApply: Bool(true), ParallelPlan: Bool(false), @@ -232,6 +236,7 @@ func TestConfig_Validate(t *testing.T) { } func TestConfig_ToValid(t *testing.T) { + auto_discover_enabled := valid.AutoDiscoverEnabledMode cases := []struct { description string input raw.RepoCfg @@ -241,25 +246,28 @@ func TestConfig_ToValid(t *testing.T) { description: "nothing set", input: raw.RepoCfg{Version: Int(2)}, exp: valid.RepoCfg{ - Version: 2, - Workflows: make(map[string]valid.Workflow), + Version: 2, + AutoDiscover: raw.DefaultAutoDiscover(), + Workflows: make(map[string]valid.Workflow), }, }, { description: "set to empty", input: raw.RepoCfg{ - Version: Int(2), - Workflows: map[string]raw.Workflow{}, - Projects: []raw.Project{}, + Version: Int(2), + AutoDiscover: &raw.AutoDiscover{}, + Workflows: map[string]raw.Workflow{}, + Projects: []raw.Project{}, }, exp: valid.RepoCfg{ - Version: 2, - Workflows: map[string]valid.Workflow{}, - Projects: nil, + Version: 2, + AutoDiscover: raw.DefaultAutoDiscover(), + Workflows: map[string]valid.Workflow{}, + Projects: nil, }, }, { - description: "automerge, parallel_apply and abort_on_execution_order_fail omitted", + description: "automerge, parallel_apply, abort_on_execution_order_fail omitted", input: raw.RepoCfg{ Version: Int(2), }, @@ -268,11 +276,12 @@ func TestConfig_ToValid(t *testing.T) { Automerge: nil, ParallelApply: nil, AbortOnExcecutionOrderFail: false, + AutoDiscover: raw.DefaultAutoDiscover(), Workflows: map[string]valid.Workflow{}, }, }, { - description: "automerge, parallel_apply and abort_on_execution_order_fail true", + description: "automerge, parallel_apply, abort_on_execution_order_fail true", input: raw.RepoCfg{ Version: Int(2), Automerge: Bool(true), @@ -284,11 +293,12 @@ func TestConfig_ToValid(t *testing.T) { Automerge: Bool(true), ParallelApply: Bool(true), AbortOnExcecutionOrderFail: true, + AutoDiscover: raw.DefaultAutoDiscover(), Workflows: map[string]valid.Workflow{}, }, }, { - description: "automerge, parallel_apply and abort_on_execution_order_fail false", + description: "automerge, parallel_apply, abort_on_execution_order_fail false", input: raw.RepoCfg{ Version: Int(2), Automerge: Bool(false), @@ -300,9 +310,38 @@ func TestConfig_ToValid(t *testing.T) { Automerge: Bool(false), ParallelApply: Bool(false), AbortOnExcecutionOrderFail: false, + AutoDiscover: raw.DefaultAutoDiscover(), Workflows: map[string]valid.Workflow{}, }, }, + { + description: "autodiscovery omitted", + input: raw.RepoCfg{ + Version: Int(2), + AutoDiscover: nil, + }, + exp: valid.RepoCfg{ + Version: 2, + AutoDiscover: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverAutoMode, + }, + Workflows: map[string]valid.Workflow{}, + }, + }, + { + description: "autodiscovery included", + input: raw.RepoCfg{ + Version: Int(2), + AutoDiscover: &raw.AutoDiscover{Mode: &auto_discover_enabled}, + }, + exp: valid.RepoCfg{ + Version: 2, + AutoDiscover: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverEnabledMode, + }, + Workflows: map[string]valid.Workflow{}, + }, + }, { description: "only plan stage set", input: raw.RepoCfg{ @@ -331,6 +370,7 @@ func TestConfig_ToValid(t *testing.T) { StateRm: valid.DefaultStateRmStage, }, }, + AutoDiscover: raw.DefaultAutoDiscover(), }, }, { @@ -339,6 +379,9 @@ func TestConfig_ToValid(t *testing.T) { Version: Int(2), Automerge: Bool(true), ParallelApply: Bool(true), + AutoDiscover: &raw.AutoDiscover{ + Mode: &auto_discover_enabled, + }, Workflows: map[string]raw.Workflow{ "myworkflow": { Apply: &raw.Stage{ @@ -388,6 +431,9 @@ func TestConfig_ToValid(t *testing.T) { Version: 2, Automerge: Bool(true), ParallelApply: Bool(true), + AutoDiscover: &valid.AutoDiscover{ + Mode: valid.AutoDiscoverEnabledMode, + }, Workflows: map[string]valid.Workflow{ "myworkflow": { Name: "myworkflow", diff --git a/server/core/config/valid/autodiscover.go b/server/core/config/valid/autodiscover.go new file mode 100644 index 0000000000..c131c3bffe --- /dev/null +++ b/server/core/config/valid/autodiscover.go @@ -0,0 +1,14 @@ +package valid + +// AutoDiscoverMode enum +type AutoDiscoverMode string + +const ( + AutoDiscoverEnabledMode AutoDiscoverMode = "enabled" + AutoDiscoverDisabledMode AutoDiscoverMode = "disabled" + AutoDiscoverAutoMode AutoDiscoverMode = "auto" +) + +type AutoDiscover struct { + Mode AutoDiscoverMode +} diff --git a/server/core/config/valid/repo_cfg.go b/server/core/config/valid/repo_cfg.go index fe441f4d05..712e96d883 100644 --- a/server/core/config/valid/repo_cfg.go +++ b/server/core/config/valid/repo_cfg.go @@ -19,6 +19,7 @@ type RepoCfg struct { Workflows map[string]Workflow PolicySets PolicySets Automerge *bool + AutoDiscover *AutoDiscover ParallelApply *bool ParallelPlan *bool ParallelPolicyCheck *bool @@ -91,6 +92,15 @@ func isRegexAllowed(name string, allowedRegexpPrefixes []string) bool { return false } +func (r RepoCfg) AutoDiscoverEnabled() bool { + if r.AutoDiscover == nil || r.AutoDiscover.Mode == AutoDiscoverAutoMode { + // Autodiscover is enabled by default when no projects are defined + return len(r.Projects) == 0 + } + + return r.AutoDiscover.Mode == AutoDiscoverEnabledMode +} + // 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 diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index 2347c9072a..3726d2aa77 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -18,6 +18,7 @@ import ( "github.com/runatlantis/atlantis/server/core/config" "github.com/runatlantis/atlantis/server/events/command" + "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/events/vcs" ) @@ -349,18 +350,23 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex return nil, errors.Wrapf(err, "parsing %s", repoCfgFile) } ctx.Log.Info("successfully parsed remote %s file", repoCfgFile) - if len(repoCfg.Projects) > 0 { - matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "", nil) - if err != nil { - return nil, err - } - ctx.Log.Info("%d projects are changed on MR %q based on their when_modified config", len(matchingProjects), ctx.Pull.Num) - if len(matchingProjects) == 0 { - ctx.Log.Info("skipping repo clone since no project was modified") - return []command.ProjectContext{}, nil + // If auto_discovery is enabled, we never want to skip cloning + if !repoCfg.AutoDiscoverEnabled() { + if len(repoCfg.Projects) > 0 { + matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "", nil) + if err != nil { + return nil, err + } + ctx.Log.Info("%d projects are changed on MR %q based on their when_modified config", len(matchingProjects), ctx.Pull.Num) + if len(matchingProjects) == 0 { + ctx.Log.Info("skipping repo clone since no project was modified") + return []command.ProjectContext{}, nil + } + } else { + ctx.Log.Info("no projects are defined in %s. Will resume automatic detection", repoCfgFile) } } else { - ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", repoCfgFile) + ctx.Log.Info("automatic project discovery enabled. Will resume automatic detection") } // NOTE: We discard this work here and end up doing it again after // cloning to ensure all the return values are set properly with @@ -454,17 +460,39 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex p.TerraformExecutor, )...) } - } else { + } + + if repoCfg.AutoDiscoverEnabled() { // If there is no config file or it specified no projects, then we'll plan each project that // our algorithm determines was modified. if hasRepoCfg { - ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", repoCfgFile) + if len(repoCfg.Projects) == 0 { + ctx.Log.Info("no projects are defined in %s. Will resume automatic detection", repoCfgFile) + } else { + ctx.Log.Info("automatic project discovery enabled. Will resume automatic detection") + } } else { ctx.Log.Info("found no %s file", repoCfgFile) } // build a module index for projects that are explicitly included - modifiedProjects := p.ProjectFinder.DetermineProjects(ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir, p.AutoplanFileList, moduleInfo) - ctx.Log.Info("automatically determined that there were %d projects modified in this pull request: %s", len(modifiedProjects), modifiedProjects) + allModifiedProjects := p.ProjectFinder.DetermineProjects(ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir, p.AutoplanFileList, moduleInfo) + // If a project is already manually configured with the same dir as a discovered project, the manually configured project should take precedence + modifiedProjects := make([]models.Project, 0) + configuredProjDirs := make(map[string]bool) + // We compare against all configured projects instead of projects which match the modified files in case a + // project is being specifically excluded (ex: when_modified doesn't match). We don't want to accidentally + // "discover" it again. + for _, configProj := range repoCfg.Projects { + // Clean the path to make sure ./rel_path is equivalent to rel_path, etc + configuredProjDirs[filepath.Clean(configProj.Dir)] = true + } + for _, mp := range allModifiedProjects { + _, dirExists := configuredProjDirs[filepath.Clean(mp.Path)] + if !dirExists { + modifiedProjects = append(modifiedProjects, mp) + } + } + ctx.Log.Info("automatically determined that there were %d additional projects modified in this pull request: %s", len(modifiedProjects), modifiedProjects) for _, mp := range modifiedProjects { ctx.Log.Debug("determining config for project at dir: %q", mp.Path) pWorkspace, err := p.ProjectFinder.DetermineWorkspaceFromHCL(ctx.Log, repoDir) diff --git a/server/events/project_command_builder_test.go b/server/events/project_command_builder_test.go index 6a3e73798d..c9b3b4be3e 100644 --- a/server/events/project_command_builder_test.go +++ b/server/events/project_command_builder_test.go @@ -956,6 +956,66 @@ projects: }, }, }, + "follow autodiscover enabled config": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: `version: 3 +autodiscover: + mode: enabled +projects: +- name: project1-custom-name + dir: project1`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "project1-custom-name", + RepoRelDir: "project1", + Workspace: "default", + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + }, + }, + }, + "autodiscover enabled but project excluded by empty when_modified": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + "project3": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: `version: 3 +autodiscover: + mode: enabled +projects: +- dir: project1 + autoplan: + when_modified: []`, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + }, + }, + }, } logger := logging.NewNoopLogger(t) @@ -1523,6 +1583,17 @@ parallel_plan: true`, ExpectedClones: Once(), ModifiedFiles: []string{"README.md"}, }, + { + AtlantisYAML: ` +version: 3 +autodiscover: + mode: enabled +projects: +- dir: dir1`, + ExpectedCtxs: 0, + ExpectedClones: Once(), + ModifiedFiles: []string{"dir2/main.tf"}, + }, } userConfig := defaultUserConfig From d17665fee911a91415a216f918eec3db1e28b078 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 01:17:42 +0000 Subject: [PATCH 5/8] fix(deps): update module go.etcd.io/bbolt to v1.3.8 in go.mod (#3901) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0a7c2546f9..d8baa2273a 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/urfave/negroni/v3 v3.0.0 github.com/warrensbox/terraform-switcher v0.1.1-0.20221027055942-201c8e92e997 github.com/xanzy/go-gitlab v0.93.2 - go.etcd.io/bbolt v1.3.7 + go.etcd.io/bbolt v1.3.8 go.uber.org/zap v1.26.0 golang.org/x/term v0.13.0 golang.org/x/text v0.13.0 diff --git a/go.sum b/go.sum index beffc5bfcf..e75bd567d6 100644 --- a/go.sum +++ b/go.sum @@ -467,8 +467,8 @@ github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0= github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= From febed33c49fe76e3b0f01a6acf17bdb633cf8a39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 04:00:16 +0000 Subject: [PATCH 6/8] fix(deps): update module github.com/google/uuid to v1.4.0 in go.mod (#3902) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d8baa2273a..fce7e13ef8 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/go-github/v54 v54.0.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/google/uuid v1.3.1 + github.com/google/uuid v1.4.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/go-getter/v2 v2.2.1 diff --git a/go.sum b/go.sum index e75bd567d6..23de6a0fb4 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= From 3411a2c557a05c8804059d000193460ce5ae25e0 Mon Sep 17 00:00:00 2001 From: CreatureKing Date: Fri, 27 Oct 2023 19:13:50 -0400 Subject: [PATCH 7/8] fix: Minor doc fixes --- runatlantis.io/docs/autodiscover.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/runatlantis.io/docs/autodiscover.md b/runatlantis.io/docs/autodiscover.md index 089d4161da..92acccc94c 100644 --- a/runatlantis.io/docs/autodiscover.md +++ b/runatlantis.io/docs/autodiscover.md @@ -18,9 +18,9 @@ The default mode of AutoDiscover is "auto". This is equivalent to the below sett mode: auto ``` 1. Server Flags -``` -atlantis server --autodiscover-mode=auto -``` + ``` + atlantis server --autodiscover-mode=auto + ``` ### Disabling auto discover unconditionally 1. In the server repo config file: @@ -36,9 +36,9 @@ atlantis server --autodiscover-mode=auto mode: disabled ``` 1. Server Flags -``` -atlantis server --autodiscover-mode=disabled -``` + ``` + atlantis server --autodiscover-mode=disabled + ``` ### Enabling auto discover unconditionally 1. In the server repo config file: @@ -52,8 +52,8 @@ atlantis server --autodiscover-mode=disabled version: 3 autodiscover: mode: enabled - + ``` 1. Server Flags -``` -atlantis server --autodiscover-mode=enabled -``` \ No newline at end of file + ``` + atlantis server --autodiscover-mode=enabled + ``` From 23751661b98003083a1974feb3c8bc08b76212ad Mon Sep 17 00:00:00 2001 From: CreatureKing Date: Thu, 2 Nov 2023 10:56:20 -0400 Subject: [PATCH 8/8] fix: Small fixes to docs/indent/tests --- runatlantis.io/docs/autodiscover.md | 59 --------------------- runatlantis.io/docs/server-configuration.md | 16 ++++++ server/core/config/parser_validator_test.go | 6 +-- server/core/config/valid/global_cfg_test.go | 7 --- 4 files changed, 19 insertions(+), 69 deletions(-) delete mode 100644 runatlantis.io/docs/autodiscover.md diff --git a/runatlantis.io/docs/autodiscover.md b/runatlantis.io/docs/autodiscover.md deleted file mode 100644 index 92acccc94c..0000000000 --- a/runatlantis.io/docs/autodiscover.md +++ /dev/null @@ -1,59 +0,0 @@ -# Auto Discover -By default, Atlantis will auto discover projects in repository when there are no projects explicitly configured (this is called auto mode). -This feature can be configured to always be disabled (never try to discover projects) or always be enabled (always try to discover projects). - -## Configuration -### Default auto discover configuration -The default mode of AutoDiscover is "auto". This is equivalent to the below settings: -1. In the server repo config file: - ```yaml - repo: - autodiscover: - mode: auto - ``` -1. In the repo `atlantis.yaml` file: - ```yaml - version: 3 - autodiscover: - mode: auto - ``` -1. Server Flags - ``` - atlantis server --autodiscover-mode=auto - ``` - -### Disabling auto discover unconditionally -1. In the server repo config file: - ```yaml - repo: - autodiscover: - mode: disabled - ``` -1. In the repo `atlantis.yaml` file: - ```yaml - version: 3 - autodiscover: - mode: disabled - ``` -1. Server Flags - ``` - atlantis server --autodiscover-mode=disabled - ``` - -### Enabling auto discover unconditionally -1. In the server repo config file: - ```yaml - repo: - autodiscover: - mode: enabled - ``` -1. In the repo `atlantis.yaml` file: - ```yaml - version: 3 - autodiscover: - mode: enabled - ``` -1. Server Flags - ``` - atlantis server --autodiscover-mode=enabled - ``` diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md index f87ec83144..e0f890615f 100644 --- a/runatlantis.io/docs/server-configuration.md +++ b/runatlantis.io/docs/server-configuration.md @@ -106,6 +106,22 @@ Values are chosen in this order: * If a load balancer with a non http/https port (not the one defined in the `--port` flag) is used, update the URL to include the port like in the example above. * This URL is used as the `details` link next to each atlantis job to view the job's logs. +### `--autodiscover-mode` + ```bash + atlantis server --autodiscover-mode="" + # or + ATLANTIS_AUTODISCOVER_MODE="" + ``` + Sets auto discover mode, default is "auto". When set to "auto", projects in a repo will be discovered by + Atlantis when there are no projects configured in the repo config. If one or more projects are defined + in the repo config then auto discovery will be completely disabled. + + When set to "enabled" projects will be discovered unconditionally. If an auto discovered project is already + defined in the projects section of the repo config, the project from the repo config will take precedence over + the auto discovered project. + + When set to "disabled" projects will never be discovered, even if there are no projects configured in the repo config. + ### `--automerge` ```bash atlantis server --automerge diff --git a/server/core/config/parser_validator_test.go b/server/core/config/parser_validator_test.go index 3812754b1c..3b269695da 100644 --- a/server/core/config/parser_validator_test.go +++ b/server/core/config/parser_validator_test.go @@ -1751,9 +1751,9 @@ func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) { "apply_requirements": ["mergeable", "approved"], "allowed_overrides": ["workflow", "apply_requirements"], "allow_custom_workflows": true, - "autodiscover": { - "mode": "enabled" - } + "autodiscover": { + "mode": "enabled" + } }, { "id": "github.com/owner/repo" diff --git a/server/core/config/valid/global_cfg_test.go b/server/core/config/valid/global_cfg_test.go index 1bd45b635c..f60c07caec 100644 --- a/server/core/config/valid/global_cfg_test.go +++ b/server/core/config/valid/global_cfg_test.go @@ -182,13 +182,6 @@ func TestNewGlobalCfg(t *testing.T) { unDivergedReq: true, policyCheckEnabled: false, }, - { - allowRepoCfg: true, - approvedReq: true, - mergeableReq: true, - unDivergedReq: true, - policyCheckEnabled: false, - }, { allowRepoCfg: true, approvedReq: true,