Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add *WithFilter helper functions #1353

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 30 additions & 15 deletions modules/files/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ import (
"github.com/mattn/go-zglob"
)

// DefaultPathFilter is the default filter used by CopyTerraformFolderToDest to determine which files to copy.
func DefaultPathFilter(path string) bool {
if PathIsTerraformVersionFile(path) || PathIsTerraformLockFile(path) {
return true
}
if PathContainsHiddenFileOrFolder(path) || PathContainsTerraformStateOrVars(path) {
return false
}
return true
}

// FileExists returns true if the given file exists.
func FileExists(path string) bool {
_, err := os.Stat(path)
Expand Down Expand Up @@ -38,24 +49,12 @@ func IsExistingDir(path string) bool {
return err == nil && fileInfo.IsDir()
}

// CopyTerraformFolderToDest creates a copy of the given folder and all its contents in a specified folder with a unique name and the given prefix.
// CopyTerraformFolderToDestWithFilter creates a copy of the given folder and all its contents in a specified folder with a unique name and the given prefix.
// This is useful when running multiple tests in parallel against the same set of Terraform files to ensure the
// tests don't overwrite each other's .terraform working directory and terraform.tfstate files. This method returns
// the path to the dest folder with the copied contents. Hidden files and folders (with the exception of the `.terraform-version` files used
// by the [tfenv tool](https://github.com/tfutils/tfenv) and `.terraform.lock.hcl` used by Terraform to lock providers versions), Terraform state
// files, and terraform.tfvars files are not copied to this temp folder, as you typically don't want them interfering with your tests.
// the path to the dest folder with the copied contents. You can configure which files you want to copy by passing in a filter function.
// This method is useful when running through a build tool so the files are copied to a destination that is cleaned on each run of the pipeline.
func CopyTerraformFolderToDest(folderPath string, destRootFolder string, tempFolderPrefix string) (string, error) {
filter := func(path string) bool {
if PathIsTerraformVersionFile(path) || PathIsTerraformLockFile(path) {
return true
}
if PathContainsHiddenFileOrFolder(path) || PathContainsTerraformStateOrVars(path) {
return false
}
return true
}

func CopyTerraformFolderToDestWithFilter(folderPath string, destRootFolder string, tempFolderPrefix string, filter func(string) bool) (string, error) {
destFolder, err := CopyFolderToDest(folderPath, destRootFolder, tempFolderPrefix, filter)
if err != nil {
return "", err
Expand All @@ -64,6 +63,22 @@ func CopyTerraformFolderToDest(folderPath string, destRootFolder string, tempFol
return destFolder, nil
}

// CopyTerraformFolderToDest creates a copy of the given folder and all its contents in a specified folder with a unique name and the given prefix.
// This is useful when running multiple tests in parallel against the same set of Terraform files to ensure the
// tests don't overwrite each other's .terraform working directory and terraform.tfstate files. This method returns
// the path to the dest folder with the copied contents. Hidden files and folders (with the exception of the `.terraform-version` files used
// by the [tfenv tool](https://github.com/tfutils/tfenv) and `.terraform.lock.hcl` used by Terraform to lock providers versions), Terraform state
// files, and terraform.tfvars files are not copied to this temp folder, as you typically don't want them interfering with your tests.
// This method is useful when running through a build tool so the files are copied to a destination that is cleaned on each run of the pipeline.
func CopyTerraformFolderToDest(folderPath string, destRootFolder string, tempFolderPrefix string) (string, error) {
return CopyTerraformFolderToDestWithFilter(folderPath, destRootFolder, tempFolderPrefix, DefaultPathFilter)
}

// CopyTerraformFolderToTempWithFilter calls CopyTerraformFolderToDestWithFilter, passing os.TempDir() as the root destination folder.
func CopyTerraformFolderToTempWithFilter(folderPath string, tempFolderPrefix string, filter func(string) bool) (string, error) {
return CopyTerraformFolderToDestWithFilter(folderPath, os.TempDir(), tempFolderPrefix, filter)
}

// CopyTerraformFolderToTemp calls CopyTerraformFolderToDest, passing os.TempDir() as the root destination folder.
func CopyTerraformFolderToTemp(folderPath string, tempFolderPrefix string) (string, error) {
return CopyTerraformFolderToDest(folderPath, os.TempDir(), tempFolderPrefix)
Expand Down
72 changes: 69 additions & 3 deletions modules/test-structure/test_structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@ func SkipStageEnvVarSet() bool {
return false
}

// CopyTerraformFolderToTempWithFilter copies the given root folder to a randomly-named temp folder and return the path to the
// given terraform modules folder within the new temp root folder. This is useful when running multiple tests in
// parallel against the same set of Terraform files to ensure the tests don't overwrite each other's .terraform working
// directory and terraform.tfstate files. To ensure relative paths work, we copy over the entire root folder to a temp
// folder, and then return the path within that temp folder to the given terraform module dir, which is where the actual
// test will be running.
// For example, suppose you had the target terraform folder you want to test in "/examples/terraform-aws-example"
// relative to the repo root. If your tests reside in the "/test" relative to the root, then you will use this as
// follows:
//
// // Root folder where terraform files should be (relative to the test folder)
// rootFolder := ".."
//
// // Relative path to terraform module being tested from the root folder
// terraformFolderRelativeToRoot := "examples/terraform-aws-example"
//
// // Copy the terraform folder to a temp folder
// tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot)
//
// // Make sure to use the temp test folder in the terraform options
// terraformOptions := &terraform.Options{
// TerraformDir: tempTestFolder,
// }
//
// Note that if any of the SKIP_<stage> environment variables is set, we assume this is a test in the local dev where
// there are no other concurrent tests running and we want to be able to cache test data between test stages, so in that
// case, we do NOT copy anything to a temp folder, and return the path to the original terraform module folder instead.
func CopyTerraformFolderToTempWithFilter(t testing.TestingT, rootFolder string, terraformModuleFolder string, filter func(string) bool) string {
return CopyTerraformFolderToDestWithFilter(t, rootFolder, terraformModuleFolder, os.TempDir(), filter)
}

// CopyTerraformFolderToTemp copies the given root folder to a randomly-named temp folder and return the path to the
// given terraform modules folder within the new temp root folder. This is useful when running multiple tests in
// parallel against the same set of Terraform files to ensure the tests don't overwrite each other's .terraform working
Expand Down Expand Up @@ -74,7 +105,7 @@ func CopyTerraformFolderToTemp(t testing.TestingT, rootFolder string, terraformM
return CopyTerraformFolderToDest(t, rootFolder, terraformModuleFolder, os.TempDir())
}

// CopyTerraformFolderToDest copies the given root folder to a randomly-named temp folder and return the path to the
// CopyTerraformFolderToDestWithFilter copies the given root folder to a randomly-named temp folder and return the path to the
// given terraform modules folder within the new temp root folder. This is useful when running multiple tests in
// parallel against the same set of Terraform files to ensure the tests don't overwrite each other's .terraform working
// directory and terraform.tfstate files. To ensure relative paths work, we copy over the entire root folder to a temp
Expand Down Expand Up @@ -105,7 +136,7 @@ func CopyTerraformFolderToTemp(t testing.TestingT, rootFolder string, terraformM
// Note that if any of the SKIP_<stage> environment variables is set, we assume this is a test in the local dev where
// there are no other concurrent tests running and we want to be able to cache test data between test stages, so in that
// case, we do NOT copy anything to a temp folder, and return the path to the original terraform module folder instead.
func CopyTerraformFolderToDest(t testing.TestingT, rootFolder string, terraformModuleFolder string, destRootFolder string) string {
func CopyTerraformFolderToDestWithFilter(t testing.TestingT, rootFolder string, terraformModuleFolder string, destRootFolder string, filter func(string) bool) string {
if SkipStageEnvVarSet() {
logger.Logf(t, "A SKIP_XXX environment variable is set. Using original examples folder rather than a temp folder so we can cache data between stages for faster local testing.")
return filepath.Join(rootFolder, terraformModuleFolder)
Expand All @@ -119,7 +150,7 @@ func CopyTerraformFolderToDest(t testing.TestingT, rootFolder string, terraformM
t.Fatal(files.DirNotFoundError{Directory: fullTerraformModuleFolder})
}

tmpRootFolder, err := files.CopyTerraformFolderToDest(rootFolder, destRootFolder, cleanName(t.Name()))
tmpRootFolder, err := files.CopyTerraformFolderToDestWithFilter(rootFolder, destRootFolder, cleanName(t.Name()), filter)
if err != nil {
t.Fatal(err)
}
Expand All @@ -132,6 +163,41 @@ func CopyTerraformFolderToDest(t testing.TestingT, rootFolder string, terraformM
return tmpTestFolder
}

// CopyTerraformFolderToDest copies the given root folder to a randomly-named temp folder and return the path to the
// given terraform modules folder within the new temp root folder. This is useful when running multiple tests in
// parallel against the same set of Terraform files to ensure the tests don't overwrite each other's .terraform working
// directory and terraform.tfstate files. To ensure relative paths work, we copy over the entire root folder to a temp
// folder, and then return the path within that temp folder to the given terraform module dir, which is where the actual
// test will be running.
// For example, suppose you had the target terraform folder you want to test in "/examples/terraform-aws-example"
// relative to the repo root. If your tests reside in the "/test" relative to the root, then you will use this as
// follows:
//
// // Destination for the copy of the files. In this example we are using the Azure Dev Ops variable
// // for the folder that is cleaned after each pipeline job.
// destRootFolder := os.Getenv("AGENT_TEMPDIRECTORY")
//
// // Root folder where terraform files should be (relative to the test folder)
// rootFolder := ".."
//
// // Relative path to terraform module being tested from the root folder
// terraformFolderRelativeToRoot := "examples/terraform-aws-example"
//
// // Copy the terraform folder to a temp folder
// tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot, destRootFolder)
//
// // Make sure to use the temp test folder in the terraform options
// terraformOptions := &terraform.Options{
// TerraformDir: tempTestFolder,
// }
//
// Note that if any of the SKIP_<stage> environment variables is set, we assume this is a test in the local dev where
// there are no other concurrent tests running and we want to be able to cache test data between test stages, so in that
// case, we do NOT copy anything to a temp folder, and return the path to the original terraform module folder instead.
func CopyTerraformFolderToDest(t testing.TestingT, rootFolder string, terraformModuleFolder string, destRootFolder string) string {
return CopyTerraformFolderToDestWithFilter(t, rootFolder, terraformModuleFolder, destRootFolder, files.DefaultPathFilter)
}

func cleanName(originalName string) string {
parts := strings.Split(originalName, "/")
return parts[len(parts)-1]
Expand Down