From b06bc301b203aa60445c7a0381ab1dc40eaa5f04 Mon Sep 17 00:00:00 2001 From: Mikhail Shilkov Date: Wed, 29 Jan 2025 22:52:51 +0100 Subject: [PATCH 1/5] Support RunPlugin for Maven and Gradle plugins --- pkg/cmd/pulumi-language-java/main.go | 63 +++++++++++++++++++++++ pkg/internal/executors/executor.go | 7 +++ pkg/internal/executors/executor_gradle.go | 17 ++++-- pkg/internal/executors/executor_maven.go | 14 ++++- 4 files changed, 94 insertions(+), 7 deletions(-) diff --git a/pkg/cmd/pulumi-language-java/main.go b/pkg/cmd/pulumi-language-java/main.go index 39d93d8633a..da1a5ccc086 100644 --- a/pkg/cmd/pulumi-language-java/main.go +++ b/pkg/cmd/pulumi-language-java/main.go @@ -16,6 +16,7 @@ import ( "os/signal" "path/filepath" "strings" + "syscall" "time" pbempty "github.com/golang/protobuf/ptypes/empty" @@ -404,6 +405,68 @@ func (host *javaLanguageHost) Run(ctx context.Context, req *pulumirpc.RunRequest return &pulumirpc.RunResponse{Error: errResult}, nil } +// RunPlugin executes a plugin program and returns its result. +func (host *javaLanguageHost) RunPlugin( + req *pulumirpc.RunPluginRequest, server pulumirpc.LanguageRuntime_RunPluginServer, +) error { + logging.V(5).Infof("Attempting to run java plugin in %s", req.Pwd) + + closer, stdout, stderr, err := rpcutil.MakeRunPluginStreams(server, false) + if err != nil { + return err + } + // Best effort close, but we try an explicit close and error check at the end as well + defer closer.Close() + + // Create new executor options with the plugin directory and runtime args + pluginExecOptions := executors.JavaExecutorOptions{ + Binary: host.execOptions.Binary, + UseExecutor: host.execOptions.UseExecutor, + WD: fsys.DirFS(req.Info.ProgramDirectory), + ProgramArgs: req.Args, + } + + executor, err := executors.NewJavaExecutor(pluginExecOptions, false) + if err != nil { + return err + } + + executable := executor.Cmd + args := executor.RunPluginArgs + + if len(args) == 0 { + return errors.Errorf("executor %s does not currently support running plugins", executor.Cmd) + } + + commandStr := strings.Join(args, " ") + logging.V(5).Infof("Language host launching process: %s %s", executable, commandStr) + + cmd := exec.Command(executable, args...) + cmd.Dir = req.Pwd + cmd.Env = req.Env + cmd.Stdout = stdout + cmd.Stderr = stderr + + if err = cmd.Run(); err != nil { + var exiterr *exec.ExitError + if errors.As(err, &exiterr) { + if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { + return server.Send(&pulumirpc.RunPluginResponse{ + //nolint:gosec // WaitStatus always uses the lower 8 bits for the exit code. + Output: &pulumirpc.RunPluginResponse_Exitcode{Exitcode: int32(status.ExitStatus())}, + }) + } + if len(exiterr.Stderr) > 0 { + return fmt.Errorf("program exited unexpectedly: %w: %s", exiterr, exiterr.Stderr) + } + return fmt.Errorf("program exited unexpectedly: %w", exiterr) + } + return fmt.Errorf("problem executing plugin program (could not run language executor): %w", err) + } + + return closer.Close() +} + // constructEnv constructs an environ for `pulumi-language-java` // by enumerating all of the optional and non-optional evn vars present // in a RunRequest. diff --git a/pkg/internal/executors/executor.go b/pkg/internal/executors/executor.go index 1649f9350e8..a48ac3724a6 100644 --- a/pkg/internal/executors/executor.go +++ b/pkg/internal/executors/executor.go @@ -31,6 +31,10 @@ type JavaExecutor struct { // by the Java program. PluginArgs []string + // Command args to run a plugin (e.g. a provider). Optional if the executor + // does not support running plugins. + RunPluginArgs []string + // Returns a list of program dependencies as configured for the executor (e.g. in a `pom.xml` for Maven, or a // `build.gradle` for Gradle). GetProgramDependencies func( @@ -51,6 +55,9 @@ type JavaExecutorOptions struct { // The value of `runtime.options.use-executor` setting from // `Pulumi.yaml`. Optional. UseExecutor string + + // Additional runtime arguments to pass to the program. + ProgramArgs []string } type javaExecutorFactory interface { diff --git a/pkg/internal/executors/executor_gradle.go b/pkg/internal/executors/executor_gradle.go index 8fbaa3d8d35..106168f3162 100644 --- a/pkg/internal/executors/executor_gradle.go +++ b/pkg/internal/executors/executor_gradle.go @@ -36,7 +36,7 @@ func (g gradle) NewJavaExecutor(opts JavaExecutorOptions) (*JavaExecutor, error) if err != nil { return nil, err } - executor, err := g.newGradleExecutor(gradleRoot, cmd, subproject) + executor, err := g.newGradleExecutor(gradleRoot, cmd, subproject, opts.ProgramArgs) if err != nil { return nil, err } @@ -103,21 +103,28 @@ func (gradle) isGradleProject(dir fs.FS, opts JavaExecutorOptions) (bool, error) return false, nil } -func (g gradle) newGradleExecutor(gradleRoot fsys.ParentFS, cmd, subproject string) (*JavaExecutor, error) { +func (g gradle) newGradleExecutor(gradleRoot fsys.ParentFS, + cmd, subproject string, args []string, +) (*JavaExecutor, error) { return &JavaExecutor{ Cmd: cmd, Dir: gradleRoot.Path(), BuildArgs: []string{g.prefix(subproject, "build"), "--console=plain"}, RunArgs: []string{g.prefix(subproject, "run"), "--console=plain"}, PluginArgs: []string{ - /* STDOUT needs to be clean of gradle output, - because we expect a JSON with plugin - results */ + // STDOUT needs to be clean of gradle output because we expect a JSON with plugin results. "-q", // must go first due to a bug https://github.com/gradle/gradle/issues/5098 g.prefix(subproject, "run"), "--console=plain", "-PmainClass=com.pulumi.bootstrap.internal.Main", "--args=packages", }, + RunPluginArgs: []string{ + // STDOUT needs to be clean of gradle output because we expect a port printed back. + "-q", // must go first due to a bug https://github.com/gradle/gradle/issues/5098 + "--project-dir", gradleRoot.Path(), // plugin's CWD is set to the Pulumi program's root + g.prefix(subproject, "run"), "--console=plain", + "--args=" + strings.Join(args, " "), + }, }, nil } diff --git a/pkg/internal/executors/executor_maven.go b/pkg/internal/executors/executor_maven.go index a1e2e172faf..460afb389ce 100644 --- a/pkg/internal/executors/executor_maven.go +++ b/pkg/internal/executors/executor_maven.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "regexp" "strings" @@ -35,7 +36,8 @@ func (m maven) NewJavaExecutor(opts JavaExecutorOptions) (*JavaExecutor, error) if err != nil { return nil, err } - return m.newMavenExecutor(cmd) + pomXMLPath := filepath.Join(opts.WD.Path(), "pom.xml") + return m.newMavenExecutor(cmd, opts.ProgramArgs, pomXMLPath) } func (maven) isMavenProject(opts JavaExecutorOptions) (bool, error) { @@ -45,7 +47,7 @@ func (maven) isMavenProject(opts JavaExecutorOptions) (bool, error) { return fsys.FileExists(opts.WD, "pom.xml") } -func (maven) newMavenExecutor(cmd string) (*JavaExecutor, error) { +func (maven) newMavenExecutor(cmd string, args []string, pomXMLPath string) (*JavaExecutor, error) { return &JavaExecutor{ Cmd: cmd, BuildArgs: []string{ @@ -68,6 +70,14 @@ func (maven) newMavenExecutor(cmd string) (*JavaExecutor, error) { "-DmainClass=com.pulumi.bootstrap.internal.Main", "-DmainArgs=packages", }, + RunPluginArgs: []string{ + /* move normal output to STDERR, because we need STDOUT for port printed back */ + "-Dorg.slf4j.simpleLogger.defaultLogLevel=warn", + "-Dorg.slf4j.simpleLogger.logFile=System.err", + "--no-transfer-progress", "compile", "exec:java", + "-f", pomXMLPath, // plugin's CWD is set to the Pulumi program's root + fmt.Sprintf("-Dexec.args=%s", strings.Join(args, " ")), + }, // Implements the GetProgramDependencies function to retrieve the dependencies of a Maven project. GetProgramDependencies: func( From 04f79be2fe9ba1adc4ac186775e62463e6fbfc6d Mon Sep 17 00:00:00 2001 From: Mikhail Shilkov Date: Wed, 5 Feb 2025 17:24:10 +0100 Subject: [PATCH 2/5] Barebones provider with GetSchema --- .../pulumi/provider/internal/Provider.java | 11 ++ .../internal/ResourceProviderService.java | 105 ++++++++++++++++++ .../internal/models/GetSchemaRequest.java | 25 +++++ .../internal/models/GetSchemaResponse.java | 13 +++ 4 files changed, 154 insertions(+) create mode 100644 sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java create mode 100644 sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/ResourceProviderService.java create mode 100644 sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaRequest.java create mode 100644 sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaResponse.java diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java new file mode 100644 index 00000000000..e4dc7857632 --- /dev/null +++ b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java @@ -0,0 +1,11 @@ +package com.pulumi.provider.internal; + +import java.util.concurrent.CompletableFuture; + +import com.pulumi.provider.internal.models.*; + +public abstract class Provider { + public CompletableFuture getSchema(GetSchemaRequest request) { + throw new UnsupportedOperationException("Method 'getSchema' is not implemented"); + } +} diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/ResourceProviderService.java b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/ResourceProviderService.java new file mode 100644 index 00000000000..3f78e00fda8 --- /dev/null +++ b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/ResourceProviderService.java @@ -0,0 +1,105 @@ +package com.pulumi.provider.internal; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import java.util.function.Function; + +public class ResourceProviderService { + + private static final Logger logger = Logger.getLogger(ResourceProviderService.class.getName()); + + private Server server; + private final Provider implementation; + + public ResourceProviderService(Provider implementation) { + this.implementation = implementation; + } + + public void startAndBlockUntilShutdown() throws IOException, InterruptedException { + start(); + blockUntilShutdown(); + } + + private void start() throws IOException { + server = ServerBuilder.forPort(0) // Use port 0 to let system assign a free port + .addService(new ResourceProviderImpl(this.implementation)) + .build() + .start(); + + // Print the actual bound port for the parent process to read + System.out.println(server.getPort()); + + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + try { + ResourceProviderService.this.stop(); + } catch (InterruptedException e) { + logger.severe(e.toString()); + } + } + }); + } + + private void stop() throws InterruptedException { + if (server != null) { + server.shutdown().awaitTermination(30, TimeUnit.SECONDS); + } + } + + private void blockUntilShutdown() throws InterruptedException { + if (server != null) { + server.awaitTermination(); + } + } + + static class ResourceProviderImpl extends pulumirpc.ResourceProviderGrpc.ResourceProviderImplBase { + private final Provider implementation; + + public ResourceProviderImpl(Provider implementation) { + this.implementation = implementation; + } + + @Override + public void getPluginInfo(Empty request, StreamObserver responseObserver) { + // Return basic plugin information + pulumirpc.Plugin.PluginInfo info = pulumirpc.Plugin.PluginInfo.newBuilder() + .setVersion("1.0.0") + .build(); + + responseObserver.onNext(info); + responseObserver.onCompleted(); + } + + @Override + public void getSchema(pulumirpc.Provider.GetSchemaRequest request, StreamObserver responseObserver) { + // protobuf sends an empty string for subpackageName/subpackageVersion, but really + // that means null in the domain model. + Function nullIfEmpty = s -> { + if (s == null || s.equals("")) { + return null; + } + return s; + }; + + var domRequest = new com.pulumi.provider.internal.models.GetSchemaRequest( + request.getVersion(), + nullIfEmpty.apply(request.getSubpackageName()), + nullIfEmpty.apply(request.getSubpackageVersion()) + ); + + this.implementation.getSchema(domRequest).thenAccept(domResponse -> { + var grpcResponse = pulumirpc.Provider.GetSchemaResponse.newBuilder() + .setSchema(domResponse.getSchema()) + .build(); + responseObserver.onNext(grpcResponse); + responseObserver.onCompleted(); + }); + } + } +} diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaRequest.java b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaRequest.java new file mode 100644 index 00000000000..7ed601e3523 --- /dev/null +++ b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaRequest.java @@ -0,0 +1,25 @@ +package com.pulumi.provider.internal.models; + +public class GetSchemaRequest { + private final int version; + private final String subpackageName; + private final String subpackageVersion; + + public GetSchemaRequest(int version, String subpackageName, String subpackageVersion) { + this.version = version; + this.subpackageName = subpackageName; + this.subpackageVersion = subpackageVersion; + } + + public int getVersion() { + return version; + } + + public String getSubpackageName() { + return subpackageName; + } + + public String getSubpackageVersion() { + return subpackageVersion; + } +} \ No newline at end of file diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaResponse.java b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaResponse.java new file mode 100644 index 00000000000..b713ab3cf64 --- /dev/null +++ b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/models/GetSchemaResponse.java @@ -0,0 +1,13 @@ +package com.pulumi.provider.internal.models; + +public class GetSchemaResponse { + private final String schema; + + public GetSchemaResponse(String schema) { + this.schema = schema; + } + + public String getSchema() { + return schema; + } +} \ No newline at end of file From f3280174ff58c534bd0ae753197b999a57238295 Mon Sep 17 00:00:00 2001 From: Mikhail Shilkov Date: Wed, 5 Feb 2025 17:24:53 +0100 Subject: [PATCH 3/5] Integration tests for Maven and Gradle providers --- .gitignore | 2 + tests/integration/java_integration_test.go | 40 ++++++ .../provider-gradle/PulumiPlugin.yaml | 1 + .../integration/provider-gradle/build.gradle | 35 +++++ .../provider-gradle/settings.gradle | 0 .../example/provider/ExampleProvider.java | 26 ++++ .../com/pulumi/example/provider/Main.java | 12 ++ .../provider-maven/PulumiPlugin.yaml | 1 + tests/integration/provider-maven/pom.xml | 132 ++++++++++++++++++ .../java/com/pulumi/example/provider/App.java | 12 ++ .../example/provider/ExampleProvider.java | 26 ++++ 11 files changed, 287 insertions(+) create mode 100644 tests/integration/provider-gradle/PulumiPlugin.yaml create mode 100644 tests/integration/provider-gradle/build.gradle create mode 100644 tests/integration/provider-gradle/settings.gradle create mode 100644 tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java create mode 100644 tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/Main.java create mode 100644 tests/integration/provider-maven/PulumiPlugin.yaml create mode 100644 tests/integration/provider-maven/pom.xml create mode 100644 tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/App.java create mode 100644 tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java diff --git a/.gitignore b/.gitignore index 9482e82c15a..fa9a52f1f5c 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,5 @@ pulumi-analyzer-policy-python.cmd # Ignore user-provided go.work files. /go.work /go.work.sum +**/build/ +**/target/ diff --git a/tests/integration/java_integration_test.go b/tests/integration/java_integration_test.go index fdfea391c5b..6e29ef2a93e 100644 --- a/tests/integration/java_integration_test.go +++ b/tests/integration/java_integration_test.go @@ -3,6 +3,8 @@ package integration import ( + "bytes" + "encoding/json" "os/exec" "path/filepath" "testing" @@ -117,6 +119,44 @@ func TestIntegrations(t *testing.T) { integration.ProgramTest(t, &test) }) + t.Run("package-schema", func(t *testing.T) { + t.Parallel() + + dir := getCwd(t) + pulumi, err := exec.LookPath("pulumi") + require.NoError(t, err) + + providers := []string{"provider-maven", "provider-gradle"} + for _, provider := range providers { + provider := provider // Create new variable to avoid loop capture + t.Run(provider, func(t *testing.T) { + t.Parallel() + + var stdout bytes.Buffer + var stderr bytes.Buffer + cmd := exec.Command(pulumi, "package", "get-schema", "./"+provider) + cmd.Dir = dir + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + err = cmd.Run() + require.NoError(t, err) + + // Validate that the schema output is valid JSON + var schema map[string]interface{} + err = json.Unmarshal(stdout.Bytes(), &schema) + require.NoError(t, err, "schema should be valid JSON") + + // Validate required schema fields + assert.Contains(t, schema, "name", "schema should have a name field") + assert.Equal(t, "example", schema["name"], "schema name should be 'example'") + assert.Contains(t, schema, "version", "schema should have a version field") + assert.Equal(t, "0.0.1", schema["version"], "schema version should be '0.0.1'") + assert.Contains(t, schema, "resources", "schema should have a resources field") + }) + } + }) + runAliasTest(t, "rename") runAliasTest(t, "rename-component") runAliasTest(t, "rename-component-and-child") diff --git a/tests/integration/provider-gradle/PulumiPlugin.yaml b/tests/integration/provider-gradle/PulumiPlugin.yaml new file mode 100644 index 00000000000..991ff723c4d --- /dev/null +++ b/tests/integration/provider-gradle/PulumiPlugin.yaml @@ -0,0 +1 @@ +runtime: java diff --git a/tests/integration/provider-gradle/build.gradle b/tests/integration/provider-gradle/build.gradle new file mode 100644 index 00000000000..f0b1f45df91 --- /dev/null +++ b/tests/integration/provider-gradle/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'application' +} + +group 'com.pulumi.example.provider' +version '0.0.1-SNAPSHOT' + +repositories { + mavenLocal() + maven { // The google mirror is less flaky than mavenCentral() + url("https://maven-central.storage-download.googleapis.com/maven2/") + } + mavenCentral() +} + +def grpcVersion = '1.67.1' +def protobufVersion = '3.25.1' +def pulumiJavaSdkVersion = System.getenv("PULUMI_JAVA_SDK_VERSION") ?: "0.0.1" + +dependencies { + implementation("com.pulumi:pulumi:$pulumiJavaSdkVersion") { + exclude group: 'io.grpc', module: 'grpc-netty-shaded' + } + implementation "io.grpc:grpc-netty-shaded:$grpcVersion" + implementation "io.grpc:grpc-protobuf:$grpcVersion" + implementation "io.grpc:grpc-stub:$grpcVersion" + implementation "javax.annotation:javax.annotation-api:1.3.2" + implementation "com.google.protobuf:protobuf-java:$protobufVersion" +} + +application { + mainClass = project.hasProperty("mainClass") + ? project.getProperty("mainClass") + : "${group}.Main" +} \ No newline at end of file diff --git a/tests/integration/provider-gradle/settings.gradle b/tests/integration/provider-gradle/settings.gradle new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java b/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java new file mode 100644 index 00000000000..6bf8db1c1c0 --- /dev/null +++ b/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java @@ -0,0 +1,26 @@ +package com.pulumi.example.provider; + +import com.pulumi.provider.internal.models.*; + +import java.util.concurrent.CompletableFuture; +import com.pulumi.provider.internal.Provider; + +public class ExampleProvider extends Provider { + @Override + public CompletableFuture getSchema(GetSchemaRequest request) { + String schema = "{\n" + + " \"name\": \"example\",\n" + + " \"version\": \"0.0.1\",\n" + + " \"resources\": {\n" + + " \"example:index:Resource\": {\n" + + " \"properties\": {\n" + + " \"value\": {\n" + + " \"type\": \"string\"\n" + + " }\n" + + " }" + + " }\n" + + " }\n" + + "}"; + return CompletableFuture.completedFuture(new GetSchemaResponse(schema)); + } +} diff --git a/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/Main.java b/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/Main.java new file mode 100644 index 00000000000..4d53283eeed --- /dev/null +++ b/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/Main.java @@ -0,0 +1,12 @@ +package com.pulumi.example.provider; + +import java.io.IOException; +import com.pulumi.provider.internal.ResourceProviderService; + +public class Main { + public static void main(String[] args) throws IOException, InterruptedException { + var server = new ResourceProviderService(new ExampleProvider()); + server.startAndBlockUntilShutdown(); + } +} + diff --git a/tests/integration/provider-maven/PulumiPlugin.yaml b/tests/integration/provider-maven/PulumiPlugin.yaml new file mode 100644 index 00000000000..991ff723c4d --- /dev/null +++ b/tests/integration/provider-maven/PulumiPlugin.yaml @@ -0,0 +1 @@ +runtime: java diff --git a/tests/integration/provider-maven/pom.xml b/tests/integration/provider-maven/pom.xml new file mode 100644 index 00000000000..0cdc5b94bc4 --- /dev/null +++ b/tests/integration/provider-maven/pom.xml @@ -0,0 +1,132 @@ + + + 4.0.0 + + com.pulumi.example + provider + 1.0-SNAPSHOT + + + UTF-8 + 11 + 11 + 11 + ${project.groupId}.${project.artifactId}.App + + 1.67.1 + 3.25.1 + UTF-8 + + + + + default-pulumi-java-sdk-dependency + + + !env.PULUMI_JAVA_SDK_VERSION + + + + + + + + com.pulumi + pulumi + 0.0.1 + + + io.grpc + grpc-netty-shaded + + + + + io.grpc + grpc-netty-shaded + ${grpc.version} + + + io.grpc + grpc-protobuf + ${grpc.version} + + + io.grpc + grpc-stub + ${grpc.version} + + + javax.annotation + javax.annotation-api + 1.3.2 + + + com.google.protobuf + protobuf-java + ${protobuf.version} + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + + + + true + ${mainClass} + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + + true + ${mainClass} + + + + jar-with-dependencies + + + + + make-my-jar-with-dependencies + package + + single + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.0.0 + + ${mainClass} + ${mainArgs} + + + + org.apache.maven.plugins + maven-wrapper-plugin + 3.1.0 + + 3.8.5 + + + + + \ No newline at end of file diff --git a/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/App.java b/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/App.java new file mode 100644 index 00000000000..afc42a3aeff --- /dev/null +++ b/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/App.java @@ -0,0 +1,12 @@ +package com.pulumi.example.provider; + +import java.io.IOException; +import com.pulumi.provider.internal.ResourceProviderService; + +public class App { + public static void main(String[] args) throws IOException, InterruptedException { + var server = new ResourceProviderService(new ExampleProvider()); + server.startAndBlockUntilShutdown(); + } +} + diff --git a/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java b/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java new file mode 100644 index 00000000000..6bf8db1c1c0 --- /dev/null +++ b/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java @@ -0,0 +1,26 @@ +package com.pulumi.example.provider; + +import com.pulumi.provider.internal.models.*; + +import java.util.concurrent.CompletableFuture; +import com.pulumi.provider.internal.Provider; + +public class ExampleProvider extends Provider { + @Override + public CompletableFuture getSchema(GetSchemaRequest request) { + String schema = "{\n" + + " \"name\": \"example\",\n" + + " \"version\": \"0.0.1\",\n" + + " \"resources\": {\n" + + " \"example:index:Resource\": {\n" + + " \"properties\": {\n" + + " \"value\": {\n" + + " \"type\": \"string\"\n" + + " }\n" + + " }" + + " }\n" + + " }\n" + + "}"; + return CompletableFuture.completedFuture(new GetSchemaResponse(schema)); + } +} From adc2d561576cf6b2e5f01c8c2a805c694b529722 Mon Sep 17 00:00:00 2001 From: Mikhail Shilkov Date: Wed, 5 Feb 2025 17:33:57 +0100 Subject: [PATCH 4/5] Changelog --- CHANGELOG_PENDING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 4e2853d3c47..c45bb382426 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,5 +1,6 @@ ### Improvements - Default to using Gradle with the Nexus publishing plugin when using `gen-sdk` +- Support RunPlugin for Maven and Gradle plugins ### Bug Fixes From 91dd3d7e8ba0b2315c55811d352a0f7830d9dd5d Mon Sep 17 00:00:00 2001 From: Mikhail Shilkov Date: Fri, 7 Feb 2025 00:45:23 +0100 Subject: [PATCH 5/5] Convert Provider to an interface --- .../java/com/pulumi/provider/internal/Provider.java | 11 +++++++---- .../com/pulumi/example/provider/ExampleProvider.java | 2 +- .../com/pulumi/example/provider/ExampleProvider.java | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java index e4dc7857632..3c162179d5a 100644 --- a/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java +++ b/sdk/java/pulumi/src/main/java/com/pulumi/provider/internal/Provider.java @@ -4,8 +4,11 @@ import com.pulumi.provider.internal.models.*; -public abstract class Provider { - public CompletableFuture getSchema(GetSchemaRequest request) { - throw new UnsupportedOperationException("Method 'getSchema' is not implemented"); - } +public interface Provider { + /** + * Returns the schema for this provider's package. + * @param request The schema request + * @return A future containing the schema response + */ + CompletableFuture getSchema(GetSchemaRequest request); } diff --git a/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java b/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java index 6bf8db1c1c0..740940f8036 100644 --- a/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java +++ b/tests/integration/provider-gradle/src/main/java/com/pulumi/example/provider/ExampleProvider.java @@ -5,7 +5,7 @@ import java.util.concurrent.CompletableFuture; import com.pulumi.provider.internal.Provider; -public class ExampleProvider extends Provider { +public class ExampleProvider implements Provider { @Override public CompletableFuture getSchema(GetSchemaRequest request) { String schema = "{\n" + diff --git a/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java b/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java index 6bf8db1c1c0..740940f8036 100644 --- a/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java +++ b/tests/integration/provider-maven/src/main/java/com/pulumi/example/provider/ExampleProvider.java @@ -5,7 +5,7 @@ import java.util.concurrent.CompletableFuture; import com.pulumi.provider.internal.Provider; -public class ExampleProvider extends Provider { +public class ExampleProvider implements Provider { @Override public CompletableFuture getSchema(GetSchemaRequest request) { String schema = "{\n" +