Remove assumptions from BootInfo and move them to the DSL extension

pull/8686/merge
Andy Wilkinson 8 years ago
parent 5708eaf41b
commit 188c9e0f42

@ -16,9 +16,15 @@
package org.springframework.boot.gradle; package org.springframework.boot.gradle;
import java.io.File;
import java.util.concurrent.Callable;
import org.gradle.api.Action; import org.gradle.api.Action;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.bundling.Jar;
import org.springframework.boot.gradle.buildinfo.BuildInfo; import org.springframework.boot.gradle.buildinfo.BuildInfo;
@ -43,7 +49,11 @@ public class SpringBootExtension {
/** /**
* Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and configures the * Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and configures the
* {@code classes} task to depend upon it. * Java plugin's {@code classes} task to depend upon it.
* <p>
* By default, the task's destination dir will be a directory named {@code META-INF}
* beneath the main source set's resources output directory, and the task's project
* artifact will be the base name of the {@code bootWar} or {@code bootJar} task.
*/ */
public void buildInfo() { public void buildInfo() {
this.buildInfo(null); this.buildInfo(null);
@ -51,16 +61,39 @@ public class SpringBootExtension {
/** /**
* Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and configures the * Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and configures the
* {@code classes} task to depend upon it. The task is passed to the given * Java plugin's {@code classes} task to depend upon it. The task is passed to the
* {@code configurer} for further configuration. * given {@code configurer} for further configuration.
* <p>
* By default, the task's destination dir will be a directory named {@code META-INF}
* beneath the main source set's resources output directory, and the task's project
* artifact will be the base name of the {@code bootWar} or {@code bootJar} task.
* *
* @param configurer the task configurer * @param configurer the task configurer
*/ */
public void buildInfo(Action<BuildInfo> configurer) { public void buildInfo(Action<BuildInfo> configurer) {
BuildInfo bootBuildInfo = this.project.getTasks().create("bootBuildInfo", BuildInfo bootBuildInfo = this.project.getTasks().create("bootBuildInfo",
BuildInfo.class); BuildInfo.class);
this.project.getPlugins().withType(JavaPlugin.class, (plugin) -> {
this.project.getTasks().getByName(JavaPlugin.CLASSES_TASK_NAME) this.project.getTasks().getByName(JavaPlugin.CLASSES_TASK_NAME)
.dependsOn(bootBuildInfo); .dependsOn(bootBuildInfo);
bootBuildInfo.getConventionMapping().map("projectArtifact",
(Callable<String>) () -> {
Jar artifactTask = (Jar) this.project.getTasks().findByName("bootWar");
if (artifactTask == null) {
artifactTask = (Jar) this.project.getTasks().findByName("bootJar");
}
String result = artifactTask == null ? null : artifactTask.getBaseName();
return result;
});
bootBuildInfo.getConventionMapping().map("destinationDir",
(Callable<File>) () -> {
return new File(
this.project.getConvention().getPlugin(JavaPluginConvention.class)
.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME)
.getOutput().getResourcesDir(),
"META-INF");
});
});
if (configurer != null) { if (configurer != null) {
configurer.execute(bootBuildInfo); configurer.execute(bootBuildInfo);
} }

@ -22,55 +22,45 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.gradle.api.DefaultTask; import org.gradle.api.Task;
import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.internal.ConventionTask;
import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskExecutionException; import org.gradle.api.tasks.TaskExecutionException;
import org.gradle.api.tasks.bundling.Jar;
import org.springframework.boot.loader.tools.BuildPropertiesWriter; import org.springframework.boot.loader.tools.BuildPropertiesWriter;
import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails; import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails;
/** /**
* {@link DefaultTask} for generating a {@code build-info.properties} file from a * {@link Task} for generating a {@code build-info.properties} file from a
* {@code Project}. * {@code Project}. The {@link #setDestinationDir destination dir} and
* <p> * {@link #setProjectArtifact project artifact} must be configured before execution.
* By default, the {@code build-info.properties} file is generated in
* project.buildDir/resources/main/META-INF.
* </p>
* *
* @author Andy Wilkinson * @author Andy Wilkinson
*/ */
public class BuildInfo extends DefaultTask { public class BuildInfo extends ConventionTask {
@OutputFile private File destinationDir;
private File outputFile = getProject().file(new File(getProject().getBuildDir(),
"resources/main/META-INF/build-info.properties"));
@Input
private String projectGroup = getProject().getGroup().toString(); private String projectGroup = getProject().getGroup().toString();
@Input private String projectArtifact;
private String projectArtifact = ((Jar) getProject().getTasks()
.getByName(JavaPlugin.JAR_TASK_NAME)).getBaseName();
@Input
private String projectVersion = getProject().getVersion().toString(); private String projectVersion = getProject().getVersion().toString();
@Input
private String projectName = getProject().getName(); private String projectName = getProject().getName();
@Input
private Map<String, Object> additionalProperties = new HashMap<>(); private Map<String, Object> additionalProperties = new HashMap<>();
@TaskAction @TaskAction
public void generateBuildProperties() { public void generateBuildProperties() {
try { try {
new BuildPropertiesWriter(this.outputFile) new BuildPropertiesWriter(
new File(getDestinationDir(), "build-info.properties"))
.writeBuildProperties(new ProjectDetails(this.projectGroup, .writeBuildProperties(new ProjectDetails(this.projectGroup,
this.projectArtifact, this.projectVersion, this.projectName, getProjectArtifact(), this.projectVersion,
this.projectName,
coerceToStringValues(this.additionalProperties))); coerceToStringValues(this.additionalProperties)));
} }
catch (IOException ex) { catch (IOException ex) {
@ -78,6 +68,7 @@ public class BuildInfo extends DefaultTask {
} }
} }
@Input
public String getProjectGroup() { public String getProjectGroup() {
return this.projectGroup; return this.projectGroup;
} }
@ -86,6 +77,7 @@ public class BuildInfo extends DefaultTask {
this.projectGroup = projectGroup; this.projectGroup = projectGroup;
} }
@Input
public String getProjectArtifact() { public String getProjectArtifact() {
return this.projectArtifact; return this.projectArtifact;
} }
@ -94,6 +86,7 @@ public class BuildInfo extends DefaultTask {
this.projectArtifact = projectArtifact; this.projectArtifact = projectArtifact;
} }
@Input
public String getProjectVersion() { public String getProjectVersion() {
return this.projectVersion; return this.projectVersion;
} }
@ -102,6 +95,7 @@ public class BuildInfo extends DefaultTask {
this.projectVersion = projectVersion; this.projectVersion = projectVersion;
} }
@Input
public String getProjectName() { public String getProjectName() {
return this.projectName; return this.projectName;
} }
@ -110,14 +104,16 @@ public class BuildInfo extends DefaultTask {
this.projectName = projectName; this.projectName = projectName;
} }
public File getOutputFile() { @OutputDirectory
return this.outputFile; public File getDestinationDir() {
return this.destinationDir;
} }
public void setOutputFile(File outputFile) { public void setDestinationDir(File destinationDir) {
this.outputFile = outputFile; this.destinationDir = destinationDir;
} }
@Input
public Map<String, Object> getAdditionalProperties() { public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties; return this.additionalProperties;
} }

@ -0,0 +1,128 @@
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.gradle.buildinfo;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.gradle.testkit.GradleBuild;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link BuildInfo} created using the
* {@link org.springframework.boot.gradle.SpringBootExtension DSL}.
*
* @author Andy Wilkinson
*/
public class BuildInfoDslIntegrationTests {
@Rule
public final GradleBuild gradleBuild = new GradleBuild();
@Test
public void basicJar() throws IOException {
assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace")
.task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties properties = buildInfoProperties();
assertThat(properties).containsEntry("build.name",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.artifact",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.group", "com.example");
assertThat(properties).containsEntry("build.version", "1.0");
}
@Test
public void jarWithCustomName() throws IOException {
assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace")
.task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties properties = buildInfoProperties();
assertThat(properties).containsEntry("build.name",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.artifact", "foo");
assertThat(properties).containsEntry("build.group", "com.example");
assertThat(properties).containsEntry("build.version", "1.0");
}
@Test
public void basicWar() throws IOException {
assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace")
.task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties properties = buildInfoProperties();
assertThat(properties).containsEntry("build.name",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.artifact",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.group", "com.example");
assertThat(properties).containsEntry("build.version", "1.0");
}
@Test
public void warWithCustomName() throws IOException {
assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace")
.task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties properties = buildInfoProperties();
assertThat(properties).containsEntry("build.name",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.artifact", "foo");
assertThat(properties).containsEntry("build.group", "com.example");
assertThat(properties).containsEntry("build.version", "1.0");
}
@Test
public void additionalProperties() throws IOException {
assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace")
.task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
Properties properties = buildInfoProperties();
assertThat(properties).containsEntry("build.name",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.artifact",
this.gradleBuild.getProjectDir().getName());
assertThat(properties).containsEntry("build.group", "com.example");
assertThat(properties).containsEntry("build.version", "1.0");
assertThat(properties).containsEntry("build.a", "alpha");
assertThat(properties).containsEntry("build.b", "bravo");
}
@Test
public void classesDependency() throws IOException {
assertThat(this.gradleBuild.build("classes", "--stacktrace")
.task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
}
private Properties buildInfoProperties() {
File file = new File(this.gradleBuild.getProjectDir(),
"build/resources/main/META-INF/build-info.properties");
assertThat(file).isFile();
Properties properties = new Properties();
try (FileReader reader = new FileReader(file)) {
properties.load(reader);
return properties;
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}

@ -0,0 +1,88 @@
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.gradle.buildinfo;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.gradle.testkit.GradleBuild;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link BuildInfo}.
*
* @author Andy Wilkinson
*/
public class BuildInfoIntegrationTests {
@Rule
public final GradleBuild gradleBuild = new GradleBuild();
@Test
public void basicExecution() {
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
}
@Test
public void upToDateWhenExecutedTwice() {
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome())
.isEqualTo(TaskOutcome.UP_TO_DATE);
}
@Test
public void notUpToDateWhenDestinationDirChanges() {
notUpToDateWithChangeToProperty("buildInfoDestinationDir");
}
@Test
public void notUpToDateWhenProjectArtifactChanges() {
notUpToDateWithChangeToProperty("buildInfoProjectArtifact");
}
@Test
public void notUpToDateWhenProjectGroupChanges() {
notUpToDateWithChangeToProperty("buildInfoProjectGroup");
}
@Test
public void notUpToDateWhenProjectVersionChanges() {
notUpToDateWithChangeToProperty("buildInfoProjectVersion");
}
@Test
public void notUpToDateWhenProjectNameChanges() {
notUpToDateWithChangeToProperty("buildInfoProjectName");
}
@Test
public void notUpToDateWhenAdditionalPropertyChanges() {
notUpToDateWithChangeToProperty("buildInfoAdditionalProperty");
}
private void notUpToDateWithChangeToProperty(String name) {
assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome())
.isEqualTo(TaskOutcome.SUCCESS);
assertThat(this.gradleBuild.build("buildInfo", "-P" + name + "=changed")
.task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
}
}

@ -0,0 +1,17 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'java'
group = 'com.example'
version = '1.0'
springBoot {
buildInfo {
additionalProperties 'a': 'alpha', 'b': 'bravo'
}
}

@ -0,0 +1,15 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'java'
group = 'com.example'
version = '1.0'
springBoot {
buildInfo()
}

@ -0,0 +1,15 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'war'
group = 'com.example'
version = '1.0'
springBoot {
buildInfo()
}

@ -0,0 +1,12 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'java'
springBoot {
buildInfo()
}

@ -0,0 +1,19 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'java'
group = 'com.example'
version = '1.0'
bootJar {
baseName = 'foo'
}
springBoot {
buildInfo()
}

@ -0,0 +1,19 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
apply plugin: 'org.springframework.boot'
apply plugin: 'war'
group = 'com.example'
version = '1.0'
bootWar {
baseName = 'foo'
}
springBoot {
buildInfo()
}

@ -0,0 +1,18 @@
buildscript {
dependencies {
classpath files(pluginClasspath.split(','))
}
}
def property(String name, Object defaultValue) {
project.hasProperty(name) ? project.getProperty(name) : defaultValue
}
task buildInfo(type: org.springframework.boot.gradle.buildinfo.BuildInfo) {
destinationDir file(property('buildInfoDestinationDir', project.buildDir))
projectArtifact property('buildInfoProjectArtifact', 'foo')
projectVersion property('buildInfoProjectVersion', '1.0')
projectGroup property('buildInfoProjectGroup', 'foo')
projectName property('buildInfoProjectName', 'foo')
additionalProperties 'additional': property('buildInfoAdditionalProperty', 'foo')
}
Loading…
Cancel
Save