Skip to content

Commit

Permalink
Merge pull request #31576 from hashicorp/jbardin/validate-deprecated-…
Browse files Browse the repository at this point in the history
…computed

validate deprecated attributes from static traversals
  • Loading branch information
jbardin committed Aug 9, 2022
2 parents 1a5e403 + 25f5a81 commit 8354bc4
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 10 deletions.
30 changes: 25 additions & 5 deletions internal/configs/configschema/validate_traversal.go
Expand Up @@ -74,14 +74,34 @@ func (b *Block) StaticValidateTraversal(traversal hcl.Traversal) tfdiags.Diagnos
}

if attrS, exists := b.Attributes[name]; exists {
// Check for Deprecated status of this attribute.
// We currently can't provide the user with any useful guidance because
// the deprecation string is not part of the schema, but we can at
// least warn them.
//
// This purposely does not attempt to recurse into nested attribute
// types. Because nested attribute values are often not accessed via a
// direct traversal to the leaf attributes, we cannot reliably detect
// if a nested, deprecated attribute value is actually used from the
// traversal alone. More precise detection of deprecated attributes
// would require adding metadata like marks to the cty value itself, to
// be caught during evaluation.
if attrS.Deprecated {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: `Deprecated attribute`,
Detail: fmt.Sprintf(`The attribute %q is deprecated. Refer to the provider documentation for details.`, name),
Subject: next.SourceRange().Ptr(),
})
}

// For attribute validation we will just apply the rest of the
// traversal to an unknown value of the attribute type and pass through
// HCL's own errors, since we don't want to replicate all of HCL's type
// checking rules here.
// traversal to an unknown value of the attribute type and pass
// through HCL's own errors, since we don't want to replicate all
// of HCL's type checking rules here.
val := cty.UnknownVal(attrS.ImpliedType())
_, hclDiags := after.TraverseRel(val)
diags = diags.Append(hclDiags)
return diags
return diags.Append(hclDiags)
}

if blockS, exists := b.BlockTypes[name]; exists {
Expand Down
16 changes: 11 additions & 5 deletions internal/configs/configschema/validate_traversal_test.go
Expand Up @@ -10,9 +10,10 @@ import (

func TestStaticValidateTraversal(t *testing.T) {
attrs := map[string]*Attribute{
"str": {Type: cty.String, Optional: true},
"list": {Type: cty.List(cty.String), Optional: true},
"dyn": {Type: cty.DynamicPseudoType, Optional: true},
"str": {Type: cty.String, Optional: true},
"list": {Type: cty.List(cty.String), Optional: true},
"dyn": {Type: cty.DynamicPseudoType, Optional: true},
"deprecated": {Type: cty.String, Computed: true, Deprecated: true},
"nested_single": {
Optional: true,
NestedType: &Object{
Expand Down Expand Up @@ -220,6 +221,10 @@ func TestStaticValidateTraversal(t *testing.T) {
`obj.nested_map["key"].optional`,
``,
},
{
`obj.deprecated`,
`Deprecated attribute: The attribute "deprecated" is deprecated. Refer to the provider documentation for details.`,
},
}

for _, test := range tests {
Expand All @@ -239,8 +244,9 @@ func TestStaticValidateTraversal(t *testing.T) {
t.Errorf("unexpected error: %s", diags.Err().Error())
}
} else {
if diags.HasErrors() {
if got := diags.Err().Error(); got != test.WantError {
err := diags.ErrWithWarnings()
if err != nil {
if got := err.Error(); got != test.WantError {
t.Errorf("wrong error\ngot: %s\nwant: %s", got, test.WantError)
}
} else {
Expand Down

0 comments on commit 8354bc4

Please sign in to comment.