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"`