Skip to content

Commit fc20b43

Browse files
support deprecating variables
1 parent 92769ee commit fc20b43

File tree

5 files changed

+205
-3
lines changed

5 files changed

+205
-3
lines changed

internal/configs/named_values.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ type Variable struct {
4848
Nullable bool
4949
NullableSet bool
5050

51+
Deprecated string
52+
DeprecatedSet bool
53+
DeprecatedRange hcl.Range
54+
5155
DeclRange hcl.Range
5256
}
5357

@@ -186,6 +190,13 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno
186190
v.Default = val
187191
}
188192

193+
if attr, exists := content.Attributes["deprecated"]; exists {
194+
valDiags := gohcl.DecodeExpression(attr.Expr, nil, &v.Deprecated)
195+
diags = append(diags, valDiags...)
196+
v.DeprecatedSet = true
197+
v.DeprecatedRange = attr.Range
198+
}
199+
189200
for _, block := range content.Blocks {
190201
switch block.Type {
191202

@@ -509,6 +520,9 @@ var variableBlockSchema = &hcl.BodySchema{
509520
{
510521
Name: "nullable",
511522
},
523+
{
524+
Name: "deprecated",
525+
},
512526
},
513527
Blocks: []hcl.BlockHeaderSchema{
514528
{

internal/configs/named_values_test.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ func TestOutputDeprecation(t *testing.T) {
5454
output "foo" {
5555
value = "bar"
5656
deprecated = "This output is deprecated"
57-
}
58-
`
57+
}
58+
`
5959

6060
hclF, diags := hclsyntax.ParseConfig([]byte(src), "test.tf", hcl.InitialPos)
6161
if diags.HasErrors() {
@@ -66,7 +66,6 @@ func TestOutputDeprecation(t *testing.T) {
6666
if diags.HasErrors() {
6767
t.Fatalf("unexpected error: %q", diags)
6868
}
69-
7069
if !b.Outputs[0].DeprecatedSet {
7170
t.Fatalf("expected output to be deprecated")
7271
}
@@ -75,3 +74,30 @@ func TestOutputDeprecation(t *testing.T) {
7574
t.Fatalf("expected output to have deprecation message")
7675
}
7776
}
77+
78+
func TestVariableDeprecation(t *testing.T) {
79+
src := `
80+
variable "foo" {
81+
type = string
82+
deprecated = "This variable is deprecated, use bar instead"
83+
}
84+
`
85+
86+
hclF, diags := hclsyntax.ParseConfig([]byte(src), "test.tf", hcl.InitialPos)
87+
if diags.HasErrors() {
88+
t.Fatal(diags.Error())
89+
}
90+
91+
b, diags := parseConfigFile(hclF.Body, nil, false, false)
92+
if diags.HasErrors() {
93+
t.Fatalf("unexpected error: %q", diags)
94+
}
95+
96+
if !b.Variables[0].DeprecatedSet {
97+
t.Fatalf("expected variable to be deprecated")
98+
}
99+
100+
if b.Variables[0].Deprecated != "This variable is deprecated, use bar instead" {
101+
t.Fatalf("expected variable to have deprecation message")
102+
}
103+
}

internal/terraform/context_plan2_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7577,3 +7577,147 @@ resource "test_resource" "test" {
75777577
},
75787578
))
75797579
}
7580+
7581+
func TestContext2Plan_deprecated_variable(t *testing.T) {
7582+
m := testModuleInline(t, map[string]string{
7583+
"mod/main.tf": `
7584+
variable "old-and-used" {
7585+
type = string
7586+
deprecated = "module variable deprecation 1"
7587+
default = "optional"
7588+
}
7589+
7590+
variable "old-and-unused" {
7591+
type = string
7592+
deprecated = "module variable deprecation 2"
7593+
default = "optional"
7594+
}
7595+
7596+
variable "new" {
7597+
type = string
7598+
default = "optional"
7599+
}
7600+
7601+
output "use-everything" {
7602+
value = {
7603+
used = var.old-and-used
7604+
unused = var.old-and-unused
7605+
new = var.new
7606+
}
7607+
}
7608+
`,
7609+
"main.tf": `
7610+
variable "root-old-and-used" {
7611+
type = string
7612+
deprecated = "root variable deprecation 1"
7613+
default = "optional"
7614+
}
7615+
7616+
variable "root-old-and-unused" {
7617+
type = string
7618+
deprecated = "root variable deprecation 2"
7619+
default = "optional"
7620+
}
7621+
7622+
variable "new" {
7623+
type = string
7624+
default = "new"
7625+
}
7626+
7627+
module "old-mod" {
7628+
source = "./mod"
7629+
old-and-used = "old"
7630+
}
7631+
7632+
module "new-mod" {
7633+
source = "./mod"
7634+
new = "new"
7635+
}
7636+
7637+
output "use-everything" {
7638+
value = {
7639+
used = var.root-old-and-used
7640+
unused = var.root-old-and-unused
7641+
new = var.new
7642+
}
7643+
}
7644+
`,
7645+
})
7646+
7647+
p := new(testing_provider.MockProvider)
7648+
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&providerSchema{
7649+
ResourceTypes: map[string]*configschema.Block{
7650+
"test_resource": {
7651+
Attributes: map[string]*configschema.Attribute{
7652+
"attr": {
7653+
Type: cty.String,
7654+
Computed: true,
7655+
},
7656+
},
7657+
},
7658+
},
7659+
})
7660+
7661+
ctx := testContext2(t, &ContextOpts{
7662+
Providers: map[addrs.Provider]providers.Factory{
7663+
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
7664+
},
7665+
})
7666+
7667+
vars := InputValues{
7668+
"root-old-and-used": {
7669+
Value: cty.StringVal("root-old-and-used"),
7670+
},
7671+
"root-old-and-unused": {
7672+
Value: cty.NullVal(cty.String),
7673+
},
7674+
"new": {
7675+
Value: cty.StringVal("new"),
7676+
},
7677+
}
7678+
7679+
// We can find module variable deprecation during validation
7680+
diags := ctx.Validate(m, &ValidateOpts{})
7681+
var expectedValidateDiags tfdiags.Diagnostics
7682+
expectedValidateDiags = expectedValidateDiags.Append(
7683+
&hcl.Diagnostic{
7684+
Severity: hcl.DiagWarning,
7685+
Summary: "Deprecated variable got a value",
7686+
Detail: "module variable deprecation 1",
7687+
Subject: &hcl.Range{
7688+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
7689+
Start: hcl.Pos{Line: 21, Column: 20, Byte: 350},
7690+
End: hcl.Pos{Line: 21, Column: 25, Byte: 355},
7691+
},
7692+
},
7693+
)
7694+
tfdiags.AssertDiagnosticsMatch(t, diags, expectedValidateDiags)
7695+
7696+
_, diags = ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, vars))
7697+
var expectedPlanDiags tfdiags.Diagnostics
7698+
expectedPlanDiags = expectedPlanDiags.Append(
7699+
&hcl.Diagnostic{
7700+
Severity: hcl.DiagWarning,
7701+
Summary: "Deprecated variable got a value",
7702+
Detail: "root variable deprecation 1",
7703+
Subject: &hcl.Range{
7704+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
7705+
Start: hcl.Pos{Line: 4, Column: 2, Byte: 48},
7706+
End: hcl.Pos{Line: 4, Column: 42, Byte: 90},
7707+
},
7708+
},
7709+
).Append(
7710+
&hcl.Diagnostic{
7711+
Severity: hcl.DiagWarning,
7712+
Summary: "Deprecated variable got a value",
7713+
Detail: "module variable deprecation 1",
7714+
Subject: &hcl.Range{
7715+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
7716+
Start: hcl.Pos{Line: 21, Column: 20, Byte: 350},
7717+
End: hcl.Pos{Line: 21, Column: 25, Byte: 355},
7718+
},
7719+
},
7720+
)
7721+
7722+
tfdiags.AssertDiagnosticsMatch(t, diags, expectedPlanDiags)
7723+
}

