mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-03 20:50:59 -05:00
add extra origin information for deprecation diagnostics
This commit is contained in:
parent
42cee35d38
commit
cfe9e3385a
6 changed files with 97 additions and 33 deletions
|
|
@ -50,12 +50,16 @@ func (d *Deprecations) Validate(value cty.Value, module addrs.Module, rng *hcl.R
|
|||
}
|
||||
|
||||
for _, depMark := range deprecationMarks {
|
||||
diags = diags.Append(&hcl.Diagnostic{
|
||||
diag := &tfdiags.DeprecationOriginDiagnosticExtra{
|
||||
Origin: depMark.Origin,
|
||||
}
|
||||
diag.WrapDiagnosticExtra(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "Deprecated value used",
|
||||
Detail: depMark.Message,
|
||||
Subject: rng,
|
||||
})
|
||||
diags = diags.Append(diag)
|
||||
}
|
||||
|
||||
return notDeprecatedValue, diags
|
||||
|
|
@ -73,13 +77,19 @@ func (d *Deprecations) ValidateAsConfig(value cty.Value, module addrs.Module) tf
|
|||
for m := range pvm.Marks {
|
||||
if depMark, ok := m.(marks.DeprecationMark); ok {
|
||||
diags = diags.Append(
|
||||
tfdiags.AttributeValue(
|
||||
tfdiags.Warning,
|
||||
"Deprecated value used",
|
||||
depMark.Message,
|
||||
pvm.Path,
|
||||
),
|
||||
)
|
||||
tfdiags.Override(
|
||||
tfdiags.AttributeValue(
|
||||
tfdiags.Warning,
|
||||
"Deprecated value used",
|
||||
depMark.Message,
|
||||
pvm.Path,
|
||||
),
|
||||
tfdiags.Warning, // We just want to override the extra info
|
||||
func() tfdiags.DiagnosticExtraWrapper {
|
||||
return &tfdiags.DeprecationOriginDiagnosticExtra{
|
||||
Origin: depMark.Origin,
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package marks
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
|
|
@ -97,6 +98,7 @@ const TypeType = valueMark("TypeType")
|
|||
// rather than a primitive type so that it can carry a deprecation message.
|
||||
type DeprecationMark struct {
|
||||
Message string
|
||||
Origin *hcl.Range
|
||||
}
|
||||
|
||||
func (d DeprecationMark) GoString() string {
|
||||
|
|
@ -104,10 +106,11 @@ func (d DeprecationMark) GoString() string {
|
|||
}
|
||||
|
||||
// Empty deprecation mark for usage in marks.Has / Contains / etc
|
||||
var Deprecation = NewDeprecation("")
|
||||
var Deprecation = NewDeprecation("", nil)
|
||||
|
||||
func NewDeprecation(message string) DeprecationMark {
|
||||
func NewDeprecation(message string, origin *hcl.Range) DeprecationMark {
|
||||
return DeprecationMark{
|
||||
Message: message,
|
||||
Origin: origin,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
func TestDeprecationMark(t *testing.T) {
|
||||
deprecation := cty.StringVal("OldValue").Mark(NewDeprecation("This is outdated"))
|
||||
deprecation := cty.StringVal("OldValue").Mark(NewDeprecation("This is outdated", nil))
|
||||
|
||||
composite := cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": deprecation,
|
||||
|
|
|
|||
|
|
@ -32,15 +32,15 @@ func TestPathsWithMark(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("deprecated"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated")),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil)),
|
||||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecations"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated")),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil)),
|
||||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecationsAndSensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated"), "sensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil), "sensitive"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -71,15 +71,15 @@ func TestPathsWithMark(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("deprecated"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated")),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil)),
|
||||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecations"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated")),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil)),
|
||||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecationsAndSensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated"), "sensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil), "sensitive"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ func TestPathsWithMark(t *testing.T) {
|
|||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecationsAndSensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated"), "sensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil), "sensitive"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -166,15 +166,15 @@ func TestRemoveAll_dataMarks(t *testing.T) {
|
|||
input := []cty.PathValueMarks{
|
||||
{
|
||||
Path: cty.GetAttrPath("deprecated"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated")),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil)),
|
||||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecations"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated")),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil)),
|
||||
},
|
||||
{
|
||||
Path: cty.GetAttrPath("multipleDeprecationsAndSensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated"), NewDeprecation("this is also deprecated"), "sensitive"),
|
||||
Marks: cty.NewValueMarks(NewDeprecation("this is deprecated", nil), NewDeprecation("this is also deprecated", nil), "sensitive"),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ func TestMarkPaths(t *testing.T) {
|
|||
cty.GetAttrPath("o").GetAttr("b"),
|
||||
cty.GetAttrPath("t").IndexInt(0),
|
||||
}
|
||||
deprecationMark := NewDeprecation("this is deprecated")
|
||||
deprecationMark := NewDeprecation("this is deprecated", nil)
|
||||
got = MarkPaths(value, deprecationMark, deprecatedPaths)
|
||||
want = cty.ObjectVal(map[string]cty.Value{
|
||||
"s": cty.StringVal(".s").Mark(deprecationMark),
|
||||
|
|
@ -365,28 +365,28 @@ func TestMarksEqual(t *testing.T) {
|
|||
},
|
||||
{
|
||||
[]cty.PathValueMarks{
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message"))},
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message", nil))},
|
||||
},
|
||||
[]cty.PathValueMarks{
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message"))},
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message", nil))},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
[]cty.PathValueMarks{
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("different"))},
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("different", nil))},
|
||||
},
|
||||
[]cty.PathValueMarks{
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("message"))},
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("message", nil))},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
[]cty.PathValueMarks{
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message"))},
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message", nil))},
|
||||
},
|
||||
[]cty.PathValueMarks{
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message"))},
|
||||
{Path: cty.Path{cty.GetAttrStep{Name: "a"}}, Marks: cty.NewValueMarks(NewDeprecation("same message", nil))},
|
||||
},
|
||||
true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.Sourc
|
|||
atys[name] = cty.DynamicPseudoType // output values are dynamically-typed
|
||||
val := cty.UnknownVal(cty.DynamicPseudoType)
|
||||
if c.DeprecatedSet {
|
||||
val = val.Mark(marks.NewDeprecation(c.Deprecated))
|
||||
val = val.Mark(marks.NewDeprecation(c.Deprecated, &c.DeclRange))
|
||||
}
|
||||
as[name] = val
|
||||
}
|
||||
|
|
@ -482,7 +482,7 @@ func (d *evaluationStateData) GetModule(addr addrs.ModuleCall, rng tfdiags.Sourc
|
|||
}
|
||||
|
||||
if cfg.DeprecatedSet {
|
||||
outputVal = outputVal.Mark(marks.NewDeprecation(cfg.Deprecated))
|
||||
outputVal = outputVal.Mark(marks.NewDeprecation(cfg.Deprecated, &cfg.DeclRange))
|
||||
}
|
||||
attrs[name] = outputVal
|
||||
}
|
||||
|
|
@ -791,7 +791,7 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
|
|||
// states populated for all resources in the configuration.
|
||||
ret := cty.DynamicVal
|
||||
if schema.Body.Deprecated {
|
||||
ret = ret.Mark(marks.NewDeprecation(fmt.Sprintf("Resource %q is deprecated", addr.Type)))
|
||||
ret = ret.Mark(marks.NewDeprecation(fmt.Sprintf("Resource %q is deprecated", addr.Type), &config.DeclRange))
|
||||
}
|
||||
return ret, diags
|
||||
}
|
||||
|
|
@ -869,7 +869,7 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
|
|||
}
|
||||
|
||||
if schema.Body.Deprecated {
|
||||
ret = ret.Mark(marks.NewDeprecation(fmt.Sprintf("Resource %q is deprecated", addr.Type)))
|
||||
ret = ret.Mark(marks.NewDeprecation(fmt.Sprintf("Resource %q is deprecated", addr.Type), &config.DeclRange))
|
||||
}
|
||||
|
||||
return ret, diags
|
||||
|
|
@ -1152,7 +1152,7 @@ func (d *evaluationStateData) GetOutput(addr addrs.OutputValue, rng tfdiags.Sour
|
|||
value = value.Mark(marks.Ephemeral)
|
||||
}
|
||||
if config.DeprecatedSet {
|
||||
value = value.Mark(marks.NewDeprecation(config.Deprecated))
|
||||
value = value.Mark(marks.NewDeprecation(config.Deprecated, &config.DeclRange))
|
||||
}
|
||||
|
||||
return value, diags
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
package tfdiags
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2"
|
||||
)
|
||||
|
||||
// This "Extra" idea is something we've inherited from HCL's diagnostic model,
|
||||
// and so it's primarily to expose that functionality from wrapped HCL
|
||||
// diagnostics but other diagnostic types could potentially implement this
|
||||
|
|
@ -260,3 +264,50 @@ func DiagnosticCausedByTestFailure(diag Diagnostic) bool {
|
|||
}
|
||||
return maybe.DiagnosticCausedByTestFailure()
|
||||
}
|
||||
|
||||
// DiagnosticExtraDeprecationOrigin is an interface implemented by values in
|
||||
// the Extra field of Diagnostic when the diagnostic is related to a
|
||||
// deprecation warning. It provides information about the origin of the
|
||||
// deprecation.
|
||||
type DiagnosticExtraDeprecationOrigin interface {
|
||||
DeprecationOrigin() *hcl.Range
|
||||
}
|
||||
|
||||
// DiagnosticDeprecationOrigin returns the origin range of a deprecation
|
||||
// warning diagnostic, or nil if the diagnostic does not have such information.
|
||||
func DiagnosticDeprecationOrigin(diag Diagnostic) *hcl.Range {
|
||||
maybe := ExtraInfo[DiagnosticExtraDeprecationOrigin](diag)
|
||||
if maybe == nil {
|
||||
return nil
|
||||
}
|
||||
return maybe.DeprecationOrigin()
|
||||
}
|
||||
|
||||
type DeprecationOriginDiagnosticExtra struct {
|
||||
Origin *hcl.Range
|
||||
|
||||
wrapped interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
_ DiagnosticExtraDeprecationOrigin = (*DeprecationOriginDiagnosticExtra)(nil)
|
||||
_ DiagnosticExtraWrapper = (*DeprecationOriginDiagnosticExtra)(nil)
|
||||
_ DiagnosticExtraUnwrapper = (*DeprecationOriginDiagnosticExtra)(nil)
|
||||
)
|
||||
|
||||
func (c *DeprecationOriginDiagnosticExtra) UnwrapDiagnosticExtra() interface{} {
|
||||
return c.wrapped
|
||||
}
|
||||
|
||||
func (c *DeprecationOriginDiagnosticExtra) WrapDiagnosticExtra(inner interface{}) {
|
||||
if c.wrapped != nil {
|
||||
// This is a logical inconsistency, the caller should know whether they
|
||||
// have already wrapped an extra or not.
|
||||
panic("Attempted to wrap a diagnostic extra into a DeprecationOriginDiagnosticExtra that is already wrapping a different extra. This is a bug in Terraform, please report it.")
|
||||
}
|
||||
c.wrapped = inner
|
||||
}
|
||||
|
||||
func (c *DeprecationOriginDiagnosticExtra) DeprecationOrigin() *hcl.Range {
|
||||
return c.Origin
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue