Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20251014-173739.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'action/schema: Added `WriteOnly` schema field for action schemas.'
time: 2025-10-14T17:37:39.087475-04:00
custom:
Issue: "1233"
8 changes: 6 additions & 2 deletions action/schema/bool_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ type BoolAttribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.Bool

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep always returns an error as it is not
Expand Down Expand Up @@ -166,9 +170,9 @@ func (a BoolAttribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a BoolAttribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
6 changes: 6 additions & 0 deletions action/schema/bool_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ func TestBoolAttributeIsWriteOnly(t *testing.T) {
attribute: schema.BoolAttribute{},
expected: false,
},
"writeOnly": {
attribute: schema.BoolAttribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions action/schema/dynamic_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ type DynamicAttribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.Dynamic

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep always returns an error as it is not
Expand Down Expand Up @@ -167,9 +171,9 @@ func (a DynamicAttribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a DynamicAttribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
9 changes: 8 additions & 1 deletion action/schema/dynamic_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import (
"testing"

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

"github.com/hashicorp/terraform-plugin-framework/action/schema"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/testing/testschema"
"github.com/hashicorp/terraform-plugin-framework/internal/testing/testtypes"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func TestDynamicAttributeApplyTerraform5AttributePathStep(t *testing.T) {
Expand Down Expand Up @@ -369,6 +370,12 @@ func TestDynamicAttributeIsWriteOnly(t *testing.T) {
attribute: schema.DynamicAttribute{},
expected: false,
},
"writeOnly": {
attribute: schema.DynamicAttribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions action/schema/float32_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ type Float32Attribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.Float32

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep always returns an error as it is not
Expand Down Expand Up @@ -169,9 +173,9 @@ func (a Float32Attribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a Float32Attribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
6 changes: 6 additions & 0 deletions action/schema/float32_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ func TestFloat32AttributeIsWriteOnly(t *testing.T) {
attribute: schema.Float32Attribute{},
expected: false,
},
"writeOnly": {
attribute: schema.Float32Attribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions action/schema/float64_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ type Float64Attribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.Float64

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep always returns an error as it is not
Expand Down Expand Up @@ -169,9 +173,9 @@ func (a Float64Attribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a Float64Attribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
8 changes: 7 additions & 1 deletion action/schema/float64_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ func TestFloat64AttributeIsSensitive(t *testing.T) {
}
}

func TestFloat54AttributeIsWriteOnly(t *testing.T) {
func TestFloat64AttributeIsWriteOnly(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
Expand All @@ -370,6 +370,12 @@ func TestFloat54AttributeIsWriteOnly(t *testing.T) {
attribute: schema.Float64Attribute{},
expected: false,
},
"writeOnly": {
attribute: schema.Float64Attribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions action/schema/int32_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ type Int32Attribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.Int32

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep always returns an error as it is not
Expand Down Expand Up @@ -169,9 +173,9 @@ func (a Int32Attribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a Int32Attribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
8 changes: 7 additions & 1 deletion action/schema/int32_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ func TestInt32AttributeIsSensitive(t *testing.T) {
}
}

func TestInt2AttributeIsWriteOnly(t *testing.T) {
func TestInt32AttributeIsWriteOnly(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
Expand All @@ -370,6 +370,12 @@ func TestInt2AttributeIsWriteOnly(t *testing.T) {
attribute: schema.Int32Attribute{},
expected: false,
},
"writeOnly": {
attribute: schema.Int32Attribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions action/schema/int64_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ type Int64Attribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.Int64

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep always returns an error as it is not
Expand Down Expand Up @@ -169,9 +173,9 @@ func (a Int64Attribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a Int64Attribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
6 changes: 6 additions & 0 deletions action/schema/int64_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ func TestInt64AttributeIsWriteOnly(t *testing.T) {
attribute: schema.Int64Attribute{},
expected: false,
},
"writeOnly": {
attribute: schema.Int64Attribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand Down
8 changes: 6 additions & 2 deletions action/schema/list_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ type ListAttribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.List

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep returns the result of stepping into a list
Expand Down Expand Up @@ -187,9 +191,9 @@ func (a ListAttribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a ListAttribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down
7 changes: 6 additions & 1 deletion action/schema/list_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,12 @@ func TestListAttributeIsWriteOnly(t *testing.T) {
attribute: schema.ListAttribute{},
expected: false,
},
"writeOnly": {
attribute: schema.ListAttribute{
WriteOnly: true,
},
expected: true,
},
}

for name, testCase := range testCases {
Expand All @@ -392,7 +398,6 @@ func TestListAttributeIsWriteOnly(t *testing.T) {
})
}
}

func TestListAttributeListValidators(t *testing.T) {
t.Parallel()

Expand Down
14 changes: 12 additions & 2 deletions action/schema/list_nested_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ type ListNestedAttribute struct {
// xattr.TypeWithValidate interface, the validators defined in this field
// are run in addition to the validation defined by the type.
Validators []validator.List

// WriteOnly indicates whether this attribute can accept ephemeral values
// or not. If WriteOnly is true, either Optional or Required must also be true.
//
// If WriteOnly is true for a nested attribute, all of its child attributes
// must also set WriteOnly to true.
WriteOnly bool
}

// ApplyTerraform5AttributePathStep returns the Attributes field value if step
Expand Down Expand Up @@ -215,9 +222,9 @@ func (a ListNestedAttribute) IsSensitive() bool {
return false
}

// IsWriteOnly always returns false as action schema attributes cannot be WriteOnly.
// IsWriteOnly returns the WriteOnly field value.
func (a ListNestedAttribute) IsWriteOnly() bool {
return false
return a.WriteOnly
}

// IsRequiredForImport returns false as this behavior is only relevant
Expand Down Expand Up @@ -245,4 +252,7 @@ func (a ListNestedAttribute) ValidateImplementation(ctx context.Context, req fws
if a.CustomType == nil && fwtype.ContainsCollectionWithDynamic(a.GetType()) {
resp.Diagnostics.Append(fwtype.AttributeCollectionWithDynamicTypeDiag(req.Path))
}
if a.IsWriteOnly() && !fwschema.ContainsAllWriteOnlyChildAttributes(a) {
resp.Diagnostics.Append(fwschema.InvalidWriteOnlyNestedAttributeDiag(req.Path))
}
}
Loading