Skip to content

Commit 96d2749

Browse files
add deprecation marks for resource attributes and blocks
1 parent 2746850 commit 96d2749

26 files changed

+1695
-86
lines changed

internal/configs/configschema/validate_traversal.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,6 @@ func (b *Block) StaticValidateTraversal(traversal hcl.Traversal) tfdiags.Diagnos
7777
}
7878

7979
if attrS, exists := b.Attributes[name]; exists {
80-
// Check for Deprecated status of this attribute.
81-
// We currently can't provide the user with any useful guidance because
82-
// the deprecation string is not part of the schema, but we can at
83-
// least warn them.
84-
//
85-
// This purposely does not attempt to recurse into nested attribute
86-
// types. Because nested attribute values are often not accessed via a
87-
// direct traversal to the leaf attributes, we cannot reliably detect
88-
// if a nested, deprecated attribute value is actually used from the
89-
// traversal alone. More precise detection of deprecated attributes
90-
// would require adding metadata like marks to the cty value itself, to
91-
// be caught during evaluation.
92-
if attrS.Deprecated {
93-
diags = diags.Append(&hcl.Diagnostic{
94-
Severity: hcl.DiagWarning,
95-
Summary: `Deprecated attribute`,
96-
Detail: fmt.Sprintf(`The attribute %q is deprecated. Refer to the provider documentation for details.`, name),
97-
Subject: next.SourceRange().Ptr(),
98-
})
99-
}
100-
10180
// For attribute validation we will just apply the rest of the
10281
// traversal to an unknown value of the attribute type and pass
10382
// through HCL's own errors, since we don't want to replicate all

internal/configs/configschema/validate_traversal_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,6 @@ func TestStaticValidateTraversal(t *testing.T) {
224224
`obj.nested_map["key"].optional`,
225225
``,
226226
},
227-
{
228-
`obj.deprecated`,
229-
`Deprecated attribute: The attribute "deprecated" is deprecated. Refer to the provider documentation for details.`,
230-
},
231227
}
232228

233229
for _, test := range tests {

internal/deprecation/deprecation.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,7 @@ func (d *Deprecations) Validate(value cty.Value, module addrs.Module, rng *hcl.R
4343
}
4444

4545
notDeprecatedValue := marks.RemoveDeprecationMarks(value)
46-
47-
// Check if we need to suppress deprecation warnings for this module call.
48-
if d.IsModuleCallDeprecationSuppressed(module) {
49-
return notDeprecatedValue, diags
50-
}
51-
52-
for _, depMark := range deprecationMarks {
53-
diags = diags.Append(&hcl.Diagnostic{
54-
Severity: hcl.DiagWarning,
55-
Summary: "Deprecated value used",
56-
Detail: depMark.Message,
57-
Subject: rng,
58-
})
59-
}
60-
46+
diags = diags.Append(d.diagnosticsForDeprecationMarks(deprecationMarks, module, rng))
6147
return notDeprecatedValue, diags
6248
}
6349

@@ -86,6 +72,27 @@ func (d *Deprecations) ValidateAsConfig(value cty.Value, module addrs.Module) tf
8672
return diags
8773
}
8874

75+
func (d *Deprecations) DiagnosticsForValueMarks(valueMarks cty.ValueMarks, module addrs.Module, rng *hcl.Range) tfdiags.Diagnostics {
76+
return d.diagnosticsForDeprecationMarks(marks.FilterDeprecationMarks(valueMarks), module, rng)
77+
}
78+
79+
func (d *Deprecations) diagnosticsForDeprecationMarks(deprecationMarks []marks.DeprecationMark, module addrs.Module, rng *hcl.Range) tfdiags.Diagnostics {
80+
var diags tfdiags.Diagnostics
81+
// Check if we need to suppress deprecation warnings for this module call.
82+
if !d.IsModuleCallDeprecationSuppressed(module) {
83+
for _, depMark := range deprecationMarks {
84+
diags = diags.Append(&hcl.Diagnostic{
85+
Severity: hcl.DiagWarning,
86+
Summary: "Deprecated value used",
87+
Detail: depMark.Message,
88+
Subject: rng,
89+
})
90+
}
91+
}
92+
93+
return diags
94+
}
95+
8996
func (d *Deprecations) IsModuleCallDeprecationSuppressed(addr addrs.Module) bool {
9097
for _, mod := range d.suppressedModules {
9198
if mod.TargetContains(addr) {

internal/deprecation/schema.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package deprecation
5+
6+
import (
7+
"github.com/hashicorp/terraform/internal/configs/configschema"
8+
"github.com/hashicorp/terraform/internal/lang/marks"
9+
"github.com/zclconf/go-cty/cty"
10+
)
11+
12+
// MarkDeprecatedValues inspects the given cty.Value according to the given
13+
// configschema.Block schema, and marks any deprecated attributes or blocks
14+
// found within the value with deprecation marks.
15+
// It works based on the given cty.Value's structure matching the given schema.
16+
func MarkDeprecatedValues(val cty.Value, schema *configschema.Block) cty.Value {
17+
if schema == nil {
18+
return val
19+
}
20+
newVal := val
21+
22+
// Check if the block is deprecated
23+
if schema.Deprecated {
24+
newVal = newVal.Mark(marks.NewDeprecation("deprecated resource block used"))
25+
}
26+
27+
if !newVal.IsKnown() {
28+
return newVal
29+
}
30+
31+
// Even if the block itself is not deprecated, its attributes might be
32+
// deprecated as well
33+
if val.Type().IsObjectType() || val.Type().IsMapType() || val.Type().IsCollectionType() {
34+
// We ignore the error, so errors are not allowed in the transform function
35+
newVal, _ = cty.Transform(newVal, func(p cty.Path, v cty.Value) (cty.Value, error) {
36+
37+
attr := schema.AttributeByPath(p)
38+
if attr != nil && attr.Deprecated {
39+
v = v.Mark(marks.NewDeprecation("deprecated resource attribute used"))
40+
}
41+
42+
block := schema.BlockByPath(p)
43+
if block != nil && block.Deprecated {
44+
v = v.Mark(marks.NewDeprecation("deprecated resource block used"))
45+
}
46+
47+
return v, nil
48+
})
49+
}
50+
51+
return newVal
52+
}

0 commit comments

Comments
 (0)