mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-18 18:29:44 -05:00
move CollectValuesFromTests to arguments package
This keeps the CollectValues and CollectValuesFromTests implementations together.
This commit is contained in:
parent
8ed768c0af
commit
792cb432cb
3 changed files with 65 additions and 227 deletions
|
|
@ -7,11 +7,13 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
hcljson "github.com/hashicorp/hcl/v2/json"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
|
|
@ -175,6 +177,60 @@ func (v *Vars) CollectValues(onFileLoad func(filename string, src []byte)) (map[
|
|||
return ret, diags
|
||||
}
|
||||
|
||||
func CollectValuesForTests(testsFilePath string, onFileLoad func(filename string, src []byte)) (map[string]UnparsedVariableValue, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
ret := map[string]UnparsedVariableValue{}
|
||||
|
||||
// We collect the variables from the ./tests directory
|
||||
// there is no other need to process environmental variables
|
||||
// as this is done via collectVariableValues function
|
||||
if testsFilePath == "" {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Warning,
|
||||
"Missing test directory",
|
||||
"The test directory was unspecified when it should always be set. This is a bug in Terraform - please report it."))
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
// Firstly we collect variables from .tfvars file
|
||||
testVarsFilename := filepath.Join(testsFilePath, DefaultVarsFilename)
|
||||
if _, err := os.Stat(testVarsFilename); err == nil {
|
||||
moreDiags := addVarsFromFile(testVarsFilename, terraform.ValueFromAutoFile, ret, onFileLoad)
|
||||
diags = diags.Append(moreDiags)
|
||||
|
||||
}
|
||||
|
||||
// Then we collect variables from .tfvars.json file
|
||||
const defaultVarsFilenameJSON = DefaultVarsFilename + ".json"
|
||||
testVarsFilenameJSON := filepath.Join(testsFilePath, defaultVarsFilenameJSON)
|
||||
|
||||
if _, err := os.Stat(testVarsFilenameJSON); err == nil {
|
||||
moreDiags := addVarsFromFile(testVarsFilenameJSON, terraform.ValueFromAutoFile, ret, onFileLoad)
|
||||
diags = diags.Append(moreDiags)
|
||||
}
|
||||
|
||||
// Also, load any variables from the *.auto.tfvars files.
|
||||
if infos, err := os.ReadDir(testsFilePath); err == nil {
|
||||
for _, info := range infos {
|
||||
if info.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !isAutoVarFile(info.Name()) {
|
||||
continue
|
||||
}
|
||||
|
||||
moreDiags := addVarsFromFile(filepath.Join(testsFilePath, info.Name()), terraform.ValueFromAutoFile, ret, onFileLoad)
|
||||
diags = diags.Append(moreDiags)
|
||||
}
|
||||
}
|
||||
|
||||
// Also, no need to additionally process variables from command line,
|
||||
// as this is also done via collectVariableValues
|
||||
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
// TODO: Can I get around mutating the to map efficiently?
|
||||
func addVarsFromFile(filename string, sourceType terraform.ValueSourceType, to map[string]UnparsedVariableValue, onFileLoad func(filename string, src []byte)) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
|
|
|||
|
|
@ -1,220 +0,0 @@
|
|||
// Copyright IBM Corp. 2014, 2026
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
hcljson "github.com/hashicorp/hcl/v2/json"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/command/arguments"
|
||||
"github.com/hashicorp/terraform/internal/configs"
|
||||
"github.com/hashicorp/terraform/internal/terraform"
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
)
|
||||
|
||||
// VarEnvPrefix is the prefix for environment variables that represent values
|
||||
// for root module input variables.
|
||||
const VarEnvPrefix = "TF_VAR_"
|
||||
|
||||
// collectVariableValuesForTests inspects the various places that test
|
||||
// values can come from and constructs a map ready to be passed to the
|
||||
// backend as part of a backendrun.Operation.
|
||||
//
|
||||
// This method returns diagnostics relating to the collection of the values,
|
||||
// but the values themselves may produce additional diagnostics when finally
|
||||
// parsed.
|
||||
func (m *Meta) collectVariableValuesForTests(testsFilePath string) (map[string]arguments.UnparsedVariableValue, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
ret := map[string]arguments.UnparsedVariableValue{}
|
||||
|
||||
// We collect the variables from the ./tests directory
|
||||
// there is no other need to process environmental variables
|
||||
// as this is done via collectVariableValues function
|
||||
if testsFilePath == "" {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Warning,
|
||||
"Missing test directory",
|
||||
"The test directory was unspecified when it should always be set. This is a bug in Terraform - please report it."))
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
// Firstly we collect variables from .tfvars file
|
||||
testVarsFilename := filepath.Join(testsFilePath, DefaultVarsFilename)
|
||||
if _, err := os.Stat(testVarsFilename); err == nil {
|
||||
moreDiags := m.addVarsFromFile(testVarsFilename, terraform.ValueFromAutoFile, ret)
|
||||
diags = diags.Append(moreDiags)
|
||||
|
||||
}
|
||||
|
||||
// Then we collect variables from .tfvars.json file
|
||||
const defaultVarsFilenameJSON = DefaultVarsFilename + ".json"
|
||||
testVarsFilenameJSON := filepath.Join(testsFilePath, defaultVarsFilenameJSON)
|
||||
|
||||
if _, err := os.Stat(testVarsFilenameJSON); err == nil {
|
||||
moreDiags := m.addVarsFromFile(testVarsFilenameJSON, terraform.ValueFromAutoFile, ret)
|
||||
diags = diags.Append(moreDiags)
|
||||
}
|
||||
|
||||
// Also, load any variables from the *.auto.tfvars files.
|
||||
if infos, err := os.ReadDir(testsFilePath); err == nil {
|
||||
for _, info := range infos {
|
||||
if info.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !isAutoVarFile(info.Name()) {
|
||||
continue
|
||||
}
|
||||
|
||||
moreDiags := m.addVarsFromFile(filepath.Join(testsFilePath, info.Name()), terraform.ValueFromAutoFile, ret)
|
||||
diags = diags.Append(moreDiags)
|
||||
}
|
||||
}
|
||||
|
||||
// Also, no need to additionally process variables from command line,
|
||||
// as this is also done via collectVariableValues
|
||||
|
||||
return ret, diags
|
||||
}
|
||||
|
||||
func (m *Meta) addVarsFromFile(filename string, sourceType terraform.ValueSourceType, to map[string]arguments.UnparsedVariableValue) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
src, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to read variables file",
|
||||
fmt.Sprintf("Given variables file %s does not exist.", filename),
|
||||
))
|
||||
} else {
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Failed to read variables file",
|
||||
fmt.Sprintf("Error while reading %s: %s.", filename, err),
|
||||
))
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
loader, err := m.initConfigLoader()
|
||||
if err != nil {
|
||||
diags = diags.Append(err)
|
||||
return diags
|
||||
}
|
||||
|
||||
// Record the file source code for snippets in diagnostic messages.
|
||||
loader.Parser().ForceFileSource(filename, src)
|
||||
|
||||
var f *hcl.File
|
||||
if strings.HasSuffix(filename, ".json") {
|
||||
var hclDiags hcl.Diagnostics
|
||||
f, hclDiags = hcljson.Parse(src, filename)
|
||||
diags = diags.Append(hclDiags)
|
||||
if f == nil || f.Body == nil {
|
||||
return diags
|
||||
}
|
||||
} else {
|
||||
var hclDiags hcl.Diagnostics
|
||||
f, hclDiags = hclsyntax.ParseConfig(src, filename, hcl.Pos{Line: 1, Column: 1})
|
||||
diags = diags.Append(hclDiags)
|
||||
if f == nil || f.Body == nil {
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
// Before we do our real decode, we'll probe to see if there are any blocks
|
||||
// of type "variable" in this body, since it's a common mistake for new
|
||||
// users to put variable declarations in tfvars rather than variable value
|
||||
// definitions, and otherwise our error message for that case is not so
|
||||
// helpful.
|
||||
{
|
||||
content, _, _ := f.Body.PartialContent(&hcl.BodySchema{
|
||||
Blocks: []hcl.BlockHeaderSchema{
|
||||
{
|
||||
Type: "variable",
|
||||
LabelNames: []string{"name"},
|
||||
},
|
||||
},
|
||||
})
|
||||
for _, block := range content.Blocks {
|
||||
name := block.Labels[0]
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Variable declaration in .tfvars file",
|
||||
Detail: fmt.Sprintf("A .tfvars file is used to assign values to variables that have already been declared in .tf files, not to declare new variables. To declare variable %q, place this block in one of your .tf files, such as variables.tf.\n\nTo set a value for this variable in %s, use the definition syntax instead:\n %s = <value>", name, block.TypeRange.Filename, name),
|
||||
Subject: &block.TypeRange,
|
||||
})
|
||||
}
|
||||
if diags.HasErrors() {
|
||||
// If we already found problems then JustAttributes below will find
|
||||
// the same problems with less-helpful messages, so we'll bail for
|
||||
// now to let the user focus on the immediate problem.
|
||||
return diags
|
||||
}
|
||||
}
|
||||
|
||||
attrs, hclDiags := f.Body.JustAttributes()
|
||||
diags = diags.Append(hclDiags)
|
||||
|
||||
for name, attr := range attrs {
|
||||
to[name] = unparsedVariableValueExpression{
|
||||
expr: attr.Expr,
|
||||
sourceType: sourceType,
|
||||
}
|
||||
}
|
||||
return diags
|
||||
}
|
||||
|
||||
// unparsedVariableValueLiteral is a backendrun.UnparsedVariableValue
|
||||
// implementation that was actually already parsed (!). This is
|
||||
// intended to deal with expressions inside "tfvars" files.
|
||||
type unparsedVariableValueExpression struct {
|
||||
expr hcl.Expression
|
||||
sourceType terraform.ValueSourceType
|
||||
}
|
||||
|
||||
func (v unparsedVariableValueExpression) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
val, hclDiags := v.expr.Value(nil) // nil because no function calls or variable references are allowed here
|
||||
diags = diags.Append(hclDiags)
|
||||
|
||||
rng := tfdiags.SourceRangeFromHCL(v.expr.Range())
|
||||
|
||||
return &terraform.InputValue{
|
||||
Value: val,
|
||||
SourceType: v.sourceType,
|
||||
SourceRange: rng,
|
||||
}, diags
|
||||
}
|
||||
|
||||
// unparsedVariableValueString is a backendrun.UnparsedVariableValue
|
||||
// implementation that parses its value from a string. This can be used
|
||||
// to deal with values given directly on the command line and via environment
|
||||
// variables.
|
||||
type unparsedVariableValueString struct {
|
||||
str string
|
||||
name string
|
||||
sourceType terraform.ValueSourceType
|
||||
}
|
||||
|
||||
func (v unparsedVariableValueString) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
val, hclDiags := mode.Parse(v.name, v.str)
|
||||
diags = diags.Append(hclDiags)
|
||||
|
||||
return &terraform.InputValue{
|
||||
Value: val,
|
||||
SourceType: v.sourceType,
|
||||
}, diags
|
||||
}
|
||||
|
|
@ -388,10 +388,6 @@ func (m *Meta) setupTestExecution(mode moduletest.CommandMode, command string, r
|
|||
}
|
||||
m.variableArgs = arguments.FlagNameValueSlice{Items: &items}
|
||||
|
||||
// Collect variables for "terraform test"
|
||||
preparation.TestVariables, moreDiags = m.collectVariableValuesForTests(preparation.Args.TestDirectory)
|
||||
diags = diags.Append(moreDiags)
|
||||
|
||||
loader, err := m.initConfigLoader()
|
||||
if err != nil {
|
||||
diags = diags.Append(err)
|
||||
|
|
@ -399,11 +395,17 @@ func (m *Meta) setupTestExecution(mode moduletest.CommandMode, command string, r
|
|||
return
|
||||
}
|
||||
|
||||
registerFileSource := func(filename string, src []byte) {
|
||||
loader.Parser().ForceFileSource(filename, src)
|
||||
}
|
||||
|
||||
// Collect variables for "terraform test"
|
||||
preparation.TestVariables, moreDiags = arguments.CollectValuesForTests(preparation.Args.TestDirectory, registerFileSource)
|
||||
diags = diags.Append(moreDiags)
|
||||
|
||||
// Collect variable value and add them to the operation request
|
||||
var varDiags tfdiags.Diagnostics
|
||||
preparation.Variables, varDiags = preparation.Args.Vars.CollectValues(func(filename string, src []byte) {
|
||||
loader.Parser().ForceFileSource(filename, src)
|
||||
})
|
||||
preparation.Variables, varDiags = preparation.Args.Vars.CollectValues(registerFileSource)
|
||||
diags = diags.Append(varDiags)
|
||||
if diags.HasErrors() {
|
||||
view.Diagnostics(nil, nil, diags)
|
||||
|
|
|
|||
Loading…
Reference in a new issue