Skip to content

Commit

Permalink
chore: add flag to enable|disable PR filter (only github scm)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcportabellaclotet-mt committed Oct 13, 2023
1 parent fc365c9 commit 3dbfa6b
Show file tree
Hide file tree
Showing 11 changed files with 151 additions and 35 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Run the tool using the following command:

- `-q, --pattern-detector string`: discover projects based on files or directories names. (Equivalent envVar: `PATTERN_DETECTOR`)

- `-y, --pr-filter string`: filter projects based on the PR changes (Only for github SCM).. (Equivalent envVar: `PR_FILTER`)

- `-p, --pull-num string`: Github Pull Request Number to check diffs. (Equivalent envVar: `PULL_NUM`)

- `--terraform-base-dir string`: Basedir for terraform resources. (Equivalent envVar: `TERRAFORM_BASE_DIR`)
Expand Down
9 changes: 2 additions & 7 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

"github.com/totmicro/atlantis-yaml-generator/pkg/atlantis"
"github.com/totmicro/atlantis-yaml-generator/pkg/config"
"github.com/totmicro/atlantis-yaml-generator/pkg/github"

"github.com/totmicro/atlantis-yaml-generator/pkg/version"

Expand Down Expand Up @@ -57,11 +56,7 @@ func runE(ccmd *cobra.Command, args []string) (err error) {
if err != nil {
return err
}
// Get the changed files from the PR
changedFiles, err := github.GetChangedFiles()
if err != nil {
return err
}
err = atlantis.GenerateAtlantisYAML(changedFiles)

err = atlantis.GenerateAtlantisYAML()
return err
}
22 changes: 22 additions & 0 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"testing"

"github.com/spf13/cobra"
"github.com/totmicro/atlantis-yaml-generator/pkg/config"
)

func TestInitFlags(t *testing.T) {
// Create a new root command
cmd := &cobra.Command{}
initFlags(cmd)

// Check that all flags have been initialized
for _, param := range config.ParameterList {
flag := cmd.PersistentFlags().Lookup(param.Name)
if flag == nil {
t.Errorf("Flag %s was not initialized", param.Name)
}
}
}
52 changes: 35 additions & 17 deletions pkg/atlantis/atlantis.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (
"strings"

"github.com/totmicro/atlantis-yaml-generator/pkg/config"
"github.com/totmicro/atlantis-yaml-generator/pkg/github"
"github.com/totmicro/atlantis-yaml-generator/pkg/helpers"

"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -40,15 +42,23 @@ type ProjectFolder struct {
}

// GenerateAtlantisYAML generates the atlantis.yaml file
func GenerateAtlantisYAML(prChangedFiles []string) error {
// Get the changed files from the PR

func GenerateAtlantisYAML() error {
// Get the changed files from the PR if prFilter is enabled
prChangedFiles := []string{}
var err error
if config.GlobalConfig.Parameters["pr-filter"] == "true" {
prChangedFiles, err = github.GetChangedFiles()
if err != nil {
return err
}
}
// Scan folders to detect projects
projectFoldersList, err := scanProjectFolders(
config.GlobalConfig.Parameters["terraform-base-dir"],
config.GlobalConfig.Parameters["workflow"],
config.GlobalConfig.Parameters["pattern-detector"],
prChangedFiles)
prChangedFiles,
config.GlobalConfig.Parameters["pr-filter"] == "true")
if err != nil {
return err
}
Expand All @@ -57,7 +67,8 @@ func GenerateAtlantisYAML(prChangedFiles []string) error {
projectFoldersList,
config.GlobalConfig.Parameters["workflow"],
config.GlobalConfig.Parameters["pattern-detector"],
prChangedFiles)
prChangedFiles,
config.GlobalConfig.Parameters["pr-filter"] == "true")
if err != nil {
return err
}
Expand Down Expand Up @@ -96,34 +107,41 @@ func GenerateAtlantisYAML(prChangedFiles []string) error {
return nil
}

func scanProjectFolders(basePath, workflow, patternDetector string, changedFiles []string) (projectFolders []ProjectFolder, err error) {
// Scan folders for projects and apply filters
func scanProjectFolders(basePath, workflow, patternDetector string, changedFiles []string, enablePRFilter bool) (projectFolders []ProjectFolder, err error) {
err = filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
if err != nil || info == nil {
return err
}

relPath, _ := filepath.Rel(basePath, filepath.Dir(path))
// Detect projects folders based on the workflow
workflowFilterResult := workflowFilter(info, path, workflow, patternDetector)
// Filter projects based on the PR changed files
prFilterResult := prFilter(relPath, changedFiles)
if workflowFilterResult && prFilterResult {
projectFolders = append(projectFolders, ProjectFolder{
Path: relPath,
})
if shouldIncludeProject(info, path, workflow, patternDetector, relPath, changedFiles, enablePRFilter) {
projectFolders = append(projectFolders, ProjectFolder{Path: relPath})
}
return nil
})

return projectFolders, err
}

func detectProjectWorkspaces(foldersList []ProjectFolder, workflow string, patternDetector string, changedFiles []string) (updatedFoldersList []ProjectFolder, err error) {
func shouldIncludeProject(info os.FileInfo, path, workflow, patternDetector string, relPath string, changedFiles []string, enablePRFilter bool) bool {
workflowFilterResult := workflowFilter(info, path, workflow, patternDetector)

// If PR filter is enabled, check if the project should be included based on changed files.
if enablePRFilter {
prFilterResult := prFilter(relPath, changedFiles)
return workflowFilterResult && prFilterResult
}

return workflowFilterResult
}

func detectProjectWorkspaces(foldersList []ProjectFolder, workflow string, patternDetector string, changedFiles []string, enablePRfilter bool) (updatedFoldersList []ProjectFolder, err error) {
// Detect project workspaces based on the workflow
switch workflow {
case "single-workspace":
updatedFoldersList, err = singleWorkspaceDetectProjectWorkspaces(foldersList)
case "multi-workspace":
updatedFoldersList, err = multiWorkspaceDetectProjectWorkspaces(changedFiles, foldersList, patternDetector)
updatedFoldersList, err = multiWorkspaceDetectProjectWorkspaces(changedFiles, enablePRfilter, foldersList, patternDetector)
}
// You can add more workflows rules here if required
return updatedFoldersList, err
Expand Down
80 changes: 74 additions & 6 deletions pkg/atlantis/atlantis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ func TestScanProjectFolders(t *testing.T) {
workflow string
patternDetector string
changedFiles []string
enablePRFilter bool
expectedProjectFolder []ProjectFolder
expectedError bool
}{
Expand All @@ -327,6 +328,20 @@ func TestScanProjectFolders(t *testing.T) {
"multiworkspace2/workspace_vars/test1.tfvars",
"multiworkspace2/workspace_vars/test2.tfvars",
},
enablePRFilter: true,
expectedProjectFolder: []ProjectFolder{
{Path: "multiworkspace"},
{Path: "multiworkspace2"},
},
},
{
basePath: "mockproject",
workflow: "multi-workspace",
patternDetector: "workspace_vars",
changedFiles: []string{
"multiworkspace/workspace_vars/test1.tfvars",
},
enablePRFilter: false,
expectedProjectFolder: []ProjectFolder{
{Path: "multiworkspace"},
{Path: "multiworkspace2"},
Expand All @@ -337,15 +352,28 @@ func TestScanProjectFolders(t *testing.T) {
workflow: "single-workspace",
patternDetector: "main.tf",
changedFiles: []string{"singleworkspace/main.tf", "file2"},
enablePRFilter: true,
expectedProjectFolder: []ProjectFolder{
{Path: "singleworkspace"},
},
},
{
basePath: "mockproject",
workflow: "single-workspace",
patternDetector: "main.tf",
changedFiles: []string{"singleworkspace/main.tf", "file2"},
enablePRFilter: false,
expectedProjectFolder: []ProjectFolder{
{Path: "singleworkspace"},
{Path: "singleworkspace2"},
},
},
{
basePath: "invalidpath", // Invalid path to check file walk error
workflow: "single-workspace",
patternDetector: "main.tf",
changedFiles: []string{"singleworkspace/main.tf", "file2"},
enablePRFilter: true,
expectedProjectFolder: []ProjectFolder{
{Path: "singleworkspace"},
},
Expand All @@ -355,7 +383,7 @@ func TestScanProjectFolders(t *testing.T) {

for _, test := range tests {
t.Run(test.workflow, func(t *testing.T) {
projectFolders, err := scanProjectFolders(test.basePath, test.workflow, test.patternDetector, test.changedFiles)
projectFolders, err := scanProjectFolders(test.basePath, test.workflow, test.patternDetector, test.changedFiles, test.enablePRFilter)
if test.expectedError {
assert.Error(t, err)
} else {
Expand Down Expand Up @@ -485,6 +513,7 @@ func TestDetectProjectWorkspaces(t *testing.T) {
workflow string
patternDetector string
changedFiles []string
enablePRFilter bool
expectedFoldersList []ProjectFolder
expectedErr bool
}{
Expand All @@ -494,8 +523,22 @@ func TestDetectProjectWorkspaces(t *testing.T) {
workflow: "single-workspace",
patternDetector: "main.tf",
changedFiles: []string{"mockproject/singleworkspace/main.tf"},
enablePRFilter: true,
expectedFoldersList: []ProjectFolder{
{Path: "mockproject/singleworkspace", WorkspaceList: []string{"default"}},
},
expectedErr: false,
},
{
name: "single-workspace",
foldersList: []ProjectFolder{{Path: "mockproject/singleworkspace"}, {Path: "mockproject/singleworkspace2"}},
workflow: "single-workspace",
patternDetector: "main.tf",
changedFiles: []string{"mockproject/singleworkspace/main.tf"},
enablePRFilter: false,
expectedFoldersList: []ProjectFolder{
{Path: "mockproject/singleworkspace", WorkspaceList: []string{"default"}},
{Path: "mockproject/singleworkspace2", WorkspaceList: []string{"default"}},
},
expectedErr: false,
},
Expand All @@ -505,6 +548,7 @@ func TestDetectProjectWorkspaces(t *testing.T) {
workflow: "multi-workspace",
patternDetector: "workspace_vard",
changedFiles: []string{"invalid/workspace_vars/test1.tfvars"},
enablePRFilter: true,
expectedFoldersList: []ProjectFolder{
{Path: "invalidpath", WorkspaceList: []string{"default"}},
},
Expand All @@ -516,6 +560,7 @@ func TestDetectProjectWorkspaces(t *testing.T) {
workflow: "multi-workspace",
patternDetector: "workspace_vars",
changedFiles: []string{"mockproject/multiworkspace/workspace_vars/test1.tfvars"},
enablePRFilter: true,
expectedFoldersList: []ProjectFolder{
{
Path: "mockproject/multiworkspace",
Expand All @@ -532,6 +577,7 @@ func TestDetectProjectWorkspaces(t *testing.T) {
changedFiles: []string{"mockproject/multiworkspace/workspace_vars/test1.tfvars",
"mockproject/multiworkspace2/workspace_vars/test2.tfvars",
},
enablePRFilter: true,
expectedFoldersList: []ProjectFolder{
{
Path: "mockproject/multiworkspace",
Expand All @@ -544,12 +590,33 @@ func TestDetectProjectWorkspaces(t *testing.T) {
},
expectedErr: false,
},
{
name: "multi-workspace",
foldersList: []ProjectFolder{{Path: "mockproject/multiworkspace"}, {Path: "mockproject/multiworkspace2"}},
workflow: "multi-workspace",
patternDetector: "workspace_vars",
changedFiles: []string{"mockproject/multiworkspace/workspace_vars/test1.tfvars",
"mockproject/multiworkspace2/workspace_vars/test2.tfvars",
},
enablePRFilter: false,
expectedFoldersList: []ProjectFolder{
{
Path: "mockproject/multiworkspace",
WorkspaceList: []string{"test1"},
},
{
Path: "mockproject/multiworkspace2",
WorkspaceList: []string{"test1", "test2"},
},
},
expectedErr: false,
},
// Add more test cases as needed
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
updatedFoldersList, err := detectProjectWorkspaces(test.foldersList, test.workflow, test.patternDetector, test.changedFiles)
updatedFoldersList, err := detectProjectWorkspaces(test.foldersList, test.workflow, test.patternDetector, test.changedFiles, test.enablePRFilter)
if test.expectedErr {
assert.Error(t, err)
} else {
Expand Down Expand Up @@ -615,7 +682,7 @@ func TestGenerateAtlantisYAML(t *testing.T) {
tempDir := t.TempDir()
tempFile := filepath.Join(tempDir, "/atlantis.yaml")

prChangedFiles := []string{"mockproject/single-workspace/main.tf"}
//prChangedFiles := []string{"mockproject/single-workspace/main.tf"}
// Define a sample configuration
config.GlobalConfig.Parameters = make(map[string]string)
config.GlobalConfig.Parameters["gh-token"] = "test-token"
Expand All @@ -630,20 +697,21 @@ func TestGenerateAtlantisYAML(t *testing.T) {
config.GlobalConfig.Parameters["parallel-apply"] = "true"
config.GlobalConfig.Parameters["parallel-plan"] = "true"
config.GlobalConfig.Parameters["automerge"] = "true"
config.GlobalConfig.Parameters["pr-filter"] = "false"

err := GenerateAtlantisYAML(prChangedFiles)
err := GenerateAtlantisYAML()
assert.NoError(t, err)

os.Remove(tempFile)

config.GlobalConfig.Parameters["output-type"] = "undefined"

err = GenerateAtlantisYAML(prChangedFiles)
err = GenerateAtlantisYAML()
assert.Error(t, err)

config.GlobalConfig.Parameters["output-type"] = "stdout"

err = GenerateAtlantisYAML(prChangedFiles)
err = GenerateAtlantisYAML()
assert.NoError(t, err)

}
Empty file.
12 changes: 8 additions & 4 deletions pkg/atlantis/multiple-workspace-workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,34 @@ func multiWorkspaceGetProjectScope(relPath, patternDetector string, changedFiles
return "workspace"
}

func multiWorkspaceGenWorkspaceList(relPath string, changedFiles []string, scope string) (workspaceList []string, err error) {
func multiWorkspaceGenWorkspaceList(relPath string, changedFiles []string, enablePRFilter bool, scope string) (workspaceList []string, err error) {
err = filepath.Walk(relPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.HasSuffix(info.Name(), tfvarsExtension) {
if helpers.IsStringInList(path, changedFiles) || (scope == "crossWorkspace") {
if helpers.IsStringInList(path, changedFiles) ||
(scope == "crossWorkspace") ||
enablePRFilter != true {
workspaceList = append(workspaceList, helpers.TrimFileExtension(info.Name()))
}
}
return nil
})

return workspaceList, err
}

func multiWorkspaceDetectProjectWorkspaces(changedFiles []string, foldersList []ProjectFolder, patternDetector string) (updatedFolderList []ProjectFolder, err error) {
func multiWorkspaceDetectProjectWorkspaces(changedFiles []string, enablePRFilter bool, foldersList []ProjectFolder, patternDetector string) (updatedFolderList []ProjectFolder, err error) {
for i := range foldersList {
scope := multiWorkspaceGetProjectScope(foldersList[i].Path, patternDetector, changedFiles)
workspaceList, err := multiWorkspaceGenWorkspaceList(foldersList[i].Path, changedFiles, scope)
workspaceList, err := multiWorkspaceGenWorkspaceList(foldersList[i].Path, changedFiles, enablePRFilter, scope)
if err != nil {
return foldersList, err
}
foldersList[i].WorkspaceList = workspaceList
}
fmt.Println(foldersList)
return foldersList, nil
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/atlantis/multiple-workspace-workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestMultiWorkspaceGetProjectScope(t *testing.T) {
func TestMultiWorkspaceGenWorkspaceList(t *testing.T) {
changedFiles := []string{"mockproject/multiworkspace/workspace_vars/test1.tfvars"}

workspaceList, err := multiWorkspaceGenWorkspaceList("mockproject/multiworkspace", changedFiles, "workspace")
workspaceList, err := multiWorkspaceGenWorkspaceList("mockproject/multiworkspace", changedFiles, true, "workspace")
assert.NoError(t, err)
assert.Equal(t, []string{"test1"}, workspaceList)

Expand Down
Loading

0 comments on commit 3dbfa6b

Please sign in to comment.