mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
Add Build-Jdk-Spec to jar and war manifest when building with Gradle
This commit adds a `Build-Jdk-Spec` attribute to the manifest in a jar or war file built with the Spring Boot Gradle plugin. This aligns the Gradle plugin's behavior with the default Maven plugin behavior. This removes the need to set a `BP_JVM_VERSION` environment variable when invoking Cloud Native Buildpacks, as the Paketo buildpacks will honor `Build-Jdk-Spec` in a jar or war manifest to determine the default JVM version. Fixes gh-32829
This commit is contained in:
parent
383d6c897f
commit
c22e76632c
@ -150,6 +150,8 @@ final class JavaPluginAction implements PluginApplicationAction {
|
||||
.provider(() -> (String) bootJar.getManifest().getAttributes().get("Start-Class"));
|
||||
bootJar.getMainClass().convention(resolveMainClassName.flatMap((resolver) -> manifestStartClass.isPresent()
|
||||
? manifestStartClass : resolveMainClassName.get().readMainClassName()));
|
||||
bootJar.getTargetJavaVersion()
|
||||
.set(project.provider(() -> javaPluginExtension(project).getTargetCompatibility()));
|
||||
});
|
||||
}
|
||||
|
||||
@ -158,8 +160,6 @@ final class JavaPluginAction implements PluginApplicationAction {
|
||||
buildImage.setDescription("Builds an OCI image of the application using the output of the bootJar task");
|
||||
buildImage.setGroup(BasePlugin.BUILD_GROUP);
|
||||
buildImage.getArchiveFile().set(bootJar.get().getArchiveFile());
|
||||
buildImage.getTargetJavaVersion()
|
||||
.set(project.provider(() -> javaPluginExtension(project).getTargetCompatibility()));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.ConfigurationContainer;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.plugins.BasePlugin;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.plugins.WarPlugin;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
@ -90,6 +91,8 @@ class WarPluginAction implements PluginApplicationAction {
|
||||
bootWar.getMainClass()
|
||||
.convention(resolveMainClassName.flatMap((resolver) -> manifestStartClass.isPresent()
|
||||
? manifestStartClass : resolveMainClassName.get().readMainClassName()));
|
||||
bootWar.getTargetJavaVersion()
|
||||
.set(project.provider(() -> javaPluginExtension(project).getTargetCompatibility()));
|
||||
});
|
||||
bootWarProvider.map(War::getClasspath);
|
||||
return bootWarProvider;
|
||||
@ -109,4 +112,8 @@ class WarPluginAction implements PluginApplicationAction {
|
||||
this.singlePublishedArtifact.addWarCandidate(bootWar);
|
||||
}
|
||||
|
||||
private JavaPluginExtension javaPluginExtension(Project project) {
|
||||
return project.getExtensions().getByType(JavaPluginExtension.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.gradle.tasks.bundling;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
@ -110,4 +111,13 @@ public interface BootArchive extends Task {
|
||||
*/
|
||||
void setClasspath(FileCollection classpath);
|
||||
|
||||
/**
|
||||
* Returns the target Java version of the project (e.g. as provided by the
|
||||
* {@code targetCompatibility} build property).
|
||||
* @return the target Java version
|
||||
*/
|
||||
@Input
|
||||
@Optional
|
||||
Property<JavaVersion> getTargetJavaVersion();
|
||||
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ class BootArchiveSupport {
|
||||
}
|
||||
|
||||
void configureManifest(Manifest manifest, String mainClass, String classes, String lib, String classPathIndex,
|
||||
String layersIndex) {
|
||||
String layersIndex, String jdkVersion) {
|
||||
Attributes attributes = manifest.getAttributes();
|
||||
attributes.putIfAbsent("Main-Class", this.loaderMainClass);
|
||||
attributes.putIfAbsent("Start-Class", mainClass);
|
||||
@ -98,6 +98,7 @@ class BootArchiveSupport {
|
||||
if (layersIndex != null) {
|
||||
attributes.putIfAbsent("Spring-Boot-Layers-Index", layersIndex);
|
||||
}
|
||||
attributes.putIfAbsent("Build-Jdk-Spec", jdkVersion);
|
||||
}
|
||||
|
||||
private String determineSpringBootVersion() {
|
||||
|
@ -22,7 +22,6 @@ import java.util.Map;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
@ -66,8 +65,6 @@ import org.springframework.util.StringUtils;
|
||||
@DisableCachingByDefault
|
||||
public abstract class BootBuildImage extends DefaultTask {
|
||||
|
||||
private static final String BUILDPACK_JVM_VERSION_KEY = "BP_JVM_VERSION";
|
||||
|
||||
private final Property<PullPolicy> pullPolicy;
|
||||
|
||||
private final String projectName;
|
||||
@ -107,15 +104,6 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
public abstract RegularFileProperty getArchiveFile();
|
||||
|
||||
/**
|
||||
* Returns the target Java version of the project (e.g. as provided by the
|
||||
* {@code targetCompatibility} build property).
|
||||
* @return the target Java version
|
||||
*/
|
||||
@Input
|
||||
@Optional
|
||||
public abstract Property<JavaVersion> getTargetJavaVersion();
|
||||
|
||||
/**
|
||||
* Returns the name of the image that will be built. When {@code null}, the name will
|
||||
* be derived from the {@link Project Project's} {@link Project#getName() name} and
|
||||
@ -340,9 +328,6 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
if (environment != null && !environment.isEmpty()) {
|
||||
request = request.withEnv(environment);
|
||||
}
|
||||
if (this.getTargetJavaVersion().isPresent() && !request.getEnv().containsKey(BUILDPACK_JVM_VERSION_KEY)) {
|
||||
request = request.withEnv(BUILDPACK_JVM_VERSION_KEY, translateTargetJavaVersion());
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -401,8 +386,4 @@ public abstract class BootBuildImage extends DefaultTask {
|
||||
return request;
|
||||
}
|
||||
|
||||
private String translateTargetJavaVersion() {
|
||||
return this.getTargetJavaVersion().get().getMajorVersion() + ".*";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -119,7 +119,8 @@ public abstract class BootJar extends Jar implements BootArchive {
|
||||
@Override
|
||||
public void copy() {
|
||||
this.support.configureManifest(getManifest(), getMainClass().get(), CLASSES_DIRECTORY, LIB_DIRECTORY,
|
||||
CLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX);
|
||||
CLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX,
|
||||
this.getTargetJavaVersion().get().getMajorVersion());
|
||||
super.copy();
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,8 @@ public abstract class BootWar extends War implements BootArchive {
|
||||
@Override
|
||||
public void copy() {
|
||||
this.support.configureManifest(getManifest(), getMainClass().get(), CLASSES_DIRECTORY, LIB_DIRECTORY,
|
||||
CLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX);
|
||||
CLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX,
|
||||
this.getTargetJavaVersion().get().getMajorVersion());
|
||||
super.copy();
|
||||
}
|
||||
|
||||
|
@ -478,6 +478,15 @@ abstract class AbstractBootArchiveIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void javaVersionIsSetInManifest() throws IOException {
|
||||
BuildResult result = this.gradleBuild.build(this.taskName);
|
||||
assertThat(result.task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
try (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0])) {
|
||||
assertThat(jarFile.getManifest().getMainAttributes().getValue("Build-Jdk-Spec")).isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyMainClassApplication() throws IOException {
|
||||
copyApplication("main");
|
||||
}
|
||||
|
@ -73,7 +73,6 @@ class BootBuildImageIntegrationTests {
|
||||
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
assertThat(result.getOutput()).contains("docker.io/library/" + projectName);
|
||||
assertThat(result.getOutput()).contains("---> Test Info buildpack building");
|
||||
assertThat(result.getOutput()).contains("env: BP_JVM_VERSION=8.*");
|
||||
assertThat(result.getOutput()).contains("Network status: HTTP/2 200");
|
||||
assertThat(result.getOutput()).contains("---> Test Info buildpack done");
|
||||
removeImages(projectName);
|
||||
@ -88,7 +87,6 @@ class BootBuildImageIntegrationTests {
|
||||
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
assertThat(result.getOutput()).contains("docker.io/library/" + projectName);
|
||||
assertThat(result.getOutput()).contains("---> Test Info buildpack building");
|
||||
assertThat(result.getOutput()).contains("env: BP_JVM_VERSION=8.*");
|
||||
assertThat(result.getOutput()).contains("---> Test Info buildpack done");
|
||||
File buildLibs = new File(this.gradleBuild.getProjectDir(), "build/libs");
|
||||
assertThat(buildLibs.listFiles())
|
||||
|
@ -21,7 +21,6 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Project;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -139,27 +138,6 @@ class BootBuildImageTests {
|
||||
.hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenJavaVersionIsSetInEnvironmentItIsIncludedInTheRequest() {
|
||||
this.buildImage.getEnvironment().put("BP_JVM_VERSION", "from-env");
|
||||
this.buildImage.getTargetJavaVersion().set(JavaVersion.VERSION_1_8);
|
||||
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("BP_JVM_VERSION", "from-env").hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTargetCompatibilityIsSetThenJavaVersionIsIncludedInTheRequest() {
|
||||
this.buildImage.getTargetJavaVersion().set(JavaVersion.VERSION_1_8);
|
||||
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("BP_JVM_VERSION", "8.*").hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenTargetCompatibilityIsSetThenJavaVersionIsAddedToEnvironment() {
|
||||
this.buildImage.getEnvironment().put("ALPHA", "a");
|
||||
this.buildImage.getTargetJavaVersion().set(JavaVersion.VERSION_11);
|
||||
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("ALPHA", "a")
|
||||
.containsEntry("BP_JVM_VERSION", "11.*").hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUsingDefaultConfigurationThenRequestHasVerboseLoggingDisabled() {
|
||||
assertThat(this.buildImage.createRequest().isVerboseLogging()).isFalse();
|
||||
|
@ -22,7 +22,9 @@ import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
@ -45,6 +47,11 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
|
||||
"BOOT-INF/");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.getTask().getTargetJavaVersion().set(JavaVersion.VERSION_17);
|
||||
}
|
||||
|
||||
@Test
|
||||
void contentCanBeAddedToBootInfUsingCopySpecFromGetter() throws IOException {
|
||||
BootJar bootJar = getTask();
|
||||
@ -194,6 +201,14 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaVersionIsWrittenToManifest() throws IOException {
|
||||
try (JarFile jarFile = new JarFile(createPopulatedJar())) {
|
||||
assertThat(jarFile.getManifest().getMainAttributes().getValue("Build-Jdk-Spec"))
|
||||
.isEqualTo(JavaVersion.VERSION_17.getMajorVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void applyLayered(Action<LayeredSpec> action) {
|
||||
getTask().layered(action);
|
||||
|
@ -21,7 +21,9 @@ import java.io.IOException;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
@ -42,6 +44,11 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> {
|
||||
"WEB-INF/");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.getTask().getTargetJavaVersion().set(JavaVersion.VERSION_17);
|
||||
}
|
||||
|
||||
@Test
|
||||
void providedClasspathJarsArePackagedInWebInfLibProvided() throws IOException {
|
||||
getTask().getMainClass().set("com.example.Main");
|
||||
@ -137,6 +144,14 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void javaVersionIsWrittenToManifest() throws IOException {
|
||||
try (JarFile jarFile = new JarFile(createPopulatedJar())) {
|
||||
assertThat(jarFile.getManifest().getMainAttributes().getValue("Build-Jdk-Spec"))
|
||||
.isEqualTo(JavaVersion.VERSION_17.getMajorVersion());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeTask() {
|
||||
getTask().copy();
|
||||
|
@ -58,8 +58,8 @@ class BuildImageTests extends AbstractArchiveIntegrationTests {
|
||||
assertThat(original).doesNotExist();
|
||||
assertThat(buildLog(project)).contains("Building image")
|
||||
.contains("docker.io/library/build-image:0.0.1.BUILD-SNAPSHOT")
|
||||
.contains("---> Test Info buildpack building").contains("env: BP_JVM_VERSION=8.*")
|
||||
.contains("---> Test Info buildpack done").contains("Successfully built image");
|
||||
.contains("---> Test Info buildpack building").contains("---> Test Info buildpack done")
|
||||
.contains("Successfully built image");
|
||||
removeImage("build-image", "0.0.1.BUILD-SNAPSHOT");
|
||||
});
|
||||
}
|
||||
@ -75,8 +75,8 @@ class BuildImageTests extends AbstractArchiveIntegrationTests {
|
||||
assertThat(classifier).doesNotExist();
|
||||
assertThat(buildLog(project)).contains("Building image")
|
||||
.contains("docker.io/library/build-image-classifier:0.0.1.BUILD-SNAPSHOT")
|
||||
.contains("---> Test Info buildpack building").contains("env: BP_JVM_VERSION=8.*")
|
||||
.contains("---> Test Info buildpack done").contains("Successfully built image");
|
||||
.contains("---> Test Info buildpack building").contains("---> Test Info buildpack done")
|
||||
.contains("Successfully built image");
|
||||
removeImage("build-image-classifier", "0.0.1.BUILD-SNAPSHOT");
|
||||
});
|
||||
}
|
||||
|
@ -68,8 +68,6 @@ import org.springframework.util.StringUtils;
|
||||
@Execute(phase = LifecyclePhase.PACKAGE)
|
||||
public class BuildImageMojo extends AbstractPackagerMojo {
|
||||
|
||||
private static final String BUILDPACK_JVM_VERSION_KEY = "BP_JVM_VERSION";
|
||||
|
||||
static {
|
||||
System.setProperty("org.slf4j.simpleLogger.log.org.apache.http.wire", "ERROR");
|
||||
}
|
||||
@ -293,22 +291,10 @@ public class BuildImageMojo extends AbstractPackagerMojo {
|
||||
}
|
||||
|
||||
private BuildRequest customize(BuildRequest request) {
|
||||
request = customizeEnvironment(request);
|
||||
request = customizeCreator(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
private BuildRequest customizeEnvironment(BuildRequest request) {
|
||||
if (!request.getEnv().containsKey(BUILDPACK_JVM_VERSION_KEY)) {
|
||||
JavaCompilerPluginConfiguration compilerConfiguration = new JavaCompilerPluginConfiguration(this.project);
|
||||
String targetJavaVersion = compilerConfiguration.getTargetMajorVersion();
|
||||
if (StringUtils.hasText(targetJavaVersion)) {
|
||||
return request.withEnv(BUILDPACK_JVM_VERSION_KEY, targetJavaVersion + ".*");
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
private BuildRequest customizeCreator(BuildRequest request) {
|
||||
String springBootVersion = VersionExtractor.forClass(BuildImageMojo.class);
|
||||
if (StringUtils.hasText(springBootVersion)) {
|
||||
|
@ -38,4 +38,5 @@ application {
|
||||
|
||||
bootBuildImage {
|
||||
archiveFile = bootDistZip.archiveFile
|
||||
environment = ['BP_JVM_VERSION': project.targetCompatibility.getMajorVersion()]
|
||||
}
|
@ -38,4 +38,5 @@ application {
|
||||
|
||||
bootBuildImage {
|
||||
archiveFile = distZip.archiveFile
|
||||
environment = ['BP_JVM_VERSION': project.targetCompatibility.getMajorVersion()]
|
||||
}
|
@ -31,5 +31,5 @@ war {
|
||||
|
||||
bootBuildImage {
|
||||
archiveFile = war.archiveFile
|
||||
environment = ['BP_TOMCAT_VERSION': '10.*']
|
||||
environment = ['BP_JVM_VERSION': project.targetCompatibility.getMajorVersion(), 'BP_TOMCAT_VERSION': '10.*']
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ def boolean isWindows() {
|
||||
task.mainClass = "com.example.ResourceHandlingApplication"
|
||||
task.classpath = sourceSets.main.runtimeClasspath.plus(configurations.getByName(container))
|
||||
task.classifier = container
|
||||
task.targetJavaVersion = project.getTargetCompatibility()
|
||||
}
|
||||
tasks.register("${container}BootJar", BootJar, configurer)
|
||||
tasks.register("${container}BootWar", BootWar, configurer)
|
||||
|
Loading…
Reference in New Issue
Block a user