diff --git a/.changelog/93.txt b/.changelog/93.txt new file mode 100644 index 000000000..cd75a272d --- /dev/null +++ b/.changelog/93.txt @@ -0,0 +1,3 @@ +```release-note:bug +tfsdk: Return warning diagnostic when using `Attribute` or `Schema` type `DeprecationMessage` field +``` diff --git a/tfsdk/attribute.go b/tfsdk/attribute.go index ce0e25f35..04a201905 100644 --- a/tfsdk/attribute.go +++ b/tfsdk/attribute.go @@ -344,4 +344,28 @@ func (a Attribute) validate(ctx context.Context, req ValidateAttributeRequest, r return } } + + if a.DeprecationMessage != "" && attributeConfig != nil { + tfValue, err := attributeConfig.ToTerraformValue(ctx) + + if err != nil { + resp.Diagnostics = append(resp.Diagnostics, &tfprotov6.Diagnostic{ + Severity: tfprotov6.DiagnosticSeverityError, + Summary: "Attribute Validation Error", + Detail: "Attribute validation cannot convert value. Report this to the provider developer:\n\n" + err.Error(), + Attribute: req.AttributePath, + }) + + return + } + + if tfValue != nil { + resp.Diagnostics = append(resp.Diagnostics, &tfprotov6.Diagnostic{ + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Attribute Deprecated", + Detail: a.DeprecationMessage, + Attribute: req.AttributePath, + }) + } + } } diff --git a/tfsdk/attribute_test.go b/tfsdk/attribute_test.go index 5a9b42f37..7a8e2cf29 100644 --- a/tfsdk/attribute_test.go +++ b/tfsdk/attribute_test.go @@ -804,6 +804,96 @@ func TestAttributeValidate(t *testing.T) { }, resp: ValidateAttributeResponse{}, }, + "deprecation-message-known": { + req: ValidateAttributeRequest{ + AttributePath: tftypes.NewAttributePath().WithAttributeName("test"), + Config: Config{ + Raw: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.String, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.String, "testvalue"), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "test": { + Type: types.StringType, + Optional: true, + DeprecationMessage: "Use something else instead.", + }, + }, + }, + }, + }, + resp: ValidateAttributeResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Attribute Deprecated", + Detail: "Use something else instead.", + Attribute: tftypes.NewAttributePath().WithAttributeName("test"), + }, + }, + }, + }, + "deprecation-message-null": { + req: ValidateAttributeRequest{ + AttributePath: tftypes.NewAttributePath().WithAttributeName("test"), + Config: Config{ + Raw: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "test": tftypes.String, + }, + }, map[string]tftypes.Value{ + "test": tftypes.NewValue(tftypes.String, nil), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "test": { + Type: types.StringType, + Optional: true, + DeprecationMessage: "Use something else instead.", + }, + }, + }, + }, + }, + resp: ValidateAttributeResponse{}, + }, + "deprecation-message-unknown": { + req: ValidateAttributeRequest{ + AttributePath: tftypes.NewAttributePath().WithAttributeName("test"), + Config: 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), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "test": { + Type: types.StringType, + Optional: true, + DeprecationMessage: "Use something else instead.", + }, + }, + }, + }, + }, + resp: ValidateAttributeResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Attribute Deprecated", + Detail: "Use something else instead.", + Attribute: tftypes.NewAttributePath().WithAttributeName("test"), + }, + }, + }, + }, "warnings": { req: ValidateAttributeRequest{ AttributePath: tftypes.NewAttributePath().WithAttributeName("test"), diff --git a/tfsdk/schema.go b/tfsdk/schema.go index cef316126..bff76a332 100644 --- a/tfsdk/schema.go +++ b/tfsdk/schema.go @@ -199,4 +199,12 @@ func (s Schema) validate(ctx context.Context, req ValidateSchemaRequest, resp *V resp.Diagnostics = attributeResp.Diagnostics } + + if s.DeprecationMessage != "" { + resp.Diagnostics = append(resp.Diagnostics, &tfprotov6.Diagnostic{ + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Deprecated", + Detail: s.DeprecationMessage, + }) + } } diff --git a/tfsdk/schema_test.go b/tfsdk/schema_test.go index ecb14610a..cb877df49 100644 --- a/tfsdk/schema_test.go +++ b/tfsdk/schema_test.go @@ -556,6 +556,43 @@ func TestSchemaValidate(t *testing.T) { }, resp: ValidateSchemaResponse{}, }, + "deprecation-message": { + req: ValidateSchemaRequest{ + Config: Config{ + Raw: tftypes.NewValue(tftypes.Object{ + AttributeTypes: map[string]tftypes.Type{ + "attr1": tftypes.String, + "attr2": tftypes.String, + }, + }, map[string]tftypes.Value{ + "attr1": tftypes.NewValue(tftypes.String, "attr1value"), + "attr2": tftypes.NewValue(tftypes.String, "attr2value"), + }), + Schema: Schema{ + Attributes: map[string]Attribute{ + "attr1": { + Type: types.StringType, + Required: true, + }, + "attr2": { + Type: types.StringType, + Required: true, + }, + }, + DeprecationMessage: "Use something else instead.", + }, + }, + }, + resp: ValidateSchemaResponse{ + Diagnostics: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Deprecated", + Detail: "Use something else instead.", + }, + }, + }, + }, "warnings": { req: ValidateSchemaRequest{ Config: Config{ diff --git a/tfsdk/serve_test.go b/tfsdk/serve_test.go index 836d90fc6..e449ca59f 100644 --- a/tfsdk/serve_test.go +++ b/tfsdk/serve_test.go @@ -413,6 +413,20 @@ func TestServerValidateProviderConfig(t *testing.T) { }), provider: &testServeProvider{}, providerType: testServeProviderProviderType, + + expectedDiags: []*tfprotov6.Diagnostic{ + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Attribute Deprecated", + Detail: `Deprecated, please use "optional" instead`, + Attribute: tftypes.NewAttributePath().WithAttributeName("deprecated"), + }, + { + Severity: tfprotov6.DiagnosticSeverityWarning, + Summary: "Deprecated", + Detail: "Deprecated in favor of other_resource", + }, + }, }, "config_validators_no_diags": { config: tftypes.NewValue(testServeResourceTypeConfigValidatorsType, map[string]tftypes.Value{