Skip to content

Commit

Permalink
Merge branch '2.3.x' into 2.4.x
Browse files Browse the repository at this point in the history
Fixes gh-24521 in 2.4.2
  • Loading branch information
scottfrederick committed Dec 16, 2020
2 parents 5fdb2ae + 0e5df22 commit dfcabe1
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 1 deletion.
@@ -1,13 +1,15 @@
[[build-image]]
== Packaging OCI Images
The plugin can create an https://github.com/opencontainers/image-spec[OCI image] from executable jars using https://buildpacks.io[Cloud Native Buildpacks] (CNB).
The plugin can create an https://github.com/opencontainers/image-spec[OCI image] from an executable jar file using https://buildpacks.io[Cloud Native Buildpacks] (CNB).
Images can be built using the `bootBuildImage` task.

NOTE: For security reasons, images build and run as non-root users.
See the {buildpacks-reference}/reference/spec/platform-api/#users[CNB specification] for more details.

The task is automatically created when the `java` plugin is applied and is an instance of {boot-build-image-javadoc}[`BootBuildImage`].

NOTE: The `bootBuildImage` task is not supported with projects using <<packaging-executable-wars, war packaging>>.

NOTE: The `bootBuildImage` task can not be used with a <<packaging-executable-configuring-launch-script, fully executable Spring Boot archive>> that includes a launch script.
Disable launch script configuration in the `bootJar` task when building a jar file that is intended to be used with `bootBuildImage`.

Expand Down
Expand Up @@ -22,6 +22,7 @@
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFile;
import org.gradle.api.internal.artifacts.dsl.LazyPublishArtifact;
import org.gradle.api.plugins.BasePlugin;
import org.gradle.api.plugins.WarPlugin;
Expand All @@ -30,6 +31,7 @@
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskProvider;

import org.springframework.boot.gradle.tasks.bundling.BootBuildImage;
import org.springframework.boot.gradle.tasks.bundling.BootWar;

/**
Expand All @@ -54,6 +56,7 @@ public Class<? extends Plugin<? extends Project>> getPluginClass() {
@Override
public void execute(Project project) {
disableWarTask(project);
disableBootBuildImageTask(project);
TaskProvider<BootWar> bootWar = configureBootWarTask(project);
configureArtifactPublication(bootWar);
}
Expand All @@ -62,6 +65,11 @@ private void disableWarTask(Project project) {
project.getTasks().named(WarPlugin.WAR_TASK_NAME).configure((war) -> war.setEnabled(false));
}

private void disableBootBuildImageTask(Project project) {
project.getTasks().named(SpringBootPlugin.BOOT_BUILD_IMAGE_TASK_NAME, BootBuildImage.class)
.configure((buildImage) -> buildImage.getJar().set((RegularFile) null));
}

private TaskProvider<BootWar> configureBootWarTask(Project project) {
Configuration developmentOnly = project.getConfigurations()
.getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);
Expand Down
Expand Up @@ -99,6 +99,7 @@ public BootBuildImage() {
* @return the jar property
*/
@Input
@Optional
public RegularFileProperty getJar() {
return this.jar;
}
Expand Down Expand Up @@ -312,6 +313,9 @@ public void docker(Closure<?> closure) {

@TaskAction
void buildImage() throws DockerEngineException, IOException {
if (!this.jar.isPresent()) {
throw new GradleException("Executable jar file required for building image");
}
Builder builder = new Builder(this.docker.asDockerConfiguration());
BuildRequest request = createRequest();
builder.build(request);
Expand Down
Expand Up @@ -181,6 +181,35 @@ void failsWithPublishMissingPublishRegistry() {
assertThat(result.getOutput()).contains("requires docker.publishRegistry");
}

@TestTemplate
void failsWithWarPackaging() {
writeMainClass();
writeLongNameResource();
BuildResult result = this.gradleBuild.buildAndFail("bootBuildImage", "-PapplyWarPlugin");
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.FAILED);
assertThat(result.getOutput()).contains("Executable jar file required for building image");
}

@TestTemplate
void buildsImageWithWarPackagingAndJarConfiguration() throws IOException {
writeMainClass();
writeLongNameResource();
BuildResult result = this.gradleBuild.build("bootBuildImage", "--pullPolicy=IF_NOT_PRESENT");
String projectName = this.gradleBuild.getProjectDir().getName();
assertThat(result.task(":bootBuildImage").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(result.getOutput()).contains("docker.io/library/" + projectName);
File buildLibs = new File(this.gradleBuild.getProjectDir(), "build/libs");
assertThat(buildLibs.listFiles())
.containsExactly(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + ".war"));
ImageReference imageReference = ImageReference.of(ImageName.of(projectName));
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
}
finally {
new DockerApi().image().remove(imageReference, false);
}
}

private void writeMainClass() {
File examplePackage = new File(this.gradleBuild.getProjectDir(), "src/main/java/example");
examplePackage.mkdirs();
Expand Down
@@ -0,0 +1,11 @@
plugins {
id 'war'
id 'org.springframework.boot' version '{version}'
}

bootBuildImage {
jar = bootWar.archiveFile
}

sourceCompatibility = '1.8'
targetCompatibility = '1.8'
Expand Up @@ -3,5 +3,9 @@ plugins {
id 'org.springframework.boot' version '{version}'
}

if (project.hasProperty('applyWarPlugin')) {
apply plugin: 'war'
}

sourceCompatibility = '1.8'
targetCompatibility = '1.8'

0 comments on commit dfcabe1

Please sign in to comment.