From d6bc1e77d6141fec7df6aa9d1d2e50d0052946fc Mon Sep 17 00:00:00 2001 From: Isaac Wilson <10012479+jukie@users.noreply.github.com> Date: Mon, 3 Apr 2023 07:25:01 -0600 Subject: [PATCH] fix(autoplan): modules for per-repo configs (#3272) * Fix autoplan modules for per-repo configs * Use utils package for slices.Contains --- server/events/modules.go | 2 +- server/events/project_command_builder.go | 15 ++++++++------- server/events/project_finder.go | 22 ++++++++++++++++++++-- server/events/project_finder_test.go | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/server/events/modules.go b/server/events/modules.go index a545d380cf..396cd59d8a 100644 --- a/server/events/modules.go +++ b/server/events/modules.go @@ -130,7 +130,7 @@ func findModuleDependants(files fs.FS, autoplanModuleDependants string) (ModuleP filter, _ := patternmatcher.New(strings.Split(autoplanModuleDependants, ",")) var projects []string err := fs.WalkDir(files, ".", func(rel string, info fs.DirEntry, err error) error { - if match, _ := filter.Matches(rel); match { + if match, _ := filter.MatchesOrParentMatches(rel); match { if projectDir := getProjectDirFromFs(files, rel); projectDir != "" { projects = append(projects, projectDir) } diff --git a/server/events/project_command_builder.go b/server/events/project_command_builder.go index b168e8b3df..9a13103bb9 100644 --- a/server/events/project_command_builder.go +++ b/server/events/project_command_builder.go @@ -298,7 +298,7 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex } ctx.Log.Info("successfully parsed remote %s file", repoCfgFile) if len(repoCfg.Projects) > 0 { - matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "") + matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, "", nil) if err != nil { return nil, err } @@ -352,8 +352,14 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex ctx.Log.Info("successfully parsed %s file", repoCfgFile) } + moduleInfo, err := FindModuleProjects(repoDir, p.AutoDetectModuleFiles) + if err != nil { + ctx.Log.Warn("error(s) loading project module dependencies: %s", err) + } + ctx.Log.Debug("moduleInfo for %s (matching %q) = %v", repoDir, p.AutoDetectModuleFiles, moduleInfo) + if len(repoCfg.Projects) > 0 { - matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, repoDir) + matchingProjects, err := p.ProjectFinder.DetermineProjectsViaConfig(ctx.Log, modifiedFiles, repoCfg, repoDir, moduleInfo) if err != nil { return nil, err } @@ -387,11 +393,6 @@ func (p *DefaultProjectCommandBuilder) buildAllCommandsByCfg(ctx *command.Contex ctx.Log.Info("found no %s file", repoCfgFile) } // build a module index for projects that are explicitly included - moduleInfo, err := FindModuleProjects(repoDir, p.AutoDetectModuleFiles) - if err != nil { - ctx.Log.Warn("error(s) loading project module dependencies: %s", err) - } - ctx.Log.Debug("moduleInfo for %s (matching %q) = %v", repoDir, p.AutoDetectModuleFiles, moduleInfo) modifiedProjects := p.ProjectFinder.DetermineProjects(ctx.Log, modifiedFiles, ctx.Pull.BaseRepo.FullName, repoDir, p.AutoplanFileList, moduleInfo) ctx.Log.Info("automatically determined that there were %d projects modified in this pull request: %s", len(modifiedProjects), modifiedProjects) for _, mp := range modifiedProjects { diff --git a/server/events/project_finder.go b/server/events/project_finder.go index 80049cc4f0..8d5ecafe52 100644 --- a/server/events/project_finder.go +++ b/server/events/project_finder.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/runatlantis/atlantis/server/core/config/valid" + "github.com/runatlantis/atlantis/server/utils" "github.com/moby/patternmatcher" "github.com/pkg/errors" @@ -44,7 +45,7 @@ type ProjectFinder interface { // DetermineProjectsViaConfig returns the list of projects that were modified // based on modifiedFiles and the repo's config. // absRepoDir is the path to the cloned repo on disk. - DetermineProjectsViaConfig(log logging.SimpleLogging, modifiedFiles []string, config valid.RepoCfg, absRepoDir string) ([]valid.Project, error) + DetermineProjectsViaConfig(log logging.SimpleLogging, modifiedFiles []string, config valid.RepoCfg, absRepoDir string, moduleInfo ModuleProjects) ([]valid.Project, error) DetermineWorkspaceFromHCL(log logging.SimpleLogging, absRepoDir string) (string, error) } @@ -174,10 +175,27 @@ func (p *DefaultProjectFinder) DetermineProjects(log logging.SimpleLogging, modi } // See ProjectFinder.DetermineProjectsViaConfig. -func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log logging.SimpleLogging, modifiedFiles []string, config valid.RepoCfg, absRepoDir string) ([]valid.Project, error) { +func (p *DefaultProjectFinder) DetermineProjectsViaConfig(log logging.SimpleLogging, modifiedFiles []string, config valid.RepoCfg, absRepoDir string, moduleInfo ModuleProjects) ([]valid.Project, error) { + + // Check moduleInfo for downstream project dependencies + var dependentProjects []string + for _, file := range modifiedFiles { + if moduleInfo != nil { + downstreamProjects := moduleInfo.DependentProjects(path.Dir(file)) + log.Debug("found downstream projects for %q: %v", file, downstreamProjects) + dependentProjects = append(dependentProjects, downstreamProjects...) + } + } + var projects []valid.Project for _, project := range config.Projects { log.Debug("checking if project at dir %q workspace %q was modified", project.Dir, project.Workspace) + + if utils.SlicesContains(dependentProjects, project.Dir) { + projects = append(projects, project) + continue + } + var whenModifiedRelToRepoRoot []string for _, wm := range project.Autoplan.WhenModified { wm = strings.TrimSpace(wm) diff --git a/server/events/project_finder_test.go b/server/events/project_finder_test.go index c88b0f123a..f3405494dd 100644 --- a/server/events/project_finder_test.go +++ b/server/events/project_finder_test.go @@ -538,7 +538,7 @@ func TestDefaultProjectFinder_DetermineProjectsViaConfig(t *testing.T) { for _, c := range cases { t.Run(c.description, func(t *testing.T) { pf := events.DefaultProjectFinder{} - projects, err := pf.DetermineProjectsViaConfig(logging.NewNoopLogger(t), c.modified, c.config, tmpDir) + projects, err := pf.DetermineProjectsViaConfig(logging.NewNoopLogger(t), c.modified, c.config, tmpDir, nil) Ok(t, err) Equals(t, len(c.expProjPaths), len(projects)) for i, proj := range projects {