Skip to content

Commit d98c6f7

Browse files
Scaffolder: generate getSDK and getTranslation methods for every controller (#2877)
1 parent 3a29c59 commit d98c6f7

File tree

9 files changed

+1234
-20
lines changed

9 files changed

+1234
-20
lines changed

tools/scaffolder/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
./bin/

tools/scaffolder/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ generate-all: build
3434
$(BINARY_PATH) --input $(CRD_FILE) --all \
3535
--indexer-out $(INDEXER_OUT) \
3636
--controller-out $(CONTROLLER_OUT) \
37+
38+
.PHONY: generate-all-override
39+
generate-all-override:
40+
$(BINARY_PATH) --input $(CRD_FILE) --all --override \
41+
--indexer-out $(INDEXER_OUT) \
42+
--controller-out $(CONTROLLER_OUT) \

tools/scaffolder/cmd/main.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var (
1717
controllerOutDir string
1818
indexerOutDir string
1919
typesPath string
20+
override bool
2021
)
2122

2223
func main() {
@@ -47,10 +48,10 @@ func main() {
4748
}
4849

4950
if allCRDs {
50-
return generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath)
51+
return generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath, override)
5152
}
5253

53-
return generate.FromConfig(inputPath, crdKind, controllerOutDir, indexerOutDir, typesPath)
54+
return generate.FromConfig(inputPath, crdKind, controllerOutDir, indexerOutDir, typesPath, override)
5455
},
5556
}
5657

