Skip to content

Commit 8d105ed

Browse files
authored
Cleaned up and fixed Lineage methods (#15949)
1 parent 4652855 commit 8d105ed

9 files changed

+127
-164
lines changed

mmv1/api/metadata/field.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package metadata
22

33
import (
4+
"strings"
5+
46
"github.com/GoogleCloudPlatform/magic-modules/mmv1/api"
7+
"github.com/GoogleCloudPlatform/magic-modules/mmv1/google"
58
)
69

710
func FromProperties(props []*api.Type) []Field {
@@ -11,11 +14,13 @@ func FromProperties(props []*api.Type) []Field {
1114
Json: p.IsJsonField(),
1215
ProviderOnly: p.ProviderOnly(),
1316
}
17+
lineage := p.Lineage()
18+
apiLineage := p.ApiLineage()
1419
if !p.ProviderOnly() {
15-
f.ApiField = p.MetadataApiLineage()
20+
f.ApiField = strings.Join(apiLineage, ".")
1621
}
17-
if p.ProviderOnly() || p.MetadataLineage() != p.MetadataDefaultLineage() {
18-
f.Field = p.MetadataLineage()
22+
if p.ProviderOnly() || !IsDefaultLineage(lineage, apiLineage) {
23+
f.Field = strings.Join(lineage, ".")
1924
}
2025
fields = append(fields, f)
2126
}
@@ -36,3 +41,18 @@ type Field struct {
3641
// have `api_field` set to `*`.
3742
Json bool `yaml:"json,omitempty"`
3843
}
44+
45+
// Returns true if the lineage is the default we'd expect for a field, and false otherwise.
46+
// If any ancestor has a non-default lineage, this will return false.
47+
func IsDefaultLineage(lineage, apiLineage []string) bool {
48+
if len(lineage) != len(apiLineage) {
49+
return false
50+
}
51+
for i, part := range lineage {
52+
apiPart := apiLineage[i]
53+
if part != google.Underscore(apiPart) {
54+
return false
55+
}
56+
}
57+
return true
58+
}

mmv1/api/metadata/field_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,70 @@ func TestFromProperties(t *testing.T) {
8181
})
8282
}
8383
}
84+
85+
func TestIsDefaultLineage(t *testing.T) {
86+
t.Parallel()
87+
88+
cases := []struct {
89+
name string
90+
lineage []string
91+
apiLineage []string
92+
want bool
93+
}{
94+
{
95+
name: "empty",
96+
lineage: []string{},
97+
apiLineage: []string{},
98+
want: true,
99+
},
100+
{
101+
name: "single field",
102+
lineage: []string{"foo_bar"},
103+
apiLineage: []string{"fooBar"},
104+
want: true,
105+
},
106+
{
107+
name: "multiple fields",
108+
lineage: []string{"foo_bar", "baz_moo"},
109+
apiLineage: []string{"fooBar", "bazMoo"},
110+
want: true,
111+
},
112+
{
113+
name: "longer lineage",
114+
lineage: []string{"foo_bar", "baz_moo"},
115+
apiLineage: []string{"fooBar"},
116+
want: false,
117+
},
118+
{
119+
name: "longer apiLineage",
120+
lineage: []string{"foo_bar"},
121+
apiLineage: []string{"fooBar", "bazMoo"},
122+
want: false,
123+
},
124+
{
125+
name: "parent override",
126+
lineage: []string{"foo_bar", "baz_moo"},
127+
apiLineage: []string{"otherName", "bazMoo"},
128+
want: false,
129+
},
130+
{
131+
name: "child override",
132+
lineage: []string{"foo_bar", "baz_moo"},
133+
apiLineage: []string{"fooBar", "otherName"},
134+
want: false,
135+
},
136+
}
137+
138+
for _, tc := range cases {
139+
tc := tc
140+
141+
t.Run(tc.name, func(t *testing.T) {
142+
t.Parallel()
143+
144+
got := IsDefaultLineage(tc.lineage, tc.apiLineage)
145+
if got != tc.want {
146+
t.Errorf("IsDefaultLineage(%s) failed; want %t, got %t", tc.name, tc.want, got)
147+
}
148+
})
149+
}
150+
}

