Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: Add support for unknown value refinement data to all types #1062

Draft
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
64d9274
quick fix on equals for later
austinvalle Oct 21, 2024
8a8f3fc
test fixes
austinvalle Oct 24, 2024
0d0f4fc
not null and string prefix implementations
austinvalle Oct 24, 2024
15121c4
add number bounds
austinvalle Oct 25, 2024
ec7cc42
Merge branch 'main' into av/refinements
austinvalle Nov 5, 2024
dfdef53
switch back to local - go mod tidy
austinvalle Nov 5, 2024
dcd19d9
switched up interface
austinvalle Nov 21, 2024
d67bd4a
Merge branch 'main' into av/refinements
austinvalle Nov 26, 2024
31d81ad
bump versions
austinvalle Nov 26, 2024
f297cce
update existing docs + equal/string methods
austinvalle Nov 26, 2024
4de17f2
new refinements
austinvalle Nov 26, 2024
0b35094
var name
austinvalle Nov 26, 2024
53802ef
update string type and value
austinvalle Nov 26, 2024
4d923dc
string tests
austinvalle Nov 26, 2024
e242cac
clean up int64 value and type, add tests
austinvalle Nov 26, 2024
12d8bb8
int32 refinements
austinvalle Nov 27, 2024
9f965c4
float64 refinements
austinvalle Nov 27, 2024
c65976c
float 32 refinements
austinvalle Nov 27, 2024
ab222bc
variable change
austinvalle Nov 27, 2024
82ad8e7
number refinements
austinvalle Nov 27, 2024
cfa53db
bool refinements
austinvalle Nov 27, 2024
cdaf3d9
object refinements
austinvalle Nov 27, 2024
cd8d8ed
tuple refinements
austinvalle Nov 27, 2024
54b5cfb
list refinements
austinvalle Nov 27, 2024
b4eee34
set refinements
austinvalle Dec 2, 2024
093adf2
fix testtype
austinvalle Dec 2, 2024
3fce8d5
map refinements
austinvalle Dec 2, 2024
cc81de3
order comment
austinvalle Dec 2, 2024
c6333be
string plan modifiers
austinvalle Dec 2, 2024
18d08f9
int64 plan modifiers
austinvalle Dec 2, 2024
6063b92
int32 plan modifiers
austinvalle Dec 2, 2024
7fd8967
float64 plan modifiers
austinvalle Dec 2, 2024
b52b2c8
float32 plan modifiers
austinvalle Dec 2, 2024
b45f8af
number plan modifiers
austinvalle Dec 2, 2024
2a7b3dd
object and bool plan modifiers
austinvalle Dec 2, 2024
411df8d
list plan modifiers
austinvalle Dec 2, 2024
972929c
map and set plan modifiers
austinvalle Dec 2, 2024
b59f093
add tests for not null refinement
austinvalle Dec 2, 2024
96d9ccf
spelling
austinvalle Dec 3, 2024
a2d4066
switch to commit hash
austinvalle Dec 3, 2024
a85b9d5
fix custom type implementations
austinvalle Dec 3, 2024
0d7af52
Merge branch 'main' into av/refinements
austinvalle Jan 16, 2025
2e14750
update plugin-go dep
austinvalle Jan 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions attr/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package attr
import (
"context"

"github.com/hashicorp/terraform-plugin-framework/types/refinement"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

Expand Down Expand Up @@ -69,3 +70,17 @@ type Value interface {
// compatibility guarantees within the framework.
String() string
}

// ValueWithNotNullRefinement defines an interface describing a Value that can contain
// a refinement that indicates the Value is unknown, but will not be null once it becomes known.
//
// This interface is implemented by all base value types except for DynamicValue, as dynamic types
// in Terraform don't support value refinements.
type ValueWithNotNullRefinement interface {
Value

// NotNullRefinement returns value refinement data and a boolean indicating if a NotNull refinement
// exists on the given Value. If a Value contains a NotNull refinement, this indicates that the value
// is unknown, but the eventual known value will not be null.
NotNullRefinement() (*refinement.NotNull, bool)
}
16 changes: 8 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.22.7

require (
github.com/google/go-cmp v0.6.0
github.com/hashicorp/terraform-plugin-go v0.25.0
github.com/hashicorp/terraform-plugin-go v0.25.1-0.20250116190359-f977ddce3f6c
github.com/hashicorp/terraform-plugin-log v0.9.0
)

Expand All @@ -16,7 +16,7 @@ require (
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-plugin v1.6.2 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-registry-address v0.2.4 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
Expand All @@ -25,10 +25,10 @@ require (
github.com/oklog/run v1.0.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/grpc v1.67.1 // indirect
google.golang.org/protobuf v1.35.1 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/grpc v1.69.4 // indirect
google.golang.org/protobuf v1.36.3 // indirect
)
48 changes: 32 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,28 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=
github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
github.com/hashicorp/terraform-plugin-go v0.25.1-0.20250116190359-f977ddce3f6c h1:jRBaf696GIfT5LT+ZflOQUWI6MNEdntXFp6YO11ACUU=
github.com/hashicorp/terraform-plugin-go v0.25.1-0.20250116190359-f977ddce3f6c/go.mod h1:+CXjuLDiFgqR+GcrM5a2E2Kal5t5q2jb0E3D57tTdNY=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM=
github.com/hashicorp/terraform-registry-address v0.2.4 h1:JXu/zHB2Ymg/TGVCRu10XqNa4Sh2bWcqCNyKWjnCPJA=
github.com/hashicorp/terraform-registry-address v0.2.4/go.mod h1:tUNYTVyCtU4OIGXXMDp7WNcJ+0W1B4nmstVDgHMjfAU=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
Expand Down Expand Up @@ -48,24 +54,34 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
67 changes: 41 additions & 26 deletions internal/fwserver/attribute_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)

// ValidateAttributeRequest repesents a request for attribute validation.
// ValidateAttributeRequest represents a request for attribute validation.
type ValidateAttributeRequest struct {
// AttributePath contains the path of the attribute. Use this path for any
// response diagnostics.
Expand Down Expand Up @@ -137,33 +137,48 @@ func AttributeValidate(ctx context.Context, a fwschema.Attribute, req ValidateAt

AttributeValidateNestedAttributes(ctx, a, req, resp)

// Show deprecation warnings only for known values.
if a.GetDeprecationMessage() != "" && !attributeConfig.IsNull() && !attributeConfig.IsUnknown() {
// Dynamic values need to perform more logic to check the config value for null/unknown-ness
dynamicValuable, ok := attributeConfig.(basetypes.DynamicValuable)
if !ok {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
return
}
// Show deprecation warnings only for known values or unknown values with a "not null" refinement.
if a.GetDeprecationMessage() != "" {
if attributeConfig.IsUnknown() {
// If the unknown value will eventually be not null, we return the deprecation message for the practitioner.
val, ok := attributeConfig.(attr.ValueWithNotNullRefinement)
if ok {
if _, notNull := val.NotNullRefinement(); notNull {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
return
}
}
} else if !attributeConfig.IsNull() && !attributeConfig.IsUnknown() {
// Dynamic values need to perform more logic to check the config value for null/unknown-ness
dynamicValuable, ok := attributeConfig.(basetypes.DynamicValuable)
if !ok {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
return
}

dynamicConfigVal, diags := dynamicValuable.ToDynamicValue(ctx)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}
dynamicConfigVal, diags := dynamicValuable.ToDynamicValue(ctx)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}

// For dynamic values, it's possible to be known when only the type is known.
// The underlying value can still be null or unknown, so check for that here
if !dynamicConfigVal.IsUnderlyingValueNull() && !dynamicConfigVal.IsUnderlyingValueUnknown() {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
// For dynamic values, it's possible to be known when only the type is known.
// The underlying value can still be null or unknown, so check for that here
if !dynamicConfigVal.IsUnderlyingValueNull() && !dynamicConfigVal.IsUnderlyingValueUnknown() {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
}
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions internal/fwserver/attribute_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-go/tftypes"
tfrefinement "github.com/hashicorp/terraform-plugin-go/tftypes/refinement"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
Expand Down Expand Up @@ -490,6 +491,40 @@ func TestAttributeValidate(t *testing.T) {
},
resp: ValidateAttributeResponse{},
},
"deprecation-message-unknown-with-not-null-refinement": {
req: ValidateAttributeRequest{
AttributePath: path.Root("test"),
Config: tfsdk.Config{
Raw: tftypes.NewValue(tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"test": tftypes.String,
},
}, map[string]tftypes.Value{
"test": tftypes.NewValue(tftypes.String, tftypes.UnknownValue).Refine(tfrefinement.Refinements{
tfrefinement.KeyNullness: tfrefinement.NewNullness(false),
}),
}),
Schema: testschema.Schema{
Attributes: map[string]fwschema.Attribute{
"test": testschema.Attribute{
Type: types.StringType,
Optional: true,
DeprecationMessage: "Use something else instead.",
},
},
},
},
},
resp: ValidateAttributeResponse{
Diagnostics: diag.Diagnostics{
diag.NewAttributeWarningDiagnostic(
path.Root("test"),
"Attribute Deprecated",
"Use something else instead.",
),
},
},
},
"deprecation-message-dynamic-underlying-value-unknown": {
req: ValidateAttributeRequest{
AttributePath: path.Root("test"),
Expand Down
6 changes: 3 additions & 3 deletions internal/testing/testtypes/numberwithvalidateattribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (v NumberValueWithValidateAttributeError) Equal(value attr.Value) bool {
return false
}

return v == other
return v.Equal(other)
}

func (v NumberValueWithValidateAttributeError) IsNull() bool {
Expand Down Expand Up @@ -92,7 +92,7 @@ func (t NumberTypeWithValidateAttributeWarning) Equal(o attr.Type) bool {
if !ok {
return false
}
return t == other
return t.NumberType.Equal(other.NumberType)
}

func (t NumberTypeWithValidateAttributeWarning) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
Expand Down Expand Up @@ -134,7 +134,7 @@ func (v NumberValueWithValidateAttributeWarning) Equal(value attr.Value) bool {
return false
}

return v.InternalNumber.Number.Equal(other.InternalNumber.Number)
return v.InternalNumber.Equal(other.InternalNumber)
}

func (v NumberValueWithValidateAttributeWarning) IsNull() bool {
Expand Down
4 changes: 2 additions & 2 deletions internal/testing/testtypes/stringwithvalidateattribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (v StringValueWithValidateAttributeError) Equal(value attr.Value) bool {
return false
}

return v == other
return v.InternalString.Equal(other.InternalString)
}

func (v StringValueWithValidateAttributeError) IsNull() bool {
Expand Down Expand Up @@ -134,7 +134,7 @@ func (v StringValueWithValidateAttributeWarning) Equal(value attr.Value) bool {
return false
}

return v == other
return v.InternalString.Equal(other.InternalString)
}

func (v StringValueWithValidateAttributeWarning) IsNull() bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (v StringValueWithValidateParameterError) Equal(value attr.Value) bool {
return false
}

return v == other
return v.InternalString.Equal(other.InternalString)
}

func (v StringValueWithValidateParameterError) IsNull() bool {
Expand Down
50 changes: 50 additions & 0 deletions resource/schema/boolplanmodifier/will_not_be_null.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package boolplanmodifier

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
)

// WillNotBeNull returns a plan modifier that will add a refinement to an unknown planned value
// which promises that the final value will not be null.
//
// This unknown value refinement allows Terraform to validate more of the configuration during plan
// and evaluate conditional logic in meta-arguments such as "count":
//
// resource "examplecloud_thing" "b" {
// // Will successfully evaluate during plan with a "not null" refinement on "bool_attribute"
// count = examplecloud_thing.a.bool_attribute != null ? 1 : 0
//
// // .. resource config
// }
func WillNotBeNull() planmodifier.Bool {
return willNotBeNullModifier{}
}

type willNotBeNullModifier struct{}

func (m willNotBeNullModifier) Description(_ context.Context) string {
return "Promises the value of this attribute will not be null once it becomes known"
}

func (m willNotBeNullModifier) MarkdownDescription(_ context.Context) string {
return "Promises the value of this attribute will not be null once it becomes known"
}

func (m willNotBeNullModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
// Do nothing if there is a known planned value.
if !req.PlanValue.IsUnknown() {
return
}

// Do nothing if there is an unknown configuration value, otherwise interpolation gets messed up.
if req.ConfigValue.IsUnknown() {
return
}

resp.PlanValue = req.PlanValue.RefineAsNotNull()
}
Loading
Loading