Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tools/scaffolder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./bin/
6 changes: 6 additions & 0 deletions tools/scaffolder/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ generate-all: build
$(BINARY_PATH) --input $(CRD_FILE) --all \
--indexer-out $(INDEXER_OUT) \
--controller-out $(CONTROLLER_OUT) \

.PHONY: generate-all-override
generate-all-override:
$(BINARY_PATH) --input $(CRD_FILE) --all --override \
--indexer-out $(INDEXER_OUT) \
--controller-out $(CONTROLLER_OUT) \
10 changes: 6 additions & 4 deletions tools/scaffolder/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var (
controllerOutDir string
indexerOutDir string
typesPath string
override bool
)

func main() {
Expand Down Expand Up @@ -47,10 +48,10 @@ func main() {
}

if allCRDs {
return generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath)
return generateAllCRDs(inputPath, controllerOutDir, indexerOutDir, typesPath, override)
}

return generate.FromConfig(inputPath, crdKind, controllerOutDir, indexerOutDir, typesPath)
return generate.FromConfig(inputPath, crdKind, controllerOutDir, indexerOutDir, typesPath, override)
},
}

Expand All @@ -61,6 +62,7 @@ func main() {
rootCmd.Flags().StringVar(&controllerOutDir, "controller-out", "", "Output directory for controller files (default: ../mongodb-atlas-kubernetes/internal/controller)")
rootCmd.Flags().StringVar(&indexerOutDir, "indexer-out", "", "Output directory for indexer files (default: ../mongodb-atlas-kubernetes/internal/indexer)")
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")
rootCmd.Flags().BoolVar(&override, "override", false, "Override existing versioned handler files (default: false)")

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

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

err := generate.FromConfig(inputPath, crd.Kind, controllerOutDir, indexerOutDir, typesPath)
err := generate.FromConfig(inputPath, crd.Kind, controllerOutDir, indexerOutDir, typesPath, override)

result := CRDGenerationResult{
CRDKind: crd.Kind,
Expand Down
7 changes: 6 additions & 1 deletion tools/scaffolder/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ require (
k8s.io/apimachinery v0.34.1 // indirect
)

require k8s.io/apiextensions-apiserver v0.34.1
require (
github.com/stretchr/testify v1.10.0
k8s.io/apiextensions-apiserver v0.34.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
Expand All @@ -23,6 +27,7 @@ require (
github.com/kr/pretty v0.3.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
Expand Down
36 changes: 27 additions & 9 deletions tools/scaffolder/internal/generate/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ type MappingWithConfig struct {
}

type ParsedConfig struct {
SelectedCRD CRDInfo
Mappings []MappingWithConfig
ResourceName string
APIVersion string // API version package (e.g., "v1", "v3")
SelectedCRD CRDInfo
Mappings []MappingWithConfig
ResourceName string
APIVersion string // API version package (e.g., "v1", "v3")
StorageVersion string
PluralName string
CRDGroup string
}

type CRDDocument struct {
Expand Down Expand Up @@ -71,6 +74,7 @@ type CRDInfo struct {
Kind string
Group string
Version string
Plural string
ShortNames []string
Categories []string
Versions []CRDVersionInfo
Expand Down Expand Up @@ -159,6 +163,7 @@ func decodeCRDDocument(content []byte) (*CRDInfo, error) {
crdInfo := &CRDInfo{
Kind: crd.Spec.Names.Kind,
Group: crd.Spec.Group,
Plural: crd.Spec.Names.Plural,
ShortNames: crd.Spec.Names.ShortNames,
Categories: crd.Spec.Names.Categories,
}
Expand Down Expand Up @@ -212,11 +217,20 @@ func ParseCRDConfig(resultPath, crdKind string) (*ParsedConfig, error) {
// apiVersion = "v3"
// }

// Extract storage version - default to "v1" if not found
storageVersion := "v1"
if crdInfo.Version != "" {
storageVersion = crdInfo.Version
}

return &ParsedConfig{
SelectedCRD: *crdInfo,
Mappings: mappings,
ResourceName: crdInfo.Kind,
APIVersion: apiVersion,
SelectedCRD: *crdInfo,
Mappings: mappings,
ResourceName: crdInfo.Kind,
APIVersion: apiVersion,
StorageVersion: storageVersion,
PluralName: crdInfo.Plural,
CRDGroup: crdInfo.Group,
}, nil
}

Expand All @@ -225,7 +239,11 @@ func ListCRDs(resultPath string) ([]CRDInfo, error) {
if err != nil {
return nil, fmt.Errorf("failed to open result file: %w", err)
}
defer file.Close()
defer func() {
if err := file.Close(); err != nil {
fmt.Printf("failed to close result file: %v\n", err)
}
}()

var crds []CRDInfo
scanner := bufio.NewScanner(file)
Expand Down
117 changes: 117 additions & 0 deletions tools/scaffolder/internal/generate/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2025 MongoDB Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package generate

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestParseCRDConfig(t *testing.T) {
testYAML := `
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: clusters.atlas.generated.mongodb.com
annotations:
api-mappings: |
properties:
spec:
properties:
v20250312:
x-atlas-sdk-version: go.mongodb.org/atlas-sdk/v20250312008/admin
spec:
group: atlas.generated.mongodb.com
names:
kind: Cluster
plural: clusters
versions:
- name: v1
`

tmpDir := t.TempDir()
testFile := filepath.Join(tmpDir, "test.yaml")
err := os.WriteFile(testFile, []byte(testYAML), 0644)
require.NoError(t, err)

t.Run("ParseValidCRD", func(t *testing.T) {
config, err := ParseCRDConfig(testFile, "Cluster")
require.NoError(t, err)
assert.Equal(t, "Cluster", config.ResourceName)
assert.Len(t, config.Mappings, 1)
assert.Equal(t, "v20250312", config.Mappings[0].Version)
assert.Equal(t, "go.mongodb.org/atlas-sdk/v20250312008/admin", config.Mappings[0].OpenAPIConfig.Package)
})

t.Run("ParseNonExistentCRD", func(t *testing.T) {
_, err := ParseCRDConfig(testFile, "NonExistent")
assert.Error(t, err)
assert.Contains(t, err.Error(), "not found")
})

t.Run("ParseInvalidFile", func(t *testing.T) {
_, err := ParseCRDConfig("/nonexistent/file.yaml", "Cluster")
assert.Error(t, err)
})
}

func TestListCRDs(t *testing.T) {
testYAML := `
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: clusters.atlas.generated.mongodb.com
spec:
group: atlas.generated.mongodb.com
names:
kind: Cluster
plural: clusters
categories: [atlas]
versions:
- name: v1
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: groups.atlas.generated.mongodb.com
spec:
group: atlas.generated.mongodb.com
names:
kind: Group
plural: groups
versions:
- name: v1
`

tmpDir := t.TempDir()
testFile := filepath.Join(tmpDir, "test.yaml")
err := os.WriteFile(testFile, []byte(testYAML), 0644)
require.NoError(t, err)

crds, err := ListCRDs(testFile)
require.NoError(t, err)
assert.Len(t, crds, 2)

assert.Equal(t, "Cluster", crds[0].Kind)
assert.Equal(t, "atlas.generated.mongodb.com", crds[0].Group)
assert.Equal(t, "v1", crds[0].Version)
assert.Contains(t, crds[0].Categories, "atlas")

assert.Equal(t, "Group", crds[1].Kind)
}
Loading