diff --git a/changelog/@unreleased/pr-2376.v2.yml b/changelog/@unreleased/pr-2376.v2.yml new file mode 100644 index 000000000..02295e956 --- /dev/null +++ b/changelog/@unreleased/pr-2376.v2.yml @@ -0,0 +1,10 @@ +type: feature +feature: + description: |- + java versions preview enhancements + + + support setting preview on a project-by-project basis. + + Fixes #2340 + + fails more elegantly if javaVersions is set on not-the-root. + links: + - https://github.com/palantir/gradle-baseline/pull/2376 diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionExtension.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionExtension.java index a93a53d2d..9e550974f 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionExtension.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionExtension.java @@ -57,6 +57,10 @@ public final void setTarget(int value) { target.set(ChosenJavaVersion.of(value)); } + public final void setTarget(String value) { + target.set(ChosenJavaVersion.fromString(value)); + } + /** Runtime {@link ChosenJavaVersion} for testing and distributions. */ public final Property runtime() { return runtime; @@ -66,6 +70,10 @@ public final void setRuntime(int value) { runtime.set(ChosenJavaVersion.of(value)); } + public final void setRuntime(String value) { + runtime.set(ChosenJavaVersion.fromString(value)); + } + /** * Overrides auto-detection if a value is present to force this module to be a * library ({@code true}) or a distribution {@code false}). diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersions.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersions.java index e80811942..5757c64a2 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersions.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersions.java @@ -56,6 +56,9 @@ public void apply(Project project) { } BaselineJavaVersionsExtension rootExtension = project.getExtensions().create(EXTENSION_NAME, BaselineJavaVersionsExtension.class, project); + project.subprojects(proj -> + proj.getExtensions().create(EXTENSION_NAME, SubprojectBaselineJavaVersionsExtension.class, proj)); + project.allprojects(proj -> proj.getPluginManager().withPlugin("java", unused -> { proj.getPluginManager().apply(BaselineJavaVersion.class); BaselineJavaVersionExtension projectVersions = diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtension.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtension.java index db984f943..234fd9634 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtension.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtension.java @@ -20,6 +20,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; +import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.provider.Property; import org.gradle.jvm.toolchain.JavaInstallationMetadata; @@ -29,7 +30,7 @@ * Extension named {@code javaVersions} on the root project used to configure all java modules * with consistent java toolchains. */ -public class BaselineJavaVersionsExtension { +public class BaselineJavaVersionsExtension implements BaselineJavaVersionsExtensionSetters { private final Property libraryTarget; private final Property distributionTarget; private final Property runtime; @@ -57,10 +58,22 @@ public final Property libraryTarget() { return libraryTarget; } + @Override public final void setLibraryTarget(int value) { libraryTarget.set(JavaLanguageVersion.of(value)); } + @Override + public final void setLibraryTarget(String value) { + ChosenJavaVersion version = ChosenJavaVersion.fromString(value); + if (version.enablePreview()) { + throw new GradleException("Because code compiled with preview features cannot be run on newer JVMs, " + + "(Java 15 preview cannot be run on Java 17, e.g.) it is unsuitable for use on projects that" + + " are published as libraries."); + } + libraryTarget.set(version.javaLanguageVersion()); + } + /** * Target {@link ChosenJavaVersion} for compilation of code used within distributions, * but not published externally. @@ -69,11 +82,13 @@ public final Property distributionTarget() { return distributionTarget; } + @Override public final void setDistributionTarget(int value) { distributionTarget.set(ChosenJavaVersion.of(value)); } /** Accepts inputs such as '17_PREVIEW'. */ + @Override public final void setDistributionTarget(String value) { distributionTarget.set(ChosenJavaVersion.fromString(value)); } @@ -83,11 +98,13 @@ public final Property runtime() { return runtime; } + @Override public final void setRuntime(int value) { runtime.set(ChosenJavaVersion.of(value)); } /** Accepts inputs such as '17_PREVIEW'. */ + @Override public final void setRuntime(String value) { runtime.set(ChosenJavaVersion.fromString(value)); } @@ -106,7 +123,7 @@ public final void jdks(LazyJdks lazyJdks) { .map(javaInstallationMetadata -> ref -> ref.set(javaInstallationMetadata))); } - public interface LazyJdks { + interface LazyJdks { Optional jdkFor(JavaLanguageVersion javaLanguageVersion, Project project); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtensionSetters.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtensionSetters.java new file mode 100644 index 000000000..b3c069e1a --- /dev/null +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/BaselineJavaVersionsExtensionSetters.java @@ -0,0 +1,37 @@ +/* + * (c) Copyright 2022 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.baseline.plugins.javaversions; + +/** + * This exists to keep the setters on the 'BaselineJavaVersionsExtension' in sync with those on + * 'SubprojectBaselineJavaVersionsExtension'. Ideally it would have a name like 'BaselineJavaVersionsExtension' + * with the main one called 'RootProjectBaselineJavaVersionsExtension', but that class is public API and is depended + * on by other Gradle plugins. + */ +public interface BaselineJavaVersionsExtensionSetters { + void setLibraryTarget(int value); + + void setLibraryTarget(String value); + + void setDistributionTarget(int value); + + void setDistributionTarget(String value); + + void setRuntime(int value); + + void setRuntime(String value); +} diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/SubprojectBaselineJavaVersionsExtension.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/SubprojectBaselineJavaVersionsExtension.java new file mode 100644 index 000000000..e2fd48e0b --- /dev/null +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/javaversions/SubprojectBaselineJavaVersionsExtension.java @@ -0,0 +1,67 @@ +/* + * (c) Copyright 2022 Palantir Technologies Inc. All rights reserved. + * + * 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 com.palantir.baseline.plugins.javaversions; + +import javax.inject.Inject; +import org.gradle.api.GradleException; +import org.gradle.api.Project; + +public class SubprojectBaselineJavaVersionsExtension implements BaselineJavaVersionsExtensionSetters { + private final Project project; + + @Inject + public SubprojectBaselineJavaVersionsExtension(Project project) { + this.project = project; + } + + @Override + public final void setLibraryTarget(int _value) { + throw throwCannotSetFromSubproject(); + } + + @Override + public final void setLibraryTarget(String value) { + throw throwCannotSetFromSubproject(); + } + + @Override + public final void setDistributionTarget(int _value) { + throw throwCannotSetFromSubproject(); + } + + @Override + public final void setDistributionTarget(String _value) { + throw throwCannotSetFromSubproject(); + } + + @Override + public final void setRuntime(int _value) { + throw throwCannotSetFromSubproject(); + } + + @Override + public final void setRuntime(String _value) { + throw throwCannotSetFromSubproject(); + } + + private RuntimeException throwCannotSetFromSubproject() { + throw new GradleException("The javaVersions extension can only be used from the root project." + + " Did you mean javaVersion, which can be used to override on a project-by-project basis?" + + " You used it from " + + project.getName()); + } +} diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineJavaVersionIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineJavaVersionIntegrationTest.groovy index 3972326fe..befc0b909 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineJavaVersionIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineJavaVersionIntegrationTest.groovy @@ -147,6 +147,36 @@ class BaselineJavaVersionIntegrationTest extends IntegrationSpec { assertBytecodeVersion(compiledClass, JAVA_17_BYTECODE, ENABLE_PREVIEW_BYTECODE) } + def 'setting library target to preview version fails'() { + when: + buildFile << ''' + javaVersions { + libraryTarget = '17_PREVIEW' + } + '''.stripIndent(true) + file('src/main/java/Main.java') << java17PreviewCode + + then: + ExecutionResult result = runTasksWithFailure('compileJava', '-i') + result.standardError.contains 'cannot be run on newer JVMs' + } + + def 'java 17 preview on single project works'() { + when: + buildFile << ''' + javaVersion { + runtime = '17_PREVIEW' + target = '17_PREVIEW' + } + '''.stripIndent(true) + file('src/main/java/Main.java') << java17PreviewCode + File compiledClass = new File(projectDir, "build/classes/java/main/Main.class") + + then: + runTasksSuccessfully('compileJava', '-i') + assertBytecodeVersion(compiledClass, JAVA_17_BYTECODE, ENABLE_PREVIEW_BYTECODE) + } + def 'java 17 preview javadoc works'() { when: buildFile << ''' @@ -220,7 +250,7 @@ class BaselineJavaVersionIntegrationTest extends IntegrationSpec { when: buildFile << ''' javaVersions { - libraryTarget = 11 + libraryTarget = '11' } '''.stripIndent(true) file('src/main/java/Main.java') << java11CompatibleCode