Skip to content

Commit 06d1e50

Browse files
authored
BugFix: fixes duplicate import inside references.go (#301)
Description of changes: * Use a set of referenced service names for generating import statements inside `references.go.tpl` * Use sorted fieldnames inside iteration for generating consistent code for `references.go.tpl`. Earlier the generated code was similar but not identical to previous generation. This will reduce cognitive load when reviewing auto-generated PRs * Added cross service reference manifests for unit testing. * Manually generated apigatewayv2 controller to test as well. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent a0a7fbd commit 06d1e50

File tree

6 files changed

+90
-26
lines changed

6 files changed

+90
-26
lines changed

pkg/generate/code/resource_reference.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ func ReferenceFieldsValidation(
3535
indentLevel int,
3636
) string {
3737
out := ""
38-
for _, field := range crd.Fields {
38+
// Sorted fieldnames are used for consistent code-generation
39+
for _, fieldName := range crd.SortedFieldNames() {
40+
field := crd.Fields[fieldName]
3941
if field.HasReference() {
4042
indent := strings.Repeat("\t", indentLevel)
4143
// Validation to make sure both target field and reference are
@@ -75,7 +77,9 @@ func ReferenceFieldsPresent(
7577
sourceVarName string,
7678
) string {
7779
out := "false"
78-
for _, field := range crd.Fields {
80+
// Sorted fieldnames are used for consistent code-generation
81+
for _, fieldName := range crd.SortedFieldNames() {
82+
field := crd.Fields[fieldName]
7983
if field.IsReference() {
8084
out += fmt.Sprintf(" || %s.Spec.%s != nil", sourceVarName,
8185
field.Names.Camel)

pkg/generate/code/resource_reference_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ func Test_ReferenceFieldsValidation_SliceOfReferences(t *testing.T) {
7676
` if ko.Spec.SecurityGroupRefs != nil && ko.Spec.SecurityGroupIDs != nil {
7777
return ackerr.ResourceReferenceAndIDNotSupportedFor("SecurityGroupIDs", "SecurityGroupRefs")
7878
}
79+
if ko.Spec.SubnetRefs != nil && ko.Spec.SubnetIDs != nil {
80+
return ackerr.ResourceReferenceAndIDNotSupportedFor("SubnetIDs", "SubnetRefs")
81+
}
82+
if ko.Spec.SubnetRefs == nil && ko.Spec.SubnetIDs == nil {
83+
return ackerr.ResourceReferenceOrIDRequiredFor("SubnetIDs", "SubnetRefs")
84+
}
7985
`
8086
assert.Equal(expected, code.ReferenceFieldsValidation(crd, "ko", 1))
8187
}
@@ -123,6 +129,6 @@ func Test_ReferenceFieldsPresent_SliceOfReferences(t *testing.T) {
123129
// just to test code generation for slices of reference
124130
crd := testutil.GetCRDByName(t, g, "VpcLink")
125131
require.NotNil(crd)
126-
expected := "false || ko.Spec.SecurityGroupRefs != nil"
132+
expected := "false || ko.Spec.SecurityGroupRefs != nil || ko.Spec.SubnetRefs != nil"
127133
assert.Equal(expected, code.ReferenceFieldsPresent(crd, "ko"))
128134
}

pkg/model/crd.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,39 @@ func (r *CRD) HasReferenceFields() bool {
794794
return false
795795
}
796796

797+
// ReferencedServiceNames returns the set of service names for ACK controllers
798+
// whose resources are referenced inside the CRD. The service name is
799+
// the go package name for the AWS service inside aws-sdk-go.
800+
//
801+
// If a CRD has no reference fields, nil is returned(zero vale of slice)
802+
func (r *CRD) ReferencedServiceNames() (serviceNames []string) {
803+
// We are using Map to implement a Set of service names
804+
serviceNamesMap := make(map[string]struct{})
805+
existsValue := struct{}{}
806+
807+
for _, field := range r.Fields {
808+
if serviceName := field.ReferencedServiceName(); serviceName != "" {
809+
serviceNamesMap[serviceName] = existsValue
810+
}
811+
}
812+
813+
for serviceName, _ := range serviceNamesMap {
814+
serviceNames = append(serviceNames, serviceName)
815+
}
816+
return serviceNames
817+
}
818+
819+
// SortedFieldNames returns the fieldNames of the CRD in a sorted
820+
// order.
821+
func (r *CRD) SortedFieldNames() []string {
822+
fieldNames := make([]string, 0, len(r.Fields))
823+
for fieldName := range r.Fields {
824+
fieldNames = append(fieldNames, fieldName)
825+
}
826+
sort.Strings(fieldNames)
827+
return fieldNames
828+
}
829+
797830
// NewCRD returns a pointer to a new `ackmodel.CRD` struct that describes a
798831
// single top-level resource in an AWS service API
799832
func NewCRD(

pkg/model/model_apigwv2_test.go

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ func TestAPIGatewayV2_Api(t *testing.T) {
6565
// The required property should get overriden for Name and ProtocolType fields.
6666
assert.False(crd.SpecFields["Name"].IsRequired())
6767
assert.False(crd.SpecFields["ProtocolType"].IsRequired())
68+
69+
assert.Nil(crd.ReferencedServiceNames())
6870
}
6971

7072
func TestAPIGatewayV2_Route(t *testing.T) {
@@ -174,6 +176,8 @@ func TestAPIGatewayV2_Route(t *testing.T) {
174176
"RouteID",
175177
}
176178
assert.Equal(expStatusFieldCamel, attrCamelNames(statusFields))
179+
180+
assert.Nil(crd.ReferencedServiceNames())
177181
}
178182

179183
func TestAPIGatewayV2_WithReference(t *testing.T) {
@@ -188,26 +192,37 @@ func TestAPIGatewayV2_WithReference(t *testing.T) {
188192
require.Nil(err)
189193

190194
// Single reference
191-
crd := getCRDByName("Integration", crds)
192-
require.NotNil(crd)
195+
integrationCrd := getCRDByName("Integration", crds)
196+
require.NotNil(integrationCrd)
193197

194-
assert.Equal("Integration", crd.Names.Camel)
195-
assert.Equal("integration", crd.Names.CamelLower)
196-
assert.Equal("integration", crd.Names.Snake)
198+
assert.Equal("Integration", integrationCrd.Names.Camel)
199+
assert.Equal("integration", integrationCrd.Names.CamelLower)
200+
assert.Equal("integration", integrationCrd.Names.Snake)
197201

198-
assert.NotNil(crd.SpecFields["ApiId"])
199-
assert.NotNil(crd.SpecFields["ApiRef"])
200-
assert.Equal("*ackv1alpha1.AWSResourceReferenceWrapper", crd.SpecFields["ApiRef"].GoType)
202+
assert.NotNil(integrationCrd.SpecFields["ApiId"])
203+
assert.NotNil(integrationCrd.SpecFields["ApiRef"])
204+
assert.Equal("*ackv1alpha1.AWSResourceReferenceWrapper", integrationCrd.SpecFields["ApiRef"].GoType)
201205

202-
// List of References
203-
crd = getCRDByName("VpcLink", crds)
204-
require.NotNil(crd)
205-
206-
assert.Equal("VPCLink", crd.Names.Camel)
207-
assert.Equal("vpcLink", crd.Names.CamelLower)
208-
assert.Equal("vpc_link", crd.Names.Snake)
206+
referencedServiceNames := integrationCrd.ReferencedServiceNames()
207+
assert.NotNil(referencedServiceNames)
208+
assert.Contains(referencedServiceNames, "apigatewayv2")
209+
assert.Equal(1, len(referencedServiceNames))
209210

210-
assert.NotNil(crd.SpecFields["SecurityGroupIds"])
211-
assert.NotNil(crd.SpecFields["SecurityGroupRefs"])
212-
assert.Equal("[]*ackv1alpha1.AWSResourceReferenceWrapper", crd.SpecFields["SecurityGroupRefs"].GoType)
211+
// List of References
212+
vpcLinkCrd := getCRDByName("VpcLink", crds)
213+
require.NotNil(vpcLinkCrd)
214+
215+
assert.Equal("VPCLink", vpcLinkCrd.Names.Camel)
216+
assert.Equal("vpcLink", vpcLinkCrd.Names.CamelLower)
217+
assert.Equal("vpc_link", vpcLinkCrd.Names.Snake)
218+
219+
assert.NotNil(vpcLinkCrd.SpecFields["SecurityGroupIds"])
220+
assert.NotNil(vpcLinkCrd.SpecFields["SecurityGroupRefs"])
221+
assert.Equal("[]*ackv1alpha1.AWSResourceReferenceWrapper", vpcLinkCrd.SpecFields["SecurityGroupRefs"].GoType)
222+
223+
referencedServiceNames = vpcLinkCrd.ReferencedServiceNames()
224+
assert.NotNil(referencedServiceNames)
225+
assert.Contains(referencedServiceNames, "ec2")
226+
assert.Contains(referencedServiceNames, "ec2-modified")
227+
assert.Equal(2, len(referencedServiceNames))
213228
}

pkg/testdata/models/apis/apigatewayv2/0000-00-00/generator-with-reference.yaml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ resources:
99
fields:
1010
SecurityGroupIds:
1111
references:
12-
resource: API
13-
path: Status.APIID
12+
resource: SecurityGroup
13+
path: Status.ID
14+
service_name: ec2
15+
SubnetIds:
16+
references:
17+
resource: Subnet
18+
path: Status.SubnetID
19+
service_name: ec2-modified #This is a dummy service name to validate multiple service references
1420
ignore:
1521
resource_names:
1622
- ApiMapping

templates/pkg/resource/references.go.tpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import (
2121
{{ $servicePackageName := .ServicePackageName -}}
2222
{{ $apiVersion := .APIVersion -}}
2323
{{ if .CRD.HasReferenceFields -}}
24-
{{ range $fieldName, $field := .CRD.Fields -}}
25-
{{ if and $field.HasReference (not (eq $field.ReferencedServiceName $servicePackageName)) -}}
26-
{{ $field.ReferencedServiceName }}apitypes "github.com/aws-controllers-k8s/{{ $field.ReferencedServiceName }}-controller/apis/{{ $apiVersion }}"
24+
{{ range $referencedServiceName := .CRD.ReferencedServiceNames -}}
25+
{{ if not (eq $referencedServiceName $servicePackageName) -}}
26+
{{ $referencedServiceName }}apitypes "github.com/aws-controllers-k8s/{{ $referencedServiceName }}-controller/apis/{{ $apiVersion }}"
2727
{{- end }}
2828
{{- end }}
2929
{{- end }}

0 commit comments

Comments
 (0)