Skip to content

pulumi package gen-sdk --language java to generate gradle dependency version ranges #1926

@pose

Description

@pose

Steps to reproduce

  1. Pick up a Pulumi component or provider.
  2. Run pulumi package gen-sdk provider/cmd/my-provider/schema.json --language java --out sdk/

What should happen?

When opening the build.gradle file, the following default dependencies section should be generated:

dependencies {
    implementation("com.google.code.findbugs:jsr305:[3.0.2,4)")
    implementation("com.google.code.gson:gson:[2.8.9,3)")
    implementation("com.pulumi:pulumi:[1.0.0,2)")
}

Notice that a range is used to specify to specify the compatible dependency versions.

What happens instead?

Versions are pinned:

dependencies {
    implementation("com.google.code.findbugs:jsr305:3.0.2")
    implementation("com.google.code.gson:gson:2.8.9")
    implementation("com.pulumi:pulumi:1.0.0")
}

Why does this matter?

Let's say tomorrow someone discovers a security vulnerability on one of our pulumi-java dependencies. For instance, com.google.code.gson:gson:2.8.9. Since we are pinning to that specific version on our build.gradle file, we will need to re-generate all SDKs to point to the updated version (or alternatively, make our customers override this dependency on their side). Instead, If we had specified our dependency with a version range such as com.google.code.gson:gson:[2.8.9,) and a 2.8.10 security patch version was released, Gradle will automatically pick the updated 2.8.10 patch version when building our customer's code without requiring an SDK code change or our users' intervention.


Some context on how Gradle works (not intuitive to me since I am used to other dependency systems which work different):

Specifying dependency versions in Gradle

When you declare a dependency version using the shorthand notation (meaning just the version), then the version is considered a required version:

[...] the selected version cannot be lower than what require accepts, but it can be higher through conflict resolution, even if the higher version has an exclusive upper bound. This is the default behavior for a direct dependency.

This can be verified by running gradle dependencies and seeing the produced dependency version tree. See for instance, what the following blocks generate:

dependencies {
    implementation('org.slf4j:slf4j-api:1.7.15')
}

Means that the minimum version will be 1.7.15 and it can be optimistically upgraded by the engine. However, if there are no other transitive dependencies that require a version greater than 1.7.15, Gradle will pick 1.7.15 instead of the latest and greatest compatible version.

To achieve getting the latest and greatest compatible version (assuming semver), you should write:

dependencies {
    implementation('org.slf4j:slf4j-api:[1.7.15,)')
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions