Skip to content

Commit e620182

Browse files
authored
tfsdk: Properly set attribute path in (Plan).SetAttribute() and (State).SetAttribute() reflection diagnostics (#133)
Reference: #128
1 parent 3c27da0 commit e620182

File tree

13 files changed

+25
-42
lines changed

13 files changed

+25
-42
lines changed

.changelog/133.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
tfsdk: Diagnostics returned from `(Plan).SetAttribute()` and `(State).SetAttribute()` reflection will now properly include attribute path
3+
```

internal/reflect/interfaces.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func NewUnknownable(ctx context.Context, typ attr.Type, val tftypes.Value, targe
6262

6363
// FromUnknownable creates an attr.Value from the data in an Unknownable.
6464
//
65-
// It is meant to be called through OutOf, not directly.
65+
// It is meant to be called through FromValue, not directly.
6666
func FromUnknownable(ctx context.Context, typ attr.Type, val Unknownable, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
6767
var diags diag.Diagnostics
6868

@@ -156,7 +156,7 @@ func NewNullable(ctx context.Context, typ attr.Type, val tftypes.Value, target r
156156

157157
// FromNullable creates an attr.Value from the data in a Nullable.
158158
//
159-
// It is meant to be called through OutOf, not directly.
159+
// It is meant to be called through FromValue, not directly.
160160
func FromNullable(ctx context.Context, typ attr.Type, val Nullable, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
161161
var diags diag.Diagnostics
162162

@@ -242,7 +242,7 @@ func NewValueConverter(ctx context.Context, typ attr.Type, val tftypes.Value, ta
242242
// tftypes.ValueCreator, calling its ToTerraform5Value method and converting
243243
// the result to an attr.Value using `typ`.
244244
//
245-
// It is meant to be called from OutOf, not directly.
245+
// It is meant to be called from FromValue, not directly.
246246
func FromValueCreator(ctx context.Context, typ attr.Type, val tftypes.ValueCreator, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
247247
var diags diag.Diagnostics
248248
raw, err := val.ToTerraform5Value()
@@ -307,7 +307,7 @@ func NewAttributeValue(ctx context.Context, typ attr.Type, val tftypes.Value, ta
307307
// validation on that attr.Value to make sure it matches the type produced by
308308
// `typ`.
309309
//
310-
// It is meant to be called through OutOf, not directly.
310+
// It is meant to be called through FromValue, not directly.
311311
func FromAttributeValue(ctx context.Context, typ attr.Type, val attr.Value, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
312312
var diags diag.Diagnostics
313313

internal/reflect/map.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func Map(ctx context.Context, typ attr.Type, val tftypes.Value, target reflect.V
9393
// `val` must be a map type with keys that are a string type. The attr.Value
9494
// will be of the type produced by `typ`.
9595
//
96-
// It is meant to be called through OutOf, not directly.
96+
// It is meant to be called through FromValue, not directly.
9797
func FromMap(ctx context.Context, typ attr.TypeWithElementType, val reflect.Value, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
9898
var diags diag.Diagnostics
9999
tfType := typ.TerraformType(ctx)

internal/reflect/number.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func Number(ctx context.Context, typ attr.Type, val tftypes.Value, target reflec
235235

236236
// FromInt creates an attr.Value using `typ` from an int64.
237237
//
238-
// It is meant to be called through OutOf, not directly.
238+
// It is meant to be called through FromValue, not directly.
239239
func FromInt(ctx context.Context, typ attr.Type, val int64, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
240240
var diags diag.Diagnostics
241241
err := tftypes.ValidateValue(tftypes.Number, val)
@@ -262,7 +262,7 @@ func FromInt(ctx context.Context, typ attr.Type, val int64, path *tftypes.Attrib
262262

263263
// FromUint creates an attr.Value using `typ` from a uint64.
264264
//
265-
// It is meant to be called through OutOf, not directly.
265+
// It is meant to be called through FromValue, not directly.
266266
func FromUint(ctx context.Context, typ attr.Type, val uint64, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
267267
var diags diag.Diagnostics
268268
err := tftypes.ValidateValue(tftypes.Number, val)
@@ -289,7 +289,7 @@ func FromUint(ctx context.Context, typ attr.Type, val uint64, path *tftypes.Attr
289289

290290
// FromFloat creates an attr.Value using `typ` from a float64.
291291
//
292-
// It is meant to be called through OutOf, not directly.
292+
// It is meant to be called through FromValue, not directly.
293293
func FromFloat(ctx context.Context, typ attr.Type, val float64, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
294294
var diags diag.Diagnostics
295295
err := tftypes.ValidateValue(tftypes.Number, val)
@@ -316,7 +316,7 @@ func FromFloat(ctx context.Context, typ attr.Type, val float64, path *tftypes.At
316316

317317
// FromBigFloat creates an attr.Value using `typ` from a *big.Float.
318318
//
319-
// It is meant to be called through OutOf, not directly.
319+
// It is meant to be called through FromValue, not directly.
320320
func FromBigFloat(ctx context.Context, typ attr.Type, val *big.Float, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
321321
var diags diag.Diagnostics
322322
err := tftypes.ValidateValue(tftypes.Number, val)
@@ -343,7 +343,7 @@ func FromBigFloat(ctx context.Context, typ attr.Type, val *big.Float, path *tfty
343343

344344
// FromBigInt creates an attr.Value using `typ` from a *big.Int.
345345
//
346-
// It is meant to be called through OutOf, not directly.
346+
// It is meant to be called through FromValue, not directly.
347347
func FromBigInt(ctx context.Context, typ attr.Type, val *big.Int, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
348348
var diags diag.Diagnostics
349349
fl := big.NewFloat(0).SetInt(val)

internal/reflect/outof.go

+1-9
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,10 @@ import (
1111
"github.com/hashicorp/terraform-plugin-go/tftypes"
1212
)
1313

14-
// OutOf is the inverse of Into, taking a Go value (`val`) and transforming it
14+
// FromValue is the inverse of Into, taking a Go value (`val`) and transforming it
1515
// into an attr.Value using the attr.Type supplied. `val` will first be
1616
// transformed into a tftypes.Value, then passed to `typ`'s ValueFromTerraform
1717
// method.
18-
func OutOf(ctx context.Context, typ attr.Type, val interface{}) (attr.Value, diag.Diagnostics) {
19-
return FromValue(ctx, typ, val, tftypes.NewAttributePath())
20-
}
21-
22-
// FromValue is recursively called to turn `val` into an `attr.Value` using
23-
// `typ`.
24-
//
25-
// It is meant to be called through OutOf, not directly.
2618
func FromValue(ctx context.Context, typ attr.Type, val interface{}, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
2719
var diags diag.Diagnostics
2820

internal/reflect/pointer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func pointerSafeZeroValue(ctx context.Context, target reflect.Value) reflect.Val
7373
// it will recurse into FromValue to find the attr.Value of the type the value
7474
// the pointer is referencing.
7575
//
76-
// It is meant to be called through OutOf, not directly.
76+
// It is meant to be called through FromValue, not directly.
7777
func FromPointer(ctx context.Context, typ attr.Type, value reflect.Value, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
7878
var diags diag.Diagnostics
7979

internal/reflect/primitive.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func Primitive(ctx context.Context, typ attr.Type, val tftypes.Value, target ref
5555

5656
// FromString returns an attr.Value as produced by `typ` from a string.
5757
//
58-
// It is meant to be called through OutOf, not directly.
58+
// It is meant to be called through FromValue, not directly.
5959
func FromString(ctx context.Context, typ attr.Type, val string, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
6060
var diags diag.Diagnostics
6161
err := tftypes.ValidateValue(tftypes.String, val)
@@ -82,7 +82,7 @@ func FromString(ctx context.Context, typ attr.Type, val string, path *tftypes.At
8282

8383
// FromBool returns an attr.Value as produced by `typ` from a bool.
8484
//
85-
// It is meant to be called through OutOf, not directly.
85+
// It is meant to be called through FromValue, not directly.
8686
func FromBool(ctx context.Context, typ attr.Type, val bool, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
8787
var diags diag.Diagnostics
8888
err := tftypes.ValidateValue(tftypes.Bool, val)

internal/reflect/slice.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func reflectSlice(ctx context.Context, typ attr.Type, val tftypes.Value, target
8888
// for each element in the slice, using the element type or types defined on
8989
// `typ` to construct values for them.
9090
//
91-
// It is meant to be called through OutOf, not directly.
91+
// It is meant to be called through FromValue, not directly.
9292
func FromSlice(ctx context.Context, typ attr.Type, val reflect.Value, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
9393
var diags diag.Diagnostics
9494

internal/reflect/struct.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func Struct(ctx context.Context, typ attr.Type, object tftypes.Value, target ref
148148
// into FromValue for each attribute, using the type of the attribute as
149149
// reported by `typ`.
150150
//
151-
// It is meant to be called through OutOf, not directly.
151+
// It is meant to be called through FromValue, not directly.
152152
func FromStruct(ctx context.Context, typ attr.TypeWithAttributeTypes, val reflect.Value, path *tftypes.AttributePath) (attr.Value, diag.Diagnostics) {
153153
var diags diag.Diagnostics
154154
objTypes := map[string]tftypes.Type{}

tfsdk/plan.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (p Plan) GetAttribute(ctx context.Context, path *tftypes.AttributePath) (at
7979
// should be a struct whose values have one of the attr.Value types. Each field
8080
// must be tagged with the corresponding schema field.
8181
func (p *Plan) Set(ctx context.Context, val interface{}) diag.Diagnostics {
82-
newPlanAttrValue, diags := reflect.OutOf(ctx, p.Schema.AttributeType(), val)
82+
newPlanAttrValue, diags := reflect.FromValue(ctx, p.Schema.AttributeType(), val, tftypes.NewAttributePath())
8383
if diags.HasError() {
8484
return diags
8585
}
@@ -115,7 +115,7 @@ func (p *Plan) SetAttribute(ctx context.Context, path *tftypes.AttributePath, va
115115
return diags
116116
}
117117

118-
newVal, newValDiags := reflect.OutOf(ctx, attrType, val)
118+
newVal, newValDiags := reflect.FromValue(ctx, attrType, val, path)
119119
diags.Append(newValDiags...)
120120

121121
if diags.HasError() {

tfsdk/plan_test.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,7 @@ func TestPlanSetAttribute(t *testing.T) {
408408
}, map[string]tftypes.Value{
409409
"name": tftypes.NewValue(tftypes.String, "originalname"),
410410
}),
411-
// TODO: Diagnostic should include WithAttributeName("name")
412-
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/128
413-
expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(tftypes.NewAttributePath())},
411+
expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("name"))},
414412
},
415413
"AttrTypeWithValidateWarning": {
416414
plan: Plan{
@@ -440,10 +438,6 @@ func TestPlanSetAttribute(t *testing.T) {
440438
"name": tftypes.NewValue(tftypes.String, "newname"),
441439
}),
442440
expectedDiags: diag.Diagnostics{
443-
// TODO: Diagnostic should include WithAttributeName("name")
444-
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/128
445-
testtypes.TestWarningDiagnostic(tftypes.NewAttributePath()),
446-
// This duplicate should go away with the above fix.
447441
testtypes.TestWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("name")),
448442
},
449443
},

tfsdk/state.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (s *State) Set(ctx context.Context, val interface{}) diag.Diagnostics {
8888
),
8989
}
9090
}
91-
newStateAttrValue, diags := reflect.OutOf(ctx, s.Schema.AttributeType(), val)
91+
newStateAttrValue, diags := reflect.FromValue(ctx, s.Schema.AttributeType(), val, tftypes.NewAttributePath())
9292
if diags.HasError() {
9393
return diags
9494
}
@@ -124,7 +124,7 @@ func (s *State) SetAttribute(ctx context.Context, path *tftypes.AttributePath, v
124124
return diags
125125
}
126126

127-
newVal, newValDiags := reflect.OutOf(ctx, attrType, val)
127+
newVal, newValDiags := reflect.FromValue(ctx, attrType, val, path)
128128
diags.Append(newValDiags...)
129129

130130
if diags.HasError() {

tfsdk/state_test.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -1539,9 +1539,7 @@ func TestStateSetAttribute(t *testing.T) {
15391539
}, map[string]tftypes.Value{
15401540
"name": tftypes.NewValue(tftypes.String, "originalname"),
15411541
}),
1542-
// TODO: Diagnostic should include WithAttributeName("name")
1543-
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/128
1544-
expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(tftypes.NewAttributePath())},
1542+
expectedDiags: diag.Diagnostics{testtypes.TestErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("name"))},
15451543
},
15461544
"AttrTypeWithValidateWarning": {
15471545
state: State{
@@ -1571,10 +1569,6 @@ func TestStateSetAttribute(t *testing.T) {
15711569
"name": tftypes.NewValue(tftypes.String, "newname"),
15721570
}),
15731571
expectedDiags: diag.Diagnostics{
1574-
// TODO: Diagnostic should include WithAttributeName("name")
1575-
// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/128
1576-
testtypes.TestWarningDiagnostic(tftypes.NewAttributePath()),
1577-
// This duplicate should go away with the above fix.
15781572
testtypes.TestWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("name")),
15791573
},
15801574
},

0 commit comments

Comments
 (0)