From e8fc393c273d087e3b4d24d3daa52dca8ab31d2c Mon Sep 17 00:00:00 2001 From: Will Jones Date: Thu, 2 Jan 2025 10:31:06 +0000 Subject: [PATCH] Implement `GetRequiredPackages` for Java As part of a Pulumi deployment, the Pulumi engine will ask the language host running the program for the set of plugins required to run that program successfully by making a `GetRequiredPlugins` gRPC call. For instance, if one has a TypeScript program whose `index.ts` `import`s `@pulumi/aws`, the NodeJS language host will find the `@pulumi/aws` package and report that the `aws` resource plugin is required. This enables features such as pre-emptively downloading a plugin ahead of time, as opposed to waiting for the first resource registration against that plugin. With the introduction of parameterized providers, `GetRequiredPlugins` falls a little short -- parameterization means that it is no longer necessarily the case that a package named `x` is provided by a plugin of the same name. For instance, with a dynamically bridged Terraform provider X, the provider name will be X, but the plugin name will be e.g. `pulumi-terraform-provider`. In pulumi/pulumi#17894, `GetRequiredPackages` was added to the language host interface to provide the additional context of a plugin's parameterization, and is now used if present instead of `GetRequiredPlugins`. This change implements `GetRequiredPackages` for Java as follows: * Presently, `GetRequiredPlugins` is implemented by running a small Java program (located in the internal `bootstrap` package of the core SDK) that walks its class path looking for `pulumi-plugin.json` files. This code is extended to parse `parameterization` blocks from those JSON files, as we do in other languages using this mechanism. * When we generate SDKs, we generate Gradle build files which generate `pulumi-plugin.json` files as part of the build process. We extend the `build.gradle` template used when generating SDK build files so that it emits `parameterization` blocks appropriately. As part of this, we also clean up the emission of package names and versions. * We now have enough to run and pass the `l2-parameterized-resource` conformance test, which in theory confirms that all of this works, so we include that as part of this work. * We remove the now-deprecated `GetRequiredPlugins` implementation. Fixes #1510 --- CHANGELOG_PENDING.md | 2 + pkg/cmd/pulumi-language-java/language_test.go | 1 - pkg/cmd/pulumi-language-java/main.go | 58 ++++--- .../l2-parameterized-resource/Pulumi.yaml | 2 + .../l2-parameterized-resource/pom.xml | 99 +++++++++++ .../src/main/java/generated_program/App.java | 25 +++ .../alpha-3.0.0-alpha.1.internal/build.gradle | 14 +- .../testdata/sdks/simple-2.0.0/build.gradle | 14 +- .../testdata/sdks/subpackage-2.0.0/README.md | 1 + .../sdks/subpackage-2.0.0/build.gradle | 162 ++++++++++++++++++ .../sdks/subpackage-2.0.0/settings.gradle | 14 ++ .../com/pulumi/subpackage/HelloWorld.java | 78 +++++++++ .../com/pulumi/subpackage/HelloWorldArgs.java | 28 +++ .../java/com/pulumi/subpackage/Provider.java | 54 ++++++ .../com/pulumi/subpackage/ProviderArgs.java | 63 +++++++ .../java/com/pulumi/subpackage/Utilities.java | 129 ++++++++++++++ pkg/codegen/java/build.gradle.template | 39 +++-- pkg/codegen/java/templates_gradle.go | 35 +++- pkg/codegen/java/templates_gradle_test.go | 2 +- .../bootstrap/internal/PulumiPlugin.java | 58 +++++-- .../PulumiPluginParameterization.java | 57 ++++++ .../bootstrap/internal/PulumiPluginTest.java | 26 ++- .../bootstrap/internal/PulumiPluginsTest.java | 2 +- 23 files changed, 888 insertions(+), 75 deletions(-) create mode 100644 pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/Pulumi.yaml create mode 100644 pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/pom.xml create mode 100644 pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/src/main/java/generated_program/App.java create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/README.md create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/build.gradle create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/settings.gradle create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorld.java create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorldArgs.java create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Provider.java create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/ProviderArgs.java create mode 100644 pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Utilities.java create mode 100644 sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPluginParameterization.java diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 9851cac33d0..e1f569dacad 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -2,6 +2,8 @@ - Update to Pulumi 3.143.0 +- Implement `GetRequiredPackages` for the Java language host + ### Bug Fixes - [Convert] Emit the `Deployment` class when using Pulumi built-in functions in PCL `stack()` and `projectName()` \ No newline at end of file diff --git a/pkg/cmd/pulumi-language-java/language_test.go b/pkg/cmd/pulumi-language-java/language_test.go index 57fde240144..a13a41383d7 100644 --- a/pkg/cmd/pulumi-language-java/language_test.go +++ b/pkg/cmd/pulumi-language-java/language_test.go @@ -178,7 +178,6 @@ var expectedFailures = map[string]string{ "l2-invoke-variants": "unimplemented for Java", "l2-large-string": "unimplemented for Java", "l2-map-keys": "unimplemented for Java", - "l2-parameterized-resource": "unimplemented for Java", "l2-plain": "unimplemented for Java", "l2-primitive-ref": "unimplemented for Java", "l2-provider-grpc-config-schema-secret": "unimplemented for Java", diff --git a/pkg/cmd/pulumi-language-java/main.go b/pkg/cmd/pulumi-language-java/main.go index e78071b00d7..171f18e3e2d 100644 --- a/pkg/cmd/pulumi-language-java/main.go +++ b/pkg/cmd/pulumi-language-java/main.go @@ -34,7 +34,9 @@ import ( "github.com/pulumi/pulumi/sdk/v3/go/common/workspace" pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/structpb" codegen "github.com/pulumi/pulumi-java/pkg/codegen/java" @@ -158,49 +160,57 @@ func (host *javaLanguageHost) Executor(attachDebugger bool) (*executors.JavaExec return executor, nil } -// GetRequiredPlugins computes the complete set of anticipated plugins required by a program. -func (host *javaLanguageHost) GetRequiredPlugins( +// GetRequiredPackages computes the complete set of anticipated packages required by a program. +func (host *javaLanguageHost) GetRequiredPackages( ctx context.Context, - req *pulumirpc.GetRequiredPluginsRequest, -) (*pulumirpc.GetRequiredPluginsResponse, error) { - logging.V(5).Infof("GetRequiredPlugins: program=%v", req.GetProgram()) //nolint:staticcheck + req *pulumirpc.GetRequiredPackagesRequest, +) (*pulumirpc.GetRequiredPackagesResponse, error) { + logging.V(5).Infof("GetRequiredPackages: programDirectory=%v", req.Info.ProgramDirectory) - // now, introspect the user project to see which pulumi resource packages it references. - pulumiPackages, err := host.determinePulumiPackages(ctx, req) + pulumiPackages, err := host.determinePulumiPackages(ctx, req.Info.ProgramDirectory) if err != nil { return nil, errors.Wrapf(err, "language host could not determine Pulumi packages") } - // Now that we know the set of pulumi packages referenced, and we know where packages have been restored to, - // we can examine each package to determine the corresponding resource-plugin for it. - - plugins := []*pulumirpc.PluginDependency{} + pkgs := []*pulumirpc.PackageDependency{} for _, pulumiPackage := range pulumiPackages { - logging.V(3).Infof( - "GetRequiredPlugins: Determining plugin dependency: %v, %v", - pulumiPackage.Name, pulumiPackage.Version, - ) - + // Skip over any packages that don't correspond to Pulumi resource plugins. if !pulumiPackage.Resource { - continue // the package has no associated resource plugin + continue } - plugins = append(plugins, &pulumirpc.PluginDependency{ + pkg := &pulumirpc.PackageDependency{ + Kind: "resource", Name: pulumiPackage.Name, Version: pulumiPackage.Version, Server: pulumiPackage.Server, - Kind: "resource", - }) + } + if pulumiPackage.Parameterization != nil { + pkg.Parameterization = &pulumirpc.PackageParameterization{ + Name: pulumiPackage.Parameterization.Name, + Version: pulumiPackage.Parameterization.Version, + Value: pulumiPackage.Parameterization.Value, + } + } + + pkgs = append(pkgs, pkg) } - logging.V(5).Infof("GetRequiredPlugins: plugins=%v", plugins) + logging.V(5).Infof("GetRequiredPackages: packages=%v", pkgs) + return &pulumirpc.GetRequiredPackagesResponse{Packages: pkgs}, nil +} - return &pulumirpc.GetRequiredPluginsResponse{Plugins: plugins}, nil +// GetRequiredPlugins computes the complete set of anticipated plugins required by a program. +func (host *javaLanguageHost) GetRequiredPlugins( + context.Context, + *pulumirpc.GetRequiredPluginsRequest, +) (*pulumirpc.GetRequiredPluginsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRequiredPlugins not implemented") } func (host *javaLanguageHost) determinePulumiPackages( ctx context.Context, - req *pulumirpc.GetRequiredPluginsRequest, + programDirectory string, ) ([]plugin.PulumiPluginJSON, error) { logging.V(3).Infof("GetRequiredPlugins: Determining Pulumi plugins") @@ -213,7 +223,7 @@ func (host *javaLanguageHost) determinePulumiPackages( cmd := exec.Cmd args := exec.PluginArgs quiet := true - output, err := host.runJavaCommand(ctx, req.Info.ProgramDirectory, cmd, args, quiet) + output, err := host.runJavaCommand(ctx, programDirectory, cmd, args, quiet) if err != nil { // Plugin determination is an advisory feature so it does not need to escalate to an error. logging.V(3).Infof("language host could not run plugin discovery command successfully, "+ diff --git a/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/Pulumi.yaml b/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/Pulumi.yaml new file mode 100644 index 00000000000..b5f00107f8e --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/Pulumi.yaml @@ -0,0 +1,2 @@ +name: l2-parameterized-resource +runtime: java diff --git a/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/pom.xml b/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/pom.xml new file mode 100644 index 00000000000..d4ee037dcbf --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + com.pulumi + l2-parameterized-resource + 1.0-SNAPSHOT + + + UTF-8 + 11 + 11 + 11 + generated_program.App + + + + + + repository-0 + REPOSITORY + + + + + + com.pulumi + pulumi + CORE.VERSION + + + com.pulumi + subpackage + 2.0.0 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + + + + true + ${mainClass} + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.4.2 + + + + true + ${mainClass} + + + + jar-with-dependencies + + + + + make-my-jar-with-dependencies + package + + single + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + ${mainClass} + ${mainArgs} + + + + org.apache.maven.plugins + maven-wrapper-plugin + 3.1.1 + + 3.8.5 + + + + + \ No newline at end of file diff --git a/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/src/main/java/generated_program/App.java b/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/src/main/java/generated_program/App.java new file mode 100644 index 00000000000..cdc151be70b --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/projects/l2-parameterized-resource/src/main/java/generated_program/App.java @@ -0,0 +1,25 @@ +package generated_program; + +import com.pulumi.Context; +import com.pulumi.Pulumi; +import com.pulumi.core.Output; +import com.pulumi.subpackage.HelloWorld; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class App { + public static void main(String[] args) { + Pulumi.run(App::stack); + } + + public static void stack(Context ctx) { + // The resource name is based on the parameter value + var example = new HelloWorld("example"); + + ctx.export("parameterValue", example.parameterValue()); + } +} diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/alpha-3.0.0-alpha.1.internal/build.gradle b/pkg/cmd/pulumi-language-java/testdata/sdks/alpha-3.0.0-alpha.1.internal/build.gradle index 18bb0cb239f..10e858fdda2 100644 --- a/pkg/cmd/pulumi-language-java/testdata/sdks/alpha-3.0.0-alpha.1.internal/build.gradle +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/alpha-3.0.0-alpha.1.internal/build.gradle @@ -67,11 +67,13 @@ def genPulumiResources = tasks.register('genPulumiResources') { def outDir = file("$resourcesDir/$subDir") outDir.mkdirs() new File(outDir, "version.txt").text = resolvedVersion - def info = new Object() - info.metaClass.resource = true - info.metaClass.name = "alpha" - info.metaClass.version = resolvedVersion - def infoJson = new groovy.json.JsonBuilder(info).toPrettyString() + def builder = new groovy.json.JsonBuilder() + builder { + resource true + name "alpha" + version resolvedVersion + } + def infoJson = builder.toPrettyString() new File(outDir, "plugin.json").text = infoJson } } @@ -152,4 +154,4 @@ if (signingKey) { useInMemoryPgpKeys(signingKey, signingPassword) sign publishing.publications.mainPublication } -} +} \ No newline at end of file diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/simple-2.0.0/build.gradle b/pkg/cmd/pulumi-language-java/testdata/sdks/simple-2.0.0/build.gradle index f6d105d2220..f48b100bd18 100644 --- a/pkg/cmd/pulumi-language-java/testdata/sdks/simple-2.0.0/build.gradle +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/simple-2.0.0/build.gradle @@ -67,11 +67,13 @@ def genPulumiResources = tasks.register('genPulumiResources') { def outDir = file("$resourcesDir/$subDir") outDir.mkdirs() new File(outDir, "version.txt").text = resolvedVersion - def info = new Object() - info.metaClass.resource = true - info.metaClass.name = "simple" - info.metaClass.version = resolvedVersion - def infoJson = new groovy.json.JsonBuilder(info).toPrettyString() + def builder = new groovy.json.JsonBuilder() + builder { + resource true + name "simple" + version resolvedVersion + } + def infoJson = builder.toPrettyString() new File(outDir, "plugin.json").text = infoJson } } @@ -152,4 +154,4 @@ if (signingKey) { useInMemoryPgpKeys(signingKey, signingPassword) sign publishing.publications.mainPublication } -} +} \ No newline at end of file diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/README.md b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/README.md new file mode 100644 index 00000000000..8d1c8b69c3f --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/README.md @@ -0,0 +1 @@ + diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/build.gradle b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/build.gradle new file mode 100644 index 00000000000..6a60a88d9bb --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/build.gradle @@ -0,0 +1,162 @@ +// *** WARNING: this file was generated by pulumi-java-gen *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +plugins { + id("signing") + id("java-library") + id("maven-publish") +} + +group = "com.pulumi" + +def resolvedVersion = System.getenv("PACKAGE_VERSION") ?: + (project.version == "unspecified" + ? "2.0.0" + : project.version) + +def signingKey = System.getenv("SIGNING_KEY") +def signingPassword = System.getenv("SIGNING_PASSWORD") +def publishRepoURL = System.getenv("PUBLISH_REPO_URL") +def publishRepoUsername = System.getenv("PUBLISH_REPO_USERNAME") +def publishRepoPassword = System.getenv("PUBLISH_REPO_PASSWORD") + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} + +compileJava { + options.fork = true + options.forkOptions.jvmArgs.addAll(["-Xmx16g"]) + options.encoding = "UTF-8" +} + +repositories { + maven { + url("REPOSITORY") + } + mavenLocal() + maven { // The google mirror is less flaky than mavenCentral() + url("https://maven-central.storage-download.googleapis.com/maven2/") + } + mavenCentral() +} + +dependencies { + implementation("com.google.code.findbugs:jsr305:3.0.2") + implementation("com.google.code.gson:gson:2.8.9") + implementation("com.pulumi:pulumi:CORE.VERSION") +} + +task sourcesJar(type: Jar) { + from sourceSets.main.allJava + archiveClassifier.set('sources') +} + +task javadocJar(type: Jar) { + from javadoc + archiveClassifier.set('javadoc') + zip64 = true +} + +def genPulumiResources = tasks.register('genPulumiResources') { + doLast { + def resourcesDir = sourceSets.main.output.resourcesDir + def subDir = project.name.replace(".", "/") + def outDir = file("$resourcesDir/$subDir") + outDir.mkdirs() + new File(outDir, "version.txt").text = resolvedVersion + def builder = new groovy.json.JsonBuilder() + builder { + resource true + name "parameterized" + version "1.2.3" + parameterization { + name "subpackage" + version resolvedVersion + value "SGVsbG9Xb3JsZA==" + } + } + def infoJson = builder.toPrettyString() + new File(outDir, "plugin.json").text = infoJson + } +} + +jar.configure { + dependsOn genPulumiResources +} + +publishing { + publications { + mainPublication(MavenPublication) { + groupId = "com.pulumi" + artifactId = "subpackage" + version = resolvedVersion + from components.java + artifact sourcesJar + artifact javadocJar + + pom { + inceptionYear = "" + name = "" + packaging = "jar" + description = " " + + url = "https://example.com" + + scm { + connection = "https://example.com" + developerConnection = "https://example.com" + url = "https://example.com" + } + + licenses { + license { + name = "" + url = "" + } + } + + developers { + developer { + id = "" + name = "" + email = "" + } + } + } + } + } + + if (publishRepoURL) { + repositories { + maven { + name = "PublishRepo" + url = publishRepoURL + credentials { + username = publishRepoUsername + password = publishRepoPassword + } + } + } + } +} + +javadoc { + if (JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } + options.jFlags("-Xmx8g", "-Xms512m") +} + +jar { + zip64 = true +} + +if (signingKey) { + signing { + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.mainPublication + } +} \ No newline at end of file diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/settings.gradle b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/settings.gradle new file mode 100644 index 00000000000..a69a846660e --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/settings.gradle @@ -0,0 +1,14 @@ +// *** WARNING: this file was generated by pulumi-java-gen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +pluginManagement { + repositories { + maven { // The google mirror is less flaky than mavenCentral() + url("https://maven-central.storage-download.googleapis.com/maven2/") + } + gradlePluginPortal() + } +} + +rootProject.name = "com.pulumi.subpackage" +include("lib") diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorld.java b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorld.java new file mode 100644 index 00000000000..2bf3f73fdbc --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorld.java @@ -0,0 +1,78 @@ +// *** WARNING: this file was generated by pulumi-language-java. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.subpackage; + +import com.pulumi.core.Output; +import com.pulumi.core.annotations.Export; +import com.pulumi.core.annotations.ResourceType; +import com.pulumi.core.internal.Codegen; +import com.pulumi.subpackage.HelloWorldArgs; +import com.pulumi.subpackage.Utilities; +import java.lang.String; +import javax.annotation.Nullable; + +@ResourceType(type="subpackage:index:HelloWorld") +public class HelloWorld extends com.pulumi.resources.CustomResource { + @Export(name="parameterValue", refs={String.class}, tree="[0]") + private Output parameterValue; + + public Output parameterValue() { + return this.parameterValue; + } + + /** + * + * @param name The _unique_ name of the resulting resource. + */ + public HelloWorld(java.lang.String name) { + this(name, HelloWorldArgs.Empty); + } + /** + * + * @param name The _unique_ name of the resulting resource. + * @param args The arguments to use to populate this resource's properties. + */ + public HelloWorld(java.lang.String name, @Nullable HelloWorldArgs args) { + this(name, args, null); + } + /** + * + * @param name The _unique_ name of the resulting resource. + * @param args The arguments to use to populate this resource's properties. + * @param options A bag of options that control this resource's behavior. + */ + public HelloWorld(java.lang.String name, @Nullable HelloWorldArgs args, @Nullable com.pulumi.resources.CustomResourceOptions options) { + super("subpackage:index:HelloWorld", name, makeArgs(args, options), makeResourceOptions(options, Codegen.empty()), false, Utilities.getPackageRef()); + } + + private HelloWorld(java.lang.String name, Output id, @Nullable com.pulumi.resources.CustomResourceOptions options) { + super("subpackage:index:HelloWorld", name, null, makeResourceOptions(options, id), false, Utilities.getPackageRef()); + } + + private static HelloWorldArgs makeArgs(@Nullable HelloWorldArgs args, @Nullable com.pulumi.resources.CustomResourceOptions options) { + if (options != null && options.getUrn().isPresent()) { + return null; + } + return args == null ? HelloWorldArgs.Empty : args; + } + + private static com.pulumi.resources.CustomResourceOptions makeResourceOptions(@Nullable com.pulumi.resources.CustomResourceOptions options, @Nullable Output id) { + var defaultOptions = com.pulumi.resources.CustomResourceOptions.builder() + .version(Utilities.getVersion()) + .build(); + return com.pulumi.resources.CustomResourceOptions.merge(defaultOptions, options, id); + } + + /** + * Get an existing Host resource's state with the given name, ID, and optional extra + * properties used to qualify the lookup. + * + * @param name The _unique_ name of the resulting resource. + * @param id The _unique_ provider ID of the resource to lookup. + * @param options Optional settings to control the behavior of the CustomResource. + */ + public static HelloWorld get(java.lang.String name, Output id, @Nullable com.pulumi.resources.CustomResourceOptions options) { + return new HelloWorld(name, id, options); + } +} diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorldArgs.java b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorldArgs.java new file mode 100644 index 00000000000..bf93d14c7f6 --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/HelloWorldArgs.java @@ -0,0 +1,28 @@ +// *** WARNING: this file was generated by pulumi-language-java. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.subpackage; + + + + +public final class HelloWorldArgs extends com.pulumi.resources.ResourceArgs { + + public static final HelloWorldArgs Empty = new HelloWorldArgs(); + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private HelloWorldArgs $; + + public Builder() { + $ = new HelloWorldArgs(); + } + public HelloWorldArgs build() { + return $; + } + } + +} diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Provider.java b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Provider.java new file mode 100644 index 00000000000..7a5a2979488 --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Provider.java @@ -0,0 +1,54 @@ +// *** WARNING: this file was generated by pulumi-language-java. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.subpackage; + +import com.pulumi.core.Output; +import com.pulumi.core.annotations.ResourceType; +import com.pulumi.core.internal.Codegen; +import com.pulumi.subpackage.ProviderArgs; +import com.pulumi.subpackage.Utilities; +import javax.annotation.Nullable; + +@ResourceType(type="pulumi:providers:subpackage") +public class Provider extends com.pulumi.resources.ProviderResource { + /** + * + * @param name The _unique_ name of the resulting resource. + */ + public Provider(java.lang.String name) { + this(name, ProviderArgs.Empty); + } + /** + * + * @param name The _unique_ name of the resulting resource. + * @param args The arguments to use to populate this resource's properties. + */ + public Provider(java.lang.String name, @Nullable ProviderArgs args) { + this(name, args, null); + } + /** + * + * @param name The _unique_ name of the resulting resource. + * @param args The arguments to use to populate this resource's properties. + * @param options A bag of options that control this resource's behavior. + */ + public Provider(java.lang.String name, @Nullable ProviderArgs args, @Nullable com.pulumi.resources.CustomResourceOptions options) { + super("subpackage", name, makeArgs(args, options), makeResourceOptions(options, Codegen.empty()), false, Utilities.getPackageRef()); + } + + private static ProviderArgs makeArgs(@Nullable ProviderArgs args, @Nullable com.pulumi.resources.CustomResourceOptions options) { + if (options != null && options.getUrn().isPresent()) { + return null; + } + return args == null ? ProviderArgs.Empty : args; + } + + private static com.pulumi.resources.CustomResourceOptions makeResourceOptions(@Nullable com.pulumi.resources.CustomResourceOptions options, @Nullable Output id) { + var defaultOptions = com.pulumi.resources.CustomResourceOptions.builder() + .version(Utilities.getVersion()) + .build(); + return com.pulumi.resources.CustomResourceOptions.merge(defaultOptions, options, id); + } + +} diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/ProviderArgs.java b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/ProviderArgs.java new file mode 100644 index 00000000000..91c0cae41c8 --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/ProviderArgs.java @@ -0,0 +1,63 @@ +// *** WARNING: this file was generated by pulumi-language-java. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.subpackage; + +import com.pulumi.core.Output; +import com.pulumi.core.annotations.Import; +import java.lang.String; +import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; + + +public final class ProviderArgs extends com.pulumi.resources.ResourceArgs { + + public static final ProviderArgs Empty = new ProviderArgs(); + + @Import(name="text") + private @Nullable Output text; + + public Optional> text() { + return Optional.ofNullable(this.text); + } + + private ProviderArgs() {} + + private ProviderArgs(ProviderArgs $) { + this.text = $.text; + } + + public static Builder builder() { + return new Builder(); + } + public static Builder builder(ProviderArgs defaults) { + return new Builder(defaults); + } + + public static final class Builder { + private ProviderArgs $; + + public Builder() { + $ = new ProviderArgs(); + } + + public Builder(ProviderArgs defaults) { + $ = new ProviderArgs(Objects.requireNonNull(defaults)); + } + + public Builder text(@Nullable Output text) { + $.text = text; + return this; + } + + public Builder text(String text) { + return text(Output.of(text)); + } + + public ProviderArgs build() { + return $; + } + } + +} diff --git a/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Utilities.java b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Utilities.java new file mode 100644 index 00000000000..17fd9b5e44e --- /dev/null +++ b/pkg/cmd/pulumi-language-java/testdata/sdks/subpackage-2.0.0/src/main/java/com/pulumi/subpackage/Utilities.java @@ -0,0 +1,129 @@ +// *** WARNING: this file was generated by pulumi-language-java. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.subpackage; + + + + + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.Optional; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import com.pulumi.core.internal.Environment; +import com.pulumi.deployment.InvokeOptions; +import com.pulumi.deployment.InvokeOutputOptions; + +import java.util.concurrent.CompletableFuture; +import com.pulumi.deployment.Deployment; + + +public class Utilities { + + public static Optional getEnv(java.lang.String... names) { + for (var n : names) { + var value = Environment.getEnvironmentVariable(n); + if (value.isValue()) { + return Optional.of(value.value()); + } + } + return Optional.empty(); + } + + public static Optional getEnvBoolean(java.lang.String... names) { + for (var n : names) { + var value = Environment.getBooleanEnvironmentVariable(n); + if (value.isValue()) { + return Optional.of(value.value()); + } + } + return Optional.empty(); + } + + public static Optional getEnvInteger(java.lang.String... names) { + for (var n : names) { + var value = Environment.getIntegerEnvironmentVariable(n); + if (value.isValue()) { + return Optional.of(value.value()); + } + } + return Optional.empty(); + } + + public static Optional getEnvDouble(java.lang.String... names) { + for (var n : names) { + var value = Environment.getDoubleEnvironmentVariable(n); + if (value.isValue()) { + return Optional.of(value.value()); + } + } + return Optional.empty(); + } + + public static InvokeOptions withVersion(@Nullable InvokeOptions options) { + if (options != null && options.getVersion().isPresent()) { + return options; + } + return new InvokeOptions( + options == null ? null : options.getParent().orElse(null), + options == null ? null : options.getProvider().orElse(null), + getVersion() + ); + } + + public static InvokeOutputOptions withVersion(@Nullable InvokeOutputOptions options) { + if (options != null && options.getVersion().isPresent()) { + return options; + } + return new InvokeOutputOptions( + options == null ? null : options.getParent().orElse(null), + options == null ? null : options.getProvider().orElse(null), + getVersion(), + options == null ? null : options.getDependsOn() + ); + } + + private static final java.lang.String version; + public static java.lang.String getVersion() { + return version; + } + + static { + var resourceName = "com/pulumi/subpackage/version.txt"; + var versionFile = Utilities.class.getClassLoader().getResourceAsStream(resourceName); + if (versionFile == null) { + throw new IllegalStateException( + java.lang.String.format("expected resource '%s' on Classpath, not found", resourceName) + ); + } + version = new BufferedReader(new InputStreamReader(versionFile)) + .lines() + .collect(Collectors.joining("\n")) + .trim(); + } + + private static final CompletableFuture packageRef; + public static CompletableFuture getPackageRef() { + return packageRef; + } + + static { + packageRef = Deployment.getInstance().registerPackage( + // Base provider name + "parameterized", + // Base provider version + "1.2.3", + // Base provider download URL + "", + // Package name + "subpackage", + // Package version + getVersion(), + // Parameter + "SGVsbG9Xb3JsZA==" + ); + } + +} diff --git a/pkg/codegen/java/build.gradle.template b/pkg/codegen/java/build.gradle.template index f6b17ff73dd..23084a9cb04 100644 --- a/pkg/codegen/java/build.gradle.template +++ b/pkg/codegen/java/build.gradle.template @@ -17,7 +17,11 @@ group = "{{ .GroupID }}" def resolvedVersion = System.getenv("PACKAGE_VERSION") ?: (project.version == "unspecified" + {{- if .Parameterization }} + ? "{{ .Parameterization.Version }}" + {{- else }} ? "{{ .Version }}" + {{- end }} : project.version) def signingKey = System.getenv("SIGNING_KEY") @@ -79,14 +83,25 @@ def genPulumiResources = tasks.register('genPulumiResources') { def outDir = file("$resourcesDir/$subDir") outDir.mkdirs() new File(outDir, "version.txt").text = resolvedVersion - def info = new Object() - info.metaClass.resource = true - info.metaClass.name = "{{ .ArtifactID }}" - {{- if .PluginDownloadURL }} - info.metaClass.server = "{{ .PluginDownloadURL }}" - {{- end }} - info.metaClass.version = resolvedVersion - def infoJson = new groovy.json.JsonBuilder(info).toPrettyString() + def builder = new groovy.json.JsonBuilder() + builder { + resource true + name "{{ .Name }}" + {{- if .PluginDownloadURL }} + server "{{ .PluginDownloadURL }}" + {{- end }} + {{- if .Parameterization }} + version "{{ .Version }}" + parameterization { + name "{{ .Parameterization.Name }}" + version resolvedVersion + value "{{ .Parameterization.Value }}" + } + {{- else }} + version resolvedVersion + {{- end }} + } + def infoJson = builder.toPrettyString() new File(outDir, "plugin.json").text = infoJson } } @@ -99,7 +114,11 @@ publishing { publications { mainPublication(MavenPublication) { groupId = "{{ .GroupID }}" - artifactId = "{{ .ArtifactID }}" + {{- if .Parameterization }} + artifactId = "{{ .Parameterization.Name }}" + {{- else }} + artifactId = "{{ .Name }}" + {{- end }} version = resolvedVersion from components.java artifact sourcesJar @@ -200,4 +219,4 @@ if (signingKey) { useInMemoryPgpKeys(signingKey, signingPassword) sign publishing.publications.mainPublication } -} +} \ No newline at end of file diff --git a/pkg/codegen/java/templates_gradle.go b/pkg/codegen/java/templates_gradle.go index f5774ff04ad..10c303347ab 100644 --- a/pkg/codegen/java/templates_gradle.go +++ b/pkg/codegen/java/templates_gradle.go @@ -5,6 +5,7 @@ package java import ( "bytes" _ "embed" + "encoding/base64" "fmt" "net/url" "slices" @@ -66,9 +67,9 @@ var settingsGradleTemplate string var buildGradleTemplate string type gradleTemplateContext struct { + Name string Version string GroupID string - ArtifactID string ProjectName string RootProjectName string ProjectURL string @@ -86,6 +87,13 @@ type gradleTemplateContext struct { GradleNexusPublishPluginVersion string GradleTestJUnitPlatformEnabled bool PluginDownloadURL string + Parameterization *gradleTemplateParameterization +} + +type gradleTemplateParameterization struct { + Name string + Version string + Value string } func newGradleTemplateContext( @@ -93,7 +101,7 @@ func newGradleTemplateContext( packageInfo *PackageInfo, ) gradleTemplateContext { ctx := gradleTemplateContext{ - ArtifactID: pkg.Name, + Name: pkg.Name, ProjectDescription: pkg.Description, ProjectURL: pkg.Repository, ProjectGitURL: formatGitURL(pkg.Repository), @@ -101,17 +109,28 @@ func newGradleTemplateContext( PluginDownloadURL: pkg.PluginDownloadURL, } - if packageInfo.GradleNexusPublishPluginVersion != "" { - ctx.GradleNexusPublishPluginEnabled = true - ctx.GradleNexusPublishPluginVersion = packageInfo.GradleNexusPublishPluginVersion - } - if pkg.Version != nil { ctx.Version = pkg.Version.String() } else { ctx.Version = "0.0.1" } + if pkg.Parameterization != nil { + ctx.Parameterization = &gradleTemplateParameterization{ + Name: ctx.Name, + Version: ctx.Version, + Value: base64.StdEncoding.EncodeToString(pkg.Parameterization.Parameter), + } + + ctx.Name = pkg.Parameterization.BaseProvider.Name + ctx.Version = pkg.Parameterization.BaseProvider.Version.String() + } + + if packageInfo.GradleNexusPublishPluginVersion != "" { + ctx.GradleNexusPublishPluginEnabled = true + ctx.GradleNexusPublishPluginVersion = packageInfo.GradleNexusPublishPluginVersion + } + if packageInfo.Repositories != nil { ctx.Repositories = packageInfo.Repositories slices.Sort(ctx.Repositories) @@ -141,7 +160,7 @@ func newGradleTemplateContext( ctx.DeveloperName = "Pulumi" ctx.DeveloperEmail = "support@pulumi.com" ctx.ProjectInceptionYear = "2022" - ctx.ProjectName = fmt.Sprintf("pulumi-%s", ctx.ArtifactID) + ctx.ProjectName = fmt.Sprintf("pulumi-%s", ctx.Name) } if ctx.RootProjectName == "" { diff --git a/pkg/codegen/java/templates_gradle_test.go b/pkg/codegen/java/templates_gradle_test.go index 48d9da0b76c..e66a52eb569 100644 --- a/pkg/codegen/java/templates_gradle_test.go +++ b/pkg/codegen/java/templates_gradle_test.go @@ -16,7 +16,7 @@ func TestNewGradleTemplateContext(t *testing.T) { tctx := newGradleTemplateContext(pkg, info) assert.Equal(t, "0.37.1", tctx.Version) assert.Equal(t, "com.pulumi", tctx.GroupID) - assert.Equal(t, "eks", tctx.ArtifactID) + assert.Equal(t, "eks", tctx.Name) assert.Equal(t, "https://github.com/pulumi/pulumi-eks", tctx.ProjectURL) assert.Equal(t, "git@github.com/pulumi/pulumi-eks.git", tctx.ProjectGitURL) assert.Equal(t, "Pulumi Amazon Web Services (AWS) EKS Components.", tctx.ProjectDescription) diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPlugin.java b/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPlugin.java index 431790bb2b9..4c68932b3c2 100644 --- a/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPlugin.java +++ b/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPlugin.java @@ -2,6 +2,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.gson.Gson; +import com.google.gson.JsonObject; import com.pulumi.core.internal.Optionals; import javax.annotation.Nullable; @@ -14,8 +15,8 @@ * Represents additional information about a package's associated Pulumi plugin. * For Java, the content is inside com/pulumi/{@literal }/plugin.json file inside the package. *

- * Keep in sync with pulumi/sdk/go/common/resource/plugin/plugin.go:51 - **/ + * Keep in sync with pulumi/sdk/go/common/resource/plugin/plugin.go's PulumiPluginJSON. + */ public final class PulumiPlugin { public final boolean resource; @@ -25,20 +26,35 @@ public final class PulumiPlugin { public final String version; @Nullable public final String server; + @Nullable + public final PulumiPluginParameterization parameterization; /** * Represents additional information about a package's associated Pulumi plugin. * - * @param resource Indicates whether the package has an associated resource plugin. Set to false indicates no plugin. - * @param name Optional plugin name. If not set, the plugin name is derived from the package name. - * @param version Optional plugin version. If not set, the version is derived from the package version (if possible). - * @param server Optional plugin server. If not set, the default server is used when installing the plugin. + * @param resource + * Indicates whether the package has an associated resource plugin. Set to false indicates no plugin. + * @param name + * Optional plugin name. If not set, the plugin name is derived from the package name. + * @param version + * Optional plugin version. If not set, the version is derived from the package version (if possible). + * @param server + * Optional plugin server. If not set, the default server is used when installing the plugin. + * @param parameterization + * Optional parameterization information for the plugin. */ - public PulumiPlugin(boolean resource, @Nullable String name, @Nullable String version, @Nullable String server) { + public PulumiPlugin( + boolean resource, + @Nullable String name, + @Nullable String version, + @Nullable String server, + @Nullable PulumiPluginParameterization parameterization + ) { this.resource = resource; this.name = name; this.version = version; this.server = server; + this.parameterization = parameterization; } public static PulumiPlugin resolve(@Nullable PulumiPlugins.RawResource plugin, @Nullable PulumiPlugins.RawResource rawVersion) { @@ -70,7 +86,11 @@ public static PulumiPlugin resolve(@Nullable PulumiPlugins.RawResource plugin, @ .flatMap(Map.Entry::getValue) .map(pulumiPlugin -> pulumiPlugin.server) .orElse(null); - return new PulumiPlugin(resource, name, version, server); + var parameterization = maybePlugin + .flatMap(Map.Entry::getValue) + .map(pulumiPlugin -> pulumiPlugin.parameterization) + .orElse(null); + return new PulumiPlugin(resource, name, version, server, parameterization); } @Override @@ -81,12 +101,13 @@ public boolean equals(Object o) { return resource == that.resource && Objects.equals(name, that.name) && Objects.equals(version, that.version) - && Objects.equals(server, that.server); + && Objects.equals(server, that.server) + && Objects.equals(parameterization, that.parameterization); } @Override public int hashCode() { - return Objects.hash(resource, name, version, server); + return Objects.hash(resource, name, version, server, parameterization); } @Override @@ -96,6 +117,7 @@ public String toString() { .add("name='" + name + "'") .add("version='" + version + "'") .add("server='" + server + "'") + .add("parameterization=" + parameterization) .toString(); } @@ -103,6 +125,18 @@ public String toString() { @VisibleForTesting static PulumiPlugin fromJson(String json) { var gson = new Gson(); - return gson.fromJson(json, PulumiPlugin.class); + + var plugin = gson.fromJson(json, PulumiPlugin.class); + if (plugin == null) { + return plugin; + } + + var raw = gson.fromJson(json, JsonObject.class); + var parameterization = raw.has("parameterization") + ? gson.fromJson(raw.get("parameterization"), PulumiPluginParameterization.class) + : null; + + plugin = new PulumiPlugin(plugin.resource, plugin.name, plugin.version, plugin.server, parameterization); + return plugin; } -} +} \ No newline at end of file diff --git a/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPluginParameterization.java b/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPluginParameterization.java new file mode 100644 index 00000000000..893c329358d --- /dev/null +++ b/sdk/java/pulumi/src/main/java/com/pulumi/bootstrap/internal/PulumiPluginParameterization.java @@ -0,0 +1,57 @@ +package com.pulumi.bootstrap.internal; + +import com.google.common.annotations.VisibleForTesting; +import com.google.gson.Gson; + +import javax.annotation.Nullable; +import java.util.Objects; +import java.util.StringJoiner; + +/** + * Represents information about a parameterization for a Pulumi plugin. + *

+ * Keep in sync with pulumi/sdk/go/common/resource/plugin/plugin.go's PulumiParameterizationJSON. + */ +public final class PulumiPluginParameterization { + + public final String name; + public final String version; + public final String value; + + public PulumiPluginParameterization(String name, String version, String value) { + this.name = name; + this.version = version; + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PulumiPluginParameterization that = (PulumiPluginParameterization) o; + return Objects.equals(name, that.name) + && Objects.equals(version, that.version) + && Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(name, version, value); + } + + @Override + public String toString() { + return new StringJoiner(", ", PulumiPluginParameterization.class.getSimpleName() + "[", "]") + .add("name='" + name + "'") + .add("version='" + version + "'") + .add("value='" + value + "'") + .toString(); + } + + @Nullable + @VisibleForTesting + static PulumiPluginParameterization fromJson(String json) { + var gson = new Gson(); + return gson.fromJson(json, PulumiPluginParameterization.class); + } +} \ No newline at end of file diff --git a/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginTest.java b/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginTest.java index 21e990ec455..bc38367af47 100644 --- a/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginTest.java +++ b/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginTest.java @@ -93,19 +93,19 @@ private static Stream testUnmarshalling() { arguments("", null, ""), arguments( "{}", - new PulumiPlugin(false, null, null, null), + new PulumiPlugin(false, null, null, null, null), "{\"resource\":false}"), arguments( "{\n" + " \"resource\":true\n" + "}", - new PulumiPlugin(true, null, null, null), + new PulumiPlugin(true, null, null, null, null), "{\"resource\":true}"), arguments("{\n" + " \"resource\": true,\n" + " \"name\": \"unittest\"\n" + "}", - new PulumiPlugin(true, "unittest", null, null), + new PulumiPlugin(true, "unittest", null, null, null), "{\"resource\":true,\"name\":\"unittest\"}"), arguments( "{\n" + @@ -113,7 +113,7 @@ private static Stream testUnmarshalling() { " \"name\": \"unittest\",\n" + " \"version\": \"1.1.1\"\n" + "}", - new PulumiPlugin(true, "unittest", "1.1.1", null), + new PulumiPlugin(true, "unittest", "1.1.1", null, null), "{\"resource\":true,\"name\":\"unittest\",\"version\":\"1.1.1\"}"), arguments( "{\n" + @@ -122,8 +122,22 @@ private static Stream testUnmarshalling() { " \"version\": \"1.1.1\",\n" + " \"server\": \"https://example.org\"\n" + "}", - new PulumiPlugin(true, "unittest", "1.1.1", "https://example.org"), - "{\"resource\":true,\"name\":\"unittest\",\"version\":\"1.1.1\",\"server\":\"https://example.org\"}") + new PulumiPlugin(true, "unittest", "1.1.1", "https://example.org", null), + "{\"resource\":true,\"name\":\"unittest\",\"version\":\"1.1.1\",\"server\":\"https://example.org\"}"), + arguments( + "{\n" + + " \"resource\": true,\n" + + " \"name\": \"unittest\",\n" + + " \"version\": \"1.1.1\",\n" + + " \"parameterization\": {\n" + + " \"name\": \"parameterized\",\n" + + " \"version\": \"2.2.2\",\n" + + " \"value\": \"value\"\n" + + " }\n" + + "}", + new PulumiPlugin(true, "unittest", "1.1.1", null, + new PulumiPluginParameterization("parameterized", "2.2.2", "value")), + "{\"resource\":true,\"name\":\"unittest\",\"version\":\"1.1.1\",\"parameterization\":{\"name\":\"parameterized\",\"version\":\"2.2.2\",\"value\":\"value\"}}") ); } diff --git a/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginsTest.java b/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginsTest.java index be9cc8c17d8..829959ae211 100644 --- a/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginsTest.java +++ b/sdk/java/pulumi/src/test/java/com/pulumi/bootstrap/internal/PulumiPluginsTest.java @@ -17,7 +17,7 @@ void testFromClasspath() { var packages = PulumiPlugins.fromClasspath(PulumiPluginsTest.class); assertThat(packages).hasSize(1).containsEntry( // minimal example, it derives both name and version - "com/pulumi/unittest", new PulumiPlugin(true, "unittest", "1.1.1", null) + "com/pulumi/unittest", new PulumiPlugin(true, "unittest", "1.1.1", null, null) ); } } \ No newline at end of file