diff --git a/CHANGELOG.md b/CHANGELOG.md index e9981a9..32607d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 1.6.0 (2025-10-17) + +- Configurable package namespaces/prefixes. (https://github.com/pulumi/crd2pulumi/pull/247) + ## 1.5.4 (2024-11-13) - NodeJS now uses correct input/output types for object metadata. (https://github.com/pulumi/crd2pulumi/issues/158) diff --git a/README.md b/README.md index 47780d9..6b0f0b6 100644 --- a/README.md +++ b/README.md @@ -59,23 +59,28 @@ Available Commands: version Print the version number of crd2pulumi Flags: - -d, --dotnet generate .NET - --dotnetName string name of .NET package (default "crds") - --dotnetPath string optional .NET output dir - -f, --force overwrite existing files - -g, --go generate Go - --goName string name of Go package (default "crds") - --goPath string optional Go output dir - -h, --help help for crd2pulumi - -j, --java generate Java - --javaName string name of Java package (default "crds") - --javaPath string optional Java output dir - -n, --nodejs generate NodeJS - --nodejsName string name of NodeJS package (default "crds") - --nodejsPath string optional NodeJS output dir - -p, --python generate Python - --pythonName string name of Python package (default "crds") - --pythonPath string optional Python output dir + -d, --dotnet generate .NET + --dotnetName string name of generated .NET package (default "crds") + --dotnetNamespace string namespace of generated .NET package + --dotnetPath string optional .NET output dir + -f, --force overwrite existing files + -g, --go generate Go + --goName string name of generated Go package (default "crds") + --goPath string optional Go output dir + -h, --help help for crd2pulumi + -j, --java generate Java + --javaBasePackage string base package of generated Java package + --javaName string name of generated Java package (default "crds") + --javaPath string optional Java output dir + -n, --nodejs generate NodeJS + --nodejsName string name of generated NodeJS package (default "crds") + --nodejsNamespace string namespace of generated NodeJS package + --nodejsPath string optional NodeJS output dir + -p, --python generate Python + --pythonName string name of generated Python package (default "crds") + --pythonPackagePrefix string prefix of generated Python package + --pythonPath string optional Python output dir + Use "crd2pulumi [command] --help" for more information about a command. ``` diff --git a/cmd/root.go b/cmd/root.go index 40ba213..25ccdc3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -123,6 +123,11 @@ func New() *cobra.Command { f.StringVarP(&pythonSettings.PackageName, "pythonName", "", codegen.DefaultName, "name of generated Python package") f.StringVarP(&javaSettings.PackageName, "javaName", "", codegen.DefaultName, "name of generated Java package") + f.StringVarP(&dotNetSettings.PackageNamespace, "dotnetNamespace", "", "", "namespace of generated .NET package") + f.StringVarP(&nodejsSettings.PackageNamespace, "nodejsNamespace", "", "", "namespace of generated NodeJS package") + f.StringVarP(&pythonSettings.PackageNamespace, "pythonPackagePrefix", "", "", "prefix of generated Python package") + f.StringVarP(&javaSettings.PackageNamespace, "javaBasePackage", "", "", "base package of generated Java package") + f.StringVarP(&dotNetSettings.OutputDir, "dotnetPath", "", "", "optional .NET output dir") f.StringVarP(&goSettings.OutputDir, "goPath", "", "", "optional Go output dir") f.StringVarP(&nodejsSettings.OutputDir, "nodejsPath", "", "", "optional NodeJS output dir") diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..d84d45e --- /dev/null +++ b/mise.toml @@ -0,0 +1,9 @@ +[tools] + +# Runtimes +go = "1.24.3" +node = '20.19.5' +python = '3.11.8' +dotnet = '8.0.414' +# Corretto version used as Java SE/OpenJDK version no longer offered +java = 'corretto-11' \ No newline at end of file diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index c672f36..2e8a0c5 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -12,7 +12,7 @@ import ( // GenerateFunc is the function that is called by the generator to generate the code. // It returns a mapping of filename to the contents of said file and any error that may have occurred. -type GenerateFunc func(pg *PackageGenerator, name string) (mapFileNameToData map[string]*bytes.Buffer, err error) +type GenerateFunc func(pg *PackageGenerator, cs *CodegenSettings) (mapFileNameToData map[string]*bytes.Buffer, err error) var codeGenFuncs = map[string]GenerateFunc{ Go: GenerateGo, @@ -59,7 +59,7 @@ func Generate(cs *CodegenSettings, yamls []io.ReadCloser) error { } // Do actual codegen - output, err := generate(pg, cs.PackageName) + output, err := generate(pg, cs) if err != nil { return fmt.Errorf("failed to generate %q package %q: %w", cs.Language, cs.PackageName, err) } diff --git a/pkg/codegen/dotnet.go b/pkg/codegen/dotnet.go index 5d03783..3263521 100644 --- a/pkg/codegen/dotnet.go +++ b/pkg/codegen/dotnet.go @@ -32,7 +32,7 @@ var unneededDotNetFiles = []string{ "Provider.cs", } -func GenerateDotNet(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, error) { +func GenerateDotNet(pg *PackageGenerator, cs *CodegenSettings) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() // Set up C# namespaces @@ -56,7 +56,8 @@ func GenerateDotNet(pg *PackageGenerator, name string) (map[string]*bytes.Buffer // `Pulumi.Kubernetes.Types.Outputs.Meta.V1.ObjectMeta`. This path would // only get generated properly if `compatibility` was `kubernetes20`. oldName := pkg.Name - pkg.Name = name + pkg.Name = cs.PackageName + pkg.Namespace = cs.PackageNamespace var err error files, err := dotnet.GeneratePackage(PulumiToolName, pkg, nil, nil) @@ -67,9 +68,13 @@ func GenerateDotNet(pg *PackageGenerator, name string) (map[string]*bytes.Buffer pkg.Name = oldName delete(pkg.Language, "csharp") - namespaceName := dotnet.Title(name) - files["KubernetesResource.cs"] = []byte(kubernetesResource(namespaceName)) - files["Utilities.cs"] = []byte(dotNetUtilities(namespaceName)) + packageName := dotnet.Title(cs.PackageName) + namespace := cs.PackageNamespace + if namespace == "" { + namespace = "Pulumi" + } + files["KubernetesResource.cs"] = []byte(kubernetesResource(namespace, packageName)) + files["Utilities.cs"] = []byte(dotNetUtilities(namespace, packageName)) // Delete unneeded files for _, unneededFile := range unneededDotNetFiles { @@ -84,9 +89,9 @@ func GenerateDotNet(pg *PackageGenerator, name string) (map[string]*bytes.Buffer return buffers, nil } -func kubernetesResource(name string) string { +func kubernetesResource(namespace string, name string) string { return `// Copyright 2016-2022, Pulumi Corporation -namespace Pulumi.` + name + `{ +namespace ` + namespace + `.` + name + `{ /// /// A base class for all Kubernetes resources. /// @@ -116,7 +121,7 @@ namespace Pulumi.` + name + `{ // tried running `pulumi up` with the normal `Utilities.cs` file. // As a temporary fix, this modified `Utilities.cs` file just removes the // `static Utilities()` method. -func dotNetUtilities(name string) string { +func dotNetUtilities(namespace string, name string) string { return `// *** WARNING: this file was generated by crd2pulumi. *** // *** Do not edit by hand unless you're certain you know what you are doing! *** @@ -124,7 +129,7 @@ using System; using System.Reflection; using Pulumi.Kubernetes; -namespace Pulumi.` + name + ` +namespace ` + namespace + `.` + name + ` { static class Utilities { diff --git a/pkg/codegen/golang.go b/pkg/codegen/golang.go index bc68b68..8ad7463 100644 --- a/pkg/codegen/golang.go +++ b/pkg/codegen/golang.go @@ -36,7 +36,7 @@ var UnneededGoFiles = codegen.NewStringSet( "utilities/pulumiVersion.go", ) -func GenerateGo(pg *PackageGenerator, name string) (buffers map[string]*bytes.Buffer, err error) { +func GenerateGo(pg *PackageGenerator, cs *CodegenSettings) (buffers map[string]*bytes.Buffer, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("%v", r) @@ -46,7 +46,7 @@ func GenerateGo(pg *PackageGenerator, name string) (buffers map[string]*bytes.Bu pkg := pg.SchemaPackageWithObjectMetaType() langName := "go" oldName := pkg.Name - pkg.Name = name + pkg.Name = cs.PackageName moduleToPackage, err := pg.ModuleToPackage() if err != nil { return nil, fmt.Errorf("%w", err) diff --git a/pkg/codegen/java.go b/pkg/codegen/java.go index 2a1aeb8..fef11fb 100644 --- a/pkg/codegen/java.go +++ b/pkg/codegen/java.go @@ -18,12 +18,13 @@ import ( "bytes" "fmt" "regexp" + "strings" "github.com/pulumi/crd2pulumi/internal/versions" javaGen "github.com/pulumi/pulumi-java/pkg/codegen/java" ) -func GenerateJava(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, error) { +func GenerateJava(pg *PackageGenerator, cs *CodegenSettings) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() // These fields are required for the Java code generation @@ -47,7 +48,19 @@ func GenerateJava(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, langName := "java" oldName := pkg.Name - pkg.Name = name + pkg.Name = cs.PackageName + pkg.Namespace = cs.PackageNamespace + + // Override Java base package to avoid pulumi-java defaulting logic adding an extra "com." prefix + if pkg.Language == nil { + pkg.Language = map[string]interface{}{} + } + pkg.Language[langName] = javaGen.PackageInfo{BasePackage: cs.PackageNamespace} + + namespacePath := "com/pulumi" + if cs.PackageNamespace != "" { + namespacePath = strings.ReplaceAll(cs.PackageNamespace, ".", "/") + } files, err := javaGen.GeneratePackage("crd2pulumi", pkg, nil, nil, true, false) if err != nil { @@ -58,10 +71,10 @@ func GenerateJava(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, delete(pkg.Language, langName) // Pin the kubernetes provider version used - utilsPath := "src/main/java/com/pulumi/" + name + "/Utilities.java" + utilsPath := "src/main/java/" + namespacePath + "/" + cs.PackageName + "/Utilities.java" utils, ok := files[utilsPath] if !ok { - return nil, fmt.Errorf("cannot find generated utilities.ts") + return nil, fmt.Errorf("cannot find generated Utilities.java at path: %s", utilsPath) } re := regexp.MustCompile(`static \{(?:[^{}]|{[^{}]*})*}`) files[utilsPath] = []byte(re.ReplaceAllString(string(utils), `static { @@ -69,8 +82,8 @@ func GenerateJava(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, }`)) var unneededJavaFiles = []string{ - "src/main/java/com/pulumi/" + name + "/Provider.java", - "src/main/java/com/pulumi/" + name + "/ProviderArgs.java", + "src/main/java/" + namespacePath + "/" + cs.PackageName + "/Provider.java", + "src/main/java/" + namespacePath + "/" + cs.PackageName + "/ProviderArgs.java", "src/main/java/com/pulumi/kubernetes/meta/v1/inputs/ObjectMetaArgs.java", "src/main/java/com/pulumi/kubernetes/meta/v1/outputs/ObjectMeta.java", } diff --git a/pkg/codegen/language.go b/pkg/codegen/language.go index 6bafd78..8ef0c5f 100644 --- a/pkg/codegen/language.go +++ b/pkg/codegen/language.go @@ -32,12 +32,13 @@ const Python string = "python" const Java string = "java" type CodegenSettings struct { - Language string - OutputDir string - PackageName string - PackageVersion string - Overwrite bool - ShouldGenerate bool + Language string + OutputDir string + PackageName string + PackageNamespace string + PackageVersion string + Overwrite bool + ShouldGenerate bool } func (cs *CodegenSettings) Path() string { diff --git a/pkg/codegen/nodejs.go b/pkg/codegen/nodejs.go index ccc6b6f..a7a4c0c 100644 --- a/pkg/codegen/nodejs.go +++ b/pkg/codegen/nodejs.go @@ -29,10 +29,11 @@ export type ObjectMeta = k8s.types.input.meta.v1.ObjectMeta; export type ObjectMetaPatch = k8s.types.input.meta.v1.ObjectMetaPatch; ` -func GenerateNodeJS(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, error) { +func GenerateNodeJS(pg *PackageGenerator, cs *CodegenSettings) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() oldName := pkg.Name - pkg.Name = name + pkg.Name = cs.PackageName + pkg.Namespace = cs.PackageNamespace files, err := nodejs.GeneratePackage(PulumiToolName, pkg, nil, nil, true, nil) if err != nil { diff --git a/pkg/codegen/python.go b/pkg/codegen/python.go index d35b154..5e57292 100644 --- a/pkg/codegen/python.go +++ b/pkg/codegen/python.go @@ -27,12 +27,13 @@ const pythonMetaFile = `from pulumi_kubernetes.meta.v1._inputs import * import pulumi_kubernetes.meta.v1.outputs ` -func GeneratePython(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, error) { +func GeneratePython(pg *PackageGenerator, cs *CodegenSettings) (map[string]*bytes.Buffer, error) { pkg := pg.SchemaPackageWithObjectMetaType() langName := "python" oldName := pkg.Name - pkg.Name = name + pkg.Name = cs.PackageName + pkg.Namespace = cs.PackageNamespace files, err := python.GeneratePackage(PulumiToolName, pkg, nil, nil) if err != nil { @@ -42,7 +43,11 @@ func GeneratePython(pg *PackageGenerator, name string) (map[string]*bytes.Buffer pkg.Name = oldName delete(pkg.Language, langName) - pythonPackageDir := "pulumi_" + name + namespace := cs.PackageNamespace + if namespace == "" { + namespace = "pulumi" + } + pythonPackageDir := namespace + "_" + cs.PackageName // Remove unneeded files var unneededPythonFiles = []string{ diff --git a/tests/unneeded_go_files_test.go b/tests/unneeded_go_files_test.go index 08e1b0b..6f60a87 100644 --- a/tests/unneeded_go_files_test.go +++ b/tests/unneeded_go_files_test.go @@ -41,17 +41,21 @@ spec: } // Pick a generated file we want to exclude - uneededGoFile := "uneededgofilestest/test/testResource.go" - codegen.UnneededGoFiles.Add(uneededGoFile) + unNeededGoFile := "unneededgofilestest/test/testResource.go" + codegen.UnneededGoFiles.Add(unNeededGoFile) // Generate the code from the mocked CRD - buffers, err := codegen.GenerateGo(pg, "crds") + goSettings := &codegen.CodegenSettings{ + Language: "go", + PackageName: "crds", + } + buffers, err := codegen.GenerateGo(pg, goSettings) if err != nil { t.Fatalf("GenerateGo failed: %v", err) } // Assert that buffers do not contain unneeded file - if _, exists := buffers["../kubernetes/"+uneededGoFile]; exists { - t.Errorf("Uneeded GO file was not excluded by GoGenerate, %s", uneededGoFile) + if _, exists := buffers["../kubernetes/"+unNeededGoFile]; exists { + t.Errorf("Unneeded GO file was not excluded by GoGenerate, %s", unNeededGoFile) } }