Commit 08e96427 authored by Scott Frederick's avatar Scott Frederick

Add command-line properties for Maven build-image options

This commit adds support for setting the image name and builder
parameters of the Maven spring-boot:build-image goal using command-line
properties as an alternative to plugin configuration in pom.xml. Per
Maven conventions, a value in pom.xml configuration will override a
command-line property when both are provided.

Fixes gh-20520
parent f470f276
......@@ -40,29 +40,34 @@ By default, the plugin chooses a builder image.
The name of the generated image is deduced from project properties.
The `image` parameter allows to configure how the builder should operate on the project.
The following table summarizes the available properties and their default values:
The following table summarizes the available parameters and their default values:
|===
| Property | Description | Default value
| Parameter | Description | User property | Default value
| `builder`
| Name of the Builder image to use.
| `spring-boot.build-image.builder`
| `cloudfoundry/cnb:0.0.53-bionic`
| `name`
| {spring-boot-api}/buildpack/platform/docker/type/ImageReference.html#of-java.lang.String-[Image name] for the generated image.
| `spring-boot.build-image.imageName`
| `docker.io/library/${project.artifactId}:${project.version}`
| `env`
| Environment variables that should be passed to the builder.
|
|
| `cleanCache`
| Whether to clean the cache before building.
|
| `false`
| `verboseLogging`
| Enables verbose logging of builder operations.
|
| `false`
|===
......@@ -79,7 +84,7 @@ include::goals/build-image.adoc[leveloffset=+1]
[[build-image-example-custom-image-builder]]
==== Custom Image Builder
If you need to customize the builder used to create the image, configure yours as shown in the following example:
If you need to customize the builder used to create the image, configure the plugin as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
......@@ -103,6 +108,13 @@ If you need to customize the builder used to create the image, configure yours a
This configuration will use a builder image with the name `mine/java-cnb-builder` and the tag `latest`.
The builder can be specified on the command line as well, as shown in this example:
[indent=0]
----
$ mvn spring-boot:build-image -Dspring-boot.build-image:builder=mine/java-cnb-builder
----
If the builder exposes configuration options, those can be set using the `env` attributes, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
......@@ -158,4 +170,12 @@ You can take control over the name, as shown in the following example:
----
Note that this configuration does not provide an explicit tag so `latest` is used.
It is possible to specify a tag as well, either using `${project.version}`, any property available in the build or a hardcoded version.
\ No newline at end of file
It is possible to specify a tag as well, either using `${project.version}`, any property available in the build or a hardcoded version.
The image name can be specified on the command line as well, as shown in this example:
[indent=0]
----
$ mvn spring-boot:build-image -Dspring-boot.build-image:imageName=example.com/library/v1
----
......@@ -67,21 +67,45 @@ public class BuildImageTests extends AbstractArchiveIntegrationTests {
@TestTemplate
void whenBuildImageIsInvokedWithCustomImageName(MavenBuild mavenBuild) {
mavenBuild.project("build-image-custom-name").goals("package").execute((project) -> {
File jar = new File(project, "target/build-image-custom-name-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar).isFile();
File original = new File(project, "target/build-image-custom-name-0.0.1.BUILD-SNAPSHOT.jar.original");
assertThat(original).doesNotExist();
assertThat(buildLog(project)).contains("Building image")
.contains("example.com/test/build-image:0.0.1.BUILD-SNAPSHOT").contains("Successfully built image");
ImageReference imageReference = ImageReference.of("example.com/test/build-image:0.0.1.BUILD-SNAPSHOT");
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
}
finally {
removeImage(imageReference);
}
});
mavenBuild.project("build-image-custom-name").goals("package")
.systemProperty("spring-boot.build-image.imageName", "example.com/test/property-ignored:pom-preferred")
.execute((project) -> {
File jar = new File(project, "target/build-image-custom-name-0.0.1.BUILD-SNAPSHOT.jar");
assertThat(jar).isFile();
File original = new File(project,
"target/build-image-custom-name-0.0.1.BUILD-SNAPSHOT.jar.original");
assertThat(original).doesNotExist();
assertThat(buildLog(project)).contains("Building image")
.contains("example.com/test/build-image:0.0.1.BUILD-SNAPSHOT")
.contains("Successfully built image");
ImageReference imageReference = ImageReference
.of("example.com/test/build-image:0.0.1.BUILD-SNAPSHOT");
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
}
finally {
removeImage(imageReference);
}
});
}
@TestTemplate
void whenBuildImageIsInvokedWithCommandLineParameters(MavenBuild mavenBuild) {
mavenBuild.project("build-image").goals("package")
.systemProperty("spring-boot.build-image.imageName", "example.com/test/cmd-property-name:v1")
.systemProperty("spring-boot.build-image.builder", "cloudfoundry/cnb:0.0.43-bionic")
.execute((project) -> {
assertThat(buildLog(project)).contains("Building image")
.contains("example.com/test/cmd-property-name:v1")
.contains("cloudfoundry/cnb:0.0.43-bionic").contains("Successfully built image");
ImageReference imageReference = ImageReference.of("example.com/test/cmd-property-name:v1");
try (GenericContainer<?> container = new GenericContainer<>(imageReference.toString())) {
container.waitingFor(Wait.forLogMessage("Launched\\n", 1)).start();
}
finally {
removeImage(imageReference);
}
});
}
@TestTemplate
......
......@@ -81,8 +81,8 @@ public abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo
/**
* The type of archive (which corresponds to how the dependencies are laid out inside
* it). Possible values are JAR, LAYERED_JAR, WAR, ZIP, DIR, NONE. Defaults to a guess
* based on the archive type.
* it). Possible values are JAR, WAR, ZIP, DIR, NONE. Defaults to a guess based on the
* archive type.
* @since 1.0.0
*/
@Parameter(property = "spring-boot.repackage.layout")
......
......@@ -101,6 +101,20 @@ public class BuildImageMojo extends AbstractPackagerMojo {
@Parameter
private Image image;
/**
* Alias for {@link Image#name to support configuration via command-line property.
* @since 2.3.0
*/
@Parameter(property = "spring-boot.build-image.imageName", readonly = true)
String imageName;
/**
* Alias for {@link Image#builder to support configuration via command-line property.
* @since 2.3.0
*/
@Parameter(property = "spring-boot.build-image.builder", readonly = true)
String imageBuilder;
@Override
public void execute() throws MojoExecutionException {
if (this.project.getPackaging().equals("pom")) {
......@@ -129,6 +143,12 @@ public class BuildImageMojo extends AbstractPackagerMojo {
private BuildRequest getBuildRequest(Libraries libraries) {
Function<Owner, TarArchive> content = (owner) -> getApplicationContent(owner, libraries);
Image image = (this.image != null) ? this.image : new Image();
if (image.name == null && this.imageName != null) {
image.setName(this.imageName);
}
if (image.builder == null && this.imageBuilder != null) {
image.setBuilder(this.imageBuilder);
}
return customize(image.getBuildRequest(this.project.getArtifact(), content));
}
......
......@@ -32,6 +32,7 @@ import org.springframework.util.StringUtils;
* Image configuration options.
*
* @author Phillip Webb
* @author Scott Frederick
* @since 2.3.0
*/
public class Image {
......@@ -61,6 +62,14 @@ public class Image {
*/
boolean verboseLogging;
void setName(String name) {
this.name = name;
}
void setBuilder(String builder) {
this.builder = builder;
}
BuildRequest getBuildRequest(Artifact artifact, Function<Owner, TarArchive> applicationContent) {
return customize(BuildRequest.of(getOrDeduceName(artifact), applicationContent));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment