From 76c482b83a68a81a887f2fe54e6d6d1534444af5 Mon Sep 17 00:00:00 2001 From: Ross Strickland Date: Fri, 7 Jul 2023 17:33:21 -0500 Subject: [PATCH] feat: global repo params (#3379) --- cmd/server.go | 10 + cmd/server_test.go | 2 + runatlantis.io/docs/automerging.md | 3 +- runatlantis.io/docs/server-configuration.md | 16 ++ .../events/events_controller_e2e_test.go | 3 + server/core/config/raw/repo_cfg.go | 32 +-- server/core/config/raw/repo_cfg_test.go | 20 +- server/core/config/valid/repo_cfg.go | 8 +- server/events/automerger.go | 14 +- server/events/project_command_builder.go | 73 ++++-- .../project_command_builder_internal_test.go | 12 + server/events/project_command_builder_test.go | 247 +++++++++++++++--- server/server.go | 3 + server/user_config.go | 2 + 14 files changed, 332 insertions(+), 113 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index 0e3aba366..869d46f3f 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -55,6 +55,8 @@ const ( AllowRepoConfigFlag = "allow-repo-config" AtlantisURLFlag = "atlantis-url" AutomergeFlag = "automerge" + ParallelPlanFlag = "parallel-plan" + ParallelApplyFlag = "parallel-apply" AutoplanModules = "autoplan-modules" AutoplanModulesFromProjects = "autoplan-modules-from-projects" AutoplanFileListFlag = "autoplan-file-list" @@ -468,6 +470,14 @@ var boolFlags = map[string]boolFlag{ "VCS support is limited to: GitHub.", defaultValue: false, }, + ParallelPlanFlag: { + description: "Run plan operations in parallel.", + defaultValue: false, + }, + ParallelApplyFlag: { + description: "Run apply operations in parallel.", + defaultValue: false, + }, QuietPolicyChecks: { description: "Exclude policy check comments from pull requests unless there's an actual error from conftest. This also excludes warnings.", defaultValue: false, diff --git a/cmd/server_test.go b/cmd/server_test.go index c8d64ef09..a597fced7 100644 --- a/cmd/server_test.go +++ b/cmd/server_test.go @@ -94,6 +94,8 @@ var testFlags = map[string]interface{}{ AllowDraftPRs: true, PortFlag: 8181, ParallelPoolSize: 100, + ParallelPlanFlag: true, + ParallelApplyFlag: true, RepoAllowlistFlag: "github.com/runatlantis/atlantis", RequireApprovalFlag: true, RequireMergeableFlag: true, diff --git a/runatlantis.io/docs/automerging.md b/runatlantis.io/docs/automerging.md index b0f4cdfe6..9cb5b6003 100644 --- a/runatlantis.io/docs/automerging.md +++ b/runatlantis.io/docs/automerging.md @@ -7,8 +7,7 @@ been successfully applied. ## How To Enable Automerging can be enabled either by: -1. Passing the `--automerge` flag to `atlantis server`. This will cause all - pull requests to be automerged and any repo config will be ignored. +1. Passing the `--automerge` flag to `atlantis server`. This sets the parameter globally; however, explicit declaration in the repo config will be respected and take priority. 1. Setting `automerge: true` in the repo's `atlantis.yaml` file: ```yaml version: 3 diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md index 96be0a62c..14c5710cd 100644 --- a/runatlantis.io/docs/server-configuration.md +++ b/runatlantis.io/docs/server-configuration.md @@ -669,6 +669,22 @@ This is useful when you have many projects and want to keep the pull request cle ``` Max size of the wait group that runs parallel plans and applies (if enabled). Defaults to `15` +### `--parallel-plan` + ```bash + atlantis server --parallel-plan + # or + ATLANTIS_PARALLEL_PLAN=true + ``` + Whether to run plan operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.html#run-plans-and-applies-in-parallel) takes precidence. + +### `--parallel-apply` + ```bash + atlantis server --parallel-apply + # or + ATLANTIS_PARALLEL_APPLY=true + ``` + Whether to run apply operations in parallel. Defaults to `false`. Explicit declaration in [repo config](repo-level-atlantis-yaml.html#run-plans-and-applies-in-parallel) takes precidence. + ### `--port` ```bash atlantis server --port=4141 diff --git a/server/controllers/events/events_controller_e2e_test.go b/server/controllers/events/events_controller_e2e_test.go index d489c1079..2481797f9 100644 --- a/server/controllers/events/events_controller_e2e_test.go +++ b/server/controllers/events/events_controller_e2e_test.go @@ -1312,6 +1312,9 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers commentParser, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, diff --git a/server/core/config/raw/repo_cfg.go b/server/core/config/raw/repo_cfg.go index b3d184c28..eb511b04a 100644 --- a/server/core/config/raw/repo_cfg.go +++ b/server/core/config/raw/repo_cfg.go @@ -7,21 +7,6 @@ import ( "github.com/runatlantis/atlantis/server/core/config/valid" ) -// DefaultAutomerge is the default setting for automerge. -const DefaultAutomerge = false - -// DefaultParallelApply is the default setting for parallel apply -const DefaultParallelApply = false - -// DefaultParallelPlan is the default setting for parallel plan -const DefaultParallelPlan = false - -// DefaultParallelPolicyCheck is the default setting for parallel plan -const DefaultParallelPolicyCheck = false - -// DefaultDeleteSourceBranchOnMerge being false is the default setting whether or not to remove a source branch on merge -const DefaultDeleteSourceBranchOnMerge = false - // DefaultEmojiReaction is the default emoji reaction for repos const DefaultEmojiReaction = "" @@ -72,20 +57,9 @@ func (r RepoCfg) ToValid() valid.RepoCfg { validProjects = append(validProjects, p.ToValid()) } - automerge := DefaultAutomerge - if r.Automerge != nil { - automerge = *r.Automerge - } - - parallelApply := DefaultParallelApply - if r.ParallelApply != nil { - parallelApply = *r.ParallelApply - } - - parallelPlan := DefaultParallelPlan - if r.ParallelPlan != nil { - parallelPlan = *r.ParallelPlan - } + automerge := r.Automerge + parallelApply := r.ParallelApply + parallelPlan := r.ParallelPlan emojiReaction := DefaultEmojiReaction if r.EmojiReaction != nil { diff --git a/server/core/config/raw/repo_cfg_test.go b/server/core/config/raw/repo_cfg_test.go index 7c138053f..178485f52 100644 --- a/server/core/config/raw/repo_cfg_test.go +++ b/server/core/config/raw/repo_cfg_test.go @@ -265,8 +265,8 @@ func TestConfig_ToValid(t *testing.T) { }, exp: valid.RepoCfg{ Version: 2, - Automerge: false, - ParallelApply: false, + Automerge: nil, + ParallelApply: nil, AbortOnExcecutionOrderFail: false, Workflows: map[string]valid.Workflow{}, }, @@ -281,8 +281,8 @@ func TestConfig_ToValid(t *testing.T) { }, exp: valid.RepoCfg{ Version: 2, - Automerge: true, - ParallelApply: true, + Automerge: Bool(true), + ParallelApply: Bool(true), AbortOnExcecutionOrderFail: true, Workflows: map[string]valid.Workflow{}, }, @@ -297,8 +297,8 @@ func TestConfig_ToValid(t *testing.T) { }, exp: valid.RepoCfg{ Version: 2, - Automerge: false, - ParallelApply: false, + Automerge: Bool(false), + ParallelApply: Bool(false), AbortOnExcecutionOrderFail: false, Workflows: map[string]valid.Workflow{}, }, @@ -319,8 +319,8 @@ func TestConfig_ToValid(t *testing.T) { }, exp: valid.RepoCfg{ Version: 2, - Automerge: false, - ParallelApply: false, + Automerge: nil, + ParallelApply: nil, Workflows: map[string]valid.Workflow{ "myworkflow": { Name: "myworkflow", @@ -386,8 +386,8 @@ func TestConfig_ToValid(t *testing.T) { }, exp: valid.RepoCfg{ Version: 2, - Automerge: true, - ParallelApply: true, + Automerge: Bool(true), + ParallelApply: Bool(true), Workflows: map[string]valid.Workflow{ "myworkflow": { Name: "myworkflow", diff --git a/server/core/config/valid/repo_cfg.go b/server/core/config/valid/repo_cfg.go index b2833a1b2..7f6f28f34 100644 --- a/server/core/config/valid/repo_cfg.go +++ b/server/core/config/valid/repo_cfg.go @@ -18,10 +18,10 @@ type RepoCfg struct { Projects []Project Workflows map[string]Workflow PolicySets PolicySets - Automerge bool - ParallelApply bool - ParallelPlan bool - ParallelPolicyCheck bool + Automerge *bool + ParallelApply *bool + ParallelPlan *bool + ParallelPolicyCheck *bool DeleteSourceBranchOnMerge *bool RepoLocking *bool EmojiReaction string diff --git a/server/events/automerger.go b/server/events/automerger.go index 2dc55dacd..ee7bc9f53 100644 --- a/server/events/automerger.go +++ b/server/events/automerger.go @@ -46,10 +46,16 @@ func (c *AutoMerger) automerge(ctx *command.Context, pullStatus models.PullStatu // automergeEnabled returns true if automerging is enabled in this context. func (c *AutoMerger) automergeEnabled(projectCmds []command.ProjectContext) bool { - // If the global automerge is set, we always automerge. - return c.GlobalAutomerge || - // Otherwise we check if this repo is configured for automerging. - (len(projectCmds) > 0 && projectCmds[0].AutomergeEnabled) + // only automerge if all projects have automerge set; or if global automerge is set and there are no projects. + automerge := c.GlobalAutomerge + if len(projectCmds) > 0 { + for _, prjCmd := range projectCmds { + if !prjCmd.AutomergeEnabled { + automerge = false + } + } + } + return automerge } // deleteSourceBranchOnMergeEnabled returns true if we should delete the source branch on merge in this context. diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index 3eba0a215..355967329 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -28,12 +28,6 @@ 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 - // 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 @@ -52,6 +46,9 @@ func NewInstrumentedProjectCommandBuilder( commentBuilder CommentBuilder, skipCloneNoChanges bool, EnableRegExpCmd bool, + EnableAutoMerge bool, + EnableParallelPlan bool, + EnableParallelApply bool, AutoDetectModuleFiles string, AutoplanFileList string, RestrictFileList bool, @@ -79,6 +76,9 @@ func NewInstrumentedProjectCommandBuilder( commentBuilder, skipCloneNoChanges, EnableRegExpCmd, + EnableAutoMerge, + EnableParallelPlan, + EnableParallelApply, AutoDetectModuleFiles, AutoplanFileList, RestrictFileList, @@ -104,6 +104,9 @@ func NewProjectCommandBuilder( commentBuilder CommentBuilder, skipCloneNoChanges bool, EnableRegExpCmd bool, + EnableAutoMerge bool, + EnableParallelPlan bool, + EnableParallelApply bool, AutoDetectModuleFiles string, AutoplanFileList string, RestrictFileList bool, @@ -122,6 +125,9 @@ func NewProjectCommandBuilder( PendingPlanFinder: pendingPlanFinder, SkipCloneNoChanges: skipCloneNoChanges, EnableRegExpCmd: EnableRegExpCmd, + EnableAutoMerge: EnableAutoMerge, + EnableParallelPlan: EnableParallelPlan, + EnableParallelApply: EnableParallelApply, AutoDetectModuleFiles: AutoDetectModuleFiles, AutoplanFileList: AutoplanFileList, RestrictFileList: RestrictFileList, @@ -204,6 +210,9 @@ type DefaultProjectCommandBuilder struct { ProjectCommandContextBuilder ProjectCommandContextBuilder SkipCloneNoChanges bool EnableRegExpCmd bool + EnableAutoMerge bool + EnableParallelPlan bool + EnableParallelApply bool AutoDetectModuleFiles string AutoplanFileList string EnableDiffMarkdownFormat bool @@ -363,6 +372,23 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex } ctx.Log.Debug("moduleInfo for %s (matching %q) = %v", repoDir, p.AutoDetectModuleFiles, moduleInfo) + automerge := p.EnableAutoMerge + parallelApply := p.EnableParallelApply + parallelPlan := p.EnableParallelPlan + abortOnExcecutionOrderFail := DefaultAbortOnExcecutionOrderFail + if hasRepoCfg { + if repoCfg.Automerge != nil { + automerge = *repoCfg.Automerge + } + if repoCfg.ParallelApply != nil { + parallelApply = *repoCfg.ParallelApply + } + if repoCfg.ParallelPlan != nil { + parallelPlan = *repoCfg.ParallelPlan + } + abortOnExcecutionOrderFail = repoCfg.AbortOnExcecutionOrderFail + } + if len(repoCfg.Projects) > 0 { matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, repoDir, moduleInfo) if err != nil { @@ -382,9 +408,9 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex mergedCfg, commentFlags, repoDir, - repoCfg.Automerge, - repoCfg.ParallelApply, - repoCfg.ParallelPlan, + automerge, + parallelApply, + parallelPlan, verbose, repoCfg.AbortOnExcecutionOrderFail, p.TerraformExecutor, @@ -407,16 +433,7 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex if err != nil { return nil, errors.Wrapf(err, "looking for Terraform Cloud workspace from configuration %s", repoDir) } - automerge := DefaultAutomergeEnabled - parallelApply := DefaultParallelApplyEnabled - parallelPlan := DefaultParallelPlanEnabled - abortOnExcecutionOrderFail := DefaultAbortOnExcecutionOrderFail - if hasRepoCfg { - automerge = repoCfg.Automerge - parallelApply = repoCfg.ParallelApply - parallelPlan = repoCfg.ParallelPlan - abortOnExcecutionOrderFail = repoCfg.AbortOnExcecutionOrderFail - } + pCfg := p.GlobalCfg.DefaultProjCfg(ctx.Log, ctx.Pull.BaseRepo.ID(), mp.Path, pWorkspace) projCtxs = append(projCtxs, @@ -703,14 +720,20 @@ func (p *DefaultProjectCommandBuilder) buildProjectCommandCtx(ctx *command.Conte } var projCtxs []command.ProjectContext var projCfg valid.MergedProjectCfg - automerge := DefaultAutomergeEnabled - parallelApply := DefaultParallelApplyEnabled - parallelPlan := DefaultParallelPlanEnabled + automerge := p.EnableAutoMerge + parallelApply := p.EnableParallelApply + parallelPlan := p.EnableParallelPlan abortOnExcecutionOrderFail := DefaultAbortOnExcecutionOrderFail if repoCfgPtr != nil { - automerge = repoCfgPtr.Automerge - parallelApply = repoCfgPtr.ParallelApply - parallelPlan = repoCfgPtr.ParallelPlan + if repoCfgPtr.Automerge != nil { + automerge = *repoCfgPtr.Automerge + } + if repoCfgPtr.ParallelApply != nil { + parallelApply = *repoCfgPtr.ParallelApply + } + if repoCfgPtr.ParallelPlan != nil { + parallelPlan = *repoCfgPtr.ParallelPlan + } abortOnExcecutionOrderFail = *&repoCfgPtr.AbortOnExcecutionOrderFail } diff --git a/server/events/project_command_builder_internal_test.go b/server/events/project_command_builder_internal_test.go index 069218ae6..46487825f 100644 --- a/server/events/project_command_builder_internal_test.go +++ b/server/events/project_command_builder_internal_test.go @@ -665,6 +665,9 @@ projects: &CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -876,6 +879,9 @@ projects: &CommentParser{ExecutableName: "atlantis"}, false, true, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1121,6 +1127,9 @@ workflows: &CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1273,6 +1282,9 @@ projects: &CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, diff --git a/server/events/project_command_builder_test.go b/server/events/project_command_builder_test.go index 59bdd09af..545f559e1 100644 --- a/server/events/project_command_builder_test.go +++ b/server/events/project_command_builder_test.go @@ -161,6 +161,9 @@ projects: &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -192,19 +195,23 @@ projects: // Test building a plan and apply command for one project. func TestDefaultProjectCommandBuilder_BuildSinglePlanApplyCommand(t *testing.T) { cases := []struct { - Description string - AtlantisYAML string - Cmd events.CommentCommand - Silenced bool - ExpCommentArgs []string - ExpWorkspace string - ExpDir string - ExpProjectName string - ExpErr string - ExpApplyReqs []string - ExpParallelApply bool - ExpParallelPlan bool - ExpNoProjects bool + Description string + AtlantisYAML string + Cmd events.CommentCommand + Silenced bool + ExpCommentArgs []string + ExpWorkspace string + ExpDir string + ExpProjectName string + ExpErr string + ExpApplyReqs []string + EnableAutoMergeUserCfg bool + EnableParallelPlanUserCfg bool + EnableParallelApplyUserCfg bool + ExpAutoMerge bool + ExpParallelPlan bool + ExpParallelApply bool + ExpNoProjects bool }{ { Description: "no atlantis.yaml", @@ -407,6 +414,61 @@ projects: ExpProjectName: "myproject", ExpApplyReqs: []string{}, }, + { + Description: "atlantis.yaml with ParallelPlan/apply and Automerge not set, but set in user conf", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: ".", + Workspace: "default", + ProjectName: "myproject", + }, + AtlantisYAML: ` +version: 3 +projects: +- name: myproject + dir: . + workspace: myworkspace +`, + EnableAutoMergeUserCfg: true, + EnableParallelPlanUserCfg: true, + EnableParallelApplyUserCfg: true, + ExpAutoMerge: true, + ExpParallelPlan: true, + ExpParallelApply: true, + ExpDir: ".", + ExpWorkspace: "myworkspace", + ExpProjectName: "myproject", + ExpApplyReqs: []string{}, + }, + { + Description: "atlantis.yaml with ParallelPlan/apply and Automerge set to false, but set to true in user conf", + Cmd: events.CommentCommand{ + Name: command.Plan, + RepoRelDir: ".", + Workspace: "default", + ProjectName: "myproject", + }, + AtlantisYAML: ` +version: 3 +automerge: false +parallel_plan: false +parallel_apply: false +projects: +- name: myproject + dir: . + workspace: myworkspace +`, + EnableAutoMergeUserCfg: true, + EnableParallelPlanUserCfg: true, + EnableParallelApplyUserCfg: true, + ExpAutoMerge: false, + ExpParallelPlan: false, + ExpParallelApply: false, + ExpDir: ".", + ExpWorkspace: "myworkspace", + ExpProjectName: "myproject", + ExpApplyReqs: []string{}, + }, } logger := logging.NewNoopLogger(t) @@ -453,6 +515,9 @@ projects: &events.CommentParser{ExecutableName: "atlantis"}, false, true, + c.EnableAutoMergeUserCfg, + c.EnableParallelPlanUserCfg, + c.EnableParallelApplyUserCfg, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -489,8 +554,9 @@ projects: Equals(t, c.ExpCommentArgs, actCtx.EscapedCommentArgs) Equals(t, c.ExpProjectName, actCtx.ProjectName) Equals(t, c.ExpApplyReqs, actCtx.ApplyRequirements) - Equals(t, c.ExpParallelApply, actCtx.ParallelApplyEnabled) + Equals(t, c.ExpAutoMerge, actCtx.AutomergeEnabled) Equals(t, c.ExpParallelPlan, actCtx.ParallelPlanEnabled) + Equals(t, c.ExpParallelApply, actCtx.ParallelApplyEnabled) }) } } @@ -635,6 +701,9 @@ projects: &events.CommentParser{ExecutableName: "atlantis"}, false, true, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", true, @@ -666,18 +735,21 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands(t *testing.T) { // Since we're focused on autoplanning here, we don't validate all the // fields so the tests are more obvious and targeted. type expCtxFields struct { - ProjectName string - RepoRelDir string - Workspace string - Automerge bool - ParallelPlanEnabled bool - ParallelApplyEnabled bool + ProjectName string + RepoRelDir string + Workspace string + Automerge bool + ExpParallelPlan bool + ExpParallelApply bool } cases := map[string]struct { - DirStructure map[string]interface{} - AtlantisYAML string - ModifiedFiles []string - Exp []expCtxFields + AutoMergeUserCfg bool + ParallelPlanEnabledUserCfg bool + ParallelApplyEnabledUserCfg bool + DirStructure map[string]interface{} + AtlantisYAML string + ModifiedFiles []string + Exp []expCtxFields }{ "no atlantis.yaml": { DirStructure: map[string]interface{}{ @@ -702,7 +774,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands(t *testing.T) { }, }, }, - "no projects in atlantis.yaml": { + "no projects in atlantis.yaml with parallel operations in atlantis.yaml": { DirStructure: map[string]interface{}{ "project1": map[string]interface{}{ "main.tf": nil, @@ -720,20 +792,93 @@ parallel_apply: true ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, Exp: []expCtxFields{ { - ProjectName: "", - RepoRelDir: "project1", - Workspace: "default", - Automerge: true, - ParallelApplyEnabled: true, - ParallelPlanEnabled: true, + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, }, { - ProjectName: "", - RepoRelDir: "project2", - Workspace: "default", - Automerge: true, - ParallelApplyEnabled: true, - ParallelPlanEnabled: true, + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + }, + }, + "no projects in atlantis.yaml with parallel operations and automerge not in atlantis.yaml, but in user conf": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: ` +version: 3 +`, + AutoMergeUserCfg: true, + ParallelPlanEnabledUserCfg: true, + ParallelApplyEnabledUserCfg: true, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: true, + ExpParallelApply: true, + ExpParallelPlan: true, + }, + }, + }, + "no projects in atlantis.yaml with parallel operations and automerge set to false in atlantis.yaml and true in user conf": { + DirStructure: map[string]interface{}{ + "project1": map[string]interface{}{ + "main.tf": nil, + }, + "project2": map[string]interface{}{ + "main.tf": nil, + }, + }, + AtlantisYAML: ` +version: 3 +automerge: false +parallel_plan: false +parallel_apply: false +`, + AutoMergeUserCfg: true, + ParallelPlanEnabledUserCfg: true, + ParallelApplyEnabledUserCfg: true, + ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"}, + Exp: []expCtxFields{ + { + ProjectName: "", + RepoRelDir: "project1", + Workspace: "default", + Automerge: false, + ExpParallelApply: false, + ExpParallelPlan: false, + }, + { + ProjectName: "", + RepoRelDir: "project2", + Workspace: "default", + Automerge: false, + ExpParallelApply: false, + ExpParallelPlan: false, }, }, }, @@ -821,6 +966,9 @@ projects: &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + c.ParallelPlanEnabledUserCfg, + c.ParallelApplyEnabledUserCfg, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -850,8 +998,8 @@ projects: Equals(t, expCtx.ProjectName, actCtx.ProjectName) Equals(t, expCtx.RepoRelDir, actCtx.RepoRelDir) Equals(t, expCtx.Workspace, actCtx.Workspace) - Equals(t, expCtx.ParallelPlanEnabled, actCtx.ParallelPlanEnabled) - Equals(t, expCtx.ParallelApplyEnabled, actCtx.ParallelApplyEnabled) + Equals(t, expCtx.ExpParallelPlan, actCtx.ParallelPlanEnabled) + Equals(t, expCtx.ExpParallelApply, actCtx.ParallelApplyEnabled) } }) } @@ -920,6 +1068,9 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) { &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1010,6 +1161,9 @@ projects: &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1095,6 +1249,9 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) { &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1262,6 +1419,9 @@ projects: &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1356,6 +1516,9 @@ parallel_plan: true`, &events.CommentParser{ExecutableName: "atlantis"}, true, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1421,6 +1584,9 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, @@ -1508,6 +1674,9 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) { &events.CommentParser{ExecutableName: "atlantis"}, false, false, + false, + false, + false, "", "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl", false, diff --git a/server/server.go b/server/server.go index 3c51d358e..ac0277402 100644 --- a/server/server.go +++ b/server/server.go @@ -584,6 +584,9 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) { commentParser, userConfig.SkipCloneNoChanges, userConfig.EnableRegExpCmd, + userConfig.Automerge, + userConfig.ParallelPlan, + userConfig.ParallelApply, userConfig.AutoplanModulesFromProjects, userConfig.AutoplanFileList, userConfig.RestrictFileList, diff --git a/server/user_config.go b/server/user_config.go index c37e321f7..209482049 100644 --- a/server/user_config.go +++ b/server/user_config.go @@ -64,6 +64,8 @@ type UserConfig struct { LogLevel string `mapstructure:"log-level"` MarkdownTemplateOverridesDir string `mapstructure:"markdown-template-overrides-dir"` ParallelPoolSize int `mapstructure:"parallel-pool-size"` + ParallelPlan bool `mapstructure:"parallel-plan"` + ParallelApply bool `mapstructure:"parallel-apply"` StatsNamespace string `mapstructure:"stats-namespace"` PlanDrafts bool `mapstructure:"allow-draft-prs"` Port int `mapstructure:"port"`