backend: Cap number of "undeclared variable" warnings at four

For users who in previous versions have relied on our lack of checking for
whether variables are declared, they may previously have seen an
overwhelming number of warnings when running Terraform v0.12.

Here we cap that number at three specific warnings and then one general
warning, so we can still give a specific source location for the first
couple (for users who have genuinely made a typo) but summarize away a
large number for those who are seeing this because they've not yet
migrated to using environment variables.
This commit is contained in:
Martin Atkins 2019-03-05 15:06:59 -08:00
parent 9336c7fba3
commit 709487b4f1
2 changed files with 85 additions and 6 deletions

View File

@ -28,6 +28,12 @@ func ParseVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*
var diags tfdiags.Diagnostics
ret := make(terraform.InputValues, len(vv))
// Currently we're generating only warnings for undeclared variables
// defined in files (see below) but we only want to generate a few warnings
// at a time because existing deployments may have lots of these and
// the result can therefore be overwhelming.
seenUndeclaredInFile := 0
for name, rv := range vv {
var mode configs.VariableParsingMode
config, declared := decls[name]
@ -56,12 +62,16 @@ func ParseVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*
// feedback to users who make typos. Those using this approach
// should migrate to using environment variables instead before
// this becomes an error in a future major release.
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Value for undeclared variable",
Detail: fmt.Sprintf("The root module does not declare a variable named %q. To use this value, add a \"variable\" block to the configuration.\n\nUsing a variables file to set an undeclared variable is deprecated and will become an error in a future release. If you wish to provide certain \"global\" settings to all configurations in your organization, use TF_VAR_... environment variables to set these instead.", name),
Subject: val.SourceRange.ToHCL().Ptr(),
})
if seenUndeclaredInFile < 3 {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Value for undeclared variable",
Detail: fmt.Sprintf("The root module does not declare a variable named %q. To use this value, add a \"variable\" block to the configuration.\n\nUsing a variables file to set an undeclared variable is deprecated and will become an error in a future release. If you wish to provide certain \"global\" settings to all configurations in your organization, use TF_VAR_... environment variables to set these instead.", name),
Subject: val.SourceRange.ToHCL().Ptr(),
})
}
seenUndeclaredInFile++
case terraform.ValueFromEnvVar:
// We allow and ignore undeclared names for environment
// variables, because users will often set these globally
@ -88,5 +98,14 @@ func ParseVariableValues(vv map[string]UnparsedVariableValue, decls map[string]*
ret[name] = val
}
if seenUndeclaredInFile >= 3 {
extras := seenUndeclaredInFile - 2
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Values for undeclared variables",
Detail: fmt.Sprintf("In addition to the other similar warnings shown, %d other variable(s) defined without being declared.", extras),
})
}
return ret, diags
}

View File

@ -0,0 +1,60 @@
package backend
import (
"testing"
"github.com/zclconf/go-cty/cty"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/terraform/tfdiags"
)
func TestParseVariableValuesUndeclared(t *testing.T) {
vv := map[string]UnparsedVariableValue{
"undeclared0": testUnparsedVariableValue("0"),
"undeclared1": testUnparsedVariableValue("1"),
"undeclared2": testUnparsedVariableValue("2"),
"undeclared3": testUnparsedVariableValue("3"),
"undeclared4": testUnparsedVariableValue("4"),
}
decls := map[string]*configs.Variable{}
_, diags := ParseVariableValues(vv, decls)
for _, diag := range diags {
t.Logf("%s: %s", diag.Description().Summary, diag.Description().Detail)
}
if got, want := len(diags), 4; got != want {
t.Fatalf("wrong number of diagnostics %d; want %d", got, want)
}
const undeclSingular = `Value for undeclared variable`
const undeclPlural = `Values for undeclared variables`
if got, want := diags[0].Description().Summary, undeclSingular; got != want {
t.Errorf("wrong summary for diagnostic 0\ngot: %s\nwant: %s", got, want)
}
if got, want := diags[1].Description().Summary, undeclSingular; got != want {
t.Errorf("wrong summary for diagnostic 1\ngot: %s\nwant: %s", got, want)
}
if got, want := diags[2].Description().Summary, undeclSingular; got != want {
t.Errorf("wrong summary for diagnostic 2\ngot: %s\nwant: %s", got, want)
}
if got, want := diags[3].Description().Summary, undeclPlural; got != want {
t.Errorf("wrong summary for diagnostic 3\ngot: %s\nwant: %s", got, want)
}
}
type testUnparsedVariableValue string
func (v testUnparsedVariableValue) ParseVariableValue(mode configs.VariableParsingMode) (*terraform.InputValue, tfdiags.Diagnostics) {
return &terraform.InputValue{
Value: cty.StringVal(string(v)),
SourceType: terraform.ValueFromNamedFile,
SourceRange: tfdiags.SourceRange{
Filename: "fake.tfvars",
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
},
}, nil
}