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

Add type-based provider-defined function parameter validation #968

Merged
merged 43 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5930e21
Add ValidateableAttribute and ValidateableParameter interfaces
bendbennett Mar 19, 2024
e3b5956
Deprecate xattr.TypeWithValidate
bendbennett Mar 19, 2024
a285776
Merge remote-tracking branch 'origin/main' into bendbennett/pdf-param…
bendbennett Mar 21, 2024
30cc1d9
Modify function signature of ArgumentsData() to return a function.Fun…
bendbennett Mar 21, 2024
b87d7ee
Modify Data.SetAtPath to use switch statement to handle validation.Va…
bendbennett Mar 21, 2024
cc06028
Modify Data.SetAtPathTransformFunc to use switch statement to handle …
bendbennett Mar 21, 2024
cf60c85
Temporarily moving ValidateableAttribute interface to xattr package t…
bendbennett Mar 22, 2024
995b96c
Adding test coverage for list, map and set for SetAtPathTransformFunc
bendbennett Mar 22, 2024
fe30c12
Adding test coverage for bool ValidateableParameter for fromproto5/6 …
bendbennett Mar 22, 2024
7328488
Adding switch statement for ValidateableAttribute to fwschemadata Dat…
bendbennett Mar 22, 2024
2437643
Merge remote-tracking branch 'origin/main' into bendbennett/pdf-param…
bendbennett Mar 22, 2024
b27c7fa
Adding switch statements to internal/reflect/interfaces to handle Val…
bendbennett Mar 22, 2024
a8103f6
Fix usage of incorrect test type
bendbennett Mar 22, 2024
06a5b87
Adding switch statements to internal/reflect/primitive to handle Vali…
bendbennett Mar 22, 2024
f410606
Renaming interfaces
bendbennett Mar 22, 2024
bab78d4
Add Equal() methods to ListValueWithValidateAttributeWarning and MapV…
bendbennett Apr 2, 2024
50c673a
Adding switch statements to reflect package FromMap() function to han…
bendbennett Apr 2, 2024
e0017b0
Adding switch statements to reflect package FromInt(), FromUint(), Fr…
bendbennett Apr 2, 2024
1d2c768
Adding switch statements to reflect package FromPointer() function to…
bendbennett Apr 2, 2024
12dcc5c
Adding switch statements to reflect package FromSlice() function to h…
bendbennett Apr 2, 2024
ce4b934
Adding switch statements to reflect package FromStruct() function to …
bendbennett Apr 2, 2024
bb76e62
Merge remote-tracking branch 'origin/main' into bendbennett/pdf-param…
bendbennett Apr 3, 2024
d04737c
fromproto5+fromproto6: Add further test coverage for validation of fu…
bendbennett Apr 3, 2024
b6d8b93
xfwfunction: Moving Definition.Parameter() method from function packa…
bendbennett Apr 3, 2024
3e0bc53
fromproto5+fromproto6: Fix function error message in ArgumentsData()
bendbennett Apr 3, 2024
6de0382
website: Add documentation for usage of xattr.ValidateableAttribute a…
bendbennett Apr 4, 2024
c8b530b
Merge remote-tracking branch 'origin/main' into bendbennett/pdf-param…
bendbennett Apr 4, 2024
ebea449
website: Add documentation for usage of xattr.ValidateableAttribute a…
bendbennett Apr 4, 2024
399acd1
Adding changelog entries
bendbennett Apr 4, 2024
6a32373
function: Remove unused Definition.Parameter() method
bendbennett Apr 5, 2024
c758c9c
attr/xattr: Remove TODO
bendbennett Apr 5, 2024
fb75b19
attr/xattr: Modify deprecation comment
bendbennett Apr 5, 2024
6f49065
fwschemadata: Reordering logging calls
bendbennett Apr 5, 2024
e26cde9
fromproto5+fromproto6: Inline logic from Parameter() function in Argu…
bendbennett Apr 9, 2024
24db3f2
Remove value type-specific interfaces for <Type>ValuableWithValidatea…
bendbennett Apr 9, 2024
6283788
website: Adding documentation for parameter validation into parameter…
bendbennett Apr 9, 2024
83293bd
function: Moving ValidateableParameter interface to function package
bendbennett Apr 9, 2024
75e30e5
Amend docs
bendbennett Apr 9, 2024
6c517b1
Apply suggestions from code review
bendbennett Apr 9, 2024
c55b74b
fromproto5: Remove unused function
bendbennett Apr 9, 2024
0d3ff07
fromproto5+fromproto6: Remove unneeded case statements
bendbennett Apr 9, 2024
cf398ce
fromproto5: Removing errant test case
bendbennett Apr 9, 2024
2d27299
attr/xattr: Modifying Validateable Go doc comment to highlight the im…
bendbennett Apr 11, 2024
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/BREAKING CHANGES-20240404-182004.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: BREAKING CHANGES
body: 'function: Removed `Definition` type `Parameter()` method'
time: 2024-04-04T18:20:04.534677+01:00
custom:
Issue: "968"
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20240404-154339.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'attr/xattr: Added `ValidateableAttribute` interface for custom value type implementations'
time: 2024-04-04T15:43:39.796606+01:00
custom:
Issue: "968"
6 changes: 6 additions & 0 deletions .changes/unreleased/FEATURES-20240404-154439.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: FEATURES
body: 'function: Added `ValidateableParameter` interface for custom value
type implementations'
time: 2024-04-04T15:44:39.289946+01:00
custom:
Issue: "968"
7 changes: 7 additions & 0 deletions .changes/unreleased/NOTES-20240404-155606.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: NOTES
body: 'attr/xattr: The `TypeWithValidate` interface has been deprecated in preference
of the `ValidateableAttribute` interface. A `ValidatableParameter` interface has
also been added to the `function` package'
time: 2024-04-04T15:56:06.494328+01:00
custom:
Issue: "968"
36 changes: 36 additions & 0 deletions attr/xattr/attribute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package xattr

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
)

