feat: add autodiscover enabled feature (#3895)

* add flag to allow the user disable the autodiscover

* add global config and doc

* feat: Implement autodiscover.mode

* fix: Minor doc fixes

* fix: Small fixes to docs/indent/tests

* fix: Line length, quoting, function comments

* fix: Add a few more tests and remove newlines

* fix: Always camel case never snake

---------

Co-authored-by: Marcelo Medeiros <m.medeiros@carepay.com>
Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
Co-authored-by: PePe Amengual <jose.amengual@gmail.com>
This commit is contained in:
jskrill
2023-11-29 18:43:53 -05:00
committed by GitHub
parent 6ff0e2f90e
commit 00aae565b2
22 changed files with 822 additions and 35 deletions

View File

@@ -1329,6 +1329,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:
mode: disabled`,
exp: valid.GlobalCfg{
Repos: []valid.Repo{
defaultCfg.Repos[0],
{
IDRegex: regexp.MustCompile(".*"),
AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverDisabledMode},
},
},
Workflows: defaultCfg.Workflows,
},
},
"no workflows key": {
input: `repos: []`,
exp: defaultCfg,
@@ -1404,6 +1420,8 @@ repos:
allowed_overrides: [plan_requirements, apply_requirements, import_requirements, workflow, delete_source_branch_on_merge]
allow_custom_workflows: true
policy_check: true
autodiscover:
mode: enabled
- id: /.*/
branch: /(master|main)/
pre_workflow_hooks:
@@ -1411,6 +1429,8 @@ repos:
post_workflow_hooks:
- run: custom workflow command
policy_check: false
autodiscover:
mode: disabled
workflows:
custom1:
plan:
@@ -1457,6 +1477,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{Mode: valid.AutoDiscoverEnabledMode},
},
{
IDRegex: regexp.MustCompile(".*"),
@@ -1464,6 +1485,7 @@ policies:
PreWorkflowHooks: preWorkflowHooks,
PostWorkflowHooks: postWorkflowHooks,
PolicyCheck: Bool(false),
AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverDisabledMode},
},
},
Workflows: map[string]valid.Workflow{
@@ -1574,6 +1596,7 @@ workflows:
RepoLocking: Bool(true),
PolicyCheck: Bool(false),
CustomPolicyCheck: Bool(false),
AutoDiscover: raw.DefaultAutoDiscover(),
},
},
Workflows: map[string]valid.Workflow{
@@ -1727,7 +1750,10 @@ func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) {
"allowed_workflows": ["custom"],
"apply_requirements": ["mergeable", "approved"],
"allowed_overrides": ["workflow", "apply_requirements"],
"allow_custom_workflows": true
"allow_custom_workflows": true,
"autodiscover": {
"mode": "enabled"
}
},
{
"id": "github.com/owner/repo"
@@ -1792,6 +1818,7 @@ func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) {
AllowedWorkflows: []string{"custom"},
AllowedOverrides: []string{"workflow", "apply_requirements"},
AllowCustomWorkflows: Bool(true),
AutoDiscover: &valid.AutoDiscover{Mode: valid.AutoDiscoverEnabledMode},
},
{
ID: "github.com/owner/repo",
@@ -1799,6 +1826,7 @@ func TestParserValidator_ParseGlobalCfgJSON(t *testing.T) {
ApplyRequirements: nil,
AllowedOverrides: nil,
AllowCustomWorkflows: nil,
AutoDiscover: nil,
},
},
Workflows: map[string]valid.Workflow{

View File

@@ -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,
}
}

View File

@@ -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) {
autoDiscoverEnabled := 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: &autoDiscoverEnabled,
},
},
}
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) {
autoDiscoverAuto := valid.AutoDiscoverAutoMode
autoDiscoverEnabled := valid.AutoDiscoverEnabledMode
autoDiscoverDisabled := valid.AutoDiscoverDisabledMode
randomString := 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: &autoDiscoverAuto,
},
errContains: nil,
},
{
description: "mode set to disabled",
input: raw.AutoDiscover{
Mode: &autoDiscoverDisabled,
},
errContains: nil,
},
{
description: "mode set to enabled",
input: raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
},
errContains: nil,
},
{
description: "mode set to random string",
input: raw.AutoDiscover{
Mode: &randomString,
},
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) {
autoDiscoverEnabled := 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: &autoDiscoverEnabled,
},
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())
})
}
}

View File

@@ -36,6 +36,7 @@ type Repo struct {
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 *AutoDiscover `yaml:"autodiscover,omitempty" json:"autodiscover,omitempty"`
}
func (g GlobalCfg) Validate() error {
@@ -211,6 +212,14 @@ func (r Repo) Validate() error {
return nil
}
autoDiscoverValid := func(value interface{}) error {
autoDiscover := value.(*AutoDiscover)
if autoDiscover != nil {
return autoDiscover.Validate()
}
return nil
}
return validation.ValidateStruct(&r,
validation.Field(&r.ID, validation.Required, validation.By(idValid)),
validation.Field(&r.Branch, validation.By(branchValid)),
@@ -221,6 +230,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)),
)
}
@@ -281,7 +291,7 @@ OuterGlobalPlanReqs:
}
// dont add policy_check step if repo have it explicitly disabled
if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && *r.PolicyCheck == false {
if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && !*r.PolicyCheck {
continue
}
mergedPlanReqs = append(mergedPlanReqs, globalReq)
@@ -295,7 +305,7 @@ OuterGlobalApplyReqs:
}
// dont add policy_check step if repo have it explicitly disabled
if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && *r.PolicyCheck == false {
if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && !*r.PolicyCheck {
continue
}
mergedApplyReqs = append(mergedApplyReqs, globalReq)
@@ -309,12 +319,17 @@ OuterGlobalImportReqs:
}
// dont add policy_check step if repo have it explicitly disabled
if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && *r.PolicyCheck == false {
if globalReq == valid.PoliciesPassedCommandReq && r.PolicyCheck != nil && !*r.PolicyCheck {
continue
}
mergedImportReqs = append(mergedImportReqs, globalReq)
}
var autoDiscover *valid.AutoDiscover
if r.AutoDiscover != nil {
autoDiscover = r.AutoDiscover.ToValid()
}
return valid.Repo{
ID: id,
IDRegex: idRegex,
@@ -333,5 +348,6 @@ OuterGlobalImportReqs:
RepoLocking: r.RepoLocking,
PolicyCheck: r.PolicyCheck,
CustomPolicyCheck: r.CustomPolicyCheck,
AutoDiscover: autoDiscover,
}
}

View File

@@ -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
}
var autoDiscover *valid.AutoDiscover
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,

View File

@@ -11,6 +11,7 @@ import (
)
func TestConfig_UnmarshalYAML(t *testing.T) {
autoDiscoverEnabled := valid.AutoDiscoverEnabledMode
cases := []struct {
description string
input string
@@ -126,6 +127,8 @@ func TestConfig_UnmarshalYAML(t *testing.T) {
input: `
version: 3
automerge: true
autodiscover:
mode: enabled
parallel_apply: true
parallel_plan: false
projects:
@@ -150,6 +153,7 @@ allowed_regexp_prefixes:
- staging/`,
exp: raw.RepoCfg{
Version: Int(3),
AutoDiscover: &raw.AutoDiscover{Mode: &autoDiscoverEnabled},
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) {
autoDiscoverEnabled := valid.AutoDiscoverEnabledMode
cases := []struct {
description string
input raw.RepoCfg
@@ -248,18 +253,20 @@ func TestConfig_ToValid(t *testing.T) {
{
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),
},
@@ -272,7 +279,7 @@ func TestConfig_ToValid(t *testing.T) {
},
},
{
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),
@@ -288,7 +295,7 @@ func TestConfig_ToValid(t *testing.T) {
},
},
{
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),
@@ -303,6 +310,30 @@ func TestConfig_ToValid(t *testing.T) {
Workflows: map[string]valid.Workflow{},
},
},
{
description: "autodiscover omitted",
input: raw.RepoCfg{
Version: Int(2),
},
exp: valid.RepoCfg{
Version: 2,
Workflows: map[string]valid.Workflow{},
},
},
{
description: "autodiscover included",
input: raw.RepoCfg{
Version: Int(2),
AutoDiscover: &raw.AutoDiscover{Mode: &autoDiscoverEnabled},
},
exp: valid.RepoCfg{
Version: 2,
AutoDiscover: &valid.AutoDiscover{
Mode: valid.AutoDiscoverEnabledMode,
},
Workflows: map[string]valid.Workflow{},
},
},
{
description: "only plan stage set",
input: raw.RepoCfg{
@@ -339,6 +370,9 @@ func TestConfig_ToValid(t *testing.T) {
Version: Int(2),
Automerge: Bool(true),
ParallelApply: Bool(true),
AutoDiscover: &raw.AutoDiscover{
Mode: &autoDiscoverEnabled,
},
Workflows: map[string]raw.Workflow{
"myworkflow": {
Apply: &raw.Stage{
@@ -388,6 +422,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",

View File

@@ -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
}

View File

@@ -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 = "autodiscover"
// 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 {
@@ -245,6 +247,7 @@ func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg {
deleteSourceBranchOnMerge := false
repoLockingKey := true
customPolicyCheck := false
autoDiscover := AutoDiscover{Mode: AutoDiscoverAutoMode}
if args.AllowRepoCfg {
allowedOverrides = []string{PlanRequirementsKey, ApplyRequirementsKey, ImportRequirementsKey, WorkflowKey, DeleteSourceBranchOnMergeKey, RepoLockingKey, PolicyCheckKey}
allowCustomWorkflows = true
@@ -269,6 +272,7 @@ func NewGlobalCfgFromArgs(args GlobalCfgArgs) GlobalCfg {
RepoLocking: &repoLockingKey,
PolicyCheck: &policyCheck,
CustomPolicyCheck: &customPolicyCheck,
AutoDiscover: &autoDiscover,
},
},
Workflows: map[string]Workflow{
@@ -305,7 +309,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, _ := g.getMatchingCfg(log, repoID)
// If repos are allowed to override certain keys then override them.
for _, key := range allowedOverrides {
@@ -407,7 +411,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, _ := g.getMatchingCfg(log, repoID)
return MergedProjectCfg{
PlanRequirements: planReqs,
ApplyRequirements: applyReqs,
@@ -426,6 +430,17 @@ func (g GlobalCfg) DefaultProjCfg(log logging.SimpleLogging, repoID string, repo
}
}
// RepoAutoDiscoverCfg returns the AutoDiscover config from the global config
// for the repo with id repoID. If no matching repo is found or there is no
// AutoDiscover config then this function returns nil.
func (g GlobalCfg) RepoAutoDiscoverCfg(repoID string) *AutoDiscover {
repo := g.MatchingRepo(repoID)
if repo != nil {
return repo.AutoDiscover
}
return nil
}
// ValidateRepoCfg validates that rCfg for repo with id repoID is valid based
// on our global config.
func (g GlobalCfg) ValidateRepoCfg(rCfg RepoCfg, repoID string) error {
@@ -528,7 +543,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"
@@ -550,6 +565,9 @@ func (g GlobalCfg) getMatchingCfg(log logging.SimpleLogging, repoID string) (pla
return fmt.Sprintf("setting %s: %s from %s", key, valStr, from)
}
// Can't use raw.DefaultAutoDiscoverMode() because of an import cycle. Should refactor to avoid that.
autoDiscover = AutoDiscover{Mode: AutoDiscoverAutoMode}
for _, key := range []string{PlanRequirementsKey, ApplyRequirementsKey, ImportRequirementsKey, WorkflowKey, AllowedOverridesKey, AllowCustomWorkflowsKey, DeleteSourceBranchOnMergeKey, RepoLockingKey, PolicyCheckKey, CustomPolicyCheckKey} {
for i, repo := range g.Repos {
if repo.IDMatches(repoID) {
@@ -604,6 +622,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.Mode)
autoDiscover = *repo.AutoDiscover
}
}
}
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/hashicorp/go-version"
"github.com/mohae/deepcopy"
"github.com/runatlantis/atlantis/server/core/config"
"github.com/runatlantis/atlantis/server/core/config/raw"
"github.com/runatlantis/atlantis/server/core/config/valid"
"github.com/runatlantis/atlantis/server/logging"
. "github.com/runatlantis/atlantis/testing"
@@ -82,6 +83,7 @@ func TestNewGlobalCfg(t *testing.T) {
RepoLocking: Bool(true),
PolicyCheck: Bool(false),
CustomPolicyCheck: Bool(false),
AutoDiscover: raw.DefaultAutoDiscover(),
},
},
Workflows: map[string]valid.Workflow{

View File

@@ -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,24 @@ func isRegexAllowed(name string, allowedRegexpPrefixes []string) bool {
return false
}
// This function returns a final true/false decision for whether AutoDiscover is enabled
// for a repo. It takes into account the defaultAutoDiscoverMode when there is no explicit
// repo config. The defaultAutoDiscoverMode param should be understood as the default
// AutoDiscover mode as may be set via CLI params or server side repo config.
func (r RepoCfg) AutoDiscoverEnabled(defaultAutoDiscoverMode AutoDiscoverMode) bool {
autoDiscoverMode := defaultAutoDiscoverMode
if r.AutoDiscover != nil {
autoDiscoverMode = r.AutoDiscover.Mode
}
if autoDiscoverMode == AutoDiscoverAutoMode {
// AutoDiscover is enabled by default when no projects are defined
return len(r.Projects) == 0
}
return autoDiscoverMode == 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

View File

@@ -216,3 +216,110 @@ func TestConfig_FindProjectsByDir(t *testing.T) {
})
}
}
func TestConfig_AutoDiscoverEnabled(t *testing.T) {
cases := []struct {
description string
repoAutoDiscover valid.AutoDiscoverMode
defaultAutoDiscover valid.AutoDiscoverMode
projects []valid.Project
expEnabled bool
}{
{
description: "repo disabled autodiscover default enabled",
repoAutoDiscover: valid.AutoDiscoverDisabledMode,
defaultAutoDiscover: valid.AutoDiscoverEnabledMode,
expEnabled: false,
},
{
description: "repo disabled autodiscover default disabled",
repoAutoDiscover: valid.AutoDiscoverDisabledMode,
defaultAutoDiscover: valid.AutoDiscoverDisabledMode,
expEnabled: false,
},
{
description: "repo enabled autodiscover default enabled",
repoAutoDiscover: valid.AutoDiscoverEnabledMode,
defaultAutoDiscover: valid.AutoDiscoverEnabledMode,
expEnabled: true,
},
{
description: "repo enabled autodiscover default disabled",
repoAutoDiscover: valid.AutoDiscoverEnabledMode,
defaultAutoDiscover: valid.AutoDiscoverDisabledMode,
expEnabled: true,
},
{
description: "repo set auto autodiscover with no projects default enabled",
repoAutoDiscover: valid.AutoDiscoverAutoMode,
defaultAutoDiscover: valid.AutoDiscoverEnabledMode,
expEnabled: true,
},
{
description: "repo set auto autodiscover with no projects default disabled",
repoAutoDiscover: valid.AutoDiscoverAutoMode,
defaultAutoDiscover: valid.AutoDiscoverDisabledMode,
expEnabled: true,
},
{
description: "repo set auto autodiscover with a project default enabled",
repoAutoDiscover: valid.AutoDiscoverAutoMode,
defaultAutoDiscover: valid.AutoDiscoverEnabledMode,
projects: []valid.Project{{}},
expEnabled: false,
},
{
description: "repo set auto autodiscover with a project default disabled",
repoAutoDiscover: valid.AutoDiscoverAutoMode,
defaultAutoDiscover: valid.AutoDiscoverDisabledMode,
projects: []valid.Project{{}},
expEnabled: false,
},
{
description: "repo unset autodiscover with no projects default enabled",
defaultAutoDiscover: valid.AutoDiscoverEnabledMode,
expEnabled: true,
},
{
description: "repo unset autodiscover with no projects default disabled",
defaultAutoDiscover: valid.AutoDiscoverDisabledMode,
expEnabled: false,
},
{
description: "repo unset autodiscover with no projects default auto",
defaultAutoDiscover: valid.AutoDiscoverAutoMode,
expEnabled: true,
},
{
description: "repo unset autodiscover with a project default enabled",
projects: []valid.Project{{}},
defaultAutoDiscover: valid.AutoDiscoverEnabledMode,
expEnabled: true,
},
{
description: "repo unset autodiscover with a project default disabled",
projects: []valid.Project{{}},
defaultAutoDiscover: valid.AutoDiscoverDisabledMode,
expEnabled: false,
},
{
description: "repo unset autodiscover with a project default auto",
projects: []valid.Project{{}},
defaultAutoDiscover: valid.AutoDiscoverAutoMode,
expEnabled: false,
},
}
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
r := valid.RepoCfg{
Projects: c.projects,
AutoDiscover: nil,
}
if c.repoAutoDiscover != "" {
r.AutoDiscover = &valid.AutoDiscover{c.repoAutoDiscover}
}
enabled := r.AutoDiscoverEnabled(c.defaultAutoDiscover)
Equals(t, c.expEnabled, enabled)
})
}
}