From 155ab41a0a04cb00d4b168924418c90f5e9d5abf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:07:54 -0500 Subject: [PATCH 01/15] AutoFlEx: Support 'autoflex:",noxmlwrapper"' struct tag on expand. --- internal/framework/flex/autoflex.go | 5 ++- internal/framework/flex/autoflex_expand.go | 45 +++++++++++---------- internal/framework/flex/autoflex_flatten.go | 11 ++--- internal/framework/flex/tags.go | 4 ++ 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/internal/framework/flex/autoflex.go b/internal/framework/flex/autoflex.go index dce7baf563c5..93973b13d3cd 100644 --- a/internal/framework/flex/autoflex.go +++ b/internal/framework/flex/autoflex.go @@ -166,8 +166,9 @@ func autoflexTags(field reflect.StructField) (string, tagOptions) { } type fieldOpts struct { - legacy bool - omitempty bool + legacy bool + omitempty bool + noXMLWrapper bool } // valueWithElementsAs extends the Value interface for values that have an ElementsAs method. diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index c76c31ee6d3f..8aa93c600c7f 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -182,19 +182,19 @@ func (expander autoExpander) convert(ctx context.Context, sourcePath path.Path, // Aggregate types. case basetypes.ObjectValuable: - diags.Append(expander.object(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.object(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags case basetypes.ListValuable: - diags.Append(expander.list(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.list(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags case basetypes.MapValuable: - diags.Append(expander.map_(ctx, vFrom, vTo)...) + diags.Append(expander.map_(ctx, vFrom, vTo, fieldOpts)...) return diags case basetypes.SetValuable: - diags.Append(expander.set(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.set(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags } @@ -538,7 +538,7 @@ func (expander autoExpander) string(ctx context.Context, vFrom basetypes.StringV } // string copies a Plugin Framework Object(ish) value to a compatible AWS API value. -func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, vFrom basetypes.ObjectValuable, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, vFrom basetypes.ObjectValuable, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics _, d := vFrom.ToObjectValue(ctx) @@ -588,7 +588,7 @@ func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, v } // list copies a Plugin Framework List(ish) value to a compatible AWS API value. -func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFrom basetypes.ListValuable, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFrom basetypes.ListValuable, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToListValue(ctx) @@ -599,16 +599,16 @@ func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFr switch v.ElementType(ctx).(type) { case basetypes.Int64Typable: - diags.Append(expander.listOrSetOfInt64(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfInt64(ctx, v, vTo, fieldOpts)...) return diags case basetypes.StringTypable: - diags.Append(expander.listOrSetOfString(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfString(ctx, v, vTo, fieldOpts)...) return diags case basetypes.ObjectTypable: if vFrom, ok := vFrom.(fwtypes.NestedObjectCollectionValue); ok { - diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags } } @@ -622,13 +622,13 @@ func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFr } // listOrSetOfInt64 copies a Plugin Framework ListOfInt64(ish) or SetOfInt64(ish) value to a compatible AWS API value. -func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct - if isXMLWrapperStruct(vTo.Type()) { + if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(vTo.Type()) { diags.Append(expander.xmlWrapper(ctx, vFrom, vTo, "Items")...) return diags } @@ -701,13 +701,13 @@ func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWi } // listOrSetOfString copies a Plugin Framework ListOfString(ish) or SetOfString(ish) value to a compatible AWS API value. -func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct - if isXMLWrapperStruct(vTo.Type()) { + if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(vTo.Type()) { diags.Append(expander.xmlWrapper(ctx, vFrom, vTo, "Items")...) return diags } @@ -766,7 +766,7 @@ func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueW } // map_ copies a Plugin Framework Map(ish) value to a compatible AWS API value. -func (expander autoExpander) map_(ctx context.Context, vFrom basetypes.MapValuable, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) map_(ctx context.Context, vFrom basetypes.MapValuable, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToMapValue(ctx) @@ -893,7 +893,7 @@ func (expander autoExpander) mapOfString(ctx context.Context, vFrom basetypes.Ma } // set copies a Plugin Framework Set(ish) value to a compatible AWS API value. -func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFrom basetypes.SetValuable, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFrom basetypes.SetValuable, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToSetValue(ctx) @@ -904,16 +904,16 @@ func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFro switch v.ElementType(ctx).(type) { case basetypes.Int64Typable: - diags.Append(expander.listOrSetOfInt64(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfInt64(ctx, v, vTo, fieldOpts)...) return diags case basetypes.StringTypable: - diags.Append(expander.listOrSetOfString(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfString(ctx, v, vTo, fieldOpts)...) return diags case basetypes.ObjectTypable: if vFrom, ok := vFrom.(fwtypes.NestedObjectCollectionValue); ok { - diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags } } @@ -927,13 +927,13 @@ func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFro } // nestedObjectCollection copies a Plugin Framework NestedObjectCollectionValue value to a compatible AWS API value. -func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourcePath path.Path, vFrom fwtypes.NestedObjectCollectionValue, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourcePath path.Path, vFrom fwtypes.NestedObjectCollectionValue, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch tTo := vTo.Type(); vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct before handling as generic struct - if isXMLWrapperStruct(tTo) { + if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(tTo) { diags.Append(expander.nestedObjectCollectionToXMLWrapper(ctx, sourcePath, vFrom, targetPath, vTo)...) return diags } @@ -947,7 +947,7 @@ func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourceP switch tElem := tTo.Elem(); tElem.Kind() { case reflect.Struct: // Check if target is a pointer to XML wrapper struct - if isXMLWrapperStruct(tElem) { + if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(tElem) { // Create new instance of the XML wrapper struct newWrapper := reflect.New(tElem) diags.Append(expander.nestedObjectCollectionToXMLWrapper(ctx, sourcePath, vFrom, targetPath, newWrapper.Elem())...) @@ -1221,7 +1221,8 @@ func expandStruct(ctx context.Context, sourcePath path.Path, from any, targetPat }) opts := fieldOpts{ - legacy: fromFieldOpts.Legacy(), + legacy: fromFieldOpts.Legacy(), + noXMLWrapper: fromFieldOpts.NoXMLWrapper(), } diags.Append(flexer.convert(ctx, sourcePath.AtName(fromFieldName), valFrom.FieldByIndex(fromField.Index), targetPath.AtName(toFieldName), toFieldVal, opts)...) diff --git a/internal/framework/flex/autoflex_flatten.go b/internal/framework/flex/autoflex_flatten.go index a3496004a268..f02ee9144d4e 100644 --- a/internal/framework/flex/autoflex_flatten.go +++ b/internal/framework/flex/autoflex_flatten.go @@ -1776,7 +1776,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa continue } toFieldName := toField.Name - toNameOverride, toOpts := autoflexTags(toField) + toNameOverride, toFieldOpts := autoflexTags(toField) toFieldVal := valTo.FieldByIndex(toField.Index) if toNameOverride == "-" { tflog.SubsystemTrace(ctx, subsystemName, "Skipping ignored target field", map[string]any{ @@ -1785,7 +1785,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa }) continue } - if toOpts.NoFlatten() { + if toFieldOpts.NoFlatten() { tflog.SubsystemTrace(ctx, subsystemName, "Skipping noflatten target field", map[string]any{ logAttrKeySourceFieldname: fromFieldName, logAttrKeyTargetFieldname: toFieldName, @@ -1807,7 +1807,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa }) // Check if target has wrapper tag and source is an XML wrapper struct - if wrapperField := toOpts.WrapperField(); wrapperField != "" { + if wrapperField := toFieldOpts.WrapperField(); wrapperField != "" { fromFieldVal := valFrom.FieldByIndex(fromField.Index) if isXMLWrapperStruct(fromFieldVal.Type()) { tflog.SubsystemTrace(ctx, subsystemName, "Converting XML wrapper struct to collection", map[string]any{ @@ -1836,8 +1836,9 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa } opts := fieldOpts{ - legacy: toOpts.Legacy(), - omitempty: toOpts.OmitEmpty(), + legacy: toFieldOpts.Legacy(), + omitempty: toFieldOpts.OmitEmpty(), + noXMLWrapper: toFieldOpts.NoXMLWrapper(), } diags.Append(flexer.convert(ctx, sourcePath.AtName(fromFieldName), valFrom.FieldByIndex(fromField.Index), targetPath.AtName(toFieldName), toFieldVal, opts)...) diff --git a/internal/framework/flex/tags.go b/internal/framework/flex/tags.go index 42118c32ce75..ed50148e61b3 100644 --- a/internal/framework/flex/tags.go +++ b/internal/framework/flex/tags.go @@ -50,6 +50,10 @@ func (o tagOptions) NoFlatten() bool { return o.Contains("noflatten") } +func (o tagOptions) NoXMLWrapper() bool { + return o.Contains("noxmlwrapper") +} + func (o tagOptions) WrapperField() string { if len(o) == 0 { return "" From 31734526cce7ddb8ba4f94bc26fa14266da24774 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:08:12 -0500 Subject: [PATCH 02/15] Add 'TestExpandNoXMLWrapper'. --- .../flex/autoflex_xml_compat_test.go | 56 ++++++ .../valid_function_associations.golden | 168 ++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index 435ca8e00854..c0cdca1d5ef6 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -336,3 +336,59 @@ func TestFlattenXMLWrapper(t *testing.T) { runAutoFlattenTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) } + +type FunctionAssociationsTF struct { + Items fwtypes.ListNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"items"` + Quantity types.Int64 `tfsdk:"quantity"` +} + +type DistributionConfigTFNoXMLWrapper struct { + FunctionAssociations fwtypes.ListNestedObjectValueOf[FunctionAssociationsTF] `tfsdk:"function_associations" autoflex:",noxmlwrapper"` +} + +func TestExpandNoXMLWrapper(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testCases := autoFlexTestCases{ + "valid function associations": { + Source: DistributionConfigTFNoXMLWrapper{ + FunctionAssociations: fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &FunctionAssociationsTF{ + Items: fwtypes.NewListNestedObjectValueOfSliceMust( + ctx, + []*FunctionAssociationTF{ + { + EventType: types.StringValue("viewer-request"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: types.StringValue("viewer-response"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }, + ), + Quantity: types.Int64Value(2), + }), + }, + Target: &DistributionConfigAWS{}, + WantTarget: &DistributionConfigAWS{ + FunctionAssociations: &FunctionAssociations{ + Quantity: aws.Int32(2), + Items: []FunctionAssociation{ + { + EventType: "viewer-request", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: "viewer-response", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }, + }, + }, + }, + } + + runAutoExpandTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) +} diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden new file mode 100644 index 000000000000..95d26e0d9b45 --- /dev/null +++ b/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden @@ -0,0 +1,168 @@ +[ + { + "@level": "info", + "@message": "Expanding", + "@module": "provider.autoflex", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionAssociations", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "autoflex.target.fieldname": "FunctionAssociations", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" + }, + { + "@level": "trace", + "@message": "Expanding NestedObjectCollection to XML wrapper", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "source_type": "SetNestedObjectTypeOf[flex.FunctionAssociationTF]", + "target_type": "flex.FunctionAssociations" + }, + { + "@level": "trace", + "@message": "Converting nested objects to items", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "items_count": 2, + "items_type": "[]flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "EventType", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "EventType", + "autoflex.target.type": "string" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionARN", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "FunctionARN", + "autoflex.target.type": "*string" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "EventType", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "EventType", + "autoflex.target.type": "string" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionARN", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "FunctionARN", + "autoflex.target.type": "*string" + }, + { + "@level": "trace", + "@message": "Successfully expanded NestedObjectCollection to XML wrapper", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "items_count": 2 + } +] \ No newline at end of file From 7de481aa4ef8aad926c30f8afd635c19275e5f7e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:10:11 -0500 Subject: [PATCH 03/15] Correct golden logs. --- .../valid_function_associations.golden | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden index 95d26e0d9b45..2b6bca7ff6b6 100644 --- a/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden +++ b/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden @@ -3,7 +3,7 @@ "@level": "info", "@message": "Expanding", "@module": "provider.autoflex", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" }, { @@ -11,7 +11,7 @@ "@message": "Converting", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper", "autoflex.target.path": "", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" }, @@ -21,7 +21,7 @@ "@module": "provider.autoflex", "autoflex.source.fieldname": "FunctionAssociations", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper", "autoflex.target.fieldname": "FunctionAssociations", "autoflex.target.path": "", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" @@ -31,59 +31,58 @@ "@message": "Converting", "@module": "provider.autoflex", "autoflex.source.path": "FunctionAssociations", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF]", "autoflex.target.path": "FunctionAssociations", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" }, { "@level": "trace", - "@message": "Expanding NestedObjectCollection to XML wrapper", + "@message": "Matched fields", "@module": "provider.autoflex", - "autoflex.source.path": "FunctionAssociations", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.source.fieldname": "Items", + "autoflex.source.path": "FunctionAssociations[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF", + "autoflex.target.fieldname": "Items", "autoflex.target.path": "FunctionAssociations", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", - "source_type": "SetNestedObjectTypeOf[flex.FunctionAssociationTF]", - "target_type": "flex.FunctionAssociations" + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" }, { - "@level": "trace", - "@message": "Converting nested objects to items", + "@level": "info", + "@message": "Converting", "@module": "provider.autoflex", - "autoflex.source.path": "FunctionAssociations", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", - "autoflex.target.path": "FunctionAssociations", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", - "items_count": 2, - "items_type": "[]flex.FunctionAssociation" + "autoflex.source.path": "FunctionAssociations[0].Items", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" }, { - "@level": "info", - "@message": "Converting", + "@level": "trace", + "@message": "Expanding nested object collection", "@module": "provider.autoflex", - "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", - "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + "autoflex.source.path": "FunctionAssociations[0].Items", + "autoflex.source.size": 2, + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" }, { "@level": "trace", "@message": "Matched fields", "@module": "provider.autoflex", "autoflex.source.fieldname": "EventType", - "autoflex.source.path": "", + "autoflex.source.path": "FunctionAssociations[0].Items[0]", "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", "autoflex.target.fieldname": "EventType", - "autoflex.target.path": "", + "autoflex.target.path": "FunctionAssociations.Items[0]", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" }, { "@level": "info", "@message": "Converting", "@module": "provider.autoflex", - "autoflex.source.path": "EventType", + "autoflex.source.path": "FunctionAssociations[0].Items[0].EventType", "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", - "autoflex.target.path": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[0].EventType", "autoflex.target.type": "string" }, { @@ -91,48 +90,39 @@ "@message": "Matched fields", "@module": "provider.autoflex", "autoflex.source.fieldname": "FunctionARN", - "autoflex.source.path": "", + "autoflex.source.path": "FunctionAssociations[0].Items[0]", "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", "autoflex.target.fieldname": "FunctionARN", - "autoflex.target.path": "", + "autoflex.target.path": "FunctionAssociations.Items[0]", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" }, { "@level": "info", "@message": "Converting", "@module": "provider.autoflex", - "autoflex.source.path": "FunctionARN", + "autoflex.source.path": "FunctionAssociations[0].Items[0].FunctionARN", "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", - "autoflex.target.path": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[0].FunctionARN", "autoflex.target.type": "*string" }, - { - "@level": "info", - "@message": "Converting", - "@module": "provider.autoflex", - "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", - "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" - }, { "@level": "trace", "@message": "Matched fields", "@module": "provider.autoflex", "autoflex.source.fieldname": "EventType", - "autoflex.source.path": "", + "autoflex.source.path": "FunctionAssociations[0].Items[1]", "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", "autoflex.target.fieldname": "EventType", - "autoflex.target.path": "", + "autoflex.target.path": "FunctionAssociations.Items[1]", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" }, { "@level": "info", "@message": "Converting", "@module": "provider.autoflex", - "autoflex.source.path": "EventType", + "autoflex.source.path": "FunctionAssociations[0].Items[1].EventType", "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", - "autoflex.target.path": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[1].EventType", "autoflex.target.type": "string" }, { @@ -140,29 +130,39 @@ "@message": "Matched fields", "@module": "provider.autoflex", "autoflex.source.fieldname": "FunctionARN", - "autoflex.source.path": "", + "autoflex.source.path": "FunctionAssociations[0].Items[1]", "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", "autoflex.target.fieldname": "FunctionARN", - "autoflex.target.path": "", + "autoflex.target.path": "FunctionAssociations.Items[1]", "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" }, { "@level": "info", "@message": "Converting", "@module": "provider.autoflex", - "autoflex.source.path": "FunctionARN", + "autoflex.source.path": "FunctionAssociations[0].Items[1].FunctionARN", "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", - "autoflex.target.path": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[1].FunctionARN", "autoflex.target.type": "*string" }, { "@level": "trace", - "@message": "Successfully expanded NestedObjectCollection to XML wrapper", + "@message": "Matched fields", "@module": "provider.autoflex", - "autoflex.source.path": "FunctionAssociations", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.SetNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.source.fieldname": "Quantity", + "autoflex.source.path": "FunctionAssociations[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF", + "autoflex.target.fieldname": "Quantity", "autoflex.target.path": "FunctionAssociations", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", - "items_count": 2 + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Quantity", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.Int64Value", + "autoflex.target.path": "FunctionAssociations.Quantity", + "autoflex.target.type": "*int32" } ] \ No newline at end of file From ede2cffe286e28ecdfa92803ef5f835e3e10894b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:15:26 -0500 Subject: [PATCH 04/15] Fix 'unnecessary type arguments' warnings. --- internal/framework/flex/autoflex_maps_test.go | 16 ++++++++-------- internal/framework/flex/autoflex_nested_test.go | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/internal/framework/flex/autoflex_maps_test.go b/internal/framework/flex/autoflex_maps_test.go index 025ffc4702d1..574a81a7320c 100644 --- a/internal/framework/flex/autoflex_maps_test.go +++ b/internal/framework/flex/autoflex_maps_test.go @@ -213,7 +213,7 @@ func TestExpandMapBlock(t *testing.T) { }, "map block key list": { Source: &tfMapBlockList{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -242,7 +242,7 @@ func TestExpandMapBlock(t *testing.T) { }, "map block key set": { Source: &tfMapBlockSet{ - MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -329,7 +329,7 @@ func TestExpandMapBlock(t *testing.T) { }, "map block enum key": { Source: &tfMapBlockListEnumKey{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElementEnumKey](ctx, []tfMapBlockElementEnumKey{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElementEnumKey{ { MapBlockKey: fwtypes.StringEnumValue(testEnumList), Attr1: types.StringValue("a"), @@ -359,7 +359,7 @@ func TestExpandMapBlock(t *testing.T) { "map block list no key": { Source: &tfMapBlockListNoKey{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElementNoKey](ctx, []tfMapBlockElementNoKey{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElementNoKey{ { Attr1: types.StringValue("a"), Attr2: types.StringValue("b"), @@ -491,7 +491,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockList{}, WantTarget: &tfMapBlockList{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -511,7 +511,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockSet{}, WantTarget: &tfMapBlockSet{ - MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -540,7 +540,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockList{}, WantTarget: &tfMapBlockList{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -580,7 +580,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockListEnumKey{}, WantTarget: &tfMapBlockListEnumKey{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElementEnumKey](ctx, []tfMapBlockElementEnumKey{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElementEnumKey{ { MapBlockKey: fwtypes.StringEnumValue(testEnumList), Attr1: types.StringValue("a"), diff --git a/internal/framework/flex/autoflex_nested_test.go b/internal/framework/flex/autoflex_nested_test.go index 18d22d83b64b..3fc3f362f407 100644 --- a/internal/framework/flex/autoflex_nested_test.go +++ b/internal/framework/flex/autoflex_nested_test.go @@ -75,7 +75,7 @@ func TestExpandSimpleSingleNestedBlock(t *testing.T) { ctx := context.Background() testCases := autoFlexTestCases{ "single nested block pointer": { - Source: &tf02{Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, + Source: &tf02{Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, Target: &aws02{}, WantTarget: &aws02{Field1: &aws01{Field1: aws.String("a"), Field2: 1}}, }, @@ -85,7 +85,7 @@ func TestExpandSimpleSingleNestedBlock(t *testing.T) { WantTarget: &aws02{}, }, "single nested block value": { - Source: &tf02{Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, + Source: &tf02{Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, Target: &aws03{}, WantTarget: &aws03{Field1: aws01{Field1: aws.String("a"), Field2: 1}}, }, @@ -171,10 +171,10 @@ func TestExpandComplexSingleNestedBlock(t *testing.T) { testCases := autoFlexTestCases{ "single nested block pointer": { Source: &tf03{ - Field1: fwtypes.NewObjectValueOfMust[tf02]( + Field1: fwtypes.NewObjectValueOfMust( ctx, &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01]( + Field1: fwtypes.NewObjectValueOfMust( ctx, &tf01{ Field1: types.BoolValue(true), @@ -796,7 +796,7 @@ func TestFlattenSimpleSingleNestedBlock(t *testing.T) { }, Target: &tf02{}, WantTarget: &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{ Field1: types.StringValue("a"), Field2: types.Int64Value(1), }), @@ -817,7 +817,7 @@ func TestFlattenSimpleSingleNestedBlock(t *testing.T) { }, Target: &tf02{}, WantTarget: &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{ Field1: types.StringValue("a"), Field2: types.Int64Value(1), }), @@ -866,8 +866,8 @@ func TestFlattenComplexSingleNestedBlock(t *testing.T) { }, Target: &tf03{}, WantTarget: &tf03{ - Field1: fwtypes.NewObjectValueOfMust[tf02](ctx, &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf02{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{ Field1: types.BoolValue(true), Field2: fwtypes.NewListValueOfMust[types.String](ctx, []attr.Value{ types.StringValue("a"), From 76c226db8dbafbe0aaa9e3601c374e1de2d451c7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:21:31 -0500 Subject: [PATCH 05/15] Fix 'unusedparams' warnings. --- internal/framework/flex/autoflex_expand.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index 8aa93c600c7f..dd8dd79d5f83 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -538,7 +538,7 @@ func (expander autoExpander) string(ctx context.Context, vFrom basetypes.StringV } // string copies a Plugin Framework Object(ish) value to a compatible AWS API value. -func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, vFrom basetypes.ObjectValuable, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { +func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, vFrom basetypes.ObjectValuable, targetPath path.Path, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics _, d := vFrom.ToObjectValue(ctx) @@ -766,7 +766,7 @@ func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueW } // map_ copies a Plugin Framework Map(ish) value to a compatible AWS API value. -func (expander autoExpander) map_(ctx context.Context, vFrom basetypes.MapValuable, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { +func (expander autoExpander) map_(ctx context.Context, vFrom basetypes.MapValuable, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToMapValue(ctx) From 267eea9f8f2067cb103494ad60073a4cc04a2dac Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:38:08 -0500 Subject: [PATCH 06/15] Check number of non-anonymous fields for XML wrapper heuristics. --- internal/framework/flex/autoflex_expand.go | 13 +++++ .../flex/autoflex_xml_compat_test.go | 58 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index dd8dd79d5f83..963651293441 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -1583,11 +1583,24 @@ func isXMLWrapperStruct(t reflect.Type) bool { return false } + //quantityField.Anonymous + // Quantity should be *int32 if quantityField.Type.Elem().Kind() != reflect.Int32 { return false } + // Items and Quantity should be the only non-anonymous fields + nNonAnonymousFields := 0 + for i := 0; i < t.NumField(); i++ { + if !t.Field(i).Anonymous { + nNonAnonymousFields++ + } + } + if nNonAnonymousFields != 2 { + return false + } + return true } diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index c0cdca1d5ef6..2b262bf38283 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -168,6 +168,11 @@ func TestExpandXMLWrapperDirect(t *testing.T) { func TestIsXMLWrapperStruct(t *testing.T) { t.Parallel() + type embedWithField struct { + Count int64 + } + type embedWithoutField struct{} + testCases := []struct { name string input any @@ -183,6 +188,14 @@ func TestIsXMLWrapperStruct(t *testing.T) { input: DirectXMLWrapper{}, expected: true, }, + { + name: "valid XML wrapper with anonymous struct", + input: struct { + Items []string + Quantity *int32 + }{}, + expected: true, + }, { name: "not a struct", input: "string", @@ -214,6 +227,51 @@ func TestIsXMLWrapperStruct(t *testing.T) { }{}, expected: false, }, + { + name: "struct with extra field", + input: struct { + Items []string + Quantity *int32 + Name string + }{}, + expected: false, + }, + { + name: "struct with anonymous embedWithField", + input: struct { + Items []string + Quantity *int32 + embedWithField + }{}, + expected: true, + }, + { + name: "struct with anonymous embedWithoutField", + input: struct { + Items []string + Quantity *int32 + embedWithoutField + }{}, + expected: true, + }, + { + name: "struct with private embedWithField", + input: struct { + Items []string + Quantity *int32 + private embedWithField + }{}, + expected: false, + }, + { + name: "struct with private embedWithoutField", + input: struct { + Items []string + Quantity *int32 + private embedWithoutField + }{}, + expected: false, + }, } for _, tc := range testCases { From 911061f1fd95eacce3178d39e55db6c649fddc1b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 12:52:31 -0500 Subject: [PATCH 07/15] AutoFlEx: Rename 'wrapper' struct tag to 'xmlwrapper'. --- internal/framework/flex/autoflex_flatten.go | 12 ++++++------ internal/framework/flex/autoflex_xml_compat_test.go | 6 +++--- internal/framework/flex/tags.go | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/framework/flex/autoflex_flatten.go b/internal/framework/flex/autoflex_flatten.go index f02ee9144d4e..8dca65f222db 100644 --- a/internal/framework/flex/autoflex_flatten.go +++ b/internal/framework/flex/autoflex_flatten.go @@ -185,7 +185,7 @@ func (flattener autoFlattener) convert(ctx context.Context, sourcePath path.Path return diags case reflect.Map: - diags.Append(flattener.map_(ctx, sourcePath, vFrom, targetPath, tTo, vTo)...) + diags.Append(flattener.map_(ctx, sourcePath, vFrom, targetPath, tTo, vTo, fieldOpts)...) return diags case reflect.Struct: @@ -193,7 +193,7 @@ func (flattener autoFlattener) convert(ctx context.Context, sourcePath path.Path return diags case reflect.Interface: - diags.Append(flattener.interface_(ctx, vFrom, tTo, vTo)...) + diags.Append(flattener.interface_(ctx, vFrom, tTo, vTo, fieldOpts)...) return diags } @@ -612,7 +612,7 @@ func (flattener autoFlattener) pointer(ctx context.Context, sourcePath path.Path return diags } -func (flattener autoFlattener) interface_(ctx context.Context, vFrom reflect.Value, tTo attr.Type, vTo reflect.Value) diag.Diagnostics { +func (flattener autoFlattener) interface_(ctx context.Context, vFrom reflect.Value, tTo attr.Type, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch tTo := tTo.(type) { @@ -846,7 +846,7 @@ func (flattener autoFlattener) slice(ctx context.Context, sourcePath path.Path, } // map_ copies an AWS API map value to a compatible Plugin Framework value. -func (flattener autoFlattener) map_(ctx context.Context, sourcePath path.Path, vFrom reflect.Value, targetPath path.Path, tTo attr.Type, vTo reflect.Value) diag.Diagnostics { +func (flattener autoFlattener) map_(ctx context.Context, sourcePath path.Path, vFrom reflect.Value, targetPath path.Path, tTo attr.Type, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch tMapKey := vFrom.Type().Key(); tMapKey.Kind() { @@ -1731,7 +1731,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa for toField := range tfreflect.ExportedStructFields(typeTo) { toFieldName := toField.Name _, toOpts := autoflexTags(toField) - if wrapperField := toOpts.WrapperField(); wrapperField != "" { + if wrapperField := toOpts.XMLWrapperField(); wrapperField != "" { toFieldVal := valTo.FieldByIndex(toField.Index) if !toFieldVal.CanSet() { continue @@ -1807,7 +1807,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa }) // Check if target has wrapper tag and source is an XML wrapper struct - if wrapperField := toFieldOpts.WrapperField(); wrapperField != "" { + if wrapperField := toFieldOpts.XMLWrapperField(); wrapperField != "" { fromFieldVal := valFrom.FieldByIndex(fromField.Index) if isXMLWrapperStruct(fromFieldVal.Type()) { tflog.SubsystemTrace(ctx, subsystemName, "Converting XML wrapper struct to collection", map[string]any{ diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index 2b262bf38283..445101d5ba87 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -304,16 +304,16 @@ type awsFunctionAssociationsForFlatten struct { } type tfFunctionAssociationsModelForFlatten struct { - FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations" autoflex:",wrapper=items"` + FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations" autoflex:",xmlwrapper=items"` } // TF model types with wrapper tags (for flattening - AWS to TF) type tfStatusCodesModelForFlatten struct { - StatusCodes fwtypes.SetValueOf[types.Int64] `tfsdk:"status_codes" autoflex:",wrapper=items"` + StatusCodes fwtypes.SetValueOf[types.Int64] `tfsdk:"status_codes" autoflex:",xmlwrapper=items"` } type tfHeadersModelForFlatten struct { - Headers fwtypes.ListValueOf[types.String] `tfsdk:"headers" autoflex:",wrapper=items"` + Headers fwtypes.ListValueOf[types.String] `tfsdk:"headers" autoflex:",xmlwrapper=items"` } func TestFlattenXMLWrapper(t *testing.T) { diff --git a/internal/framework/flex/tags.go b/internal/framework/flex/tags.go index ed50148e61b3..c5d4e6047a0d 100644 --- a/internal/framework/flex/tags.go +++ b/internal/framework/flex/tags.go @@ -54,7 +54,7 @@ func (o tagOptions) NoXMLWrapper() bool { return o.Contains("noxmlwrapper") } -func (o tagOptions) WrapperField() string { +func (o tagOptions) XMLWrapperField() string { if len(o) == 0 { return "" } @@ -62,7 +62,7 @@ func (o tagOptions) WrapperField() string { for s != "" { var option string option, s, _ = strings.Cut(s, ",") - if name, value, found := strings.Cut(option, "="); found && name == "wrapper" { + if name, value, found := strings.Cut(option, "="); found && name == "xmlwrapper" { return value } } From 016b0e2cf2c03e05fbed6cbab77938443366d86e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 13:47:22 -0500 Subject: [PATCH 08/15] Add 'TestFlattenNoXMLWrapper'. --- .../flex/autoflex_xml_compat_test.go | 80 +++++++-- ...complex_type__function_associations.golden | 168 ++++++++++++++++++ 2 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index 445101d5ba87..1a642e948716 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -364,20 +364,16 @@ func TestFlattenXMLWrapper(t *testing.T) { }, Target: &tfFunctionAssociationsModelForFlatten{}, WantTarget: &tfFunctionAssociationsModelForFlatten{ - FunctionAssociations: func() fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] { - elems := []*FunctionAssociationTF{ - { - EventType: types.StringValue("viewer-request"), - FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/example-function"), - }, - { - EventType: types.StringValue("viewer-response"), - FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/another-function"), - }, - } - setValue, _ := fwtypes.NewSetNestedObjectValueOfSlice(ctx, elems, nil) - return setValue - }(), + FunctionAssociations: fwtypes.NewSetNestedObjectValueOfSliceMust(ctx, []*FunctionAssociationTF{ + { + EventType: types.StringValue("viewer-request"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/example-function"), + }, + { + EventType: types.StringValue("viewer-response"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/another-function"), + }, + }), }, }, "empty slice to null set": { @@ -450,3 +446,59 @@ func TestExpandNoXMLWrapper(t *testing.T) { runAutoExpandTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) } + +func TestFlattenNoXMLWrapper(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testCases := autoFlexTestCases{ + "complex type - function associations": { + Source: DistributionConfigAWS{ + FunctionAssociations: &FunctionAssociations{ + Quantity: aws.Int32(2), + Items: []FunctionAssociation{ + { + EventType: "viewer-request", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: "viewer-response", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }, + }, + }, + // Items: []FunctionAssociation{ + // { + // EventType: "viewer-request", + // FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/example-function"), + // }, + // { + // EventType: "viewer-response", + // FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/another-function"), + // }, + // }, + // Quantity: aws.Int32(2), + // }, + Target: &DistributionConfigTFNoXMLWrapper{}, + WantTarget: &DistributionConfigTFNoXMLWrapper{ + FunctionAssociations: fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &FunctionAssociationsTF{ + Items: fwtypes.NewListNestedObjectValueOfSliceMust(ctx, []*FunctionAssociationTF{ + { + EventType: types.StringValue("viewer-request"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: types.StringValue("viewer-response"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }), + Quantity: types.Int64Value(2), + }), + }, + }, + } + + runAutoFlattenTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) +} diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden new file mode 100644 index 000000000000..573c3187aa8c --- /dev/null +++ b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden @@ -0,0 +1,168 @@ +[ + { + "@level": "info", + "@message": "Flattening", + "@module": "provider.autoflex", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionAssociations", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS", + "autoflex.target.fieldname": "FunctionAssociations", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF]" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Quantity", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.fieldname": "Quantity", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Quantity", + "autoflex.source.type": "*int32", + "autoflex.target.path": "FunctionAssociations.Quantity", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.Int64Value" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Items", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.fieldname": "Items", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items", + "autoflex.source.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]" + }, + { + "@level": "trace", + "@message": "Flattening nested object collection", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items", + "autoflex.source.size": 2, + "autoflex.source.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "FunctionAssociations.Items[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[0]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[0].EventType", + "autoflex.source.type": "string", + "autoflex.target.path": "FunctionAssociations.Items[0].EventType", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "FunctionAssociations.Items[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[0]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[0].FunctionARN", + "autoflex.source.type": "*string", + "autoflex.target.path": "FunctionAssociations.Items[0].FunctionARN", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "FunctionAssociations.Items[1]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[1]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[1].EventType", + "autoflex.source.type": "string", + "autoflex.target.path": "FunctionAssociations.Items[1].EventType", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "FunctionAssociations.Items[1]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[1]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[1].FunctionARN", + "autoflex.source.type": "*string", + "autoflex.target.path": "FunctionAssociations.Items[1].FunctionARN", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + } +] \ No newline at end of file From d14d34b162271c7b7eb036b2023b482db0297472 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 14:23:22 -0500 Subject: [PATCH 09/15] Simplify. --- .../flex/autoflex_xml_compat_test.go | 22 +++------- ...complex_type__function_associations.golden | 40 ++++++++--------- ...complex_type__function_associations.golden | 44 +++++++++---------- 3 files changed, 48 insertions(+), 58 deletions(-) diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index 1a642e948716..e478cbe022d0 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -23,8 +23,8 @@ type FunctionAssociation struct { } type FunctionAssociations struct { - Quantity *int32 - Items []FunctionAssociation + Items []FunctionAssociation `json:"Items"` + Quantity *int32 `json:"Quantity"` } // Terraform model types @@ -34,7 +34,7 @@ type FunctionAssociationTF struct { } type DistributionConfigTF struct { - FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations"` + FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations" autoflex:",xmlwrapper=items"` } type DistributionConfigAWS struct { @@ -297,16 +297,6 @@ type awsHeadersForFlatten struct { Quantity *int32 } -// CloudFront FunctionAssociation test types -type awsFunctionAssociationsForFlatten struct { - Items []FunctionAssociation `json:"Items"` - Quantity *int32 `json:"Quantity"` -} - -type tfFunctionAssociationsModelForFlatten struct { - FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations" autoflex:",xmlwrapper=items"` -} - // TF model types with wrapper tags (for flattening - AWS to TF) type tfStatusCodesModelForFlatten struct { StatusCodes fwtypes.SetValueOf[types.Int64] `tfsdk:"status_codes" autoflex:",xmlwrapper=items"` @@ -349,7 +339,7 @@ func TestFlattenXMLWrapper(t *testing.T) { }, }, "complex type - function associations": { - Source: awsFunctionAssociationsForFlatten{ + Source: FunctionAssociations{ Items: []FunctionAssociation{ { EventType: "viewer-request", @@ -362,8 +352,8 @@ func TestFlattenXMLWrapper(t *testing.T) { }, Quantity: aws.Int32(2), }, - Target: &tfFunctionAssociationsModelForFlatten{}, - WantTarget: &tfFunctionAssociationsModelForFlatten{ + Target: &DistributionConfigTF{}, + WantTarget: &DistributionConfigTF{ FunctionAssociations: fwtypes.NewSetNestedObjectValueOfSliceMust(ctx, []*FunctionAssociationTF{ { EventType: types.StringValue("viewer-request"), diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden index 573c3187aa8c..15b240a7e704 100644 --- a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden +++ b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden @@ -35,26 +35,6 @@ "autoflex.target.path": "FunctionAssociations", "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF]" }, - { - "@level": "trace", - "@message": "Matched fields", - "@module": "provider.autoflex", - "autoflex.source.fieldname": "Quantity", - "autoflex.source.path": "FunctionAssociations", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", - "autoflex.target.fieldname": "Quantity", - "autoflex.target.path": "FunctionAssociations", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF" - }, - { - "@level": "info", - "@message": "Converting", - "@module": "provider.autoflex", - "autoflex.source.path": "FunctionAssociations.Quantity", - "autoflex.source.type": "*int32", - "autoflex.target.path": "FunctionAssociations.Quantity", - "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.Int64Value" - }, { "@level": "trace", "@message": "Matched fields", @@ -164,5 +144,25 @@ "autoflex.source.type": "*string", "autoflex.target.path": "FunctionAssociations.Items[1].FunctionARN", "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Quantity", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.fieldname": "Quantity", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Quantity", + "autoflex.source.type": "*int32", + "autoflex.target.path": "FunctionAssociations.Quantity", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.Int64Value" } ] \ No newline at end of file diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden index bad79202da75..e481e95568ce 100644 --- a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden +++ b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden @@ -3,27 +3,27 @@ "@level": "info", "@message": "Flattening", "@module": "provider.autoflex", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten" + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF" }, { "@level": "info", "@message": "Converting", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten" + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF" }, { "@level": "trace", "@message": "Converting entire XML wrapper struct to collection field", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "flex.FunctionAssociations", "autoflex.target.fieldname": "FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "wrapper_field": "items" }, { @@ -31,10 +31,10 @@ "@message": "Starting XML wrapper flatten", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", - "source_type": "flex.awsFunctionAssociationsForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "source_type": "flex.FunctionAssociations", "target_type": "SetNestedObjectTypeOf[flex.FunctionAssociationTF]", "wrapper_field": "items" }, @@ -43,9 +43,9 @@ "@message": "Found Items field", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "items_is_nil": false, "items_kind": "slice", "items_len": 2, @@ -56,9 +56,9 @@ "@message": "Using target element type", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "element_type": "ObjectTypeOf[flex.FunctionAssociationTF]" }, { @@ -66,9 +66,9 @@ "@message": "Converting items to set elements", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "items_count": 2 }, { @@ -76,9 +76,9 @@ "@message": "Processing item", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "index": 0, "item_kind": "struct", "item_value": { @@ -140,9 +140,9 @@ "@message": "Processing item", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "index": 1, "item_kind": "struct", "item_value": { @@ -204,10 +204,10 @@ "@message": "Creating set value", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "element_count": 2, "element_type": "ObjectTypeOf[flex.FunctionAssociationTF]" } -] \ No newline at end of file +] From 1d8cf873ba10f6131e0af9504a2d4b43e4eeb515 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 14:35:24 -0500 Subject: [PATCH 10/15] No need for 'noxmlwrapper' struct field tag as we have 'xmlwrapper'. --- internal/framework/flex/autoflex.go | 6 +++--- internal/framework/flex/autoflex_expand.go | 12 ++++++------ internal/framework/flex/autoflex_flatten.go | 6 +++--- internal/framework/flex/autoflex_xml_compat_test.go | 4 ++-- internal/framework/flex/tags.go | 4 ---- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/internal/framework/flex/autoflex.go b/internal/framework/flex/autoflex.go index 93973b13d3cd..1322c7504893 100644 --- a/internal/framework/flex/autoflex.go +++ b/internal/framework/flex/autoflex.go @@ -166,9 +166,9 @@ func autoflexTags(field reflect.StructField) (string, tagOptions) { } type fieldOpts struct { - legacy bool - omitempty bool - noXMLWrapper bool + legacy bool + omitempty bool + xmlWrapper bool } // valueWithElementsAs extends the Value interface for values that have an ElementsAs method. diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index 963651293441..ae42955e087c 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -628,7 +628,7 @@ func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWi switch vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct - if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(vTo.Type()) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(vTo.Type()) { diags.Append(expander.xmlWrapper(ctx, vFrom, vTo, "Items")...) return diags } @@ -707,7 +707,7 @@ func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueW switch vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct - if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(vTo.Type()) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(vTo.Type()) { diags.Append(expander.xmlWrapper(ctx, vFrom, vTo, "Items")...) return diags } @@ -933,7 +933,7 @@ func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourceP switch tTo := vTo.Type(); vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct before handling as generic struct - if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(tTo) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(tTo) { diags.Append(expander.nestedObjectCollectionToXMLWrapper(ctx, sourcePath, vFrom, targetPath, vTo)...) return diags } @@ -947,7 +947,7 @@ func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourceP switch tElem := tTo.Elem(); tElem.Kind() { case reflect.Struct: // Check if target is a pointer to XML wrapper struct - if !fieldOpts.noXMLWrapper && isXMLWrapperStruct(tElem) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(tElem) { // Create new instance of the XML wrapper struct newWrapper := reflect.New(tElem) diags.Append(expander.nestedObjectCollectionToXMLWrapper(ctx, sourcePath, vFrom, targetPath, newWrapper.Elem())...) @@ -1221,8 +1221,8 @@ func expandStruct(ctx context.Context, sourcePath path.Path, from any, targetPat }) opts := fieldOpts{ - legacy: fromFieldOpts.Legacy(), - noXMLWrapper: fromFieldOpts.NoXMLWrapper(), + legacy: fromFieldOpts.Legacy(), + xmlWrapper: fromFieldOpts.XMLWrapperField() != "", } diags.Append(flexer.convert(ctx, sourcePath.AtName(fromFieldName), valFrom.FieldByIndex(fromField.Index), targetPath.AtName(toFieldName), toFieldVal, opts)...) diff --git a/internal/framework/flex/autoflex_flatten.go b/internal/framework/flex/autoflex_flatten.go index 8dca65f222db..c7f6513bf48f 100644 --- a/internal/framework/flex/autoflex_flatten.go +++ b/internal/framework/flex/autoflex_flatten.go @@ -1836,9 +1836,9 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa } opts := fieldOpts{ - legacy: toFieldOpts.Legacy(), - omitempty: toFieldOpts.OmitEmpty(), - noXMLWrapper: toFieldOpts.NoXMLWrapper(), + legacy: toFieldOpts.Legacy(), + omitempty: toFieldOpts.OmitEmpty(), + xmlWrapper: toFieldOpts.XMLWrapperField() != "", } diags.Append(flexer.convert(ctx, sourcePath.AtName(fromFieldName), valFrom.FieldByIndex(fromField.Index), targetPath.AtName(toFieldName), toFieldVal, opts)...) diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index e478cbe022d0..630d939eaa3c 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -132,7 +132,7 @@ type DirectXMLWrapper struct { } type DirectWrapperTF struct { - Items fwtypes.SetValueOf[types.String] `tfsdk:"items"` + Items fwtypes.SetValueOf[types.String] `tfsdk:"items" autoflex:",xmlwrapper=items"` } type DirectWrapperAWS struct { @@ -387,7 +387,7 @@ type FunctionAssociationsTF struct { } type DistributionConfigTFNoXMLWrapper struct { - FunctionAssociations fwtypes.ListNestedObjectValueOf[FunctionAssociationsTF] `tfsdk:"function_associations" autoflex:",noxmlwrapper"` + FunctionAssociations fwtypes.ListNestedObjectValueOf[FunctionAssociationsTF] `tfsdk:"function_associations"` } func TestExpandNoXMLWrapper(t *testing.T) { diff --git a/internal/framework/flex/tags.go b/internal/framework/flex/tags.go index c5d4e6047a0d..9177b43b3755 100644 --- a/internal/framework/flex/tags.go +++ b/internal/framework/flex/tags.go @@ -50,10 +50,6 @@ func (o tagOptions) NoFlatten() bool { return o.Contains("noflatten") } -func (o tagOptions) NoXMLWrapper() bool { - return o.Contains("noxmlwrapper") -} - func (o tagOptions) XMLWrapperField() string { if len(o) == 0 { return "" From 3cb7a8c56e9dc8656055ce18fe41e5f8fd9d5dae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 14:55:29 -0500 Subject: [PATCH 11/15] Add CHANGELOG entry. --- .changelog/#####.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/#####.txt diff --git a/.changelog/#####.txt b/.changelog/#####.txt new file mode 100644 index 000000000000..15e50a5048e9 --- /dev/null +++ b/.changelog/#####.txt @@ -0,0 +1,2 @@ +```release-note:bug +resource/aws_cloudfront_continuous_deployment_policy: Fix `Source type "...cloudfront.stagingDistributionDNSNamesModel" does not implement attr.Value` error. This fixes a regression introduced in [v6.17.0](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md#6170-october-16-2025) \ No newline at end of file From a8935ca700e248db17850d506b9d364f3d20d6eb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 14:59:33 -0500 Subject: [PATCH 12/15] Correct CHANGELOG entry file name. --- .changelog/{#####.txt => 44972.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .changelog/{#####.txt => 44972.txt} (100%) diff --git a/.changelog/#####.txt b/.changelog/44972.txt similarity index 100% rename from .changelog/#####.txt rename to .changelog/44972.txt From beee5ef9d77d379d9d406bf73354eefa101df28d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 15:01:12 -0500 Subject: [PATCH 13/15] r/aws_cloudfront_vpc_origin: No need for custom flatteners and expanders. --- internal/service/cloudfront/vpc_origin.go | 114 ---------------------- 1 file changed, 114 deletions(-) diff --git a/internal/service/cloudfront/vpc_origin.go b/internal/service/cloudfront/vpc_origin.go index 12b51938214b..23c900e82081 100644 --- a/internal/service/cloudfront/vpc_origin.go +++ b/internal/service/cloudfront/vpc_origin.go @@ -13,7 +13,6 @@ import ( awstypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -421,116 +420,3 @@ type originSSLProtocolsModel struct { Items fwtypes.SetOfStringEnum[awstypes.SslProtocol] `tfsdk:"items"` Quantity types.Int64 `tfsdk:"quantity"` } - -var ( - _ fwflex.Expander = vpcOriginEndpointConfigModel{} - _ fwflex.Flattener = &vpcOriginEndpointConfigModel{} -) - -func (m vpcOriginEndpointConfigModel) Expand(ctx context.Context) (any, diag.Diagnostics) { - var diags diag.Diagnostics - - config := &awstypes.VpcOriginEndpointConfig{ - Arn: fwflex.StringFromFramework(ctx, m.ARN), - HTTPPort: aws.Int32(int32(m.HTTPPort.ValueInt64())), - HTTPSPort: aws.Int32(int32(m.HTTPSPort.ValueInt64())), - Name: fwflex.StringFromFramework(ctx, m.Name), - OriginProtocolPolicy: m.OriginProtocolPolicy.ValueEnum(), - } - - if !m.OriginSSLProtocols.IsNull() { - sslList, d := m.OriginSSLProtocols.ToSlice(ctx) - diags.Append(d...) - if diags.HasError() { - return nil, diags - } - if len(sslList) > 0 { - expanded, d := sslList[0].Expand(ctx) - diags.Append(d...) - if diags.HasError() { - return nil, diags - } - if sslProto, ok := expanded.(*awstypes.OriginSslProtocols); ok { - config.OriginSslProtocols = sslProto - } else { - diags.AddError("error expanding Origin SSL Protocols", fmt.Sprintf("expected OriginSslProtocols, got: %T", expanded)) - } - } - } - - return config, diags -} - -func (m *vpcOriginEndpointConfigModel) Flatten(ctx context.Context, v any) diag.Diagnostics { - var diags diag.Diagnostics - - if v == nil { - return diags - } - if t, ok := v.(awstypes.VpcOriginEndpointConfig); ok { - m.ARN = fwflex.StringToFramework(ctx, t.Arn) - m.HTTPPort = types.Int64Value(int64(aws.ToInt32(t.HTTPPort))) - m.HTTPSPort = types.Int64Value(int64(aws.ToInt32(t.HTTPSPort))) - m.Name = fwflex.StringToFramework(ctx, t.Name) - m.OriginProtocolPolicy = fwtypes.StringEnumValue(t.OriginProtocolPolicy) - - if t.OriginSslProtocols != nil { - var sslModel originSSLProtocolsModel - diags.Append(fwflex.Flatten(ctx, t.OriginSslProtocols, &sslModel)...) - if diags.HasError() { - return diags - } - sslList, d := fwtypes.NewListNestedObjectValueOfPtr(ctx, &sslModel) - diags.Append(d...) - if diags.HasError() { - return diags - } - m.OriginSSLProtocols = sslList - } - } else { - diags.AddError("error flattening VPC Origin Endpoint Config", fmt.Sprintf("expected VpcOriginEndpointConfig, got: %T", v)) - } - return diags -} - -var ( - _ fwflex.Expander = originSSLProtocolsModel{} - _ fwflex.Flattener = &originSSLProtocolsModel{} -) - -func (m originSSLProtocolsModel) Expand(ctx context.Context) (any, diag.Diagnostics) { - var diags diag.Diagnostics - - var protocols []awstypes.SslProtocol - diags.Append(fwflex.Expand(ctx, m.Items, &protocols)...) - if diags.HasError() { - return nil, diags - } - - result := awstypes.OriginSslProtocols{ - Items: protocols, - Quantity: aws.Int32(int32(m.Quantity.ValueInt64())), - } - - return &result, diags -} - -func (m *originSSLProtocolsModel) Flatten(ctx context.Context, v any) diag.Diagnostics { - var diags diag.Diagnostics - - if v == nil { - return diags - } - - if t, ok := v.(awstypes.OriginSslProtocols); ok { - diags.Append(fwflex.Flatten(ctx, t.Items, &m.Items)...) - if diags.HasError() { - return diags - } - - m.Quantity = types.Int64Value(int64(aws.ToInt32(t.Quantity))) - } else { - diags.AddError("error flattening Origin SSL Protocols", fmt.Sprintf("expected OriginSslProtocols, got: %T", v)) - } - return diags -} From c0a783f31214cdeea895b8c5f3ed9c65c08e3305 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 15:06:04 -0500 Subject: [PATCH 14/15] Remove comment. --- internal/framework/flex/autoflex_expand.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index ae42955e087c..4655746cd716 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -1583,8 +1583,6 @@ func isXMLWrapperStruct(t reflect.Type) bool { return false } - //quantityField.Anonymous - // Quantity should be *int32 if quantityField.Type.Elem().Kind() != reflect.Int32 { return false From 7fe3d6eb80828c1edc91777f2034d1116ba289d6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 6 Nov 2025 15:24:03 -0500 Subject: [PATCH 15/15] Fix golangci-lint 'S1008'. --- internal/framework/flex/autoflex_expand.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index 4655746cd716..22d543d5499e 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -1595,11 +1595,8 @@ func isXMLWrapperStruct(t reflect.Type) bool { nNonAnonymousFields++ } } - if nNonAnonymousFields != 2 { - return false - } - return true + return nNonAnonymousFields == 2 } // nestedObjectCollectionToXMLWrapper converts a NestedObjectCollectionValue to an XML wrapper struct