diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc index 80c06db0b36d..c06699fb9aa5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/docs/asciidoc/packaging-oci-image.adoc @@ -1,11 +1,13 @@ [[build-image]] == Packaging OCI Images -The plugin can create an https://github.com/opencontainers/image-spec[OCI image] 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 `build-image` goal. 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. +NOTE: The `build-image` goal is not supported with projects using <>. + The easiest way to get started is to invoke `mvn spring-boot:build-image` on a project. It is possible to automate the creation of an image whenever the `package` phase is invoked, as shown in the following example: diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java index 5a39c40d5de0..61a537ed04e4 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildImageTests.java @@ -164,6 +164,12 @@ void failsWhenBuilderFails(MavenBuild mavenBuild) { .containsPattern("Builder lifecycle '.*' failed with status code")); } + @TestTemplate + void failsWithWarPackaging(MavenBuild mavenBuild) { + mavenBuild.project("build-image-war-packaging").goals("package").executeAndFail( + (project) -> assertThat(buildLog(project)).contains("Executable jar file required for building image")); + } + private void writeLongNameResource(File project) { StringBuilder name = new StringBuilder(); new Random().ints('a', 'z' + 1).limit(128).forEach((i) -> name.append((char) i)); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-war-packaging/pom.xml b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-war-packaging/pom.xml new file mode 100644 index 000000000000..6c009af94c4f --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-war-packaging/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + org.springframework.boot.maven.it + build-image-war + 0.0.1.BUILD-SNAPSHOT + war + + UTF-8 + @java.version@ + @java.version@ + + + + + @project.groupId@ + @project.artifactId@ + @project.version@ + + + + build-image + + + + + + org.apache.maven.plugins + maven-war-plugin + @maven-war-plugin.version@ + + + + Foo + + + + + + + + + org.springframework + spring-context + @spring-framework.version@ + + + jakarta.servlet + jakarta.servlet-api + @jakarta-servlet.version@ + provided + + + diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-war-packaging/src/main/java/org/test/SampleApplication.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-war-packaging/src/main/java/org/test/SampleApplication.java new file mode 100644 index 000000000000..61b70979bac6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/build-image-war-packaging/src/main/java/org/test/SampleApplication.java @@ -0,0 +1,24 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * https://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 org.test; + +public class SampleApplication { + + public static void main(String[] args) throws Exception { + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java index e094d2abbeee..ddd5ce1b7a74 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java @@ -230,7 +230,11 @@ private File getJarFile() { name.append("-").append(this.classifier); } name.append(".jar"); - return new File(this.sourceDirectory, name.toString()); + File jarFile = new File(this.sourceDirectory, name.toString()); + if (!jarFile.exists()) { + throw new IllegalStateException("Executable jar file required for building image"); + } + return jarFile; } private BuildRequest customize(BuildRequest request) {