@@ -61,6 +62,7 @@ func main() {
6162
rootCmd.Flags().StringVar(&controllerOutDir, "controller-out", "", "Output directory for controller files (default: ../mongodb-atlas-kubernetes/internal/controller)")
6263
rootCmd.Flags().StringVar(&indexerOutDir, "indexer-out", "", "Output directory for indexer files (default: ../mongodb-atlas-kubernetes/internal/indexer)")
6364
rootCmd.Flags().StringVar(&typesPath, "types-path", "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/nextapi/generated/v1", "Full import path to the API types package")
65+
rootCmd.Flags().BoolVar(&override, "override", false, "Override existing versioned handler files (default: false)")
6466

6567
if err := rootCmd.Execute(); err != nil {
6668
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
@@ -92,7 +94,7 @@ func validateGoImportPath(path string) error {
9294
return nil
9395
}
9496

95-
func generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath string) error {
97+
func generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath string, override bool) error {
9698
crds, err := generate.ListCRDs(inputPath)
9799
if err != nil {
98100
return fmt.Errorf("failed to list CRDs: %w", err)
@@ -106,7 +108,7 @@ func generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath strin
106108
for _, crd := range crds {
107109
fmt.Printf("Generating for CRD: %s...\n", crd.Kind)
108110

109-
err := generate.FromConfig(inputPath, crd.Kind, controllerOutDir, indexerOutDir, typesPath)
111+
err := generate.FromConfig(inputPath, crd.Kind, controllerOutDir, indexerOutDir, typesPath, override)
110112

111113
result := CRDGenerationResult{
112114
CRDKind: crd.Kind,

tools/scaffolder/go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ require (
1212
k8s.io/apimachinery v0.34.1 // indirect
1313
)
1414

15-
require k8s.io/apiextensions-apiserver v0.34.1
15+
require (
16+
github.com/stretchr/testify v1.10.0
17+
k8s.io/apiextensions-apiserver v0.34.1
18+
)
1619

1720
require (
21+
github.com/davecgh/go-spew v1.1.1 // indirect
1822
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
1923
github.com/go-logr/logr v1.4.2 // indirect
2024
github.com/gogo/protobuf v1.3.2 // indirect
@@ -23,6 +27,7 @@ require (
2327
github.com/kr/pretty v0.3.1 // indirect
2428
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
2529
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
30+
github.com/pmezard/go-difflib v1.0.0 // indirect
2631
github.com/spf13/pflag v1.0.9 // indirect
2732
github.com/x448/float16 v0.8.4 // indirect
2833
go.yaml.in/yaml/v2 v2.4.2 // indirect

tools/scaffolder/internal/generate/config.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,13 @@ type MappingWithConfig struct {
3737
}
3838

3939
type ParsedConfig struct {
40-
SelectedCRD CRDInfo
41-
Mappings []MappingWithConfig
42-
ResourceName string
43-
APIVersion string // API version package (e.g., "v1", "v3")
40+
SelectedCRD CRDInfo
41+
Mappings []MappingWithConfig
42+
ResourceName string
43+
APIVersion string // API version package (e.g., "v1", "v3")
44+
StorageVersion string
45+
PluralName string
46+
CRDGroup string
4447
}
4548

4649
type CRDDocument struct {
@@ -71,6 +74,7 @@ type CRDInfo struct {
7174
Kind string
7275
Group string
7376
Version string
77+
Plural string
7478
ShortNames []string
7579
Categories []string
7680
Versions []CRDVersionInfo
@@ -159,6 +163,7 @@ func decodeCRDDocument(content []byte) (*CRDInfo, error) {
159163
crdInfo := &CRDInfo{
160164
Kind: crd.Spec.Names.Kind,
161165
Group: crd.Spec.Group,
166+
Plural: crd.Spec.Names.Plural,
162167
ShortNames: crd.Spec.Names.ShortNames,
163168
Categories: crd.Spec.Names.Categories,
164169
}
@@ -212,11 +217,20 @@ func ParseCRDConfig(resultPath, crdKind string) (*ParsedConfig, error) {
212217
// apiVersion = "v3"
213218
// }
214219

220+
// Extract storage version - default to "v1" if not found
221+
storageVersion := "v1"
222+
if crdInfo.Version != "" {
223+
storageVersion = crdInfo.Version
224+
}
225+
215226
return &ParsedConfig{
216-
SelectedCRD: *crdInfo,
217-
Mappings: mappings,
218-
ResourceName: crdInfo.Kind,
219-
APIVersion: apiVersion,
227+
SelectedCRD: *crdInfo,
228+
Mappings: mappings,
229+
ResourceName: crdInfo.Kind,
230+
APIVersion: apiVersion,
231+
StorageVersion: storageVersion,
232+
PluralName: crdInfo.Plural,
233+
CRDGroup: crdInfo.Group,
220234
}, nil
221235
}
222236

@@ -225,7 +239,11 @@ func ListCRDs(resultPath string) ([]CRDInfo, error) {
225239
if err != nil {
226240
return nil, fmt.Errorf("failed to open result file: %w", err)
227241
}
228-
defer file.Close()
242+
defer func() {
243+
if err := file.Close(); err != nil {
244+
fmt.Printf("failed to close result file: %v\n", err)
245+
}
246+
}()
229247

230248
var crds []CRDInfo
231249
scanner := bufio.NewScanner(file)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2025 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package generate
16+
17+
import (
18+
"os"
19+
"path/filepath"
20+
"testing"
21+
22+
"github.com/stretchr/testify/assert"
23+
"github.com/stretchr/testify/require"
24+
)
25+
26+
func TestParseCRDConfig(t *testing.T) {
27+
testYAML := `
28+
apiVersion: apiextensions.k8s.io/v1
29+
kind: CustomResourceDefinition
30+
metadata:
31+
name: clusters.atlas.generated.mongodb.com
32+
annotations:
33+
api-mappings: |
34+
properties:
35+
spec:
36+
properties:
37+
v20250312:
38+
x-atlas-sdk-version: go.mongodb.org/atlas-sdk/v20250312008/admin
39+
spec:
40+
group: atlas.generated.mongodb.com
41+
names:
42+
kind: Cluster
43+
plural: clusters
44+
versions:
45+
- name: v1
46+
`
47+
48+
tmpDir := t.TempDir()
49+
testFile := filepath.Join(tmpDir, "test.yaml")
50+
err := os.WriteFile(testFile, []byte(testYAML), 0644)
51+
require.NoError(t, err)
52+
53+
t.Run("ParseValidCRD", func(t *testing.T) {
54+
config, err := ParseCRDConfig(testFile, "Cluster")
55+
require.NoError(t, err)
56+
assert.Equal(t, "Cluster", config.ResourceName)
57+
assert.Len(t, config.Mappings, 1)
58+
assert.Equal(t, "v20250312", config.Mappings[0].Version)
59+
assert.Equal(t, "go.mongodb.org/atlas-sdk/v20250312008/admin", config.Mappings[0].OpenAPIConfig.Package)
60+
})
61+
62+
t.Run("ParseNonExistentCRD", func(t *testing.T) {
63+
_, err := ParseCRDConfig(testFile, "NonExistent")
64+
assert.Error(t, err)
65+
assert.Contains(t, err.Error(), "not found")
66+
})
67+
68+
t.Run("ParseInvalidFile", func(t *testing.T) {
69+
_, err := ParseCRDConfig("/nonexistent/file.yaml", "Cluster")
70+
assert.Error(t, err)
71+
})
72+
}
73+
74+
func TestListCRDs(t *testing.T) {
75+
testYAML := `
76+
apiVersion: apiextensions.k8s.io/v1
77+
kind: CustomResourceDefinition
78+
metadata:
79+
name: clusters.atlas.generated.mongodb.com
80+
spec:
81+
group: atlas.generated.mongodb.com
82+
names:
83+
kind: Cluster
84+
plural: clusters
85+
categories: [atlas]
86+
versions:
87+
- name: v1
88+
---
89+
apiVersion: apiextensions.k8s.io/v1
90+
kind: CustomResourceDefinition
91+
metadata:
92+
name: groups.atlas.generated.mongodb.com
93+
spec:
94+
group: atlas.generated.mongodb.com
95+
names:
96+
kind: Group
97+
plural: groups
98+
versions:
99+
- name: v1
100+
`
101+
102+
tmpDir := t.TempDir()
103+
testFile := filepath.Join(tmpDir, "test.yaml")
104+
err := os.WriteFile(testFile, []byte(testYAML), 0644)
105+
require.NoError(t, err)
106+
107+
crds, err := ListCRDs(testFile)
108+
require.NoError(t, err)
109+
assert.Len(t, crds, 2)
110+
111+
assert.Equal(t, "Cluster", crds[0].Kind)
112+
assert.Equal(t, "atlas.generated.mongodb.com", crds[0].Group)
113+
assert.Equal(t, "v1", crds[0].Version)
114+
assert.Contains(t, crds[0].Categories, "atlas")
115+
116+
assert.Equal(t, "Group", crds[1].Kind)
117+
}

0 commit comments

Comments
 (0)