mmv1/api/resource.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ func (r Resource) SensitivePropsToString() string {
678678
var props []string
679679

680680
for _, prop := range r.SensitiveProps() {
681-
props = append(props, fmt.Sprintf("`%s`", prop.Lineage()))
681+
props = append(props, fmt.Sprintf("`%s`", strings.Join(prop.Lineage(), ".")))
682682
}
683683

684684
return strings.Join(props, ", ")
@@ -688,7 +688,7 @@ func (r Resource) WriteOnlyPropsToString() string {
688688
var props []string
689689

690690
for _, prop := range r.WriteOnlyProps() {
691-
props = append(props, fmt.Sprintf("`%s`", prop.Lineage()))
691+
props = append(props, fmt.Sprintf("`%s`", strings.Join(prop.Lineage(), ".")))
692692
}
693693

694694
return strings.Join(props, ", ")
@@ -765,7 +765,7 @@ func (r Resource) LeafProperties() []*Type {
765765

766766
// Sort types by lineage
767767
slices.SortFunc(types, func(a, b *Type) int {
768-
if a.MetadataLineage() < b.MetadataLineage() {
768+
if strings.Join(a.Lineage(), ".") < strings.Join(b.Lineage(), ".") {
769769
return -1
770770
}
771771
return 1
@@ -855,7 +855,7 @@ func (r *Resource) attachConstraintGroup(groupType string, source []string) *[]s
855855
}
856856

857857
func buildWriteOnlyField(name string, versionFieldName string, originalField *Type) *Type {
858-
originalFieldLineage := originalField.TerraformLineage()
858+
originalFieldLineage := strings.Join(originalField.Lineage(), ".0.")
859859
newFieldLineage := strings.ReplaceAll(originalFieldLineage, google.Underscore(originalField.Name), google.Underscore(name))
860860
requiredWith := strings.ReplaceAll(originalFieldLineage, google.Underscore(originalField.Name), google.Underscore(versionFieldName))
861861

@@ -907,7 +907,7 @@ func buildWriteOnlyField(name string, versionFieldName string, originalField *Ty
907907

908908
func buildWriteOnlyVersionField(name string, originalField *Type, writeOnlyField *Type) *Type {
909909
description := fmt.Sprintf("Triggers update of `%s` write-only. Increment this value when an update to `%s` is needed. For more info see [updating write-only arguments](/docs/providers/google/guides/using_write_only_arguments.html#updating-write-only-arguments)", google.Underscore(writeOnlyField.Name), google.Underscore(writeOnlyField.Name))
910-
requiredWith := strings.ReplaceAll(originalField.TerraformLineage(), google.Underscore(originalField.Name), google.Underscore(writeOnlyField.Name))
910+
requiredWith := strings.ReplaceAll(strings.Join(originalField.Lineage(), ".0."), google.Underscore(originalField.Name), google.Underscore(writeOnlyField.Name))
911911

912912
options := []func(*Type){
913913
propertyWithType("Int"),
@@ -1069,7 +1069,7 @@ func (r Resource) IgnoreReadLabelsFields(props []*Type) []string {
10691069
if p.IsA("KeyValueLabels") ||
10701070
p.IsA("KeyValueTerraformLabels") ||
10711071
p.IsA("KeyValueAnnotations") {
1072-
fields = append(fields, p.TerraformLineage())
1072+
fields = append(fields, strings.Join(p.Lineage(), ".0."))
10731073
} else if p.IsA("NestedObject") && len(p.AllProperties()) > 0 {
10741074
fields = google.Concat(fields, r.IgnoreReadLabelsFields(p.AllProperties()))
10751075
}
@@ -1466,7 +1466,7 @@ func ignoreReadFields(props []*Type) []string {
14661466
var fields []string
14671467
for _, tp := range props {
14681468
if tp.IgnoreRead && !tp.UrlParamOnly && !tp.IsA("ResourceRef") {
1469-
fields = append(fields, tp.TerraformLineage())
1469+
fields = append(fields, strings.Join(tp.Lineage(), ".0."))
14701470
} else if tp.IsA("NestedObject") && tp.AllProperties() != nil {
14711471
fields = append(fields, ignoreReadFields(tp.AllProperties())...)
14721472
}
@@ -2546,13 +2546,13 @@ func (r Resource) TGCTestIgnorePropertiesToStrings() []string {
25462546
"timeouts",
25472547
}
25482548
for _, tp := range r.VirtualFields {
2549-
props = append(props, tp.MetadataLineage())
2549+
props = append(props, strings.Join(tp.Lineage(), "."))
25502550
}
25512551
for _, tp := range r.AllNestedProperties(r.RootProperties()) {
25522552
if tp.UrlParamOnly {
25532553
props = append(props, google.Underscore(tp.Name))
25542554
} else if tp.IsMissingInCai || tp.IgnoreRead || tp.ClientSide || tp.WriteOnlyLegacy {
2555-
props = append(props, tp.MetadataLineage())
2555+
props = append(props, strings.Join(tp.Lineage(), "."))
25562556
}
25572557
}
25582558

mmv1/api/type.go

Lines changed: 18 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -524,82 +524,38 @@ func (t *Type) Validate(rName string) {
524524
// check the allowed types for Type field
525525
// check the allowed fields for each type, for example, KeyName is only allowed for Map
526526

527-
// Prints a dot notation path to where the field is nested within the parent
528-
// object. eg: parent.meta.label.foo
529-
// The only intended purpose is to allow better error messages. Some objects
530-
// and at some points in the build this doesn't output a valid output.
531-
func (t Type) Lineage() string {
532-
if t.ParentMetadata == nil {
533-
return google.Underscore(t.Name)
534-
}
535-
536-
return fmt.Sprintf("%s.%s", t.ParentMetadata.Lineage(), google.Underscore(t.Name))
537-
}
538-
539-
// Returns the actual Terraform lineage for the field, formatted for resource metadata.
540-
// This will return a simple dot notation path, like: foo_field.bar_field
541-
func (t Type) MetadataLineage() string {
527+
// Returns a slice of Terraform field names representing where the field is nested within the parent resource.
528+
// For example, []string{"parent_field", "meta", "label", "foo_bar"}.
529+
func (t Type) Lineage() []string {
542530
if t.ParentMetadata == nil || t.ParentMetadata.FlattenObject {
543-
return google.Underscore(t.Name)
531+
return []string{google.Underscore(t.Name)}
544532
}
545533

546-
// Skip arrays because otherwise the array name will be included twice
534+
// Skip arrays because otherwise the array will be included twice
547535
if t.ParentMetadata.IsA("Array") {
548-
return t.ParentMetadata.MetadataLineage()
536+
return t.ParentMetadata.Lineage()
549537
}
550538

551-
return fmt.Sprintf("%s.%s", t.ParentMetadata.MetadataLineage(), google.Underscore(t.Name))
539+
return append(t.ParentMetadata.Lineage(), google.Underscore(t.Name))
552540
}
553541

554-
// Returns the default Terraform lineage for the field, based on converting MetadataApiLineage
555-
// to snake_case. This is used to determine whether an explicit Terraform field name is required.
556-
// This will return a simple dot notation path like: foo_field.bar_field
557-
func (t Type) MetadataDefaultLineage() string {
558-
apiLineage := t.MetadataApiLineage()
559-
parts := strings.Split(apiLineage, ".")
560-
var snakeParts []string
561-
for _, p := range parts {
562-
snakeParts = append(snakeParts, google.Underscore(p))
563-
}
564-
return strings.Join(snakeParts, ".")
565-
}
566-
567-
// Returns the actual API lineage for the field (that is, using API names), formatted for
568-
// resource metadata. This will return a simple dot notation path, like: fooField.barField
569-
// This format is intended for to represent an API type.
570-
func (t Type) MetadataApiLineage() string {
571-
apiName := t.ApiName
542+
// Returns a slice of API field names representing where the field is nested within the parent resource.
543+
// For example, []string{"parentField", "meta", "label", "fooBar"}. For fine-grained resources, this will
544+
// include the field on the API resource that the fine-grained resource manages.
545+
func (t Type) ApiLineage() []string {
572546
if t.ParentMetadata == nil {
573547
if !t.UrlParamOnly && t.ResourceMetadata.ApiResourceField != "" {
574-
apiName = fmt.Sprintf("%s.%s", t.ResourceMetadata.ApiResourceField, apiName)
548+
return []string{t.ResourceMetadata.ApiResourceField, t.ApiName}
575549
}
576-
return apiName
550+
return []string{t.ApiName}
577551
}
578552

553+
// Skip arrays because otherwise the array will be included twice
579554
if t.ParentMetadata.IsA("Array") {
580-
return t.ParentMetadata.MetadataApiLineage()
581-
}
582-
583-
return fmt.Sprintf("%s.%s", t.ParentMetadata.MetadataApiLineage(), apiName)
584-
}
585-
586-
// Returns the lineage in snake case
587-
func (t Type) LineageAsSnakeCase() string {
588-
if t.ParentMetadata == nil {
589-
return google.Underscore(t.Name)
590-
}
591-
592-
return fmt.Sprintf("%s_%s", t.ParentMetadata.LineageAsSnakeCase(), google.Underscore(t.Name))
593-
}
594-
595-
// Prints the access path of the field in the configration eg: metadata.0.labels
596-
// The only intended purpose is to get the value of the labes field by calling d.Get().
597-
func (t Type) TerraformLineage() string {
598-
if t.ParentMetadata == nil || t.ParentMetadata.FlattenObject {
599-
return google.Underscore(t.Name)
555+
return t.ParentMetadata.ApiLineage()
600556
}
601557

602-
return fmt.Sprintf("%s.0.%s", t.ParentMetadata.TerraformLineage(), google.Underscore(t.Name))
558+
return append(t.ParentMetadata.ApiLineage(), t.ApiName)
603559
}
604560

605561
func (t Type) EnumValuesToString(quoteSeperator string, addEmpty bool) string {
@@ -1114,7 +1070,7 @@ func (t Type) AllProperties() []*Type {
11141070
func (t Type) UserProperties() []*Type {
11151071
if t.IsA("NestedObject") {
11161072
if t.Properties == nil {
1117-
log.Fatalf("Field '{%s}' properties are nil!", t.Lineage())
1073+
log.Fatalf("Field '{%s}' properties are nil!", strings.Join(t.Lineage(), "."))
11181074
}
11191075

11201076
return google.Reject(t.Properties, func(p *Type) bool {
@@ -1268,7 +1224,7 @@ func propertyWithAtLeastOneOfPointer(ptr *[]string) func(*Type) {
12681224
func (t *Type) validateLabelsField() {
12691225
productName := t.ResourceMetadata.ProductMetadata.Name
12701226
resourceName := t.ResourceMetadata.Name
1271-
lineage := t.Lineage()
1227+
lineage := strings.Join(t.Lineage(), ".")
12721228
if lineage == "labels" || lineage == "metadata.labels" || lineage == "configuration.labels" {
12731229
if !t.IsA("KeyValueLabels") &&
12741230
// The label value must be empty string, so skip this resource

0 commit comments

Comments
 (0)