Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Java generation #129

Merged
merged 1 commit into from
Mar 20, 2024
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

- Fix: Pin the Kubernetes version for generated nodejs resources(<https://github.com/pulumi/crd2pulumi/pull/121>)
- Feat: Add Java generation support (<https://github.com/pulumi/crd2pulumi/pull/129>)

## 1.3.0 (2023-12-12)

Expand Down
44 changes: 40 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ CustomResources to use in Pulumi programs, based on a
CustomResourceDefinition YAML schema.

Usage:
crd2pulumi [-dgnp] [--nodejsPath path] [--pythonPath path] [--dotnetPath path] [--goPath path] <crd1.yaml> [crd2.yaml ...] [flags]
crd2pulumi [-dgnp] [--nodejsPath path] [--pythonPath path] [--dotnetPath path] [--goPath path] [--javaPath path] <crd1.yaml> [crd2.yaml ...] [flags]
crd2pulumi [command]

Examples:
Expand All @@ -67,6 +67,9 @@ Flags:
--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
Expand All @@ -77,9 +80,9 @@ Flags:
Use "crd2pulumi [command] --help" for more information about a command.
```
Setting only a language-specific flag will output the generated code in the default directory; so `-d` will output to
`crds/dotnet`, `-g` will output to `crds/go`, `-n` will output to `crds/nodejs`, and `-p` will output to `crds/python`.
You can also specify a language-specific path (`--pythonPath`, `--nodejsPath`, etc) to control where the code will be
outputted, in which case setting `-p`, `-n`, etc becomes unnecessary.
`crds/dotnet`, `-g` will output to `crds/go`, `-j` will output to `crds/java`, `-n` will output to `crds/nodejs`, and
`-p` will output to `crds/python`. You can also specify a language-specific path (`--pythonPath`, `--nodejsPath`, etc)
to control where the code will be outputted, in which case setting `-p`, `-n`, etc becomes unnecessary.

## Examples
Let's use the example CronTab CRD specified in `resourcedefinition.yaml` from the
Expand Down Expand Up @@ -226,8 +229,41 @@ class MyStack : Stack
}

```

> If you get an `Duplicate 'global::System.Runtime.Versioning.TargetFrameworkAttribute' attribute` error when trying to run `pulumi up`, then try deleting the `crontabs/bin` and `crontabs/obj` folders.

### Java
```bash
$ crd2pulumi --javaPath ./crontabs resourcedefinition.yaml
```
```java
package com.example;

import com.pulumi.Pulumi;

public class MyStack {

public static void main(String[] args) {
Pulumi.run(ctx -> {
// Register a CronTab CRD (Coming Soon - see https://www.pulumi.com/registry/packages/kubernetes/api-docs/yaml/configfile/)

// Instantiate a CronTab resource.
var cronTabInstance = new com.pulumi.crds.stable.v1.CronTab("cronTabInstance",
com.pulumi.crds.stable.v1.CronTabArgs.builder()
.metadata(com.pulumi.kubernetes.meta.v1.inputs.ObjectMetaArgs.builder()
.name("my-new-cron-object")
.build())
.spec(com.pulumi.kubernetes.stable.v1.inputs.CronTabSpecArgs.builder()
.cronSpec("* * * * */5")
.image("my-awesome-cron-image")
.build())
.build());
});
}
}

```

Now let's run the program and perform the update.
```bash
$ pulumi up
Expand Down
8 changes: 6 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ func Execute() error {
goSettings := &codegen.CodegenSettings{Language: "go"}
nodejsSettings := &codegen.CodegenSettings{Language: "nodejs"}
pythonSettings := &codegen.CodegenSettings{Language: "python"}
allSettings := []*codegen.CodegenSettings{dotNetSettings, goSettings, nodejsSettings, pythonSettings}
javaSettings := &codegen.CodegenSettings{Language: "java"}
allSettings := []*codegen.CodegenSettings{dotNetSettings, goSettings, nodejsSettings, pythonSettings, javaSettings}

var force bool
var packageVersion string
Expand Down Expand Up @@ -119,16 +120,19 @@ func Execute() error {
f.StringVarP(&dotNetSettings.PackageName, "dotnetName", "", codegen.DefaultName, "name of generated .NET package")
f.StringVarP(&goSettings.PackageName, "goName", "", codegen.DefaultName, "name of generated Go package")
f.StringVarP(&nodejsSettings.PackageName, "nodejsName", "", codegen.DefaultName, "name of generated NodeJS package")
f.StringVarP(&pythonSettings.PackageName, "pythonName", "", codegen.DefaultName, "name of generated Python paclkage")
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.OutputDir, "dotnetPath", "", "", "optional .NET output dir")
f.StringVarP(&goSettings.OutputDir, "goPath", "", "", "optional Go output dir")
f.StringVarP(&nodejsSettings.OutputDir, "nodejsPath", "", "", "optional NodeJS output dir")
f.StringVarP(&pythonSettings.OutputDir, "pythonPath", "", "", "optional Python output dir")
f.StringVarP(&javaSettings.OutputDir, "javaPath", "", "", "optional Java output dir")

f.BoolVarP(&dotNetSettings.ShouldGenerate, "dotnet", "d", false, "generate .NET")
f.BoolVarP(&goSettings.ShouldGenerate, "go", "g", false, "generate Go")
f.BoolVarP(&nodejsSettings.ShouldGenerate, "nodejs", "n", false, "generate NodeJS")
f.BoolVarP(&pythonSettings.ShouldGenerate, "python", "p", false, "generate Python")
f.BoolVarP(&javaSettings.ShouldGenerate, "java", "j", false, "generate Java")
return rootCmd.Execute()
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.19

require (
github.com/iancoleman/strcase v0.3.0
github.com/pulumi/pulumi-java/pkg v0.9.8
github.com/pulumi/pulumi/pkg/v3 v3.95.0
github.com/pulumi/pulumi/sdk/v3 v3.95.0
github.com/spf13/cobra v1.8.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 h1:vkHw5I/plNdTr435
github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231/go.mod h1:murToZ2N9hNJzewjHBgfFdXhZKjY3z5cYC1VXk+lbFE=
github.com/pulumi/esc v0.6.1-0.20231111193429-44b746a5b3b5 h1:1DJMji9F7XPea46bSuhy4/85n8J4/Mfz8PWLZtjKKiI=
github.com/pulumi/esc v0.6.1-0.20231111193429-44b746a5b3b5/go.mod h1:Y6W21yUukvxS2NnS5ae1beMSPhMvj0xNAYcDqDHVj/g=
github.com/pulumi/pulumi-java/pkg v0.9.8 h1:c8mYsalnRXA2Ibgvv6scefOn6mW1Vb0UT0mcDqjsivQ=
github.com/pulumi/pulumi-java/pkg v0.9.8/go.mod h1:c6rSw/+q4O0IImgJ9axxoC6QesbPYWBaG5gimbHouUQ=
github.com/pulumi/pulumi/pkg/v3 v3.95.0 h1:FBA0EmjRaqUgzleFMpLSAQUojXH2PyIVERzAm53p63U=
github.com/pulumi/pulumi/pkg/v3 v3.95.0/go.mod h1:4mjOPC8lb49ihR/HbGmid0y9GFlpfP9Orumr0wFOGno=
github.com/pulumi/pulumi/sdk/v3 v3.95.0 h1:SBpFZYdbVF8DtmiEosut2BRVRjLxPpcQf5bOkyPWosQ=
Expand Down
1 change: 1 addition & 0 deletions pkg/codegen/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var codeGenFuncs = map[string]GenerateFunc{
DotNet: GenerateDotNet,
NodeJS: GenerateNodeJS,
Python: GeneratePython,
Java: GenerateJava,
}

// PulumiToolName is a symbol that identifies to Pulumi the name of this program.
Expand Down
101 changes: 101 additions & 0 deletions pkg/codegen/java.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2016-2022, Pulumi Corporation.
//
// 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 codegen

import (
"bytes"
"fmt"
ijson "github.com/pulumi/crd2pulumi/internal/json"
"github.com/pulumi/crd2pulumi/internal/versions"
javaGen "github.com/pulumi/pulumi-java/pkg/codegen/java"
"regexp"
)

func GenerateJava(pg *PackageGenerator, name string) (map[string]*bytes.Buffer, error) {
pkg := pg.SchemaPackageWithObjectMetaType()

// These fields are required for the Java code generation
pkg.Description = "Generated Java SDK via crd2pulumi"
pkg.Repository = "Placeholder"

// Set up packages
packages := map[string]string{}
for _, groupVersion := range pg.GroupVersions {
group, version, err := versions.SplitGroupVersion(groupVersion)
if err != nil {
return nil, fmt.Errorf("invalid version: %w", err)
}
groupPrefix, err := versions.GroupPrefix(group)
if err != nil {
return nil, fmt.Errorf("invalid version: %w", err)
}
packages[groupVersion] = groupPrefix + "." + version
}
packages["meta/v1"] = "meta.v1"

langName := "java"
oldName := pkg.Name
pkg.Name = name

jsonData, err := ijson.RawMessage(map[string]any{
"buildFiles": "gradle",
"dependencies": map[string]string{
"com.pulumi:kubernetes": "4.9.0",
},
"packages": packages,
})
if err != nil {
return nil, fmt.Errorf("failed to marshal language metadata: %w", err)
}
pkg.Language[langName] = jsonData

files, err := javaGen.GeneratePackage("crd2pulumi", pkg, nil)
if err != nil {
return nil, fmt.Errorf("could not generate Java package: %w", err)
}

pkg.Name = oldName
delete(pkg.Language, langName)

// Pin the kubernetes provider version used
utilsPath := "src/main/java/com/pulumi/" + name + "/Utilities.java"
utils, ok := files[utilsPath]
if !ok {
return nil, fmt.Errorf("cannot find generated utilities.ts")
}
re := regexp.MustCompile(`static \{(?:[^{}]|{[^{}]*})*}`)
files[utilsPath] = []byte(re.ReplaceAllString(string(utils), `static {
version = "4.9.0";
}`))

var unneededJavaFiles = []string{
"src/main/java/com/pulumi/" + name + "/Provider.java",
"src/main/java/com/pulumi/" + name + "/ProviderArgs.java",
"src/main/java/com/pulumi/kubernetes/meta/v1/inputs/ObjectMetaArgs.java",
"src/main/java/com/pulumi/kubernetes/meta/v1/outputs/ObjectMeta.java",
}

// Remove unneeded files
for _, unneededFile := range unneededJavaFiles {
delete(files, unneededFile)
}

buffers := map[string]*bytes.Buffer{}
for name, code := range files {
buffers[name] = bytes.NewBuffer(code)
}

return buffers, err
}
1 change: 1 addition & 0 deletions pkg/codegen/language.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const DotNet string = "dotnet"
const Go string = "go"
const NodeJS string = "nodejs"
const Python string = "python"
const Java string = "java"

type CodegenSettings struct {
Language string
Expand Down
2 changes: 1 addition & 1 deletion tests/crds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/stretchr/testify/require"
)

var languages = []string{"dotnet", "go", "nodejs", "python"}
var languages = []string{"dotnet", "go", "nodejs", "python", "java"}

const gkeManagedCertsUrl = "https://raw.githubusercontent.com/GoogleCloudPlatform/gke-managed-certs/master/deploy/managedcertificates-crd.yaml"

Expand Down
Loading