Added support to use .tfvars files from tests folder (#1386)

Signed-off-by: sanskruti-shahu <sanskruti.shahu@harness.io>
This commit is contained in:
Sanskruti Shahu 2024-03-29 18:14:27 +05:30 committed by GitHub
parent 8c6e334b39
commit 08f9a740ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 77 additions and 28 deletions

View File

@ -15,6 +15,7 @@ NEW FEATURES:
* Add support for a `removed` block that allows users to remove resources or modules from the state without destroying them. ([#1158](https://github.com/opentofu/opentofu/pull/1158)) * Add support for a `removed` block that allows users to remove resources or modules from the state without destroying them. ([#1158](https://github.com/opentofu/opentofu/pull/1158))
ENHANCEMENTS: ENHANCEMENTS:
* Added support to use `.tfvars` files from tests folder. ([#1386](https://github.com/opentofu/opentofu/pull/1386))
* Added `templatestring` function that takes a string and renders it as a template using a supplied set of template variables. ([#1223](https://github.com/opentofu/opentofu/pull/1223)) * Added `templatestring` function that takes a string and renders it as a template using a supplied set of template variables. ([#1223](https://github.com/opentofu/opentofu/pull/1223))
* Added `base64gunzip` function that takes a base64 encoded gzip string and returns the decompressed data as a string. ([#800](https://github.com/opentofu/opentofu/issues/800)) * Added `base64gunzip` function that takes a base64 encoded gzip string and returns the decompressed data as a string. ([#800](https://github.com/opentofu/opentofu/issues/800))
* Added `cidrcontains` function that determines if an address belongs to a certain prefix. ([#366](https://github.com/opentofu/opentofu/issues/366)) * Added `cidrcontains` function that determines if an address belongs to a certain prefix. ([#366](https://github.com/opentofu/opentofu/issues/366))

View File

@ -8,6 +8,7 @@ package command
import ( import (
"fmt" "fmt"
"os" "os"
"path/filepath"
"strings" "strings"
"github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2"
@ -62,30 +63,12 @@ func (m *Meta) collectVariableValues() (map[string]backend.UnparsedVariableValue
} }
} }
// Next up we have some implicit files that are loaded automatically // Next up we load implicit files from the specified directory (first root then tests dir
// if they are present. There's the original terraform.tfvars // as tests dir files have higher precendence). These files are automatically loaded if present.
// (DefaultVarsFilename) along with the later-added search for all files // There's the original terraform.tfvars (DefaultVarsFilename) along with the later-added
// ending in .auto.tfvars. // search for all files ending in .auto.tfvars.
if _, err := os.Stat(DefaultVarsFilename); err == nil { diags = diags.Append(m.addVarsFromDir(".", ret))
moreDiags := m.addVarsFromFile(DefaultVarsFilename, tofu.ValueFromAutoFile, ret) diags = diags.Append(m.addVarsFromDir("tests", ret))
diags = diags.Append(moreDiags)
}
const defaultVarsFilenameJSON = DefaultVarsFilename + ".json"
if _, err := os.Stat(defaultVarsFilenameJSON); err == nil {
moreDiags := m.addVarsFromFile(defaultVarsFilenameJSON, tofu.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)
}
if infos, err := os.ReadDir("."); err == nil {
// "infos" is already sorted by name, so we just need to filter it here.
for _, info := range infos {
name := info.Name()
if !isAutoVarFile(name) {
continue
}
moreDiags := m.addVarsFromFile(name, tofu.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)
}
}
// Finally we process values given explicitly on the command line, either // Finally we process values given explicitly on the command line, either
// as individual literal settings or as additional files to read. // as individual literal settings or as additional files to read.
@ -135,6 +118,33 @@ func (m *Meta) collectVariableValues() (map[string]backend.UnparsedVariableValue
return ret, diags return ret, diags
} }
func (m *Meta) addVarsFromDir(currDir string, ret map[string]backend.UnparsedVariableValue) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if _, err := os.Stat(filepath.Join(currDir, DefaultVarsFilename)); err == nil {
moreDiags := m.addVarsFromFile(filepath.Join(currDir, DefaultVarsFilename), tofu.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)
}
const defaultVarsFilenameJSON = DefaultVarsFilename + ".json"
if _, err := os.Stat(filepath.Join(currDir, defaultVarsFilenameJSON)); err == nil {
moreDiags := m.addVarsFromFile(filepath.Join(currDir, defaultVarsFilenameJSON), tofu.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)
}
if infos, err := os.ReadDir(currDir); err == nil {
// "infos" is already sorted by name, so we just need to filter it here.
for _, info := range infos {
name := info.Name()
if !isAutoVarFile(name) {
continue
}
moreDiags := m.addVarsFromFile(filepath.Join(currDir, name), tofu.ValueFromAutoFile, ret)
diags = diags.Append(moreDiags)
}
}
return diags
}
func (m *Meta) addVarsFromFile(filename string, sourceType tofu.ValueSourceType, to map[string]backend.UnparsedVariableValue) tfdiags.Diagnostics { func (m *Meta) addVarsFromFile(filename string, sourceType tofu.ValueSourceType, to map[string]backend.UnparsedVariableValue) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics var diags tfdiags.Diagnostics

View File

@ -161,6 +161,14 @@ func TestTest(t *testing.T) {
expected: "1 passed, 0 failed.", expected: "1 passed, 0 failed.",
code: 0, code: 0,
}, },
"pass_with_tests_dir_variables": {
expected: "1 passed, 0 failed.",
code: 0,
},
"override_with_tests_dir_variables": {
expected: "1 passed, 0 failed.",
code: 0,
},
} }
for name, tc := range tcs { for name, tc := range tcs {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {

View File

@ -0,0 +1,7 @@
variable "testVar" {
type = string
}
resource "test_resource" "testRes" {
value = var.testVar
}

View File

@ -0,0 +1 @@
testVar = "ValueFROM./tfvars"

View File

@ -0,0 +1,6 @@
run "validate_test_resource" {
assert {
condition = test_resource.testRes.value == "ValueFROMtests/tfvars"
error_message = "invalid value"
}
}

View File

@ -0,0 +1 @@
testVar = "ValueFROMtests/tfvars"

View File

@ -0,0 +1,7 @@
variable "testVar" {
type = string
}
resource "test_resource" "testRes" {
value = var.testVar
}

View File

@ -0,0 +1,6 @@
run "validate_test_resource" {
assert {
condition = test_resource.testRes.value == "ValueFROMtests/tfvars"
error_message = "invalid value"
}
}

View File

@ -0,0 +1 @@
testVar = "ValueFROMtests/tfvars"

View File

@ -244,10 +244,11 @@ can provide variables to your test run using any of the following methods:
| Order | Source | | Order | Source |
|:------:|:-------------------------------------------------------------------------------------------------------------------------------| |:------:|:-------------------------------------------------------------------------------------------------------------------------------|
| 1 | Environment variables with the `TF_VAR_` prefix. | | 1 | Environment variables with the `TF_VAR_` prefix. |
| 2 | tfvar files specified: `terraform.tfvars` and `*.auto.tfvars`. | | 2 | tfvar files specified in the current directory: `terraform.tfvars` and `*.auto.tfvars`. |
| 3 | Commandline variables defined using the flag `-var`, and the variables defined in the files specified by the flag `-var-file`. | | 3 | tfvar files specified in the tests directory: `tests/terraform.tfvars` and `tests/*.auto.tfvars`. |
| 4 | The variables from the `variables` block in a test file. | | 4 | Commandline variables defined using the flag `-var`, and the variables defined in the files specified by the flag `-var-file`. |
| 5 | The variables from the `variables` block in `run` block. | | 5 | The variables from the `variables` block in a test file. |
| 6 | The variables from the `variables` block in `run` block. |
OpenTofu evaluates the variables in the order listed above, so you can use it to override the previously set variable. OpenTofu evaluates the variables in the order listed above, so you can use it to override the previously set variable.
For example: For example: