Skip to content

Commit 10179df

Browse files
add deprecation marks to resources based on schema
1 parent de0d028 commit 10179df

File tree

8 files changed

+1618
-58
lines changed

8 files changed

+1618
-58
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: ENHANCEMENTS
2+
body: improve detection of deprecated resource attributes / blocks
3+
time: 2026-01-20T17:28:31.861321+01:00
4+
custom:
5+
Issue: "38077"

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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,7 @@ func (d *Deprecations) IsModuleCallDeprecationSuppressed(addr addrs.Module) bool
131131
}
132132
return false
133133
}
134+
135+
func (d *Deprecations) DiagnosticsForValueMarks(valueMarks cty.ValueMarks, module addrs.Module, rng *hcl.Range) tfdiags.Diagnostics {
136+
return d.deprecationMarksToDiagnostics(marks.FilterDeprecationMarks(valueMarks), module, rng)
137+
}

internal/deprecation/schema.go

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

0 commit comments

Comments
 (0)