// ValidateableAttribute defines an interface for validating an attribute value.
type ValidateableAttribute interface {
bendbennett marked this conversation as resolved.
Show resolved Hide resolved
// ValidateAttribute returns any warnings or errors generated during validation
// of the attribute. It is generally used to check the data format and ensure
// that it complies with the requirements of the Value.
ValidateAttribute(context.Context, ValidateAttributeRequest, *ValidateAttributeResponse)
}

// ValidateAttributeRequest represents a request for the Value to call its
// validation logic. An instance of this request struct is supplied as an
// argument to the ValidateAttribute method.
type ValidateAttributeRequest struct {
// Path is the path to the attribute being validated.
Path path.Path
}

// ValidateAttributeResponse represents a response to a ValidateAttributeRequest.
// An instance of this response struct is supplied as an argument to the
// ValidateAttribute method.
type ValidateAttributeResponse struct {
// Diagnostics is a collection of warnings or errors generated during
// validation of the Value.
Diagnostics diag.Diagnostics
}
7 changes: 6 additions & 1 deletion attr/xattr/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ package xattr
import (
"context"

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

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

// TypeWithValidate extends the attr.Type interface to include a Validate
// method, used to bundle consistent validation logic with the Type.
//
// Deprecated: Use the ValidateableAttribute interface instead for schema
// attribute validation. Use the function.ValidateableParameter interface
// for provider-defined function parameter validation.
type TypeWithValidate interface {
attr.Type

Expand Down
35 changes: 0 additions & 35 deletions function/definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,41 +51,6 @@ type Definition struct {
DeprecationMessage string
}

// Parameter returns the Parameter for a given argument position. This may be
// from the Parameters field or, if defined, the VariadicParameter field. An
// error diagnostic is raised if the position is outside the expected arguments.
func (d Definition) Parameter(ctx context.Context, position int) (Parameter, diag.Diagnostics) {
if d.VariadicParameter != nil && position >= len(d.Parameters) {
return d.VariadicParameter, nil
}

if len(d.Parameters) == 0 {
return nil, diag.Diagnostics{
diag.NewErrorDiagnostic(
"Invalid Parameter Position for Definition",
"When determining the parameter for the given argument position, an invalid value was given. "+
"This is always an issue in the provider code and should be reported to the provider developers.\n\n"+
"Function does not implement parameters.\n"+
fmt.Sprintf("Given position: %d", position),
),
}
}

if position >= len(d.Parameters) {
return nil, diag.Diagnostics{
diag.NewErrorDiagnostic(
"Invalid Parameter Position for Definition",
"When determining the parameter for the given argument position, an invalid value was given. "+
"This is always an issue in the provider code and should be reported to the provider developers.\n\n"+
fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+
fmt.Sprintf("Given position: %d", position),
),
}
}

return d.Parameters[position], nil
}

// ValidateImplementation contains logic for validating the provider-defined
// implementation of the definition to prevent unexpected errors or panics. This
// logic runs during the GetProviderSchema RPC, or via provider-defined unit
Expand Down
133 changes: 0 additions & 133 deletions function/definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,139 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

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

testCases := map[string]struct {
definition function.Definition
position int
expected function.Parameter
expectedDiagnostics diag.Diagnostics
}{
"none": {
definition: function.Definition{
// no Parameters or VariadicParameter
},
position: 0,
expected: nil,
expectedDiagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Invalid Parameter Position for Definition",
"When determining the parameter for the given argument position, an invalid value was given. "+
"This is always an issue in the provider code and should be reported to the provider developers.\n\n"+
"Function does not implement parameters.\n"+
"Given position: 0",
),
},
},
"parameters-first": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
function.Int64Parameter{},
function.StringParameter{},
},
},
position: 0,
expected: function.BoolParameter{},
},
"parameters-last": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
function.Int64Parameter{},
function.StringParameter{},
},
},
position: 2,
expected: function.StringParameter{},
},
"parameters-middle": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
function.Int64Parameter{},
function.StringParameter{},
},
},
position: 1,
expected: function.Int64Parameter{},
},
"parameters-only": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
},
},
position: 0,
expected: function.BoolParameter{},
},
"parameters-over": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
},
},
position: 1,
expected: nil,
expectedDiagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Invalid Parameter Position for Definition",
"When determining the parameter for the given argument position, an invalid value was given. "+
"This is always an issue in the provider code and should be reported to the provider developers.\n\n"+
"Max argument position: 0\n"+
"Given position: 1",
),
},
},
"variadicparameter-and-parameters-select-parameter": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
},
VariadicParameter: function.StringParameter{},
},
position: 0,
expected: function.BoolParameter{},
},
"variadicparameter-and-parameters-select-variadicparameter": {
definition: function.Definition{
Parameters: []function.Parameter{
function.BoolParameter{},
},
VariadicParameter: function.StringParameter{},
},
position: 1,
expected: function.StringParameter{},
},
"variadicparameter-only": {
definition: function.Definition{
VariadicParameter: function.StringParameter{},
},
position: 0,
expected: function.StringParameter{},
},
}

