Update BuildInfo to support Gradle's configuration cache

See gh-22922
pull/23886/head
Andy Wilkinson 4 years ago
parent 83cfd3b2e6
commit d1f543fc1d

@ -24,6 +24,7 @@ import java.util.Map;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.internal.ConventionTask;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.OutputDirectory;
@ -44,7 +45,12 @@ public class BuildInfo extends ConventionTask {
private final BuildInfoProperties properties = new BuildInfoProperties(getProject());
private File destinationDir;
private final DirectoryProperty destinationDir;
public BuildInfo() {
this.destinationDir = getProject().getObjects().directoryProperty()
.convention(getProject().getLayout().getBuildDirectory());
}
/**
* Generates the {@code build-info.properties} file in the configured
@ -73,7 +79,7 @@ public class BuildInfo extends ConventionTask {
*/
@OutputDirectory
public File getDestinationDir() {
return (this.destinationDir != null) ? this.destinationDir : getProject().getBuildDir();
return this.destinationDir.getAsFile().get();
}
/**
@ -81,7 +87,7 @@ public class BuildInfo extends ConventionTask {
* @param destinationDir the destination directory
*/
public void setDestinationDir(File destinationDir) {
this.destinationDir = destinationDir;
this.destinationDir.set(destinationDir);
}
/**

@ -16,6 +16,8 @@
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.util.HashMap;
@ -23,6 +25,7 @@ import java.util.Map;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
@ -35,6 +38,8 @@ import org.gradle.api.tasks.Optional;
@SuppressWarnings("serial")
public class BuildInfoProperties implements Serializable {
private transient Instant creationTime = Instant.now();
private final Property<String> group;
private final Property<String> artifact;
@ -43,22 +48,35 @@ public class BuildInfoProperties implements Serializable {
private final Property<String> name;
private final Property<Instant> time;
private final Property<Long> time;
private boolean timeConfigured = false;
private Map<String, Object> additionalProperties = new HashMap<>();
BuildInfoProperties(Project project) {
this.time = project.getObjects().property(Instant.class);
this.time.set(Instant.now());
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(project.provider(() -> project.getVersion().toString()));
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) {
try {
Provider<String> externalVersionProperty = project.getProviders().gradleProperty("version")
.forUseAtConfigurationTime();
externalVersionProperty.getOrNull();
}
catch (NoSuchMethodError ex) {
// Gradle < 6.5
}
return project.provider(() -> project.getVersion().toString());
}
/**
* Returns the value used for the {@code build.group} property. Defaults to the
* {@link Project#getGroup() Project's group}.
@ -142,7 +160,14 @@ public class BuildInfoProperties implements Serializable {
@Input
@Optional
public Instant getTime() {
return this.time.getOrNull();
Long epochMillis = this.time.getOrNull();
if (epochMillis != null) {
return Instant.ofEpochMilli(epochMillis);
}
if (this.timeConfigured) {
return null;
}
return this.creationTime;
}
/**
@ -150,7 +175,8 @@ public class BuildInfoProperties implements Serializable {
* @param time the build time
*/
public void setTime(Instant time) {
this.time.set(time);
this.timeConfigured = true;
this.time.set((time != null) ? time.toEpochMilli() : null);
}
/**
@ -173,4 +199,9 @@ public class BuildInfoProperties implements Serializable {
this.additionalProperties = additionalProperties;
}
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
input.defaultReadObject();
this.creationTime = Instant.now();
}
}

@ -19,9 +19,13 @@ package org.springframework.boot.gradle.tasks.buildinfo;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Instant;
import java.util.Properties;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.InvalidRunnerConfigurationException;
import org.gradle.testkit.runner.TaskOutcome;
import org.gradle.testkit.runner.UnexpectedBuildFailure;
@ -38,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Andy Wilkinson
*/
@GradleCompatibility
@GradleCompatibility(configurationCache = true)
class BuildInfoIntegrationTests {
GradleBuild gradleBuild;
@ -69,7 +73,14 @@ class BuildInfoIntegrationTests {
@TestTemplate
void notUpToDateWhenExecutedTwiceAsTimeChanges() {
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties first = buildInfoProperties();
String firstBuildTime = first.getProperty("build.time");
assertThat(firstBuildTime).isNotNull();
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties second = buildInfoProperties();
String secondBuildTime = second.getProperty("build.time");
assertThat(secondBuildTime).isNotNull();
assertThat(Instant.parse(firstBuildTime).isBefore(Instant.parse(secondBuildTime)));
}
@TestTemplate
@ -81,11 +92,22 @@ class BuildInfoIntegrationTests {
}
@TestTemplate
void notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedProjectVersion() {
assertThat(this.gradleBuild.build("buildInfo", "-PnullTime").task(":buildInfo").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
BuildResult result = this.gradleBuild.build("buildInfo", "-PnullTime", "-PprojectVersion=0.2.0");
assertThat(result.task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
void notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedProjectVersion() throws IOException {
assertThat(this.gradleBuild.scriptProperty("projectVersion", "0.1.0").build("buildInfo").task(":buildInfo")
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(this.gradleBuild.scriptProperty("projectVersion", "0.2.0").build("buildInfo").task(":buildInfo")
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
}
@TestTemplate
void notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedGradlePropertiesProjectVersion() throws IOException {
Path gradleProperties = new File(this.gradleBuild.getProjectDir(), "gradle.properties").toPath();
Files.write(gradleProperties, "version=0.1.0".getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE,
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Files.write(gradleProperties, "version=0.2.0".getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE,
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
}
@TestTemplate

@ -24,6 +24,8 @@ import java.time.format.DateTimeFormatter;
import java.util.Properties;
import org.gradle.api.Project;
import org.gradle.api.internal.project.ProjectInternal;
import org.gradle.initialization.GradlePropertiesController;
import org.gradle.testfixtures.ProjectBuilder;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@ -125,7 +127,10 @@ class BuildInfoTests {
private Project createProject(String projectName) {
File projectDir = new File(this.temp, projectName);
return ProjectBuilder.builder().withProjectDir(projectDir).withName(projectName).build();
Project project = ProjectBuilder.builder().withProjectDir(projectDir).withName(projectName).build();
((ProjectInternal) project).getServices().get(GradlePropertiesController.class)
.loadGradlePropertiesFrom(projectDir);
return project;
}
private BuildInfo createTask(Project project) {

@ -176,7 +176,7 @@ public class GradleBuild {
new File(this.projectDir, "repository"));
GradleRunner gradleRunner = GradleRunner.create().withProjectDir(this.projectDir)
.withPluginClasspath(pluginClasspath());
if (this.dsl != Dsl.KOTLIN) {
if (this.dsl != Dsl.KOTLIN && !this.configurationCache) {
// see https://github.com/gradle/gradle/issues/6862
gradleRunner.withDebug(true);
}

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

@ -2,8 +2,4 @@ plugins {
id 'org.springframework.boot' version '{version}' apply false
}
def property(String name, Object defaultValue) {
project.hasProperty(name) ? project.getProperty(name) : defaultValue
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo)

@ -0,0 +1,5 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo)

@ -0,0 +1,13 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
properties {
artifact = 'example'
group = 'com.example'
name = 'example'
additional = ['additional': 'alpha']
time = null
}
}

@ -0,0 +1,15 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
version = '{projectVersion}'
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
properties {
artifact = 'example'
group = 'com.example'
name = 'example'
additional = ['additional': 'alpha']
time = null
}
}

@ -0,0 +1,9 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
properties {
time = null
}
}

@ -0,0 +1,9 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
properties {
time = null
}
}

@ -1,22 +0,0 @@
plugins {
id 'org.springframework.boot' version '{version}' apply false
}
def property(String name, Object defaultValue) {
project.hasProperty(name) ? project.getProperty(name) : defaultValue
}
version = property('projectVersion', '0.1.0')
task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {
destinationDir file(property('buildInfoDestinationDir', project.buildDir))
properties {
artifact = property('buildInfoArtifact', 'foo')
group = property('buildInfoGroup', 'foo')
name = property('buildInfoName', 'foo')
additional = ['additional': property('buildInfoAdditional', 'foo')]
if (project.hasProperty('nullTime')) {
time = null
}
}
}
Loading…
Cancel
Save