Add support for layered jars in gradle plugin

Closes gh-19792

Co-authored-by: Andy Wilkinson <awilkinson@pivotal.io>
This commit is contained in:
Madhura Bhave
2020-01-18 10:57:12 -08:00
parent 9ff50f903f
commit df5b0f1163
8 changed files with 214 additions and 2 deletions

View File

@@ -178,6 +178,18 @@ class PackagingDocumentationTests {
assertThat(bootJar).isFile();
}
@TestTemplate
void bootJarLayered() throws IOException {
this.gradleBuild.script("src/docs/gradle/packaging/boot-jar-layered").build("bootJar");
File file = new File(this.gradleBuild.getProjectDir(),
"build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar");
assertThat(file).isFile();
try (JarFile jar = new JarFile(file)) {
JarEntry entry = jar.getJarEntry("BOOT-INF/layers.idx");
assertThat(entry).isNotNull();
}
}
protected void jarFile(File file) throws IOException {
try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {
jar.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,15 @@
package org.springframework.boot.gradle.tasks.bundling;
import java.io.IOException;
import org.gradle.testkit.runner.InvalidRunnerConfigurationException;
import org.gradle.testkit.runner.TaskOutcome;
import org.gradle.testkit.runner.UnexpectedBuildFailure;
import org.junit.jupiter.api.TestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link BootJar}.
*
@@ -27,4 +36,21 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
super("bootJar");
}
@TestTemplate
void upToDateWhenBuiltTwiceWithLayers()
throws InvalidRunnerConfigurationException, UnexpectedBuildFailure, IOException {
assertThat(this.gradleBuild.build("-Playered=true", "bootJar").task(":bootJar").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
assertThat(this.gradleBuild.build("-Playered=true", "bootJar").task(":bootJar").getOutcome())
.isEqualTo(TaskOutcome.UP_TO_DATE);
}
@TestTemplate
void notUpToDateWhenBuiltWithoutLayersAndThenWithLayers()
throws InvalidRunnerConfigurationException, UnexpectedBuildFailure, IOException {
assertThat(this.gradleBuild.build("bootJar").task(":bootJar").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(this.gradleBuild.build("-Playered=true", "bootJar").task(":bootJar").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
}
}

View File

@@ -18,6 +18,8 @@ package org.springframework.boot.gradle.tasks.bundling;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.jar.JarFile;
import org.junit.jupiter.api.Test;
@@ -28,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link BootJar}.
*
* @author Andy Wilkinson
* @author Madhura Bhave
*/
class BootJarTests extends AbstractBootArchiveTests<BootJar> {
@@ -57,6 +60,48 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
}
}
@Test
void layers() throws IOException {
BootJar bootJar = getTask();
bootJar.setMainClassName("com.example.Main");
bootJar.layered();
File classesJavaMain = new File(this.temp, "classes/java/main");
File applicationClass = new File(classesJavaMain, "com/example/Application.class");
applicationClass.getParentFile().mkdirs();
applicationClass.createNewFile();
File resourcesMain = new File(this.temp, "resources/main");
File applicationProperties = new File(resourcesMain, "application.properties");
applicationProperties.getParentFile().mkdirs();
applicationProperties.createNewFile();
File staticResources = new File(resourcesMain, "static");
staticResources.mkdir();
File css = new File(staticResources, "test.css");
css.createNewFile();
bootJar.classpath(classesJavaMain, resourcesMain, jarFile("first-library.jar"), jarFile("second-library.jar"),
jarFile("third-library-SNAPSHOT.jar"));
bootJar.requiresUnpack("second-library.jar");
executeTask();
List<String> entryNames = getEntryNames(bootJar.getArchiveFile().get().getAsFile());
assertThat(entryNames).containsSubsequence("org/springframework/boot/loader/",
"BOOT-INF/layers/application/classes/com/example/Application.class",
"BOOT-INF/layers/resources/classes/static/test.css",
"BOOT-INF/layers/application/classes/application.properties",
"BOOT-INF/layers/dependencies/lib/first-library.jar",
"BOOT-INF/layers/dependencies/lib/second-library.jar",
"BOOT-INF/layers/snapshot-dependencies/lib/third-library-SNAPSHOT.jar");
assertThat(entryNames).doesNotContain("BOOT-INF/classes").doesNotContain("BOOT-INF/lib")
.doesNotContain("BOOT-INF/com/");
try (JarFile jarFile = new JarFile(bootJar.getArchiveFile().get().getAsFile())) {
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Classes")).isEqualTo(null);
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Lib")).isEqualTo(null);
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Layers-Index"))
.isEqualTo("BOOT-INF/layers.idx");
try (InputStream input = jarFile.getInputStream(jarFile.getEntry("BOOT-INF/layers.idx"))) {
assertThat(input).hasContent("dependencies\nsnapshot-dependencies\nresources\napplication\n");
}
}
}
@Override
protected void executeTask() {
getTask().copy();