for name, testCase := range testCases {
name, testCase := name, testCase

t.Run(name, func(t *testing.T) {
t.Parallel()

got, diags := testCase.definition.Parameter(context.Background(), testCase.position)

if diff := cmp.Diff(got, testCase.expected); diff != "" {
t.Errorf("unexpected difference: %s", diff)
}

if diff := cmp.Diff(diags, testCase.expectedDiagnostics); diff != "" {
t.Errorf("unexpected diagnostics difference: %s", diff)
}
})
}
}

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

Expand Down
26 changes: 26 additions & 0 deletions function/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package function

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/attr"
)

Expand Down Expand Up @@ -38,3 +40,27 @@ type Parameter interface {
// Function type Run method.
GetType() attr.Type
}

// ValidateableParameter defines an interface for validating a parameter value.
type ValidateableParameter interface {
// ValidateParameter returns any error generated during validation
// of the parameter. It is generally used to check the data format and ensure
// that it complies with the requirements of the Value.
bendbennett marked this conversation as resolved.
Show resolved Hide resolved
ValidateParameter(context.Context, ValidateParameterRequest, *ValidateParameterResponse)
}

// ValidateParameterRequest represents a request for the Value to call its
// validation logic. An instance of this request struct is supplied as an
// argument to the Value type ValidateParameter method.
bendbennett marked this conversation as resolved.
Show resolved Hide resolved
type ValidateParameterRequest struct {
// Position is the zero-ordered position of the parameter being validated.
Position int64
}

// ValidateParameterResponse represents a response to a ValidateParameterRequest.
// An instance of this response struct is supplied as an argument to the
// ValidateParameter method.
type ValidateParameterResponse struct {
// Error is a function error generated during validation of the Value.
bendbennett marked this conversation as resolved.
Show resolved Hide resolved
Error *FuncError
}
Loading
Loading