mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 23:48:20 +00:00
Signed-off-by: Andrew Borg <andrew.b.borg@gmail.com> Co-authored-by: PePe Amengual <2208324+jamengual@users.noreply.github.com> Co-authored-by: Simon Heather <32168619+X-Guardian@users.noreply.github.com>
1462 lines
38 KiB
Go
1462 lines
38 KiB
Go
package events
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
version "github.com/hashicorp/go-version"
|
|
. "github.com/petergtz/pegomock/v4"
|
|
"github.com/runatlantis/atlantis/server/core/config"
|
|
"github.com/runatlantis/atlantis/server/core/config/valid"
|
|
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
|
"github.com/runatlantis/atlantis/server/events/command"
|
|
"github.com/runatlantis/atlantis/server/events/models"
|
|
vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks"
|
|
"github.com/runatlantis/atlantis/server/logging"
|
|
"github.com/runatlantis/atlantis/server/metrics"
|
|
. "github.com/runatlantis/atlantis/testing"
|
|
)
|
|
|
|
// Test different permutations of global and repo config.
|
|
func TestBuildProjectCmdCtx(t *testing.T) {
|
|
logger := logging.NewNoopLogger(t)
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
emptyPolicySets := valid.PolicySets{
|
|
Version: nil,
|
|
PolicySets: []valid.PolicySet{},
|
|
}
|
|
baseRepo := models.Repo{
|
|
FullName: "owner/repo",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
},
|
|
}
|
|
pull := models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
}
|
|
cases := map[string]struct {
|
|
globalCfg string
|
|
repoCfg string
|
|
expErr string
|
|
expCtx command.ProjectContext
|
|
expPlanSteps []string
|
|
expApplySteps []string
|
|
}{
|
|
// Test that if we've set global defaults and no project config
|
|
// that the global defaults are used.
|
|
"global defaults": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- 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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{},
|
|
ApplyRequirements: []string{},
|
|
ImportRequirements: []string{},
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"init", "plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
|
|
// Test that if we've set global defaults, that they are used but the
|
|
// allowed project config values also come through.
|
|
"global defaults with repo cfg": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{},
|
|
ApplyRequirements: []string{},
|
|
ImportRequirements: []string{},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"init", "plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
|
|
// Set a global apply req that should be used.
|
|
"global requirements": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
plan_requirements: [approved, mergeable]
|
|
apply_requirements: [approved, mergeable]
|
|
import_requirements: [approved, mergeable]
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{"approved", "mergeable"},
|
|
ApplyRequirements: []string{"approved", "mergeable"},
|
|
ImportRequirements: []string{"approved", "mergeable"},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"init", "plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
|
|
// If we have global config that matches a specific repo, it should be used.
|
|
"specific repo": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
- id: github.com/owner/repo
|
|
workflow: specific
|
|
plan_requirements: [approved]
|
|
apply_requirements: [approved]
|
|
import_requirements: [approved]
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply
|
|
specific:
|
|
plan:
|
|
steps:
|
|
- plan
|
|
apply:
|
|
steps: []`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{"approved"},
|
|
ApplyRequirements: []string{"approved"},
|
|
ImportRequirements: []string{"approved"},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"plan"},
|
|
expApplySteps: []string{},
|
|
},
|
|
|
|
// We should get an error if the repo sets an apply req when its
|
|
// not allowed.
|
|
"repo defines apply_requirements": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
apply_requirements: [approved, mergeable]
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
apply_requirements: []
|
|
`,
|
|
expErr: "repo config not allowed to set 'apply_requirements' key: server-side config needs 'allowed_overrides: [apply_requirements]'",
|
|
},
|
|
|
|
// We should get an error if a repo sets a workflow when it's not allowed.
|
|
"repo sets its own workflow": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
apply_requirements: [approved, mergeable]
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
workflow: default
|
|
`,
|
|
expErr: "repo config not allowed to set 'workflow' key: server-side config needs 'allowed_overrides: [workflow]'",
|
|
},
|
|
|
|
// We should get an error if a repo defines a workflow when it's not
|
|
// allowed.
|
|
"repo defines new workflow": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
apply_requirements: [approved, mergeable]
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
workflows:
|
|
new: ~
|
|
`,
|
|
expErr: "repo config not allowed to define custom workflows: server-side config needs 'allow_custom_workflows: true'",
|
|
},
|
|
|
|
// If the repos are allowed to set everything then their config should
|
|
// come through.
|
|
"full repo permissions": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
apply_requirements: [approved]
|
|
import_requirements: [approved]
|
|
allowed_overrides: [apply_requirements, import_requirements, workflow]
|
|
allow_custom_workflows: true
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps: []
|
|
apply:
|
|
steps: []
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
terraform_version: v10.0
|
|
apply_requirements: []
|
|
import_requirements: []
|
|
workflow: custom
|
|
workflows:
|
|
custom:
|
|
plan:
|
|
steps:
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- 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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{},
|
|
ApplyRequirements: []string{},
|
|
ImportRequirements: []string{},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
|
|
// Repos can choose server-side workflows.
|
|
"repos choose server-side workflow": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
allowed_overrides: [workflow]
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps: []
|
|
apply:
|
|
steps: []
|
|
custom:
|
|
plan:
|
|
steps: [plan]
|
|
apply:
|
|
steps: [apply]
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
terraform_version: v10.0
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{},
|
|
ApplyRequirements: []string{},
|
|
ImportRequirements: []string{},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
|
|
// Repo-side workflows with the same name override server-side if
|
|
// allowed.
|
|
"repo-side workflow override": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: custom
|
|
allowed_overrides: [workflow]
|
|
allow_custom_workflows: true
|
|
workflows:
|
|
custom:
|
|
plan:
|
|
steps: [plan]
|
|
apply:
|
|
steps: [apply]
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
terraform_version: v10.0
|
|
workflow: custom
|
|
workflows:
|
|
custom:
|
|
plan:
|
|
steps: []
|
|
apply:
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{},
|
|
ApplyRequirements: []string{},
|
|
ImportRequirements: []string{},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{},
|
|
expApplySteps: []string{},
|
|
},
|
|
// Test that if we leave keys undefined, that they don't override.
|
|
"cascading matches": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
plan_requirements: [approved]
|
|
apply_requirements: [approved]
|
|
import_requirements: [approved]
|
|
- id: github.com/owner/repo
|
|
workflow: custom
|
|
workflows:
|
|
custom:
|
|
plan:
|
|
steps: [plan]
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
projects:
|
|
- dir: project1
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{"approved"},
|
|
ApplyRequirements: []string{"approved"},
|
|
ImportRequirements: []string{"approved"},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
}
|
|
|
|
for name, c := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
tmp := DirStructure(t, map[string]interface{}{
|
|
"project1": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
"modules": map[string]interface{}{
|
|
"module": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
},
|
|
})
|
|
|
|
workingDir := NewMockWorkingDir()
|
|
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
|
|
Any[string]())).ThenReturn(tmp, false, nil)
|
|
vcsClient := vcsmocks.NewMockClient()
|
|
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
|
|
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
|
|
|
|
// Write and parse the global config file.
|
|
globalCfgPath := filepath.Join(tmp, "global.yaml")
|
|
Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600))
|
|
parser := &config.ParserValidator{}
|
|
globalCfgArgs := valid.GlobalCfgArgs{}
|
|
globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs))
|
|
Ok(t, err)
|
|
|
|
if c.repoCfg != "" {
|
|
Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600))
|
|
}
|
|
|
|
terraformClient := tfclientmocks.NewMockClient()
|
|
|
|
builder := NewProjectCommandBuilder(
|
|
false,
|
|
parser,
|
|
&DefaultProjectFinder{},
|
|
vcsClient,
|
|
workingDir,
|
|
NewDefaultWorkingDirLocker(),
|
|
globalCfg,
|
|
&DefaultPendingPlanFinder{},
|
|
&CommentParser{ExecutableName: "atlantis"},
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
"",
|
|
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
|
false,
|
|
false,
|
|
false,
|
|
"auto",
|
|
statsScope,
|
|
terraformClient,
|
|
)
|
|
|
|
// We run a test for each type of command.
|
|
for _, cmd := range []command.Name{command.Plan, command.Apply} {
|
|
t.Run(cmd.String(), func(t *testing.T) {
|
|
ctxs, err := builder.buildProjectCommandCtx(&command.Context{
|
|
Log: logger,
|
|
Scope: statsScope,
|
|
Pull: models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
},
|
|
PullRequestStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
}, cmd, "", "", []string{"flag"}, tmp, "project1", "myworkspace", true)
|
|
|
|
if c.expErr != "" {
|
|
ErrEquals(t, c.expErr, err)
|
|
return
|
|
}
|
|
|
|
Ok(t, err)
|
|
ctx := ctxs[0]
|
|
|
|
// Construct expected steps.
|
|
var stepNames []string
|
|
switch cmd {
|
|
case command.Plan:
|
|
stepNames = c.expPlanSteps
|
|
case command.Apply:
|
|
stepNames = c.expApplySteps
|
|
}
|
|
var expSteps []valid.Step
|
|
for _, stepName := range stepNames {
|
|
expSteps = append(expSteps, valid.Step{
|
|
StepName: stepName,
|
|
})
|
|
}
|
|
|
|
c.expCtx.CommandName = cmd
|
|
// Init fields we couldn't in our cases map.
|
|
c.expCtx.Steps = expSteps
|
|
ctx.PolicySets = emptyPolicySets
|
|
|
|
// Job ID cannot be compared since its generated at random
|
|
ctx.JobID = ""
|
|
|
|
Equals(t, c.expCtx, ctx)
|
|
// Equals() doesn't compare TF version properly so have to
|
|
// use .String().
|
|
if c.expCtx.TerraformVersion != nil {
|
|
Equals(t, c.expCtx.TerraformVersion.String(), ctx.TerraformVersion.String())
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildProjectCmdCtx_WithRegExpCmdEnabled(t *testing.T) {
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
emptyPolicySets := valid.PolicySets{
|
|
Version: nil,
|
|
PolicySets: []valid.PolicySet{},
|
|
}
|
|
baseRepo := models.Repo{
|
|
FullName: "owner/repo",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
},
|
|
}
|
|
pull := models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
}
|
|
cases := map[string]struct {
|
|
globalCfg string
|
|
repoCfg string
|
|
expErr string
|
|
expCtx command.ProjectContext
|
|
expPlanSteps []string
|
|
expApplySteps []string
|
|
}{
|
|
|
|
// Test that if we've set global defaults, that they are used but the
|
|
// allowed project config values also come through.
|
|
"global defaults with repo cfg": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
workflows:
|
|
default:
|
|
plan:
|
|
steps:
|
|
- init
|
|
- plan
|
|
apply:
|
|
steps:
|
|
- apply`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- name: myproject_1
|
|
dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
terraform_version: v10.0
|
|
- name: myproject_2
|
|
dir: project2
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
terraform_version: v10.0
|
|
- name: myproject_3
|
|
dir: project3
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "myproject_1",
|
|
PlanRequirements: []string{},
|
|
ApplyRequirements: []string{},
|
|
ImportRequirements: []string{},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -p myproject_1 -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPlanSteps: []string{"init", "plan"},
|
|
expApplySteps: []string{"apply"},
|
|
},
|
|
}
|
|
|
|
for name, c := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
tmp := DirStructure(t, map[string]interface{}{
|
|
"project1": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
"modules": map[string]interface{}{
|
|
"module": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
},
|
|
})
|
|
|
|
workingDir := NewMockWorkingDir()
|
|
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
|
|
Any[string]())).ThenReturn(tmp, false, nil)
|
|
vcsClient := vcsmocks.NewMockClient()
|
|
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
|
|
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
|
|
|
|
// Write and parse the global config file.
|
|
globalCfgPath := filepath.Join(tmp, "global.yaml")
|
|
Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600))
|
|
parser := &config.ParserValidator{}
|
|
globalCfgArgs := valid.GlobalCfgArgs{}
|
|
globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs))
|
|
Ok(t, err)
|
|
|
|
if c.repoCfg != "" {
|
|
Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600))
|
|
}
|
|
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
|
|
terraformClient := tfclientmocks.NewMockClient()
|
|
|
|
builder := NewProjectCommandBuilder(
|
|
false,
|
|
parser,
|
|
&DefaultProjectFinder{},
|
|
vcsClient,
|
|
workingDir,
|
|
NewDefaultWorkingDirLocker(),
|
|
globalCfg,
|
|
&DefaultPendingPlanFinder{},
|
|
&CommentParser{ExecutableName: "atlantis"},
|
|
false,
|
|
true,
|
|
false,
|
|
false,
|
|
false,
|
|
"",
|
|
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
|
false,
|
|
false,
|
|
false,
|
|
"auto",
|
|
statsScope,
|
|
terraformClient,
|
|
)
|
|
|
|
// We run a test for each type of command, again specific projects
|
|
for _, cmd := range []command.Name{command.Plan, command.Apply} {
|
|
t.Run(cmd.String(), func(t *testing.T) {
|
|
ctxs, err := builder.buildProjectCommandCtx(&command.Context{
|
|
Pull: models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
},
|
|
Log: logging.NewNoopLogger(t),
|
|
Scope: statsScope,
|
|
PullRequestStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
}, cmd, "", "myproject_[1-2]", []string{"flag"}, tmp, "project1", "myworkspace", true)
|
|
|
|
if c.expErr != "" {
|
|
ErrEquals(t, c.expErr, err)
|
|
return
|
|
}
|
|
|
|
Ok(t, err)
|
|
ctx := ctxs[0]
|
|
|
|
Equals(t, 2, len(ctxs))
|
|
// Construct expected steps.
|
|
var stepNames []string
|
|
switch cmd {
|
|
case command.Plan:
|
|
stepNames = c.expPlanSteps
|
|
case command.Apply:
|
|
stepNames = c.expApplySteps
|
|
}
|
|
var expSteps []valid.Step
|
|
for _, stepName := range stepNames {
|
|
expSteps = append(expSteps, valid.Step{
|
|
StepName: stepName,
|
|
})
|
|
}
|
|
|
|
c.expCtx.CommandName = cmd
|
|
// Init fields we couldn't in our cases map.
|
|
c.expCtx.Steps = expSteps
|
|
ctx.PolicySets = emptyPolicySets
|
|
|
|
// Job ID cannot be compared since its generated at random
|
|
ctx.JobID = ""
|
|
|
|
Equals(t, c.expCtx, ctx)
|
|
// Equals() doesn't compare TF version properly so have to
|
|
// use .String().
|
|
if c.expCtx.TerraformVersion != nil {
|
|
Equals(t, c.expCtx.TerraformVersion.String(), ctx.TerraformVersion.String())
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildProjectCmdCtx_WithPolicCheckEnabled(t *testing.T) {
|
|
logger := logging.NewNoopLogger(t)
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
emptyPolicySets := valid.PolicySets{
|
|
Version: nil,
|
|
PolicySets: []valid.PolicySet{},
|
|
}
|
|
baseRepo := models.Repo{
|
|
FullName: "owner/repo",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
},
|
|
}
|
|
pull := models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
}
|
|
cases := map[string]struct {
|
|
globalCfg string
|
|
repoCfg string
|
|
expErr string
|
|
expCtx command.ProjectContext
|
|
expPolicyCheckSteps []string
|
|
}{
|
|
// Test that if we've set global defaults and no project config
|
|
// that the global defaults are used.
|
|
"global defaults": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
`,
|
|
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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{"policies_passed"},
|
|
ApplyRequirements: []string{"policies_passed"},
|
|
ImportRequirements: []string{"policies_passed"},
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
},
|
|
expPolicyCheckSteps: []string{"show", "policy_check"},
|
|
},
|
|
|
|
// If the repos are allowed to set everything then their config should
|
|
// come through.
|
|
"full repo permissions": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
workflow: default
|
|
apply_requirements: [approved]
|
|
allowed_overrides: [apply_requirements, workflow]
|
|
allow_custom_workflows: true
|
|
workflows:
|
|
default:
|
|
policy_check:
|
|
steps: []
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
autoplan:
|
|
enabled: true
|
|
when_modified: [../modules/**/*.tf]
|
|
terraform_version: v10.0
|
|
apply_requirements: []
|
|
workflow: custom
|
|
workflows:
|
|
custom:
|
|
policy_check:
|
|
steps:
|
|
- 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,
|
|
PullReqStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
Pull: pull,
|
|
ProjectName: "",
|
|
PlanRequirements: []string{"policies_passed"},
|
|
ApplyRequirements: []string{"policies_passed"},
|
|
ImportRequirements: []string{"policies_passed"},
|
|
RepoConfigVersion: 3,
|
|
RePlanCmd: "atlantis plan -d project1 -w myworkspace -- flag",
|
|
RepoRelDir: "project1",
|
|
TerraformVersion: mustVersion("v10.0"),
|
|
User: models.User{},
|
|
Verbose: true,
|
|
Workspace: "myworkspace",
|
|
PolicySets: emptyPolicySets,
|
|
RepoLocksMode: valid.DefaultRepoLocksMode,
|
|
PolicySetTarget: "",
|
|
},
|
|
expPolicyCheckSteps: []string{"policy_check"},
|
|
},
|
|
}
|
|
|
|
for name, c := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
tmp := DirStructure(t, map[string]interface{}{
|
|
"project1": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
"modules": map[string]interface{}{
|
|
"module": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
},
|
|
})
|
|
|
|
workingDir := NewMockWorkingDir()
|
|
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
|
|
Any[string]())).ThenReturn(tmp, false, nil)
|
|
vcsClient := vcsmocks.NewMockClient()
|
|
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
|
|
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
|
|
|
|
// Write and parse the global config file.
|
|
globalCfgPath := filepath.Join(tmp, "global.yaml")
|
|
Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600))
|
|
parser := &config.ParserValidator{}
|
|
globalCfgArgs := valid.GlobalCfgArgs{
|
|
PolicyCheckEnabled: true,
|
|
}
|
|
|
|
globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs))
|
|
Ok(t, err)
|
|
|
|
if c.repoCfg != "" {
|
|
Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600))
|
|
}
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
|
|
terraformClient := tfclientmocks.NewMockClient()
|
|
|
|
builder := NewProjectCommandBuilder(
|
|
true,
|
|
parser,
|
|
&DefaultProjectFinder{},
|
|
vcsClient,
|
|
workingDir,
|
|
NewDefaultWorkingDirLocker(),
|
|
globalCfg,
|
|
&DefaultPendingPlanFinder{},
|
|
&CommentParser{ExecutableName: "atlantis"},
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
"",
|
|
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
|
false,
|
|
false,
|
|
false,
|
|
"auto",
|
|
statsScope,
|
|
terraformClient,
|
|
)
|
|
|
|
cmd := command.PolicyCheck
|
|
t.Run(cmd.String(), func(t *testing.T) {
|
|
ctxs, err := builder.buildProjectCommandCtx(&command.Context{
|
|
Log: logger,
|
|
Scope: statsScope,
|
|
Pull: models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
},
|
|
PullRequestStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
}, command.Plan, "", "", []string{"flag"}, tmp, "project1", "myworkspace", true)
|
|
|
|
if c.expErr != "" {
|
|
ErrEquals(t, c.expErr, err)
|
|
return
|
|
}
|
|
|
|
Ok(t, err)
|
|
ctx := ctxs[1]
|
|
|
|
// Construct expected steps.
|
|
var stepNames []string
|
|
var expSteps []valid.Step
|
|
|
|
stepNames = c.expPolicyCheckSteps
|
|
for _, stepName := range stepNames {
|
|
expSteps = append(expSteps, valid.Step{
|
|
StepName: stepName,
|
|
})
|
|
}
|
|
|
|
c.expCtx.CommandName = cmd
|
|
// Init fields we couldn't in our cases map.
|
|
c.expCtx.Steps = expSteps
|
|
ctx.PolicySets = emptyPolicySets
|
|
|
|
// Job ID cannot be compared since its generated at random
|
|
ctx.JobID = ""
|
|
|
|
Equals(t, c.expCtx, ctx)
|
|
// Equals() doesn't compare TF version properly so have to
|
|
// use .String().
|
|
if c.expCtx.TerraformVersion != nil {
|
|
Equals(t, c.expCtx.TerraformVersion.String(), ctx.TerraformVersion.String())
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildProjectCmdCtx_WithSilenceNoProjects(t *testing.T) {
|
|
globalCfg := `
|
|
repos:
|
|
- id: /.*/
|
|
`
|
|
logger := logging.NewNoopLogger(t)
|
|
baseRepo := models.Repo{
|
|
FullName: "owner/repo",
|
|
VCSHost: models.VCSHost{
|
|
Hostname: "github.com",
|
|
},
|
|
}
|
|
cases := map[string]struct {
|
|
repoCfg string
|
|
expLen int
|
|
}{
|
|
// One project matches the repo cfg, return it
|
|
"matching project": {
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
`,
|
|
expLen: 1,
|
|
},
|
|
// No project matches the repo cfg, ignore it
|
|
"no matching project": {
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project2
|
|
workspace: myworkspace
|
|
`,
|
|
expLen: 0,
|
|
},
|
|
}
|
|
|
|
for name, c := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
tmp := DirStructure(t, map[string]interface{}{
|
|
"project1": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
"modules": map[string]interface{}{
|
|
"module": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
},
|
|
})
|
|
|
|
workingDir := NewMockWorkingDir()
|
|
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
|
|
Any[string]())).ThenReturn(tmp, false, nil)
|
|
vcsClient := vcsmocks.NewMockClient()
|
|
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
|
|
Any[models.PullRequest]())).ThenReturn([]string{"modules/module/main.tf"}, nil)
|
|
|
|
// Write and parse the global config file.
|
|
globalCfgPath := filepath.Join(tmp, "global.yaml")
|
|
Ok(t, os.WriteFile(globalCfgPath, []byte(globalCfg), 0600))
|
|
parser := &config.ParserValidator{}
|
|
globalCfgArgs := valid.GlobalCfgArgs{}
|
|
|
|
globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs))
|
|
Ok(t, err)
|
|
|
|
if c.repoCfg != "" {
|
|
Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600))
|
|
}
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
|
|
terraformClient := tfclientmocks.NewMockClient()
|
|
|
|
builder := NewProjectCommandBuilder(
|
|
false,
|
|
parser,
|
|
&DefaultProjectFinder{},
|
|
vcsClient,
|
|
workingDir,
|
|
NewDefaultWorkingDirLocker(),
|
|
globalCfg,
|
|
&DefaultPendingPlanFinder{},
|
|
&CommentParser{ExecutableName: "atlantis"},
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
"",
|
|
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
|
false,
|
|
true,
|
|
false,
|
|
"auto",
|
|
statsScope,
|
|
terraformClient,
|
|
)
|
|
|
|
for _, cmd := range []command.Name{command.Plan, command.Apply} {
|
|
t.Run(cmd.String(), func(t *testing.T) {
|
|
ctxs, err := builder.buildProjectCommandCtx(&command.Context{
|
|
Log: logger,
|
|
Scope: statsScope,
|
|
Pull: models.PullRequest{
|
|
BaseRepo: baseRepo,
|
|
},
|
|
PullRequestStatus: models.PullReqStatus{
|
|
Mergeable: true,
|
|
},
|
|
}, cmd, "", "", []string{}, tmp, "project1", "myworkspace", true)
|
|
Equals(t, c.expLen, len(ctxs))
|
|
Ok(t, err)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildProjectCmdCtx_AutoDiscoverRespectsRepoConfig(t *testing.T) {
|
|
logger := logging.NewNoopLogger(t)
|
|
cases := map[string]struct {
|
|
globalCfg string
|
|
repoCfg string
|
|
modifiedFiles []string
|
|
expLen int
|
|
}{
|
|
"autodiscover disabled": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
autodiscover:
|
|
mode: disabled
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
`,
|
|
modifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"},
|
|
expLen: 0,
|
|
},
|
|
"autodiscover auto": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
autodiscover:
|
|
mode: auto
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
`,
|
|
modifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"},
|
|
expLen: 1,
|
|
},
|
|
"autodiscover enabled": {
|
|
globalCfg: `
|
|
repos:
|
|
- id: /.*/
|
|
autodiscover:
|
|
mode: enabled
|
|
`,
|
|
repoCfg: `
|
|
version: 3
|
|
automerge: true
|
|
projects:
|
|
- dir: project1
|
|
workspace: myworkspace
|
|
`,
|
|
modifiedFiles: []string{"project1/main.tf", "project2/main.tf", "project3/main.tf"},
|
|
expLen: 3,
|
|
},
|
|
}
|
|
|
|
for name, c := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
tmp := DirStructure(t, map[string]interface{}{
|
|
"project1": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
"project2": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
"project3": map[string]interface{}{
|
|
"main.tf": nil,
|
|
},
|
|
})
|
|
|
|
workingDir := NewMockWorkingDir()
|
|
When(workingDir.Clone(Any[logging.SimpleLogging](), Any[models.Repo](), Any[models.PullRequest](),
|
|
Any[string]())).ThenReturn(tmp, false, nil)
|
|
vcsClient := vcsmocks.NewMockClient()
|
|
When(vcsClient.GetModifiedFiles(Any[logging.SimpleLogging](), Any[models.Repo](),
|
|
Any[models.PullRequest]())).ThenReturn(c.modifiedFiles, nil)
|
|
|
|
// Write and parse the global config file.
|
|
globalCfgPath := filepath.Join(tmp, "global.yaml")
|
|
Ok(t, os.WriteFile(globalCfgPath, []byte(c.globalCfg), 0600))
|
|
parser := &config.ParserValidator{}
|
|
globalCfgArgs := valid.GlobalCfgArgs{
|
|
AllowAllRepoSettings: false,
|
|
}
|
|
|
|
globalCfg, err := parser.ParseGlobalCfg(globalCfgPath, valid.NewGlobalCfgFromArgs(globalCfgArgs))
|
|
Ok(t, err)
|
|
|
|
if c.repoCfg != "" {
|
|
Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600))
|
|
}
|
|
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
|
|
|
terraformClient := tfclientmocks.NewMockClient()
|
|
|
|
builder := NewProjectCommandBuilder(
|
|
false,
|
|
parser,
|
|
&DefaultProjectFinder{},
|
|
vcsClient,
|
|
workingDir,
|
|
NewDefaultWorkingDirLocker(),
|
|
globalCfg,
|
|
&DefaultPendingPlanFinder{},
|
|
&CommentParser{ExecutableName: "atlantis"},
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
"",
|
|
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
|
false,
|
|
true,
|
|
false,
|
|
"auto",
|
|
statsScope,
|
|
terraformClient,
|
|
)
|
|
|
|
ctxs, err := builder.BuildPlanCommands(
|
|
&command.Context{
|
|
Log: logger,
|
|
Scope: statsScope,
|
|
},
|
|
&CommentCommand{
|
|
RepoRelDir: "",
|
|
Flags: nil,
|
|
Name: command.Plan,
|
|
Verbose: false,
|
|
},
|
|
)
|
|
Equals(t, c.expLen, len(ctxs))
|
|
Ok(t, err)
|
|
|
|
})
|
|
}
|
|
}
|
|
|
|
func mustVersion(v string) *version.Version {
|
|
vers, err := version.NewVersion(v)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return vers
|
|
}
|