Make consistent use of Property for Gradle task configuration

Closes gh-32769
This commit is contained in:
Andy Wilkinson
2022-10-19 17:29:46 +01:00
parent e5c12c2b56
commit 8621be6bba
60 changed files with 554 additions and 960 deletions

View File

@@ -60,13 +60,27 @@ include::../gradle/integrating-with-actuator/build-info-custom-values.gradle[tag
include::../gradle/integrating-with-actuator/build-info-custom-values.gradle.kts[tags=custom-values]
----
NOTE: To omit any of the default properties from the generated build information, set its value to `null`.
To exclude any of the default properties from the generated build information, add its name to the excludes.
For example, the `time` property can be excluded as follows:
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
include::../gradle/integrating-with-actuator/build-info-exclude-time.gradle[tags=exclude-time]
----
[source,kotlin,indent=0,subs="verbatim,attributes",role="secondary"]
.Kotlin
----
include::../gradle/integrating-with-actuator/build-info-exclude-time.gradle.kts[tags=exclude-time]
----
The default value for `build.time` is the instant at which the project is being built.
A side-effect of this is that the task will never be up-to-date.
As a result, builds will take longer as more tasks, including the project's tests, will have to be executed.
Another side-effect is that the task's output will always change and, therefore, the build will not be truly repeatable.
If you value build performance or repeatability more highly than the accuracy of the `build.time` property, set `time` to `null` or a fixed value.
If you value build performance or repeatability more highly than the accuracy of the `build.time` property, exclude the `time` property as shown in the preceding example.
Additional properties can also be added to the build information:

View File

@@ -7,10 +7,10 @@ plugins {
springBoot {
buildInfo {
properties {
additional = mapOf(
additional.set(mapOf(
"a" to "alpha",
"b" to "bravo"
)
))
}
}
}

View File

@@ -7,10 +7,10 @@ plugins {
springBoot {
buildInfo {
properties {
artifact = "example-app"
version = "1.2.3"
group = "com.example"
name = "Example application"
artifact.set("example-app")
version.set("1.2.3")
group.set("com.example")
name.set("Example application")
}
}
}

View File

@@ -0,0 +1,12 @@
plugins {
id 'java'
id 'org.springframework.boot' version '{gradle-project-version}'
}
// tag::exclude-time[]
springBoot {
buildInfo {
excludes = ['time']
}
}
// end::exclude-time[]

View File

@@ -0,0 +1,12 @@
plugins {
java
id("org.springframework.boot") version "{gradle-project-version}"
}
// tag::exclude-time[]
springBoot {
buildInfo {
excludes.set(setOf("time"))
}
}
// end::exclude-time[]

View File

@@ -16,7 +16,7 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageBuilder") {
doFirst {
println("builder=${tasks.bootBuildImage.builder}")
println("runImage=${tasks.bootBuildImage.runImage}")
println("builder=${tasks.bootBuildImage.builder.get()}")
println("runImage=${tasks.bootBuildImage.runImage.get()}")
}
}

View File

@@ -12,14 +12,14 @@ tasks.named<BootJar>("bootJar") {
// tag::builder[]
tasks.named<BootBuildImage>("bootBuildImage") {
builder = "mine/java-cnb-builder"
runImage = "mine/java-cnb-run"
builder.set("mine/java-cnb-builder")
runImage.set("mine/java-cnb-run")
}
// end::builder[]
tasks.register("bootBuildImageBuilder") {
doFirst {
println("builder=${tasks.getByName<BootBuildImage>("bootBuildImage").builder}")
println("runImage=${tasks.getByName<BootBuildImage>("bootBuildImage").runImage}")
println("builder=${tasks.getByName<BootBuildImage>("bootBuildImage").builder.get()}")
println("runImage=${tasks.getByName<BootBuildImage>("bootBuildImage").runImage.get()}")
}
}

View File

@@ -11,6 +11,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageBuildpacks") {
doFirst {
bootBuildImage.buildpacks.each { reference -> println "$reference" }
bootBuildImage.buildpacks.get().each { reference -> println "$reference" }
}
}

View File

@@ -7,13 +7,13 @@ plugins {
// tag::buildpacks[]
tasks.named<BootBuildImage>("bootBuildImage") {
buildpacks = listOf("file:///path/to/example-buildpack.tgz", "urn:cnb:builder:paketo-buildpacks/java")
buildpacks.set(listOf("file:///path/to/example-buildpack.tgz", "urn:cnb:builder:paketo-buildpacks/java"))
}
// end::buildpacks[]
tasks.register("bootBuildImageBuildpacks") {
doFirst {
for(reference in tasks.getByName<BootBuildImage>("bootBuildImage").buildpacks) {
for(reference in tasks.getByName<BootBuildImage>("bootBuildImage").buildpacks.get()) {
print(reference)
}
}

View File

@@ -9,12 +9,12 @@ plugins {
tasks.named<BootBuildImage>("bootBuildImage") {
buildCache {
volume {
name = "cache-${rootProject.name}.build"
name.set("cache-${rootProject.name}.build")
}
}
launchCache {
volume {
name = "cache-${rootProject.name}.launch"
name.set("cache-${rootProject.name}.launch")
}
}
}

View File

@@ -19,6 +19,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageDocker") {
doFirst {
println("token=${tasks.bootBuildImage.docker.builderRegistry.token}")
println("token=${tasks.bootBuildImage.docker.builderRegistry.token.get()}")
}
}

View File

@@ -14,7 +14,7 @@ tasks.named<BootJar>("bootJar") {
tasks.named<BootBuildImage>("bootBuildImage") {
docker {
builderRegistry {
token = "9cbaf023786cd7..."
token.set("9cbaf023786cd7...")
}
}
}
@@ -22,6 +22,6 @@ tasks.named<BootBuildImage>("bootBuildImage") {
tasks.register("bootBuildImageDocker") {
doFirst {
println("token=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.token}")
println("token=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.token.get()}")
}
}

View File

@@ -22,9 +22,9 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageDocker") {
doFirst {
println("username=${tasks.bootBuildImage.docker.builderRegistry.username}")
println("password=${tasks.bootBuildImage.docker.builderRegistry.password}")
println("url=${tasks.bootBuildImage.docker.builderRegistry.url}")
println("email=${tasks.bootBuildImage.docker.builderRegistry.email}")
println("username=${tasks.bootBuildImage.docker.builderRegistry.username.get()}")
println("password=${tasks.bootBuildImage.docker.builderRegistry.password.get()}")
println("url=${tasks.bootBuildImage.docker.builderRegistry.url.get()}")
println("email=${tasks.bootBuildImage.docker.builderRegistry.email.get()}")
}
}

View File

@@ -14,10 +14,10 @@ tasks.named<BootJar>("bootJar") {
tasks.named<BootBuildImage>("bootBuildImage") {
docker {
builderRegistry {
username = "user"
password = "secret"
url = "https://docker.example.com/v1/"
email = "user@example.com"
username.set("user")
password.set("secret")
url.set("https://docker.example.com/v1/")
email.set("user@example.com")
}
}
}
@@ -25,9 +25,9 @@ tasks.named<BootBuildImage>("bootBuildImage") {
tasks.register("bootBuildImageDocker") {
doFirst {
println("username=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.username}")
println("password=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.password}")
println("url=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.url}")
println("email=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.email}")
println("username=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.username.get()}")
println("password=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.password.get()}")
println("url=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.url.get()}")
println("email=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.builderRegistry.email.get()}")
}
}

View File

@@ -18,7 +18,7 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageDocker") {
doFirst {
println("host=${tasks.bootBuildImage.docker.host}")
println("bindHostToBuilder=${tasks.bootBuildImage.docker.bindHostToBuilder}")
println("host=${tasks.bootBuildImage.docker.host.get()}")
println("bindHostToBuilder=${tasks.bootBuildImage.docker.bindHostToBuilder.get()}")
}
}

View File

@@ -13,15 +13,15 @@ tasks.named<BootJar>("bootJar") {
// tag::docker-host[]
tasks.named<BootBuildImage>("bootBuildImage") {
docker {
host = "unix:///run/user/1000/podman/podman.sock"
isBindHostToBuilder = true
host.set("unix:///run/user/1000/podman/podman.sock")
bindHostToBuilder.set(true)
}
}
// end::docker-host[]
tasks.register("bootBuildImageDocker") {
doFirst {
println("host=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.host}")
println("bindHostToBuilder=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.isBindHostToBuilder}")
println("host=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.host.get()}")
println("bindHostToBuilder=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.bindHostToBuilder.get()}")
}
}

View File

@@ -19,8 +19,8 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageDocker") {
doFirst {
println("host=${tasks.bootBuildImage.docker.host}")
println("tlsVerify=${tasks.bootBuildImage.docker.tlsVerify}")
println("certPath=${tasks.bootBuildImage.docker.certPath}")
println("host=${tasks.bootBuildImage.docker.host.get()}")
println("tlsVerify=${tasks.bootBuildImage.docker.tlsVerify.get()}")
println("certPath=${tasks.bootBuildImage.docker.certPath.get()}")
}
}

View File

@@ -13,17 +13,17 @@ tasks.named<BootJar>("bootJar") {
// tag::docker-host[]
tasks.named<BootBuildImage>("bootBuildImage") {
docker {
host = "tcp://192.168.99.100:2376"
isTlsVerify = true
certPath = "/home/user/.minikube/certs"
host.set("tcp://192.168.99.100:2376")
tlsVerify.set(true)
certPath.set("/home/user/.minikube/certs")
}
}
// end::docker-host[]
tasks.register("bootBuildImageDocker") {
doFirst {
println("host=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.host}")
println("tlsVerify=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.isTlsVerify}")
println("certPath=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.certPath}")
println("host=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.host.get()}")
println("tlsVerify=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.tlsVerify.get()}")
println("certPath=${tasks.getByName<BootBuildImage>("bootBuildImage").docker.certPath.get()}")
}
}

View File

@@ -14,6 +14,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageEnvironment") {
doFirst {
bootBuildImage.environment.each { name, value -> println "$name=$value" }
bootBuildImage.environment.get().each { name, value -> println "$name=$value" }
}
}

View File

@@ -7,14 +7,14 @@ plugins {
// tag::env[]
tasks.named<BootBuildImage>("bootBuildImage") {
environment = mapOf("HTTP_PROXY" to "http://proxy.example.com",
"HTTPS_PROXY" to "https://proxy.example.com")
environment.set(mapOf("HTTP_PROXY" to "http://proxy.example.com",
"HTTPS_PROXY" to "https://proxy.example.com"))
}
// end::env[]
tasks.register("bootBuildImageEnvironment") {
doFirst {
for((name, value) in tasks.getByName<BootBuildImage>("bootBuildImage").environment) {
for((name, value) in tasks.getByName<BootBuildImage>("bootBuildImage").environment.get()) {
print(name + "=" + value)
}
}

View File

@@ -18,6 +18,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageEnvironment") {
doFirst {
bootBuildImage.environment.each { name, value -> println "$name=$value" }
bootBuildImage.environment.get().each { name, value -> println "$name=$value" }
}
}

View File

@@ -7,16 +7,16 @@ plugins {
// tag::env-runtime[]
tasks.named<BootBuildImage>("bootBuildImage") {
environment = mapOf(
environment.set(mapOf(
"BPE_DELIM_JAVA_TOOL_OPTIONS" to " ",
"BPE_APPEND_JAVA_TOOL_OPTIONS" to "-XX:+HeapDumpOnOutOfMemoryError"
)
))
}
// end::env-runtime[]
tasks.register("bootBuildImageEnvironment") {
doFirst {
for((name, value) in tasks.getByName<BootBuildImage>("bootBuildImage").environment) {
for((name, value) in tasks.getByName<BootBuildImage>("bootBuildImage").environment.get()) {
print(name + "=" + value)
}
}

View File

@@ -11,6 +11,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageEnvironment") {
doFirst {
bootBuildImage.environment.each { name, value -> println "$name=$value" }
bootBuildImage.environment.get().each { name, value -> println "$name=$value" }
}
}

View File

@@ -7,13 +7,13 @@ plugins {
// tag::env[]
tasks.named<BootBuildImage>("bootBuildImage") {
environment = mapOf("BP_JVM_VERSION" to "8.*")
environment.set(mapOf("BP_JVM_VERSION" to "8.*"))
}
// end::env[]
tasks.register("bootBuildImageEnvironment") {
doFirst {
for((name, value) in tasks.getByName<BootBuildImage>("bootBuildImage").environment) {
for((name, value) in tasks.getByName<BootBuildImage>("bootBuildImage").environment.get()) {
print(name + "=" + value)
}
}

View File

@@ -11,6 +11,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImageName") {
doFirst {
println(tasks.bootBuildImage.imageName)
println(tasks.bootBuildImage.imageName.get())
}
}

View File

@@ -7,12 +7,12 @@ plugins {
// tag::image-name[]
tasks.named<BootBuildImage>("bootBuildImage") {
imageName = "example.com/library/${project.name}"
imageName.set("example.com/library/${project.name}")
}
// end::image-name[]
tasks.register("bootBuildImageName") {
doFirst {
println(tasks.getByName<BootBuildImage>("bootBuildImage").imageName)
println(tasks.getByName<BootBuildImage>("bootBuildImage").imageName.get())
}
}

View File

@@ -9,7 +9,7 @@ tasks.named("bootJar") {
// tag::publish[]
tasks.named("bootBuildImage") {
imageName = "docker.example.com/library/${project.name}"
imageName.set("docker.example.com/library/${project.name}")
publish = true
docker {
publishRegistry {
@@ -22,6 +22,6 @@ tasks.named("bootBuildImage") {
tasks.register("bootBuildImagePublish") {
doFirst {
println(tasks.bootBuildImage.publish)
println(tasks.bootBuildImage.publish.get())
}
}

View File

@@ -12,12 +12,12 @@ tasks.named<BootJar>("bootJar") {
// tag::publish[]
tasks.named<BootBuildImage>("bootBuildImage") {
imageName = "docker.example.com/library/${project.name}"
isPublish = true
imageName.set("docker.example.com/library/${project.name}")
publish.set(true)
docker {
publishRegistry {
username = "user"
password = "secret"
username.set("user")
password.set("secret")
}
}
}
@@ -25,6 +25,6 @@ tasks.named<BootBuildImage>("bootBuildImage") {
tasks.register("bootBuildImagePublish") {
doFirst {
println(tasks.getByName<BootBuildImage>("bootBuildImage").isPublish)
println(tasks.getByName<BootBuildImage>("bootBuildImage").publish.get())
}
}

View File

@@ -24,7 +24,7 @@ tasks.named<BootJar>("bootJar") {
}
intoLayer("dependencies")
}
layerOrder = listOf("dependencies", "spring-boot-loader", "snapshot-dependencies", "application")
layerOrder.set(listOf("dependencies", "spring-boot-loader", "snapshot-dependencies", "application"))
}
}
// end::layered[]

View File

@@ -12,7 +12,7 @@ tasks.named<BootJar>("bootJar") {
// tag::layered[]
tasks.named<BootJar>("bootJar") {
layered {
isEnabled = false
enabled.set(false)
}
}
// end::layered[]

View File

@@ -12,7 +12,7 @@ tasks.named<BootJar>("bootJar") {
// tag::layered[]
tasks.named<BootJar>("bootJar") {
layered {
isIncludeLayerTools = false
includeLayerTools.set(false)
}
}
// end::layered[]

View File

@@ -11,6 +11,6 @@ tasks.named("bootRun") {
tasks.register("optimizedLaunch") {
doLast {
println bootRun.optimizedLaunch
println bootRun.optimizedLaunch.get()
}
}

View File

@@ -7,12 +7,12 @@ plugins {
// tag::launch[]
tasks.named<BootRun>("bootRun") {
isOptimizedLaunch = false
optimizedLaunch.set(false)
}
// end::launch[]
tasks.register("optimizedLaunch") {
doLast {
println(tasks.getByName<BootRun>("bootRun").isOptimizedLaunch)
println(tasks.getByName<BootRun>("bootRun").optimizedLaunch.get())
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@@ -30,7 +30,6 @@ import org.gradle.api.tasks.TaskProvider;
import org.gradle.jvm.tasks.Jar;
import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo;
import org.springframework.boot.gradle.tasks.buildinfo.BuildInfoProperties;
/**
* Entry point to Spring Boot's Gradle DSL.
@@ -92,12 +91,8 @@ public class SpringBootExtension {
this::configureBuildInfoTask);
this.project.getPlugins().withType(JavaPlugin.class, (plugin) -> {
tasks.named(JavaPlugin.CLASSES_TASK_NAME).configure((task) -> task.dependsOn(bootBuildInfo));
this.project.afterEvaluate((evaluated) -> bootBuildInfo.configure((buildInfo) -> {
BuildInfoProperties properties = buildInfo.getProperties();
if (properties.getArtifact() == null) {
properties.setArtifact(determineArtifactBaseName());
}
}));
bootBuildInfo.configure((buildInfo) -> buildInfo.getProperties().getArtifact()
.convention(this.project.provider(() -> determineArtifactBaseName())));
});
if (configurer != null) {
bootBuildInfo.configure(configurer);
@@ -107,8 +102,8 @@ public class SpringBootExtension {
private void configureBuildInfoTask(BuildInfo task) {
task.setGroup(BasePlugin.BUILD_GROUP);
task.setDescription("Generates a META-INF/build-info.properties file.");
task.getConventionMapping().map("destinationDir",
() -> new File(determineMainSourceSetResourcesOutputDir(), "META-INF"));
task.getDestinationDir().convention(this.project.getLayout()
.dir(this.project.provider(() -> new File(determineMainSourceSetResourcesOutputDir(), "META-INF"))));
}
private File determineMainSourceSetResourcesOutputDir() {

View File

@@ -89,8 +89,8 @@ class NativeImagePluginAction implements PluginApplicationAction {
private void configureBootBuildImageToProduceANativeImage(Project project) {
project.getTasks().named(SpringBootPlugin.BOOT_BUILD_IMAGE_TASK_NAME, BootBuildImage.class)
.configure((bootBuildImage) -> {
bootBuildImage.setBuilder("paketobuildpacks/builder:tiny");
bootBuildImage.environment("BP_NATIVE_IMAGE", "true");
bootBuildImage.getBuilder().convention("paketobuildpacks/builder:tiny");
bootBuildImage.getEnvironment().put("BP_NATIVE_IMAGE", "true");
});
}

View File

@@ -32,25 +32,20 @@ import org.gradle.api.tasks.TaskAction;
* @since 3.0.0
*/
@CacheableTask
public class ProcessAot extends AbstractAot {
private final Property<String> applicationClass;
public abstract class ProcessAot extends AbstractAot {
public ProcessAot() {
this.applicationClass = getProject().getObjects().property(String.class);
getMainClass().set("org.springframework.boot.SpringApplicationAotProcessor");
}
@Input
public Property<String> getApplicationClass() {
return this.applicationClass;
}
public abstract Property<String> getApplicationClass();
@Override
@TaskAction
public void exec() {
List<String> args = new ArrayList<>();
args.add(this.applicationClass.get());
args.add(getApplicationClass().get());
args.addAll(processorArgs());
this.setArgs(args);
super.exec();

View File

@@ -18,14 +18,13 @@ package org.springframework.boot.gradle.tasks.buildinfo;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.internal.ConventionTask;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
@@ -43,28 +42,35 @@ import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetail
* @since 2.0.0
*/
@DisableCachingByDefault(because = "Not worth caching")
public class BuildInfo extends ConventionTask {
public abstract class BuildInfo extends DefaultTask {
private final BuildInfoProperties properties = new BuildInfoProperties(getProject());
private final DirectoryProperty destinationDir;
private final BuildInfoProperties properties;
public BuildInfo() {
this.destinationDir = getProject().getObjects().directoryProperty()
.convention(getProject().getLayout().getBuildDirectory());
this.properties = getProject().getObjects().newInstance(BuildInfoProperties.class, getExcludes());
getDestinationDir().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
}
/**
* Returns the names of the properties to exclude from the output.
* @return names of the properties to exclude
* @since 3.0.0
*/
@Internal
public abstract SetProperty<String> getExcludes();
/**
* Generates the {@code build-info.properties} file in the configured
* {@link #setDestinationDir(File) destination}.
* {@link #getDestinationDir destination}.
*/
@TaskAction
public void generateBuildProperties() {
try {
ProjectDetails details = new ProjectDetails(this.properties.getGroup(), this.properties.getArtifact(),
this.properties.getVersion(), this.properties.getName(), this.properties.getTime(),
coerceToStringValues(this.properties.getAdditional()));
new BuildPropertiesWriter(new File(getDestinationDir(), "build-info.properties"))
ProjectDetails details = new ProjectDetails(this.properties.getGroupIfNotExcluded(),
this.properties.getArtifactIfNotExcluded(), this.properties.getVersionIfNotExcluded(),
this.properties.getNameIfNotExcluded(), this.properties.getTimeIfNotExcluded(),
this.properties.getAdditionalIfNotExcluded());
new BuildPropertiesWriter(new File(getDestinationDir().get().getAsFile(), "build-info.properties"))
.writeBuildProperties(details);
}
catch (IOException ex) {
@@ -74,21 +80,11 @@ public class BuildInfo extends ConventionTask {
/**
* Returns the directory to which the {@code build-info.properties} file will be
* written. Defaults to the {@link Project#getBuildDir() Project's build directory}.
* written.
* @return the destination directory
*/
@OutputDirectory
public File getDestinationDir() {
return this.destinationDir.getAsFile().get();
}
/**
* Sets the directory to which the {@code build-info.properties} file will be written.
* @param destinationDir the destination directory
*/
public void setDestinationDir(File destinationDir) {
this.destinationDir.set(destinationDir);
}
public abstract DirectoryProperty getDestinationDir();
/**
* Returns the {@link BuildInfoProperties properties} that will be included in the
@@ -108,10 +104,4 @@ public class BuildInfo extends ConventionTask {
action.execute(this.properties);
}
private Map<String, String> coerceToStringValues(Map<String, Object> input) {
Map<String, String> output = new HashMap<>();
input.forEach((key, value) -> output.put(key, (value != null) ? value.toString() : null));
return output;
}
}

View File

@@ -16,19 +16,27 @@
package org.springframework.boot.gradle.tasks.buildinfo;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import javax.inject.Inject;
import org.gradle.api.Project;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.springframework.util.function.SingletonSupplier;
/**
* The properties that are written into the {@code build-info.properties} file.
*
@@ -36,164 +44,135 @@ import org.gradle.api.tasks.Optional;
* @since 2.0.0
*/
@SuppressWarnings("serial")
public class BuildInfoProperties implements Serializable {
public abstract class BuildInfoProperties implements Serializable {
private transient Instant creationTime = Instant.now();
private final SetProperty<String> excludes;
private final Property<String> group;
private final Supplier<String> creationTime = SingletonSupplier.of(new CurrentIsoInstantSupplier());
private final Property<String> artifact;
private final Property<String> version;
private final Property<String> name;
private final Property<Long> time;
private boolean timeConfigured = false;
private Map<String, Object> additionalProperties = new HashMap<>();
BuildInfoProperties(Project project) {
this.time = project.getObjects().property(Long.class);
this.group = project.getObjects().property(String.class);
this.group.set(project.provider(() -> project.getGroup().toString()));
this.artifact = project.getObjects().property(String.class);
this.version = project.getObjects().property(String.class);
this.version.set(projectVersion(project));
this.name = project.getObjects().property(String.class);
this.name.set(project.provider(project::getName));
}
private Provider<String> projectVersion(Project project) {
return project.provider(() -> project.getVersion().toString());
@Inject
public BuildInfoProperties(Project project, SetProperty<String> excludes) {
this.excludes = excludes;
getGroup().convention(project.provider(() -> project.getGroup().toString()));
getVersion().convention(project.provider(() -> project.getVersion().toString()));
getArtifact()
.convention(project.provider(() -> project.findProperty("archivesBaseName")).map(Object::toString));
getName().convention(project.provider(project::getName));
}
/**
* Returns the value used for the {@code build.group} property. Defaults to the
* {@link Project#getGroup() Project's group}.
* @return the group
* Returns the {@code build.group} property. Defaults to the {@link Project#getGroup()
* Project's group}.
* @return the group property
*/
@Input
@Optional
public String getGroup() {
return this.group.getOrNull();
}
@Internal
public abstract Property<String> getGroup();
/**
* Sets the value used for the {@code build.group} property.
* @param group the group name
* Returns the {@code build.artifact} property.
* @return the artifact property
*/
public void setGroup(String group) {
this.group.set(group);
}
@Internal
public abstract Property<String> getArtifact();
/**
* Returns the value used for the {@code build.artifact} property.
* @return the artifact
*/
@Input
@Optional
public String getArtifact() {
return this.artifact.getOrNull();
}
/**
* Sets the value used for the {@code build.artifact} property.
* @param artifact the artifact
*/
public void setArtifact(String artifact) {
this.artifact.set(artifact);
}
/**
* Returns the value used for the {@code build.version} property. Defaults to the
* Returns the {@code build.version} property. Defaults to the
* {@link Project#getVersion() Project's version}.
* @return the version
*/
@Input
@Optional
public String getVersion() {
return this.version.getOrNull();
}
@Internal
public abstract Property<String> getVersion();
/**
* Sets the value used for the {@code build.version} property.
* @param version the version
*/
public void setVersion(String version) {
this.version.set(version);
}
/**
* Returns the value used for the {@code build.name} property. Defaults to the
* {@link Project#getDisplayName() Project's display name}.
* Returns the {@code build.name} property. Defaults to the {@link Project#getName()
* Project's name}.
* @return the name
*/
@Input
@Optional
public String getName() {
return this.name.getOrNull();
}
@Internal
public abstract Property<String> getName();
/**
* Sets the value used for the {@code build.name} property.
* @param name the name
*/
public void setName(String name) {
this.name.set(name);
}
/**
* Returns the value used for the {@code build.time} property. Defaults to
* {@link Instant#now} when the {@code BuildInfoProperties} instance was created.
* Returns the {@code build.time} property.
* @return the time
*/
@Input
@Optional
public Instant getTime() {
Long epochMillis = this.time.getOrNull();
if (epochMillis != null) {
return Instant.ofEpochMilli(epochMillis);
}
if (this.timeConfigured) {
return null;
}
return this.creationTime;
}
/**
* Sets the value used for the {@code build.time} property.
* @param time the build time
*/
public void setTime(Instant time) {
this.timeConfigured = true;
this.time.set((time != null) ? time.toEpochMilli() : null);
}
@Internal
public abstract Property<String> getTime();
/**
* Returns the additional properties that will be included. When written, the name of
* each additional property is prefixed with {@code build.}.
* @return the additional properties
*/
@Internal
public abstract MapProperty<String, Object> getAdditional();
@Input
@Optional
public Map<String, Object> getAdditional() {
return this.additionalProperties;
String getArtifactIfNotExcluded() {
return getIfNotExcluded(getArtifact(), "artifact");
}
/**
* Sets the additional properties that will be included. When written, the name of
* each additional property is prefixed with {@code build.}.
* @param additionalProperties the additional properties
*/
public void setAdditional(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
@Input
@Optional
String getGroupIfNotExcluded() {
return getIfNotExcluded(getGroup(), "group");
}
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
input.defaultReadObject();
this.creationTime = Instant.now();
@Input
@Optional
String getNameIfNotExcluded() {
return getIfNotExcluded(getName(), "name");
}
@Input
@Optional
Instant getTimeIfNotExcluded() {
String time = getIfNotExcluded(getTime(), "time", this.creationTime);
return (time != null) ? Instant.parse(time) : null;
}
@Input
@Optional
String getVersionIfNotExcluded() {
return getIfNotExcluded(getVersion(), "version");
}
@Input
Map<String, String> getAdditionalIfNotExcluded() {
return coerceToStringValues(applyExclusions(getAdditional().getOrElse(Collections.emptyMap())));
}
private <T> T getIfNotExcluded(Property<T> property, String name) {
return getIfNotExcluded(property, name, () -> null);
}
private <T> T getIfNotExcluded(Property<T> property, String name, Supplier<T> defaultValue) {
if (this.excludes.getOrElse(Collections.emptySet()).contains(name)) {
return null;
}
return property.getOrElse(defaultValue.get());
}
private Map<String, String> coerceToStringValues(Map<String, Object> input) {
Map<String, String> output = new HashMap<>();
input.forEach((key, value) -> output.put(key, (value != null) ? value.toString() : null));
return output;
}
private Map<String, Object> applyExclusions(Map<String, Object> input) {
Map<String, Object> output = new HashMap<>();
Set<String> exclusions = this.excludes.getOrElse(Collections.emptySet());
input.forEach((key, value) -> output.put(key, (!exclusions.contains(key)) ? value : null));
return output;
}
private static final class CurrentIsoInstantSupplier implements Supplier<String> {
@Override
public String get() {
return DateTimeFormatter.ISO_INSTANT.format(Instant.now());
}
}
}

View File

@@ -17,7 +17,6 @@
package org.springframework.boot.gradle.tasks.bundling;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -28,6 +27,7 @@ import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
@@ -64,42 +64,12 @@ import org.springframework.util.StringUtils;
* @since 2.3.0
*/
@DisableCachingByDefault
public class BootBuildImage extends DefaultTask {
public abstract class BootBuildImage extends DefaultTask {
private static final String BUILDPACK_JVM_VERSION_KEY = "BP_JVM_VERSION";
private final String projectName;
private final Property<String> projectVersion;
private RegularFileProperty archiveFile;
private Property<JavaVersion> targetJavaVersion;
private String imageName;
private String builder;
private String runImage;
private Map<String, String> environment = new HashMap<>();
private boolean cleanCache;
private boolean verboseLogging;
private PullPolicy pullPolicy;
private boolean publish;
private final ListProperty<String> buildpacks;
private final ListProperty<String> bindings;
private String network;
private final ListProperty<String> tags;
private final CacheSpec buildCache;
private final CacheSpec launchCache;
@@ -107,15 +77,20 @@ public class BootBuildImage extends DefaultTask {
private final DockerSpec docker;
public BootBuildImage() {
this.archiveFile = getProject().getObjects().fileProperty();
this.targetJavaVersion = getProject().getObjects().property(JavaVersion.class);
this.projectName = getProject().getName();
this.projectVersion = getProject().getObjects().property(String.class);
Project project = getProject();
this.projectVersion.set(getProject().provider(() -> project.getVersion().toString()));
this.buildpacks = getProject().getObjects().listProperty(String.class);
this.bindings = getProject().getObjects().listProperty(String.class);
this.tags = getProject().getObjects().listProperty(String.class);
Property<String> projectVersion = project.getObjects().property(String.class)
.convention(project.provider(() -> project.getVersion().toString()));
getImageName().convention(project.provider(() -> {
ImageName imageName = ImageName.of(this.projectName);
if ("unspecified".equals(projectVersion.get())) {
return ImageReference.of(imageName).toString();
}
return ImageReference.of(imageName, projectVersion.get()).toString();
}));
getCleanCache().convention(false);
getVerboseLogging().convention(false);
getPublish().convention(false);
this.buildCache = getProject().getObjects().newInstance(CacheSpec.class);
this.launchCache = getProject().getObjects().newInstance(CacheSpec.class);
this.docker = getProject().getObjects().newInstance(DockerSpec.class);
@@ -127,9 +102,7 @@ public class BootBuildImage extends DefaultTask {
*/
@InputFile
@PathSensitive(PathSensitivity.RELATIVE)
public RegularFileProperty getArchiveFile() {
return this.archiveFile;
}
public abstract RegularFileProperty getArchiveFile();
/**
* Returns the target Java version of the project (e.g. as provided by the
@@ -138,9 +111,7 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public Property<JavaVersion> getTargetJavaVersion() {
return this.targetJavaVersion;
}
public abstract Property<JavaVersion> getTargetJavaVersion();
/**
* Returns the name of the image that will be built. When {@code null}, the name will
@@ -150,18 +121,8 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public String getImageName() {
return determineImageReference().toString();
}
/**
* Sets the name of the image that will be built.
* @param imageName name of the image
*/
@Option(option = "imageName", description = "The name of the image to generate")
public void setImageName(String imageName) {
this.imageName = imageName;
}
public abstract Property<String> getImageName();
/**
* Returns the builder that will be used to build the image. When {@code null}, the
@@ -170,18 +131,8 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public String getBuilder() {
return this.builder;
}
/**
* Sets the builder that will be used to build the image.
* @param builder the builder
*/
@Option(option = "builder", description = "The name of the builder image to use")
public void setBuilder(String builder) {
this.builder = builder;
}
public abstract Property<String> getBuilder();
/**
* Returns the run image that will be included in the built image. When {@code null},
@@ -190,88 +141,32 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public String getRunImage() {
return this.runImage;
}
/**
* Sets the run image that will be included in the built image.
* @param runImage the run image
*/
@Option(option = "runImage", description = "The name of the run image to use")
public void setRunImage(String runImage) {
this.runImage = runImage;
}
public abstract Property<String> getRunImage();
/**
* Returns the environment that will be used when building the image.
* @return the environment
*/
@Input
public Map<String, String> getEnvironment() {
return this.environment;
}
/**
* Sets the environment that will be used when building the image.
* @param environment the environment
*/
public void setEnvironment(Map<String, String> environment) {
this.environment = environment;
}
/**
* Add an entry to the environment that will be used when building the image.
* @param name the name of the entry
* @param value the value of the entry
*/
public void environment(String name, String value) {
this.environment.put(name, value);
}
/**
* Adds entries to the environment that will be used when building the image.
* @param entries the entries to add to the environment
*/
public void environment(Map<String, String> entries) {
this.environment.putAll(entries);
}
public abstract MapProperty<String, String> getEnvironment();
/**
* Returns whether caches should be cleaned before packaging.
* @return whether caches should be cleaned
* @since 3.0.0
*/
@Input
public boolean isCleanCache() {
return this.cleanCache;
}
/**
* Sets whether caches should be cleaned before packaging.
* @param cleanCache {@code true} to clean the cache, otherwise {@code false}.
*/
@Option(option = "cleanCache", description = "Clean caches before packaging")
public void setCleanCache(boolean cleanCache) {
this.cleanCache = cleanCache;
}
public abstract Property<Boolean> getCleanCache();
/**
* Whether verbose logging should be enabled while building the image.
* @return whether verbose logging should be enabled
* @since 3.0.0
*/
@Input
public boolean isVerboseLogging() {
return this.verboseLogging;
}
/**
* Sets whether verbose logging should be enabled while building the image.
* @param verboseLogging {@code true} to enable verbose logging, otherwise
* {@code false}.
*/
public void setVerboseLogging(boolean verboseLogging) {
this.verboseLogging = verboseLogging;
}
public abstract Property<Boolean> getVerboseLogging();
/**
* Returns image pull policy that will be used when building the image.
@@ -279,36 +174,17 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public PullPolicy getPullPolicy() {
return this.pullPolicy;
}
/**
* Sets image pull policy that will be used when building the image.
* @param pullPolicy image pull policy {@link PullPolicy}
*/
@Option(option = "pullPolicy", description = "The image pull policy")
public void setPullPolicy(PullPolicy pullPolicy) {
this.pullPolicy = pullPolicy;
}
public abstract Property<PullPolicy> getPullPolicy();
/**
* Whether the built image should be pushed to a registry.
* @return whether the built image should be pushed
* @since 3.0.0
*/
@Input
public boolean isPublish() {
return this.publish;
}
/**
* Sets whether the built image should be pushed to a registry.
* @param publish {@code true} the push the built image to a registry. {@code false}.
*/
@Option(option = "publishImage", description = "Publish the built image to a registry")
public void setPublish(boolean publish) {
this.publish = publish;
}
public abstract Property<Boolean> getPublish();
/**
* Returns the buildpacks that will be used when building the image.
@@ -316,33 +192,7 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public List<String> getBuildpacks() {
return this.buildpacks.getOrNull();
}
/**
* Sets the buildpacks that will be used when building the image.
* @param buildpacks the buildpack references
*/
public void setBuildpacks(List<String> buildpacks) {
this.buildpacks.set(buildpacks);
}
/**
* Add an entry to the buildpacks that will be used when building the image.
* @param buildpack the buildpack reference
*/
public void buildpack(String buildpack) {
this.buildpacks.add(buildpack);
}
/**
* Adds entries to the buildpacks that will be used when building the image.
* @param buildpacks the buildpack references
*/
public void buildpacks(List<String> buildpacks) {
this.buildpacks.addAll(buildpacks);
}
public abstract ListProperty<String> getBuildpacks();
/**
* Returns the volume bindings that will be mounted to the container when building the
@@ -351,36 +201,7 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public List<String> getBindings() {
return this.bindings.getOrNull();
}
/**
* Sets the volume bindings that will be mounted to the container when building the
* image.
* @param bindings the bindings
*/
public void setBindings(List<String> bindings) {
this.bindings.set(bindings);
}
/**
* Add an entry to the volume bindings that will be mounted to the container when
* building the image.
* @param binding the binding
*/
public void binding(String binding) {
this.bindings.add(binding);
}
/**
* Add entries to the volume bindings that will be mounted to the container when
* building the image.
* @param bindings the bindings
*/
public void bindings(List<String> bindings) {
this.bindings.addAll(bindings);
}
public abstract ListProperty<String> getBindings();
/**
* Returns the tags that will be created for the built image.
@@ -388,33 +209,7 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public List<String> getTags() {
return this.tags.getOrNull();
}
/**
* Sets the tags that will be created for the built image.
* @param tags the tags
*/
public void setTags(List<String> tags) {
this.tags.set(tags);
}
/**
* Add an entry to the tags that will be created for the built image.
* @param tag the tag
*/
public void tag(String tag) {
this.tags.add(tag);
}
/**
* Add entries to the tags that will be created for the built image.
* @param tags the tags
*/
public void tags(List<String> tags) {
this.tags.addAll(tags);
}
public abstract ListProperty<String> getTags();
/**
* Returns the network the build container will connect to.
@@ -422,18 +217,8 @@ public class BootBuildImage extends DefaultTask {
*/
@Input
@Optional
public String getNetwork() {
return this.network;
}
/**
* Sets the network the build container will connect to.
* @param network the network
*/
@Option(option = "network", description = "Connect detect and build containers to network")
public void setNetwork(String network) {
this.network = network;
}
public abstract Property<String> getNetwork();
/**
* Returns the build cache that will be used when building the image.
@@ -500,19 +285,8 @@ public class BootBuildImage extends DefaultTask {
}
BuildRequest createRequest() {
return customize(BuildRequest.of(determineImageReference(),
(owner) -> new ZipFileTarArchive(this.archiveFile.get().getAsFile(), owner)));
}
private ImageReference determineImageReference() {
if (StringUtils.hasText(this.imageName)) {
return ImageReference.of(this.imageName);
}
ImageName imageName = ImageName.of(this.projectName);
if ("unspecified".equals(this.projectVersion.get())) {
return ImageReference.of(imageName);
}
return ImageReference.of(imageName, this.projectVersion.get());
return customize(BuildRequest.of(getImageName().map(ImageReference::of).get(),
(owner) -> new ZipFileTarArchive(getArchiveFile().get().getAsFile(), owner)));
}
private BuildRequest customize(BuildRequest request) {
@@ -520,37 +294,40 @@ public class BootBuildImage extends DefaultTask {
request = customizeRunImage(request);
request = customizeEnvironment(request);
request = customizeCreator(request);
request = request.withCleanCache(this.cleanCache);
request = request.withVerboseLogging(this.verboseLogging);
request = request.withCleanCache(getCleanCache().get());
request = request.withVerboseLogging(getVerboseLogging().get());
request = customizePullPolicy(request);
request = customizePublish(request);
request = customizeBuildpacks(request);
request = customizeBindings(request);
request = customizeTags(request);
request = customizeCaches(request);
request = request.withNetwork(this.network);
request = request.withNetwork(getNetwork().getOrNull());
return request;
}
private BuildRequest customizeBuilder(BuildRequest request) {
if (StringUtils.hasText(this.builder)) {
return request.withBuilder(ImageReference.of(this.builder));
String builder = this.getBuilder().getOrNull();
if (StringUtils.hasText(builder)) {
return request.withBuilder(ImageReference.of(builder));
}
return request;
}
private BuildRequest customizeRunImage(BuildRequest request) {
if (StringUtils.hasText(this.runImage)) {
return request.withRunImage(ImageReference.of(this.runImage));
String runImage = this.getRunImage().getOrNull();
if (StringUtils.hasText(runImage)) {
return request.withRunImage(ImageReference.of(runImage));
}
return request;
}
private BuildRequest customizeEnvironment(BuildRequest request) {
if (this.environment != null && !this.environment.isEmpty()) {
request = request.withEnv(this.environment);
Map<String, String> environment = this.getEnvironment().getOrNull();
if (environment != null && !environment.isEmpty()) {
request = request.withEnv(environment);
}
if (this.targetJavaVersion.isPresent() && !request.getEnv().containsKey(BUILDPACK_JVM_VERSION_KEY)) {
if (this.getTargetJavaVersion().isPresent() && !request.getEnv().containsKey(BUILDPACK_JVM_VERSION_KEY)) {
request = request.withEnv(BUILDPACK_JVM_VERSION_KEY, translateTargetJavaVersion());
}
return request;
@@ -565,19 +342,20 @@ public class BootBuildImage extends DefaultTask {
}
private BuildRequest customizePullPolicy(BuildRequest request) {
if (this.pullPolicy != null) {
request = request.withPullPolicy(this.pullPolicy);
PullPolicy pullPolicy = getPullPolicy().getOrNull();
if (pullPolicy != null) {
request = request.withPullPolicy(pullPolicy);
}
return request;
}
private BuildRequest customizePublish(BuildRequest request) {
request = request.withPublish(this.publish);
request = request.withPublish(getPublish().get());
return request;
}
private BuildRequest customizeBuildpacks(BuildRequest request) {
List<String> buildpacks = this.buildpacks.getOrNull();
List<String> buildpacks = getBuildpacks().getOrNull();
if (buildpacks != null && !buildpacks.isEmpty()) {
return request.withBuildpacks(buildpacks.stream().map(BuildpackReference::of).toList());
}
@@ -585,7 +363,7 @@ public class BootBuildImage extends DefaultTask {
}
private BuildRequest customizeBindings(BuildRequest request) {
List<String> bindings = this.bindings.getOrNull();
List<String> bindings = getBindings().getOrNull();
if (bindings != null && !bindings.isEmpty()) {
return request.withBindings(bindings.stream().map(Binding::of).toList());
}
@@ -593,7 +371,7 @@ public class BootBuildImage extends DefaultTask {
}
private BuildRequest customizeTags(BuildRequest request) {
List<String> tags = this.tags.getOrNull();
List<String> tags = getTags().getOrNull();
if (tags != null && !tags.isEmpty()) {
return request.withTags(tags.stream().map(ImageReference::of).toList());
}
@@ -611,7 +389,7 @@ public class BootBuildImage extends DefaultTask {
}
private String translateTargetJavaVersion() {
return this.targetJavaVersion.get().getMajorVersion() + ".*";
return this.getTargetJavaVersion().get().getMajorVersion() + ".*";
}
}

View File

@@ -29,7 +29,6 @@ import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileCopyDetails;
import org.gradle.api.file.FileTreeElement;
import org.gradle.api.internal.file.copy.CopyAction;
import org.gradle.api.provider.Property;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Nested;
@@ -46,7 +45,7 @@ import org.gradle.work.DisableCachingByDefault;
* @since 2.0.0
*/
@DisableCachingByDefault(because = "Not worth caching")
public class BootJar extends Jar implements BootArchive {
public abstract class BootJar extends Jar implements BootArchive {
private static final String LAUNCHER = "org.springframework.boot.loader.JarLauncher";
@@ -64,8 +63,6 @@ public class BootJar extends Jar implements BootArchive {
private final CopySpec bootInfSpec;
private final Property<String> mainClass;
private final LayeredSpec layered;
private FileCollection classpath;
@@ -77,7 +74,6 @@ public class BootJar extends Jar implements BootArchive {
this.support = new BootArchiveSupport(LAUNCHER, new LibrarySpec(), new ZipCompressionResolver());
Project project = getProject();
this.bootInfSpec = project.copySpec().into("BOOT-INF");
this.mainClass = project.getObjects().property(String.class);
this.layered = project.getObjects().newInstance(LayeredSpec.class);
configureBootInfSpec(this.bootInfSpec);
getMainSpec().with(this.bootInfSpec);
@@ -128,24 +124,19 @@ public class BootJar extends Jar implements BootArchive {
}
private boolean isLayeredDisabled() {
return this.layered != null && !this.layered.isEnabled();
return !getLayered().getEnabled().get();
}
@Override
protected CopyAction createCopyAction() {
if (!isLayeredDisabled()) {
LayerResolver layerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary);
String layerToolsLocation = this.layered.isIncludeLayerTools() ? LIB_DIRECTORY : null;
String layerToolsLocation = this.layered.getIncludeLayerTools().get() ? LIB_DIRECTORY : null;
return this.support.createCopyAction(this, this.resolvedDependencies, layerResolver, layerToolsLocation);
}
return this.support.createCopyAction(this, this.resolvedDependencies);
}
@Override
public Property<String> getMainClass() {
return this.mainClass;
}
@Override
public void requiresUnpack(String... patterns) {
this.support.requiresUnpack(patterns);

View File

@@ -28,7 +28,6 @@ import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileCopyDetails;
import org.gradle.api.file.FileTreeElement;
import org.gradle.api.internal.file.copy.CopyAction;
import org.gradle.api.provider.Property;
import org.gradle.api.specs.Spec;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Internal;
@@ -46,7 +45,7 @@ import org.gradle.work.DisableCachingByDefault;
* @since 2.0.0
*/
@DisableCachingByDefault(because = "Not worth caching")
public class BootWar extends War implements BootArchive {
public abstract class BootWar extends War implements BootArchive {
private static final String LAUNCHER = "org.springframework.boot.loader.WarLauncher";
@@ -62,8 +61,6 @@ public class BootWar extends War implements BootArchive {
private final BootArchiveSupport support;
private final Property<String> mainClass;
private final ResolvedDependencies resolvedDependencies = new ResolvedDependencies();
private final LayeredSpec layered;
@@ -76,7 +73,6 @@ public class BootWar extends War implements BootArchive {
public BootWar() {
this.support = new BootArchiveSupport(LAUNCHER, new LibrarySpec(), new ZipCompressionResolver());
Project project = getProject();
this.mainClass = project.getObjects().property(String.class);
this.layered = project.getObjects().newInstance(LayeredSpec.class);
getWebInf().into("lib-provided", fromCallTo(this::getProvidedLibFiles));
this.support.moveModuleInfoToRoot(getRootSpec());
@@ -103,24 +99,19 @@ public class BootWar extends War implements BootArchive {
}
private boolean isLayeredDisabled() {
return this.layered != null && !this.layered.isEnabled();
return !this.layered.getEnabled().get();
}
@Override
protected CopyAction createCopyAction() {
if (!isLayeredDisabled()) {
LayerResolver layerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary);
String layerToolsLocation = this.layered.isIncludeLayerTools() ? LIB_DIRECTORY : null;
String layerToolsLocation = this.layered.getIncludeLayerTools().get() ? LIB_DIRECTORY : null;
return this.support.createCopyAction(this, this.resolvedDependencies, layerResolver, layerToolsLocation);
}
return this.support.createCopyAction(this, this.resolvedDependencies);
}
@Override
public Property<String> getMainClass() {
return this.mainClass;
}
@Override
public void requiresUnpack(String... patterns) {
this.support.requiresUnpack(patterns);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2021-2021 the original author or authors.
* Copyright 2021-2022 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.
@@ -20,6 +20,8 @@ import javax.inject.Inject;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.springframework.boot.buildpack.platform.build.Cache;
@@ -32,11 +34,13 @@ import org.springframework.boot.buildpack.platform.build.Cache;
*/
public class CacheSpec {
private final ObjectFactory objectFactory;
private Cache cache = null;
@Inject
public CacheSpec() {
public CacheSpec(ObjectFactory objectFactory) {
this.objectFactory = objectFactory;
}
public Cache asCache() {
@@ -51,34 +55,22 @@ public class CacheSpec {
if (this.cache != null) {
throw new GradleException("Each image building cache can be configured only once");
}
VolumeCacheSpec spec = new VolumeCacheSpec();
VolumeCacheSpec spec = this.objectFactory.newInstance(VolumeCacheSpec.class);
action.execute(spec);
this.cache = Cache.volume(spec.getName());
this.cache = Cache.volume(spec.getName().get());
}
/**
* Configuration for an image building cache stored in a Docker volume.
*/
public static class VolumeCacheSpec {
private String name;
public abstract static class VolumeCacheSpec {
/**
* Returns the name of the cache.
* @return the cache name
*/
@Input
public String getName() {
return this.name;
}
/**
* Sets the name of the cache.
* @param name the cache name
*/
public void setName(String name) {
this.name = name;
}
public abstract Property<String> getName();
}

View File

@@ -16,8 +16,12 @@
package org.springframework.boot.gradle.tasks.bundling;
import javax.inject.Inject;
import org.gradle.api.Action;
import org.gradle.api.GradleException;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
@@ -31,23 +35,18 @@ import org.springframework.boot.buildpack.platform.docker.configuration.DockerCo
* @author Scott Frederick
* @since 2.4.0
*/
public class DockerSpec {
private String host;
private boolean tlsVerify;
private String certPath;
private boolean bindHostToBuilder;
public abstract class DockerSpec {
private final DockerRegistrySpec builderRegistry;
private final DockerRegistrySpec publishRegistry;
public DockerSpec() {
this.builderRegistry = new DockerRegistrySpec();
this.publishRegistry = new DockerRegistrySpec();
@Inject
public DockerSpec(ObjectFactory objects) {
this.builderRegistry = objects.newInstance(DockerRegistrySpec.class);
this.publishRegistry = objects.newInstance(DockerRegistrySpec.class);
getBindHostToBuilder().convention(false);
getTlsVerify().convention(false);
}
DockerSpec(DockerRegistrySpec builderRegistry, DockerRegistrySpec publishRegistry) {
@@ -57,43 +56,19 @@ public class DockerSpec {
@Input
@Optional
public String getHost() {
return this.host;
}
public void setHost(String host) {
this.host = host;
}
public abstract Property<String> getHost();
@Input
@Optional
public Boolean isTlsVerify() {
return this.tlsVerify;
}
public void setTlsVerify(boolean tlsVerify) {
this.tlsVerify = tlsVerify;
}
public abstract Property<Boolean> getTlsVerify();
@Input
@Optional
public String getCertPath() {
return this.certPath;
}
public void setCertPath(String certPath) {
this.certPath = certPath;
}
public abstract Property<String> getCertPath();
@Input
@Optional
public Boolean isBindHostToBuilder() {
return this.bindHostToBuilder;
}
public void setBindHostToBuilder(boolean use) {
this.bindHostToBuilder = use;
}
public abstract Property<Boolean> getBindHostToBuilder();
/**
* Returns the {@link DockerRegistrySpec} that configures authentication to the
@@ -142,15 +117,16 @@ public class DockerSpec {
DockerConfiguration asDockerConfiguration() {
DockerConfiguration dockerConfiguration = new DockerConfiguration();
dockerConfiguration = customizeHost(dockerConfiguration);
dockerConfiguration = dockerConfiguration.withBindHostToBuilder(this.bindHostToBuilder);
dockerConfiguration = dockerConfiguration.withBindHostToBuilder(getBindHostToBuilder().get());
dockerConfiguration = customizeBuilderAuthentication(dockerConfiguration);
dockerConfiguration = customizePublishAuthentication(dockerConfiguration);
return dockerConfiguration;
}
private DockerConfiguration customizeHost(DockerConfiguration dockerConfiguration) {
if (this.host != null) {
return dockerConfiguration.withHost(this.host, this.tlsVerify, this.certPath);
String host = getHost().getOrNull();
if (host != null) {
return dockerConfiguration.withHost(host, getTlsVerify().get(), getCertPath().getOrNull());
}
return dockerConfiguration;
}
@@ -160,11 +136,12 @@ public class DockerSpec {
return dockerConfiguration;
}
if (this.builderRegistry.hasTokenAuth() && !this.builderRegistry.hasUserAuth()) {
return dockerConfiguration.withBuilderRegistryTokenAuthentication(this.builderRegistry.getToken());
return dockerConfiguration.withBuilderRegistryTokenAuthentication(this.builderRegistry.getToken().get());
}
if (this.builderRegistry.hasUserAuth() && !this.builderRegistry.hasTokenAuth()) {
return dockerConfiguration.withBuilderRegistryUserAuthentication(this.builderRegistry.getUsername(),
this.builderRegistry.getPassword(), this.builderRegistry.getUrl(), this.builderRegistry.getEmail());
return dockerConfiguration.withBuilderRegistryUserAuthentication(this.builderRegistry.getUsername().get(),
this.builderRegistry.getPassword().get(), this.builderRegistry.getUrl().getOrNull(),
this.builderRegistry.getEmail().getOrNull());
}
throw new GradleException(
"Invalid Docker builder registry configuration, either token or username/password must be provided");
@@ -175,11 +152,12 @@ public class DockerSpec {
return dockerConfiguration.withEmptyPublishRegistryAuthentication();
}
if (this.publishRegistry.hasTokenAuth() && !this.publishRegistry.hasUserAuth()) {
return dockerConfiguration.withPublishRegistryTokenAuthentication(this.publishRegistry.getToken());
return dockerConfiguration.withPublishRegistryTokenAuthentication(this.publishRegistry.getToken().get());
}
if (this.publishRegistry.hasUserAuth() && !this.publishRegistry.hasTokenAuth()) {
return dockerConfiguration.withPublishRegistryUserAuthentication(this.publishRegistry.getUsername(),
this.publishRegistry.getPassword(), this.publishRegistry.getUrl(), this.publishRegistry.getEmail());
return dockerConfiguration.withPublishRegistryUserAuthentication(this.publishRegistry.getUsername().get(),
this.publishRegistry.getPassword().get(), this.publishRegistry.getUrl().getOrNull(),
this.publishRegistry.getEmail().getOrNull());
}
throw new GradleException(
"Invalid Docker publish registry configuration, either token or username/password must be provided");
@@ -188,31 +166,7 @@ public class DockerSpec {
/**
* Encapsulates Docker registry authentication configuration options.
*/
public static class DockerRegistrySpec {
private String username;
private String password;
private String url;
private String email;
private String token;
public DockerRegistrySpec() {
}
DockerRegistrySpec(String username, String password, String url, String email) {
this.username = username;
this.password = password;
this.url = url;
this.email = email;
}
DockerRegistrySpec(String token) {
this.token = token;
}
public abstract static class DockerRegistrySpec {
/**
* Returns the username to use when authenticating to the Docker registry.
@@ -220,17 +174,7 @@ public class DockerSpec {
*/
@Input
@Optional
public String getUsername() {
return this.username;
}
/**
* Sets the username to use when authenticating to the Docker registry.
* @param username the registry username
*/
public void setUsername(String username) {
this.username = username;
}
public abstract Property<String> getUsername();
/**
* Returns the password to use when authenticating to the Docker registry.
@@ -238,17 +182,7 @@ public class DockerSpec {
*/
@Input
@Optional
public String getPassword() {
return this.password;
}
/**
* Sets the password to use when authenticating to the Docker registry.
* @param password the registry username
*/
public void setPassword(String password) {
this.password = password;
}
public abstract Property<String> getPassword();
/**
* Returns the Docker registry URL.
@@ -256,17 +190,7 @@ public class DockerSpec {
*/
@Input
@Optional
public String getUrl() {
return this.url;
}
/**
* Sets the Docker registry URL.
* @param url the registry URL
*/
public void setUrl(String url) {
this.url = url;
}
public abstract Property<String> getUrl();
/**
* Returns the email address associated with the Docker registry username.
@@ -274,17 +198,7 @@ public class DockerSpec {
*/
@Input
@Optional
public String getEmail() {
return this.email;
}
/**
* Sets the email address associated with the Docker registry username.
* @param email the registry email address
*/
public void setEmail(String email) {
this.email = email;
}
public abstract Property<String> getEmail();
/**
* Returns the identity token to use when authenticating to the Docker registry.
@@ -292,29 +206,36 @@ public class DockerSpec {
*/
@Input
@Optional
public String getToken() {
return this.token;
}
/**
* Sets the identity token to use when authenticating to the Docker registry.
* @param token the registry identity token
*/
public void setToken(String token) {
this.token = token;
}
public abstract Property<String> getToken();
boolean hasEmptyAuth() {
return this.username == null && this.password == null && this.url == null && this.email == null
&& this.token == null;
return nonePresent(getUsername(), getPassword(), getUrl(), getEmail(), getToken());
}
private boolean nonePresent(Property<?>... properties) {
for (Property<?> property : properties) {
if (property.isPresent()) {
return false;
}
}
return true;
}
boolean hasUserAuth() {
return this.getUsername() != null && this.getPassword() != null;
return allPresent(getUsername(), getPassword());
}
private boolean allPresent(Property<?>... properties) {
for (Property<?> property : properties) {
if (!property.isPresent()) {
return false;
}
}
return true;
}
boolean hasTokenAuth() {
return this.getToken() != null;
return this.getToken().isPresent();
}
}

View File

@@ -27,6 +27,8 @@ import javax.inject.Inject;
import org.gradle.api.Action;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
@@ -49,64 +51,38 @@ import org.springframework.util.Assert;
* @author Phillip Webb
* @since 2.3.0
*/
public class LayeredSpec {
private boolean includeLayerTools = true;
private boolean enabled = true;
public abstract class LayeredSpec {
private ApplicationSpec application;
private DependenciesSpec dependencies;
@Optional
private List<String> layerOrder;
private Layers layers;
@Inject
public LayeredSpec(ObjectFactory objects) {
this.application = objects.newInstance(ApplicationSpec.class);
this.dependencies = objects.newInstance(DependenciesSpec.class);
getEnabled().convention(true);
getIncludeLayerTools().convention(true);
}
/**
* Returns whether the layer tools should be included as a dependency in the layered
* archive.
* @return whether the layer tools should be included
* @since 3.0.0
*/
@Input
public boolean isIncludeLayerTools() {
return this.includeLayerTools;
}
/**
* Sets whether the layer tools should be included as a dependency in the layered
* archive.
* @param includeLayerTools {@code true} if the layer tools should be included,
* otherwise {@code false}
*/
public void setIncludeLayerTools(boolean includeLayerTools) {
this.includeLayerTools = includeLayerTools;
}
public abstract Property<Boolean> getIncludeLayerTools();
/**
* Returns whether the layers.idx should be included in the archive.
* @return whether the layers.idx should be included
* @since 3.0.0
*/
@Input
public boolean isEnabled() {
return this.enabled;
}
/**
* Sets whether the layers.idx should be included in the archive.
* @param enabled {@code true} layers.idx should be included in the archive, otherwise
* {@code false}
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public abstract Property<Boolean> getEnabled();
/**
* Returns the {@link ApplicationSpec} that controls the layers to which application
@@ -168,25 +144,8 @@ public class LayeredSpec {
* @return the layer order
*/
@Input
public List<String> getLayerOrder() {
return this.layerOrder;
}
/**
* Sets the order of the layers in the archive from least to most frequently changing.
* @param layerOrder the layer order
*/
public void setLayerOrder(String... layerOrder) {
this.layerOrder = Arrays.asList(layerOrder);
}
/**
* Sets the order of the layers in the archive from least to most frequently changing.
* @param layerOrder the layer order
*/
public void setLayerOrder(List<String> layerOrder) {
this.layerOrder = layerOrder;
}
@Optional
public abstract ListProperty<String> getLayerOrder();
/**
* Return this configuration as a {@link Layers} instance. This method should only be
@@ -203,12 +162,13 @@ public class LayeredSpec {
}
private Layers createLayers() {
if (this.layerOrder == null || this.layerOrder.isEmpty()) {
List<String> layerOrder = getLayerOrder().getOrNull();
if (layerOrder == null || layerOrder.isEmpty()) {
Assert.state(this.application.isEmpty() && this.dependencies.isEmpty(),
"The 'layerOrder' must be defined when using custom layering");
return Layers.IMPLICIT;
}
List<Layer> layers = this.layerOrder.stream().map(Layer::new).toList();
List<Layer> layers = layerOrder.stream().map(Layer::new).toList();
return new CustomLayers(layers, this.application.asSelectors(), this.dependencies.asSelectors());
}

View File

@@ -20,6 +20,7 @@ import java.io.File;
import java.util.Set;
import org.gradle.api.file.SourceDirectorySet;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.SourceSet;
@@ -33,30 +34,20 @@ import org.gradle.work.DisableCachingByDefault;
* @since 2.0.0
*/
@DisableCachingByDefault(because = "Application should always run")
public class BootRun extends JavaExec {
public abstract class BootRun extends JavaExec {
private boolean optimizedLaunch = true;
public BootRun() {
getOptimizedLaunch().convention(true);
}
/**
* Returns {@code true} if the JVM's launch should be optimized, otherwise
* {@code false}. Defaults to {@code true}.
* Returns the property for whether the JVM's launch should be optimized. The property
* defaults to {@code true}.
* @return whether the JVM's launch should be optimized
* @since 2.2.0
* @since 3.0.0
*/
@Input
public boolean isOptimizedLaunch() {
return this.optimizedLaunch;
}
/**
* Sets whether the JVM's launch should be optimized. Defaults to {@code true}.
* @param optimizedLaunch {@code true} if the JVM's launch should be optimised,
* otherwise {@code false}
* @since 2.2.0
*/
public void setOptimizedLaunch(boolean optimizedLaunch) {
this.optimizedLaunch = optimizedLaunch;
}
public abstract Property<Boolean> getOptimizedLaunch();
/**
* Adds the {@link SourceDirectorySet#getSrcDirs() source directories} of the given
@@ -73,7 +64,7 @@ public class BootRun extends JavaExec {
@Override
public void exec() {
if (this.optimizedLaunch) {
if (this.getOptimizedLaunch().get()) {
setJvmArgs(getJvmArgs());
jvmArgs("-XX:TieredStopAtLevel=1");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@@ -58,6 +58,7 @@ class IntegratingWithActuatorDocumentationTests {
assertThat(properties).containsEntry("build.version", "1.2.3");
assertThat(properties).containsEntry("build.group", "com.example");
assertThat(properties).containsEntry("build.name", "Example application");
assertThat(properties).containsKey("build.time");
}
@TestTemplate
@@ -71,6 +72,16 @@ class IntegratingWithActuatorDocumentationTests {
assertThat(properties).containsEntry("build.b", "bravo");
}
@TestTemplate
void buildInfoExcludeTime() {
this.gradleBuild.script("src/docs/gradle/integrating-with-actuator/build-info-exclude-time")
.build("bootBuildInfo");
File file = new File(this.gradleBuild.getProjectDir(), "build/resources/main/META-INF/build-info.properties");
assertThat(file).isFile();
Properties properties = buildInfoProperties(file);
assertThat(properties).doesNotContainKey("build.time");
}
private Properties buildInfoProperties(File file) {
assertThat(file).isFile();
Properties properties = new Properties();

View File

@@ -112,7 +112,7 @@ class BuildInfoIntegrationTests {
void reproducibleOutputWithFixedTime() throws IOException, InterruptedException {
assertThat(this.gradleBuild.build("buildInfo", "-PnullTime").task(":buildInfo").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
File buildInfoProperties = new File(this.gradleBuild.getProjectDir(), "build/build-info.properties");
File buildInfoProperties = new File(this.gradleBuild.getProjectDir(), "build/buildInfo/build-info.properties");
String firstHash = FileUtils.sha1Hash(buildInfoProperties);
assertThat(buildInfoProperties.delete()).isTrue();
Thread.sleep(1500);
@@ -123,17 +123,7 @@ class BuildInfoIntegrationTests {
}
@TestTemplate
void removePropertiesUsingNulls() {
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties buildInfoProperties = buildInfoProperties();
assertThat(buildInfoProperties).doesNotContainKey("build.group");
assertThat(buildInfoProperties).doesNotContainKey("build.artifact");
assertThat(buildInfoProperties).doesNotContainKey("build.version");
assertThat(buildInfoProperties).doesNotContainKey("build.name");
}
@TestTemplate
void removePropertiesUsingEmptyStrings() {
void excludeProperties() {
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties buildInfoProperties = buildInfoProperties();
assertThat(buildInfoProperties).doesNotContainKey("build.group");
@@ -143,7 +133,7 @@ class BuildInfoIntegrationTests {
}
private Properties buildInfoProperties() {
File file = new File(this.gradleBuild.getProjectDir(), "build/build-info.properties");
File file = new File(this.gradleBuild.getProjectDir(), "build/buildInfo/build-info.properties");
assertThat(file).isFile();
Properties properties = new Properties();
try (FileReader reader = new FileReader(file)) {

View File

@@ -60,21 +60,14 @@ class BuildInfoTests {
@Test
void customArtifactIsReflectedInProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setArtifact("custom");
task.getProperties().getArtifact().set("custom");
assertThat(buildInfoProperties(task)).containsEntry("build.artifact", "custom");
}
@Test
void artifactCanBeRemovedFromPropertiesUsingNull() {
void artifactCanBeExcludedFromProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setArtifact(null);
assertThat(buildInfoProperties(task)).doesNotContainKey("build.artifact");
}
@Test
void artifactCanBeRemovedFromPropertiesUsingEmptyString() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setArtifact("");
task.getExcludes().addAll("artifact");
assertThat(buildInfoProperties(task)).doesNotContainKey("build.artifact");
}
@@ -88,42 +81,28 @@ class BuildInfoTests {
@Test
void customGroupIsReflectedInProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setGroup("com.example");
task.getProperties().getGroup().set("com.example");
assertThat(buildInfoProperties(task)).containsEntry("build.group", "com.example");
}
@Test
void groupCanBeRemovedFromPropertiesUsingNull() {
void groupCanBeExcludedFromProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setGroup(null);
assertThat(buildInfoProperties(task)).doesNotContainKey("build.group");
}
@Test
void groupCanBeRemovedFromPropertiesUsingEmptyString() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setGroup("");
task.getExcludes().add("group");
assertThat(buildInfoProperties(task)).doesNotContainKey("build.group");
}
@Test
void customNameIsReflectedInProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setName("Example");
task.getProperties().getName().set("Example");
assertThat(buildInfoProperties(task)).containsEntry("build.name", "Example");
}
@Test
void nameCanBeRemovedFromPropertiesUsingNull() {
void nameCanBeExludedRemovedFromProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setName(null);
assertThat(buildInfoProperties(task)).doesNotContainKey("build.name");
}
@Test
void nameCanBeRemovedFromPropertiesUsingEmptyString() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setName("");
task.getExcludes().add("name");
assertThat(buildInfoProperties(task)).doesNotContainKey("build.name");
}
@@ -137,45 +116,36 @@ class BuildInfoTests {
@Test
void customVersionIsReflectedInProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setVersion("2.3.4");
task.getProperties().getVersion().set("2.3.4");
assertThat(buildInfoProperties(task)).containsEntry("build.version", "2.3.4");
}
@Test
void versionCanBeRemovedFromPropertiesUsingNull() {
void versionCanBeExcludedFromProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setVersion(null);
assertThat(buildInfoProperties(task)).doesNotContainKey("build.version");
}
@Test
void versionCanBeRemovedFromPropertiesUsingEmptyString() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setVersion("");
task.getExcludes().add("version");
assertThat(buildInfoProperties(task)).doesNotContainKey("build.version");
}
@Test
void timeIsSetInProperties() {
BuildInfo task = createTask(createProject("test"));
assertThat(buildInfoProperties(task)).containsEntry("build.time",
DateTimeFormatter.ISO_INSTANT.format(task.getProperties().getTime()));
assertThat(buildInfoProperties(task)).containsKey("build.time");
}
@Test
void timeCanBeRemovedFromProperties() {
void timeCanBeExcludedFromProperties() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().setTime(null);
task.getExcludes().add("time");
assertThat(buildInfoProperties(task)).doesNotContainKey("build.time");
}
@Test
void timeCanBeCustomizedInProperties() {
Instant now = Instant.now();
BuildInfo task = createTask(createProject("test"));
task.getProperties().setTime(now);
assertThat(buildInfoProperties(task)).containsEntry("build.time",
DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochMilli(now.toEpochMilli())));
String isoTime = DateTimeFormatter.ISO_INSTANT.format(Instant.now());
task.getProperties().getTime().set(isoTime);
assertThat(buildInfoProperties(task)).containsEntry("build.time", isoTime);
}
@Test
@@ -183,16 +153,22 @@ class BuildInfoTests {
BuildInfo task = createTask(createProject("test"));
task.getProperties().getAdditional().put("a", "alpha");
task.getProperties().getAdditional().put("b", "bravo");
assertThat(buildInfoProperties(task)).containsEntry("build.a", "alpha");
assertThat(buildInfoProperties(task)).containsEntry("build.b", "bravo");
assertThat(buildInfoProperties(task)).containsEntry("build.a", "alpha").containsEntry("build.b", "bravo");
}
@Test
void additionalPropertiesCanBeExcluded() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().getAdditional().put("a", "alpha");
task.getExcludes().add("b");
assertThat(buildInfoProperties(task)).containsEntry("build.a", "alpha").doesNotContainKey("b");
}
@Test
void nullAdditionalPropertyProducesInformativeFailure() {
BuildInfo task = createTask(createProject("test"));
task.getProperties().getAdditional().put("a", null);
assertThatThrownBy(() -> buildInfoProperties(task))
.hasMessage("Additional property 'a' is illegal as its value is null");
assertThatThrownBy(() -> task.getProperties().getAdditional().put("a", null))
.hasMessage("Cannot add an entry with a null value to a property of type Map.");
}
private Project createProject(String projectName) {
@@ -209,7 +185,7 @@ class BuildInfoTests {
private Properties buildInfoProperties(BuildInfo task) {
task.generateBuildProperties();
return buildInfoProperties(new File(task.getDestinationDir(), "build-info.properties"));
return buildInfoProperties(new File(task.getDestinationDir().get().getAsFile(), "build-info.properties"));
}
private Properties buildInfoProperties(File file) {

View File

@@ -451,7 +451,8 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
void jarWhenLayersDisabledShouldNotContainLayersIndex() throws IOException {
List<String> entryNames = getEntryNames(createLayeredJar((configuration) -> configuration.setEnabled(false)));
List<String> entryNames = getEntryNames(
createLayeredJar((configuration) -> configuration.getEnabled().set(false)));
assertThat(entryNames).doesNotContain(this.indexPath + "layers.idx");
}
@@ -519,7 +520,8 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
dependencies.intoLayer("my-internal-deps", (spec) -> spec.include("com.example:*:*"));
dependencies.intoLayer("my-deps");
});
layered.setLayerOrder("my-deps", "my-internal-deps", "my-snapshot-deps", "resources", "application");
layered.getLayerOrder()
.set(List.of("my-deps", "my-internal-deps", "my-snapshot-deps", "resources", "application"));
});
try (JarFile jarFile = new JarFile(jar)) {
List<String> entryNames = getEntryNames(jar);
@@ -567,7 +569,7 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
@Test
void whenArchiveIsLayeredAndIncludeLayerToolsIsFalseThenLayerToolsAreNotAddedToTheJar() throws IOException {
List<String> entryNames = getEntryNames(
createLayeredJar((configuration) -> configuration.setIncludeLayerTools(false)));
createLayeredJar((configuration) -> configuration.getIncludeLayerTools().set(false)));
assertThat(entryNames)
.doesNotContain(this.indexPath + "layers/dependencies/lib/spring-boot-jarmode-layertools.jar");
}

View File

@@ -62,7 +62,7 @@ class BootBuildImageTests {
@Test
void whenProjectVersionIsUnspecifiedThenItIsIgnoredWhenDerivingImageName() {
assertThat(this.buildImage.getImageName()).isEqualTo("docker.io/library/build-image-test");
assertThat(this.buildImage.getImageName().get()).isEqualTo("docker.io/library/build-image-test");
BuildRequest request = this.buildImage.createRequest();
assertThat(request.getName().getDomain()).isEqualTo("docker.io");
assertThat(request.getName().getName()).isEqualTo("library/build-image-test");
@@ -73,7 +73,7 @@ class BootBuildImageTests {
@Test
void whenProjectVersionIsSpecifiedThenItIsUsedInTagOfImageName() {
this.project.setVersion("1.2.3");
assertThat(this.buildImage.getImageName()).isEqualTo("docker.io/library/build-image-test:1.2.3");
assertThat(this.buildImage.getImageName().get()).isEqualTo("docker.io/library/build-image-test:1.2.3");
BuildRequest request = this.buildImage.createRequest();
assertThat(request.getName().getDomain()).isEqualTo("docker.io");
assertThat(request.getName().getName()).isEqualTo("library/build-image-test");
@@ -84,8 +84,8 @@ class BootBuildImageTests {
@Test
void whenImageNameIsSpecifiedThenItIsUsedInRequest() {
this.project.setVersion("1.2.3");
this.buildImage.setImageName("example.com/test/build-image:1.0");
assertThat(this.buildImage.getImageName()).isEqualTo("example.com/test/build-image:1.0");
this.buildImage.getImageName().set("example.com/test/build-image:1.0");
assertThat(this.buildImage.getImageName().get()).isEqualTo("example.com/test/build-image:1.0");
BuildRequest request = this.buildImage.createRequest();
assertThat(request.getName().getDomain()).isEqualTo("example.com");
assertThat(request.getName().getName()).isEqualTo("test/build-image");
@@ -102,8 +102,8 @@ class BootBuildImageTests {
@Test
void whenIndividualEntriesAreAddedToTheEnvironmentThenTheyAreIncludedInTheRequest() {
this.buildImage.environment("ALPHA", "a");
this.buildImage.environment("BRAVO", "b");
this.buildImage.getEnvironment().put("ALPHA", "a");
this.buildImage.getEnvironment().put("BRAVO", "b");
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("ALPHA", "a").containsEntry("BRAVO", "b")
.hasSize(2);
}
@@ -113,7 +113,7 @@ class BootBuildImageTests {
Map<String, String> environment = new HashMap<>();
environment.put("ALPHA", "a");
environment.put("BRAVO", "b");
this.buildImage.environment(environment);
this.buildImage.getEnvironment().putAll(environment);
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("ALPHA", "a").containsEntry("BRAVO", "b")
.hasSize(2);
}
@@ -123,7 +123,7 @@ class BootBuildImageTests {
Map<String, String> environment = new HashMap<>();
environment.put("ALPHA", "a");
environment.put("BRAVO", "b");
this.buildImage.setEnvironment(environment);
this.buildImage.getEnvironment().set(environment);
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("ALPHA", "a").containsEntry("BRAVO", "b")
.hasSize(2);
}
@@ -133,15 +133,15 @@ class BootBuildImageTests {
Map<String, String> environment = new HashMap<>();
environment.put("ALPHA", "a");
environment.put("BRAVO", "b");
this.buildImage.environment("C", "Charlie");
this.buildImage.setEnvironment(environment);
this.buildImage.getEnvironment().put("C", "Charlie");
this.buildImage.getEnvironment().set(environment);
assertThat(this.buildImage.createRequest().getEnv()).containsEntry("ALPHA", "a").containsEntry("BRAVO", "b")
.hasSize(2);
}
@Test
void whenJavaVersionIsSetInEnvironmentItIsIncludedInTheRequest() {
this.buildImage.environment("BP_JVM_VERSION", "from-env");
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);
}
@@ -154,7 +154,7 @@ class BootBuildImageTests {
@Test
void whenTargetCompatibilityIsSetThenJavaVersionIsAddedToEnvironment() {
this.buildImage.environment("ALPHA", "a");
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);
@@ -167,7 +167,7 @@ class BootBuildImageTests {
@Test
void whenVerboseLoggingIsEnabledThenRequestHasVerboseLoggingEnabled() {
this.buildImage.setVerboseLogging(true);
this.buildImage.getVerboseLogging().set(true);
assertThat(this.buildImage.createRequest().isVerboseLogging()).isTrue();
}
@@ -178,7 +178,7 @@ class BootBuildImageTests {
@Test
void whenCleanCacheIsEnabledThenRequestHasCleanCacheEnabled() {
this.buildImage.setCleanCache(true);
this.buildImage.getCleanCache().set(true);
assertThat(this.buildImage.createRequest().isCleanCache()).isTrue();
}
@@ -194,7 +194,7 @@ class BootBuildImageTests {
@Test
void whenBuilderIsConfiguredThenRequestUsesSpecifiedBuilder() {
this.buildImage.setBuilder("example.com/test/builder:1.2");
this.buildImage.getBuilder().set("example.com/test/builder:1.2");
assertThat(this.buildImage.createRequest().getBuilder().getName()).isEqualTo("test/builder");
}
@@ -205,7 +205,7 @@ class BootBuildImageTests {
@Test
void whenRunImageIsConfiguredThenRequestUsesSpecifiedRunImage() {
this.buildImage.setRunImage("example.com/test/run:1.0");
this.buildImage.getRunImage().set("example.com/test/run:1.0");
assertThat(this.buildImage.createRequest().getRunImage().getName()).isEqualTo("test/run");
}
@@ -216,7 +216,7 @@ class BootBuildImageTests {
@Test
void whenPullPolicyIsConfiguredThenRequestHasPullPolicy() {
this.buildImage.setPullPolicy(PullPolicy.NEVER);
this.buildImage.getPullPolicy().set(PullPolicy.NEVER);
assertThat(this.buildImage.createRequest().getPullPolicy()).isEqualTo(PullPolicy.NEVER);
}
@@ -227,22 +227,22 @@ class BootBuildImageTests {
@Test
void whenBuildpacksAreConfiguredThenRequestHasBuildpacks() {
this.buildImage.setBuildpacks(Arrays.asList("example/buildpack1", "example/buildpack2"));
this.buildImage.getBuildpacks().set(Arrays.asList("example/buildpack1", "example/buildpack2"));
assertThat(this.buildImage.createRequest().getBuildpacks()).containsExactly(
BuildpackReference.of("example/buildpack1"), BuildpackReference.of("example/buildpack2"));
}
@Test
void whenEntriesAreAddedToBuildpacksThenRequestHasBuildpacks() {
this.buildImage.buildpacks(Arrays.asList("example/buildpack1", "example/buildpack2"));
this.buildImage.getBuildpacks().addAll(Arrays.asList("example/buildpack1", "example/buildpack2"));
assertThat(this.buildImage.createRequest().getBuildpacks()).containsExactly(
BuildpackReference.of("example/buildpack1"), BuildpackReference.of("example/buildpack2"));
}
@Test
void whenIndividualEntriesAreAddedToBuildpacksThenRequestHasBuildpacks() {
this.buildImage.buildpack("example/buildpack1");
this.buildImage.buildpack("example/buildpack2");
this.buildImage.getBuildpacks().add("example/buildpack1");
this.buildImage.getBuildpacks().add("example/buildpack2");
assertThat(this.buildImage.createRequest().getBuildpacks()).containsExactly(
BuildpackReference.of("example/buildpack1"), BuildpackReference.of("example/buildpack2"));
}
@@ -254,29 +254,30 @@ class BootBuildImageTests {
@Test
void whenBindingsAreConfiguredThenRequestHasBindings() {
this.buildImage.setBindings(Arrays.asList("host-src:container-dest:ro", "volume-name:container-dest:rw"));
this.buildImage.getBindings().set(Arrays.asList("host-src:container-dest:ro", "volume-name:container-dest:rw"));
assertThat(this.buildImage.createRequest().getBindings())
.containsExactly(Binding.of("host-src:container-dest:ro"), Binding.of("volume-name:container-dest:rw"));
}
@Test
void whenEntriesAreAddedToBindingsThenRequestHasBindings() {
this.buildImage.bindings(Arrays.asList("host-src:container-dest:ro", "volume-name:container-dest:rw"));
this.buildImage.getBindings()
.addAll(Arrays.asList("host-src:container-dest:ro", "volume-name:container-dest:rw"));
assertThat(this.buildImage.createRequest().getBindings())
.containsExactly(Binding.of("host-src:container-dest:ro"), Binding.of("volume-name:container-dest:rw"));
}
@Test
void whenIndividualEntriesAreAddedToBindingsThenRequestHasBindings() {
this.buildImage.binding("host-src:container-dest:ro");
this.buildImage.binding("volume-name:container-dest:rw");
this.buildImage.getBindings().add("host-src:container-dest:ro");
this.buildImage.getBindings().add("volume-name:container-dest:rw");
assertThat(this.buildImage.createRequest().getBindings())
.containsExactly(Binding.of("host-src:container-dest:ro"), Binding.of("volume-name:container-dest:rw"));
}
@Test
void whenNetworkIsConfiguredThenRequestHasNetwork() {
this.buildImage.setNetwork("test");
this.buildImage.getNetwork().set("test");
assertThat(this.buildImage.createRequest().getNetwork()).isEqualTo("test");
}
@@ -287,25 +288,25 @@ class BootBuildImageTests {
@Test
void whenTagsAreConfiguredThenRequestHasTags() {
this.buildImage.setTags(
Arrays.asList("my-app:latest", "example.com/my-app:0.0.1-SNAPSHOT", "example.com/my-app:latest"));
this.buildImage.getTags()
.set(Arrays.asList("my-app:latest", "example.com/my-app:0.0.1-SNAPSHOT", "example.com/my-app:latest"));
assertThat(this.buildImage.createRequest().getTags()).containsExactly(ImageReference.of("my-app:latest"),
ImageReference.of("example.com/my-app:0.0.1-SNAPSHOT"), ImageReference.of("example.com/my-app:latest"));
}
@Test
void whenEntriesAreAddedToTagsThenRequestHasTags() {
this.buildImage
.tags(Arrays.asList("my-app:latest", "example.com/my-app:0.0.1-SNAPSHOT", "example.com/my-app:latest"));
this.buildImage.getTags().addAll(
Arrays.asList("my-app:latest", "example.com/my-app:0.0.1-SNAPSHOT", "example.com/my-app:latest"));
assertThat(this.buildImage.createRequest().getTags()).containsExactly(ImageReference.of("my-app:latest"),
ImageReference.of("example.com/my-app:0.0.1-SNAPSHOT"), ImageReference.of("example.com/my-app:latest"));
}
@Test
void whenIndividualEntriesAreAddedToTagsThenRequestHasTags() {
this.buildImage.tag("my-app:latest");
this.buildImage.tag("example.com/my-app:0.0.1-SNAPSHOT");
this.buildImage.tag("example.com/my-app:latest");
this.buildImage.getTags().add("my-app:latest");
this.buildImage.getTags().add("example.com/my-app:0.0.1-SNAPSHOT");
this.buildImage.getTags().add("example.com/my-app:latest");
assertThat(this.buildImage.createRequest().getTags()).containsExactly(ImageReference.of("my-app:latest"),
ImageReference.of("example.com/my-app:0.0.1-SNAPSHOT"), ImageReference.of("example.com/my-app:latest"));
}

View File

@@ -16,11 +16,16 @@
package org.springframework.boot.gradle.tasks.bundling;
import java.io.File;
import org.gradle.api.GradleException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.buildpack.platform.docker.configuration.DockerConfiguration;
import org.springframework.boot.buildpack.platform.docker.configuration.DockerHost;
import org.springframework.boot.gradle.junit.GradleProjectBuilder;
import org.springframework.util.Base64Utils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -34,10 +39,17 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
class DockerSpecTests {
private DockerSpec dockerSpec;
@BeforeEach
void prepareDockerSpec(@TempDir File temp) {
this.dockerSpec = GradleProjectBuilder.builder().withProjectDir(temp).build().getObjects()
.newInstance(DockerSpec.class);
}
@Test
void asDockerConfigurationWithDefaults() {
DockerSpec dockerSpec = new DockerSpec();
DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration();
DockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
assertThat(dockerConfiguration.getHost()).isNull();
assertThat(dockerConfiguration.getBuilderRegistryAuthentication()).isNull();
assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader()))
@@ -47,17 +59,16 @@ class DockerSpecTests {
@Test
void asDockerConfigurationWithHostConfiguration() {
DockerSpec dockerSpec = new DockerSpec();
dockerSpec.setHost("docker.example.com");
dockerSpec.setTlsVerify(true);
dockerSpec.setCertPath("/tmp/ca-cert");
DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration();
this.dockerSpec.getHost().set("docker.example.com");
this.dockerSpec.getTlsVerify().set(true);
this.dockerSpec.getCertPath().set("/tmp/ca-cert");
DockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
DockerHost host = dockerConfiguration.getHost();
assertThat(host.getAddress()).isEqualTo("docker.example.com");
assertThat(host.isSecure()).isEqualTo(true);
assertThat(host.getCertificatePath()).isEqualTo("/tmp/ca-cert");
assertThat(dockerConfiguration.isBindHostToBuilder()).isFalse();
assertThat(dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull();
assertThat(this.dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull();
assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader()))
.contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"")
.contains("\"serveraddress\" : \"\"");
@@ -65,15 +76,14 @@ class DockerSpecTests {
@Test
void asDockerConfigurationWithHostConfigurationNoTlsVerify() {
DockerSpec dockerSpec = new DockerSpec();
dockerSpec.setHost("docker.example.com");
DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration();
this.dockerSpec.getHost().set("docker.example.com");
DockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
DockerHost host = dockerConfiguration.getHost();
assertThat(host.getAddress()).isEqualTo("docker.example.com");
assertThat(host.isSecure()).isEqualTo(false);
assertThat(host.getCertificatePath()).isNull();
assertThat(dockerConfiguration.isBindHostToBuilder()).isFalse();
assertThat(dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull();
assertThat(this.dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull();
assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader()))
.contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"")
.contains("\"serveraddress\" : \"\"");
@@ -81,16 +91,15 @@ class DockerSpecTests {
@Test
void asDockerConfigurationWithBindHostToBuilder() {
DockerSpec dockerSpec = new DockerSpec();
dockerSpec.setHost("docker.example.com");
dockerSpec.setBindHostToBuilder(true);
DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration();
this.dockerSpec.getHost().set("docker.example.com");
this.dockerSpec.getBindHostToBuilder().set(true);
DockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
DockerHost host = dockerConfiguration.getHost();
assertThat(host.getAddress()).isEqualTo("docker.example.com");
assertThat(host.isSecure()).isEqualTo(false);
assertThat(host.getCertificatePath()).isNull();
assertThat(dockerConfiguration.isBindHostToBuilder()).isTrue();
assertThat(dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull();
assertThat(this.dockerSpec.asDockerConfiguration().getBuilderRegistryAuthentication()).isNull();
assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader()))
.contains("\"username\" : \"\"").contains("\"password\" : \"\"").contains("\"email\" : \"\"")
.contains("\"serveraddress\" : \"\"");
@@ -98,12 +107,19 @@ class DockerSpecTests {
@Test
void asDockerConfigurationWithUserAuth() {
DockerSpec dockerSpec = new DockerSpec(
new DockerSpec.DockerRegistrySpec("user1", "secret1", "https://docker1.example.com",
"docker1@example.com"),
new DockerSpec.DockerRegistrySpec("user2", "secret2", "https://docker2.example.com",
"docker2@example.com"));
DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration();
this.dockerSpec.builderRegistry((registry) -> {
registry.getUsername().set("user1");
registry.getPassword().set("secret1");
registry.getUrl().set("https://docker1.example.com");
registry.getEmail().set("docker1@example.com");
});
this.dockerSpec.publishRegistry((registry) -> {
registry.getUsername().set("user2");
registry.getPassword().set("secret2");
registry.getUrl().set("https://docker2.example.com");
registry.getEmail().set("docker2@example.com");
});
DockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
assertThat(decoded(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader()))
.contains("\"username\" : \"user1\"").contains("\"password\" : \"secret1\"")
.contains("\"email\" : \"docker1@example.com\"")
@@ -112,32 +128,36 @@ class DockerSpecTests {
.contains("\"username\" : \"user2\"").contains("\"password\" : \"secret2\"")
.contains("\"email\" : \"docker2@example.com\"")
.contains("\"serveraddress\" : \"https://docker2.example.com\"");
assertThat(dockerSpec.asDockerConfiguration().getHost()).isNull();
assertThat(this.dockerSpec.asDockerConfiguration().getHost()).isNull();
}
@Test
void asDockerConfigurationWithIncompleteBuilderUserAuthFails() {
DockerSpec.DockerRegistrySpec builderRegistry = new DockerSpec.DockerRegistrySpec("user", null,
"https://docker.example.com", "docker@example.com");
DockerSpec dockerSpec = new DockerSpec(builderRegistry, null);
assertThatExceptionOfType(GradleException.class).isThrownBy(dockerSpec::asDockerConfiguration)
this.dockerSpec.builderRegistry((registry) -> {
registry.getUsername().set("user1");
registry.getUrl().set("https://docker1.example.com");
registry.getEmail().set("docker1@example.com");
});
assertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)
.withMessageContaining("Invalid Docker builder registry configuration");
}
@Test
void asDockerConfigurationWithIncompletePublishUserAuthFails() {
DockerSpec.DockerRegistrySpec publishRegistry = new DockerSpec.DockerRegistrySpec("user2", null,
"https://docker2.example.com", "docker2@example.com");
DockerSpec dockerSpec = new DockerSpec(null, publishRegistry);
assertThatExceptionOfType(GradleException.class).isThrownBy(dockerSpec::asDockerConfiguration)
this.dockerSpec.publishRegistry((registry) -> {
registry.getUsername().set("user2");
registry.getUrl().set("https://docker2.example.com");
registry.getEmail().set("docker2@example.com");
});
assertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)
.withMessageContaining("Invalid Docker publish registry configuration");
}
@Test
void asDockerConfigurationWithTokenAuth() {
DockerSpec dockerSpec = new DockerSpec(new DockerSpec.DockerRegistrySpec("token1"),
new DockerSpec.DockerRegistrySpec("token2"));
DockerConfiguration dockerConfiguration = dockerSpec.asDockerConfiguration();
this.dockerSpec.builderRegistry((registry) -> registry.getToken().set("token1"));
this.dockerSpec.publishRegistry((registry) -> registry.getToken().set("token2"));
DockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();
assertThat(decoded(dockerConfiguration.getBuilderRegistryAuthentication().getAuthHeader()))
.contains("\"identitytoken\" : \"token1\"");
assertThat(decoded(dockerConfiguration.getPublishRegistryAuthentication().getAuthHeader()))
@@ -146,12 +166,12 @@ class DockerSpecTests {
@Test
void asDockerConfigurationWithUserAndTokenAuthFails() {
DockerSpec.DockerRegistrySpec builderRegistry = new DockerSpec.DockerRegistrySpec();
builderRegistry.setUsername("user");
builderRegistry.setPassword("secret");
builderRegistry.setToken("token");
DockerSpec dockerSpec = new DockerSpec(builderRegistry, null);
assertThatExceptionOfType(GradleException.class).isThrownBy(dockerSpec::asDockerConfiguration)
this.dockerSpec.builderRegistry((registry) -> {
registry.getUsername().set("user");
registry.getPassword().set("secret");
registry.getToken().set("token");
});
assertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)
.withMessageContaining("Invalid Docker builder registry configuration");
}

View File

@@ -9,7 +9,7 @@ version = '1.0'
springBoot {
buildInfo {
properties {
additionalProperties = [
additional = [
'a': 'alpha', 'b': 'bravo'
]
}

View File

@@ -7,7 +7,7 @@ apply plugin: 'org.graalvm.buildtools.native'
task('bootBuildImageConfiguration') {
doFirst {
println "builder = ${tasks.getByName('bootBuildImage').builder}"
println "BP_NATIVE_IMAGE = ${tasks.getByName('bootBuildImage').environment['BP_NATIVE_IMAGE']}"
println "builder = ${tasks.getByName('bootBuildImage').builder.get()}"
println "BP_NATIVE_IMAGE = ${tasks.getByName('bootBuildImage').environment.get()['BP_NATIVE_IMAGE']}"
}
}

View File

@@ -5,7 +5,6 @@ plugins {
version = '0.1.0'
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
destinationDir project.buildDir
properties {
artifact = 'foo'
group = 'foo'

View File

@@ -6,11 +6,5 @@ group = 'foo'
version = '0.1.0'
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
destinationDir project.buildDir
properties {
group = ''
artifact = ''
version = ''
name = ''
}
excludes = ['group', 'artifact', 'version', 'name']
}

View File

@@ -3,11 +3,11 @@ plugins {
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
excludes = ["time"]
properties {
artifact = 'example'
group = 'com.example'
name = 'example'
additional = ['additional': 'alpha']
time = null
}
}

View File

@@ -5,11 +5,11 @@ plugins {
version = '{projectVersion}'
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
excludes = ["time"]
properties {
artifact = 'example'
group = 'com.example'
name = 'example'
additional = ['additional': 'alpha']
time = null
}
}

View File

@@ -1,16 +0,0 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
group = 'foo'
version = '0.1.0'
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
destinationDir project.buildDir
properties {
group = null
artifact = null
version = null
name = null
}
}

View File

@@ -3,7 +3,5 @@ plugins {
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
properties {
time = null
}
excludes = ["time"]
}

View File

@@ -3,7 +3,5 @@ plugins {
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
properties {
time = null
}
excludes = ["time"]
}