internal/terraform/node_module_variable.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,15 @@ func (n *nodeModuleVariable) evalModuleVariable(ctx EvalContext, validateOnly bo
307307
finalVal, moreDiags := PrepareFinalInputVariableValue(n.Addr, rawVal, n.Config)
308308
diags = diags.Append(moreDiags)
309309

310+
if n.Config.DeprecatedSet && !givenVal.IsNull() {
311+
diags = diags.Append(&hcl.Diagnostic{
312+
Severity: hcl.DiagWarning,
313+
Summary: "Deprecated variable got a value",
314+
Detail: n.Config.Deprecated,
315+
Subject: n.Expr.Range().Ptr(),
316+
})
317+
}
318+
310319
return finalVal, diags.ErrWithWarnings()
311320
}
312321

internal/terraform/node_root_variable.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ func (n *NodeRootVariable) Execute(ctx EvalContext, op walkOperation) tfdiags.Di
9292
}
9393
}
9494

95+
if n.Config.DeprecatedSet && !givenVal.Value.IsNull() && givenVal.Value.IsKnown() {
96+
diags = diags.Append(&hcl.Diagnostic{
97+
Severity: hcl.DiagWarning,
98+
Summary: "Deprecated variable got a value",
99+
Detail: n.Config.Deprecated,
100+
Subject: &n.Config.DeprecatedRange,
101+
})
102+
}
103+
95104
if n.Planning {
96105
if checkState := ctx.Checks(); checkState.ConfigHasChecks(n.Addr.InModule(addrs.RootModule)) {
97106
ctx.Checks().ReportCheckableObjects(

0 commit comments

Comments
 (0)