mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-05 07:48:28 +00:00
feat: support atlantis.yaml without defined projects (#2300)
* Support atlantis.yaml without defined projects * Update server/events/project_command_builder.go * Update server/events/project_command_builder.go * Correct test of no modified projects * Flip if statement * Remove duplicate check on hasRepoCfg Co-authored-by: nitrocode <7775707+nitrocode@users.noreply.github.com>
This commit is contained in:
@@ -237,14 +237,18 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
|
||||
return nil, errors.Wrapf(err, "parsing %s", config.AtlantisYAMLFilename)
|
||||
}
|
||||
ctx.Log.Info("successfully parsed remote %s file", config.AtlantisYAMLFilename)
|
||||
matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.Log.Info("%d projects are changed on MR %q based on their when_modified config", len(matchingProjects), ctx.Pull.Num)
|
||||
if len(matchingProjects) == 0 {
|
||||
ctx.Log.Info("skipping repo clone since no project was modified")
|
||||
return []command.ProjectContext{}, nil
|
||||
if len(repoCfg.Projects) > 0 {
|
||||
matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.Log.Info("%d projects are changed on MR %q based on their when_modified config", len(matchingProjects), ctx.Pull.Num)
|
||||
if len(matchingProjects) == 0 {
|
||||
ctx.Log.Info("skipping repo clone since no project was modified")
|
||||
return []command.ProjectContext{}, nil
|
||||
}
|
||||
} else {
|
||||
ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", config.AtlantisYAMLFilename)
|
||||
}
|
||||
// NOTE: We discard this work here and end up doing it again after
|
||||
// cloning to ensure all the return values are set properly with
|
||||
@@ -275,15 +279,19 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
|
||||
}
|
||||
|
||||
var projCtxs []command.ProjectContext
|
||||
var repoCfg valid.RepoCfg
|
||||
|
||||
if hasRepoCfg {
|
||||
// If there's a repo cfg then we'll use it to figure out which projects
|
||||
// If there's a repo cfg with projects then we'll use it to figure out which projects
|
||||
// should be planed.
|
||||
repoCfg, err := p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch)
|
||||
repoCfg, err = p.ParserValidator.ParseRepoCfg(repoDir, p.GlobalCfg, ctx.Pull.BaseRepo.ID(), ctx.Pull.BaseBranch)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parsing %s", config.AtlantisYAMLFilename)
|
||||
}
|
||||
ctx.Log.Info("successfully parsed %s file", config.AtlantisYAMLFilename)
|
||||
}
|
||||
|
||||
if len(repoCfg.Projects) > 0 {
|
||||
matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, repoDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -309,9 +317,13 @@ func (p *DefaultProjectCommandBuilder) buildPlanAllCommands(ctx *command.Context
|
||||
)...)
|
||||
}
|
||||
} else {
|
||||
// If there is no config file, then we'll plan each project that
|
||||
// If there is no config file or it specified no projects, then we'll plan each project that
|
||||
// our algorithm determines was modified.
|
||||
ctx.Log.Info("found no %s file", config.AtlantisYAMLFilename)
|
||||
if hasRepoCfg {
|
||||
ctx.Log.Info("No projects are defined in %s. Will resume automatic detection", config.AtlantisYAMLFilename)
|
||||
} else {
|
||||
ctx.Log.Info("found no %s file", config.AtlantisYAMLFilename)
|
||||
}
|
||||
// build a module index for projects that are explicitly included
|
||||
moduleInfo, err := FindModuleProjects(repoDir, p.AutoDetectModuleFiles)
|
||||
if err != nil {
|
||||
|
||||
@@ -500,6 +500,33 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"no projects in atlantis.yaml": {
|
||||
DirStructure: map[string]interface{}{
|
||||
"project1": map[string]interface{}{
|
||||
"main.tf": nil,
|
||||
},
|
||||
"project2": map[string]interface{}{
|
||||
"main.tf": nil,
|
||||
},
|
||||
},
|
||||
AtlantisYAML: `
|
||||
version: 3
|
||||
parallel_plan: true
|
||||
`,
|
||||
ModifiedFiles: []string{"project1/main.tf", "project2/main.tf"},
|
||||
Exp: []expCtxFields{
|
||||
{
|
||||
ProjectName: "",
|
||||
RepoRelDir: "project1",
|
||||
Workspace: "default",
|
||||
},
|
||||
{
|
||||
ProjectName: "",
|
||||
RepoRelDir: "project2",
|
||||
Workspace: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
"no modified files": {
|
||||
DirStructure: map[string]interface{}{
|
||||
"main.tf": nil,
|
||||
@@ -1074,61 +1101,83 @@ projects:
|
||||
|
||||
// Test that we don't clone the repo if there were no changes based on the atlantis.yaml file.
|
||||
func TestDefaultProjectCommandBuilder_SkipCloneNoChanges(t *testing.T) {
|
||||
atlantisYAML := `
|
||||
cases := []struct {
|
||||
AtlantisYAML string
|
||||
ExpectedCtxs int
|
||||
ExpectedClones InvocationCountMatcher
|
||||
ModifiedFiles []string
|
||||
}{
|
||||
{
|
||||
AtlantisYAML: `
|
||||
version: 3
|
||||
projects:
|
||||
- dir: dir1`
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
vcsClient := vcsmocks.NewMockClient()
|
||||
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn([]string{"main.tf"}, nil)
|
||||
When(vcsClient.SupportsSingleFileDownload(matchers.AnyModelsRepo())).ThenReturn(true)
|
||||
When(vcsClient.DownloadRepoConfigFile(matchers.AnyModelsPullRequest())).ThenReturn(true, []byte(atlantisYAML), nil)
|
||||
workingDir := mocks.NewMockWorkingDir()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
|
||||
globalCfgArgs := valid.GlobalCfgArgs{
|
||||
AllowRepoCfg: true,
|
||||
MergeableReq: false,
|
||||
ApprovedReq: false,
|
||||
UnDivergedReq: false,
|
||||
}
|
||||
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
&config.ParserValidator{},
|
||||
&events.DefaultProjectFinder{},
|
||||
vcsClient,
|
||||
workingDir,
|
||||
events.NewDefaultWorkingDirLocker(),
|
||||
valid.NewGlobalCfgFromArgs(globalCfgArgs),
|
||||
&events.DefaultPendingPlanFinder{},
|
||||
&events.CommentParser{},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
||||
scope,
|
||||
logger,
|
||||
)
|
||||
|
||||
var actCtxs []command.ProjectContext
|
||||
var err error
|
||||
actCtxs, err = builder.BuildAutoplanCommands(&command.Context{
|
||||
HeadRepo: models.Repo{},
|
||||
Pull: models.PullRequest{},
|
||||
User: models.User{},
|
||||
Log: logger,
|
||||
Scope: scope,
|
||||
PullRequestStatus: models.PullReqStatus{
|
||||
Mergeable: true,
|
||||
- dir: dir1`,
|
||||
ExpectedCtxs: 0,
|
||||
ExpectedClones: Never(),
|
||||
ModifiedFiles: []string{"dir2/main.tf"},
|
||||
},
|
||||
})
|
||||
Ok(t, err)
|
||||
Equals(t, 0, len(actCtxs))
|
||||
workingDir.VerifyWasCalled(Never()).Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())
|
||||
{
|
||||
AtlantisYAML: `
|
||||
version: 3
|
||||
parallel_plan: true`,
|
||||
ExpectedCtxs: 0,
|
||||
ExpectedClones: Once(),
|
||||
ModifiedFiles: []string{"README.md"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
RegisterMockTestingT(t)
|
||||
vcsClient := vcsmocks.NewMockClient()
|
||||
When(vcsClient.GetModifiedFiles(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(c.ModifiedFiles, nil)
|
||||
When(vcsClient.SupportsSingleFileDownload(matchers.AnyModelsRepo())).ThenReturn(true)
|
||||
When(vcsClient.DownloadRepoConfigFile(matchers.AnyModelsPullRequest())).ThenReturn(true, []byte(c.AtlantisYAML), nil)
|
||||
workingDir := mocks.NewMockWorkingDir()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
|
||||
globalCfgArgs := valid.GlobalCfgArgs{
|
||||
AllowRepoCfg: true,
|
||||
MergeableReq: false,
|
||||
ApprovedReq: false,
|
||||
UnDivergedReq: false,
|
||||
}
|
||||
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
&config.ParserValidator{},
|
||||
&events.DefaultProjectFinder{},
|
||||
vcsClient,
|
||||
workingDir,
|
||||
events.NewDefaultWorkingDirLocker(),
|
||||
valid.NewGlobalCfgFromArgs(globalCfgArgs),
|
||||
&events.DefaultPendingPlanFinder{},
|
||||
&events.CommentParser{},
|
||||
true,
|
||||
false,
|
||||
"",
|
||||
"**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl",
|
||||
scope,
|
||||
logger,
|
||||
)
|
||||
|
||||
var actCtxs []command.ProjectContext
|
||||
var err error
|
||||
actCtxs, err = builder.BuildAutoplanCommands(&command.Context{
|
||||
HeadRepo: models.Repo{},
|
||||
Pull: models.PullRequest{},
|
||||
User: models.User{},
|
||||
Log: logger,
|
||||
Scope: scope,
|
||||
PullRequestStatus: models.PullReqStatus{
|
||||
Mergeable: true,
|
||||
},
|
||||
})
|
||||
Ok(t, err)
|
||||
Equals(t, c.ExpectedCtxs, len(actCtxs))
|
||||
workingDir.VerifyWasCalled(c.ExpectedClones).Clone(matchers.AnyPtrToLoggingSimpleLogger(), matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest(), AnyString())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanCommand(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user