deprecation.Validate should only check top-level marks

This commit is contained in:
Daniel Schmidt 2026-01-14 14:15:13 +01:00
parent 75445e1ef8
commit 2f392d904e
3 changed files with 77 additions and 1 deletions

View file

@ -35,6 +35,9 @@ func (d *Deprecations) SuppressModuleCallDeprecation(addr addrs.Module) {
d.suppressedModules.Add(addr)
}
// Validate checks the given value for deprecation marks and returns diagnostics
// for each deprecation found, unless deprecation warnings are suppressed for the given module.
// It does not check for deeply nested deprecation marks.
func (d *Deprecations) Validate(value cty.Value, module addrs.Module, rng *hcl.Range) (cty.Value, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
deprecationMarks := marks.GetDeprecationMarks(value)
@ -67,6 +70,9 @@ func (d *Deprecations) Validate(value cty.Value, module addrs.Module, rng *hcl.R
return notDeprecatedValue, diags
}
// ValidateAsConfig checks the given value for deprecation marks and returns diagnostics
// for each deprecation found, unless deprecation warnings are suppressed for the given module.
// It checks for deeply nested deprecation marks as well.
func (d *Deprecations) ValidateAsConfig(value cty.Value, module addrs.Module) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
_, pvms := value.UnmarkDeepWithPaths()

View file

@ -64,7 +64,7 @@ func FilterDeprecationMarks(marks cty.ValueMarks) []DeprecationMark {
// GetDeprecationMarks returns all deprecation marks present on the given
// cty.Value.
func GetDeprecationMarks(val cty.Value) []DeprecationMark {
_, marks := val.UnmarkDeep()
_, marks := val.Unmark()
return FilterDeprecationMarks(marks)
}

View file

@ -4594,3 +4594,73 @@ locals {
},
}))
}
func TestContext2Validate_using_module_with_deprecated_output(t *testing.T) {
m := testModuleInline(t, map[string]string{
"mod/main.tf": `
output "old" {
deprecated = "Please stop using this"
value = "old"
}
`,
"main.tf": `
module "mod" {
source = "./mod"
}
locals {
m = module.mod # OK - deprecated value is not used
}
output "test_output" {
value = module.mod.old # WARNING
}
`,
})
p := new(testing_provider.MockProvider)
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&providerSchema{
ResourceTypes: map[string]*configschema.Block{
"test_resource": {
Attributes: map[string]*configschema.Attribute{
"attr": {
Type: cty.String,
Computed: true,
},
},
},
},
Actions: map[string]*providers.ActionSchema{
"test_action": {
ConfigSchema: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"attr": {
Type: cty.String,
Required: true,
},
},
},
},
},
})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
diags := ctx.Validate(m, &ValidateOpts{})
tfdiags.AssertDiagnosticsMatch(t, diags, tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{
Severity: hcl.DiagWarning,
Summary: "Deprecated value used",
Detail: "Please stop using this",
Subject: &hcl.Range{
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
Start: hcl.Pos{Line: 11, Column: 13, Byte: 143},
End: hcl.Pos{Line: 11, Column: 27, Byte: 157},
},
}))
}