Commit 21536f64 authored by Stephane Nicoll's avatar Stephane Nicoll

Polish info contributor feature

This commit improves the `InfoContributor` infrastructure as follows:

* `InfoEndpoint` no longer breaks its public API and returns a Map as
before
* `Info` is now immutable
* All properties of the build are now displayed. Since we control the
generation of that file, there is no longer a mode to restrict what's
shown
* Build info is now generated in `META-INF/build-info.properties` by
default

Closes gh-5734
parent a1413bdb
...@@ -82,8 +82,7 @@ public class InfoContributorAutoConfiguration { ...@@ -82,8 +82,7 @@ public class InfoContributorAutoConfiguration {
@ConditionalOnSingleCandidate(BuildProperties.class) @ConditionalOnSingleCandidate(BuildProperties.class)
@Order(DEFAULT_ORDER) @Order(DEFAULT_ORDER)
public InfoContributor buildInfoContributor(BuildProperties buildProperties) { public InfoContributor buildInfoContributor(BuildProperties buildProperties) {
return new BuildInfoContributor(buildProperties, return new BuildInfoContributor(buildProperties);
this.properties.getBuild().getMode());
} }
} }
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.actuate.autoconfigure;
import org.springframework.boot.actuate.info.BuildInfoContributor;
import org.springframework.boot.actuate.info.GitInfoContributor; import org.springframework.boot.actuate.info.GitInfoContributor;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
...@@ -29,34 +28,12 @@ import org.springframework.boot.context.properties.ConfigurationProperties; ...@@ -29,34 +28,12 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("management.info") @ConfigurationProperties("management.info")
public class InfoContributorProperties { public class InfoContributorProperties {
private final Build build = new Build();
private final Git git = new Git(); private final Git git = new Git();
public Build getBuild() {
return this.build;
}
public Git getGit() { public Git getGit() {
return this.git; return this.git;
} }
public static class Build {
/**
* Mode to use to expose build information.
*/
private BuildInfoContributor.Mode mode = BuildInfoContributor.Mode.SIMPLE;
public BuildInfoContributor.Mode getMode() {
return this.mode;
}
public void setMode(BuildInfoContributor.Mode mode) {
this.mode = mode;
}
}
public static class Git { public static class Git {
......
...@@ -33,7 +33,7 @@ import org.springframework.util.Assert; ...@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@ConfigurationProperties(prefix = "endpoints.info") @ConfigurationProperties(prefix = "endpoints.info")
public class InfoEndpoint extends AbstractEndpoint<Info> { public class InfoEndpoint extends AbstractEndpoint<Map<String, Object>> {
private final List<InfoContributor> infoContributors; private final List<InfoContributor> infoContributors;
...@@ -48,13 +48,14 @@ public class InfoEndpoint extends AbstractEndpoint<Info> { ...@@ -48,13 +48,14 @@ public class InfoEndpoint extends AbstractEndpoint<Info> {
} }
@Override @Override
public Info invoke() { public Map<String, Object> invoke() {
Info.Builder builder = new Info.Builder(); Info.Builder builder = new Info.Builder();
for (InfoContributor contributor : this.infoContributors) { for (InfoContributor contributor : this.infoContributors) {
contributor.contribute(builder); contributor.contribute(builder);
} }
builder.withDetails(getAdditionalInfo()); builder.withDetails(getAdditionalInfo());
return builder.build(); Info build = builder.build();
return build.getDetails();
} }
/** /**
......
...@@ -31,12 +31,8 @@ import org.springframework.core.env.PropertySource; ...@@ -31,12 +31,8 @@ import org.springframework.core.env.PropertySource;
*/ */
public class BuildInfoContributor extends InfoPropertiesInfoContributor<BuildProperties> { public class BuildInfoContributor extends InfoPropertiesInfoContributor<BuildProperties> {
public BuildInfoContributor(BuildProperties properties, Mode mode) {
super(properties, mode);
}
public BuildInfoContributor(BuildProperties properties) { public BuildInfoContributor(BuildProperties properties) {
this(properties, Mode.SIMPLE); super(properties, Mode.FULL);
} }
@Override @Override
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.boot.actuate.info; package org.springframework.boot.actuate.info;
import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
...@@ -39,8 +40,9 @@ public final class Info { ...@@ -39,8 +40,9 @@ public final class Info {
private final Map<String, Object> details; private final Map<String, Object> details;
private Info(Builder builder) { private Info(Builder builder) {
this.details = new LinkedHashMap<String, Object>(); LinkedHashMap<String, Object> content = new LinkedHashMap<String, Object>();
this.details.putAll(builder.content); content.putAll(builder.content);
this.details = Collections.unmodifiableMap(content);
} }
/** /**
......
...@@ -187,7 +187,7 @@ public class EndpointAutoConfigurationTests { ...@@ -187,7 +187,7 @@ public class EndpointAutoConfigurationTests {
this.context.refresh(); this.context.refresh();
InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class);
Info info = endpoint.invoke(); Map<String, Object> info = endpoint.invoke();
assertThat(info).isNotNull(); assertThat(info).isNotNull();
assertThat(info.get("name")).isEqualTo("foo"); assertThat(info.get("name")).isEqualTo("foo");
assertThat(info.get("version")).isEqualTo("1.0"); assertThat(info.get("version")).isEqualTo("1.0");
......
...@@ -115,7 +115,7 @@ public class InfoContributorAutoConfigurationTests { ...@@ -115,7 +115,7 @@ public class InfoContributorAutoConfigurationTests {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Test @Test
public void buildPropertiesDefaultMode() { public void buildProperties() {
load(BuildPropertiesConfiguration.class); load(BuildPropertiesConfiguration.class);
Map<String, InfoContributor> beans = this.context Map<String, InfoContributor> beans = this.context
.getBeansOfType(InfoContributor.class); .getBeansOfType(InfoContributor.class);
...@@ -125,18 +125,6 @@ public class InfoContributorAutoConfigurationTests { ...@@ -125,18 +125,6 @@ public class InfoContributorAutoConfigurationTests {
Object build = content.get("build"); Object build = content.get("build");
assertThat(build).isInstanceOf(Map.class); assertThat(build).isInstanceOf(Map.class);
Map<String, Object> buildInfo = (Map<String, Object>) build; Map<String, Object> buildInfo = (Map<String, Object>) build;
assertThat(buildInfo).containsOnlyKeys("group", "artifact");
}
@SuppressWarnings("unchecked")
@Test
public void buildPropertiesFullMode() {
load(BuildPropertiesConfiguration.class, "management.info.build.mode=full");
Map<String, Object> content = invokeContributor(
this.context.getBean("buildInfoContributor", InfoContributor.class));
Object build = content.get("build");
assertThat(build).isInstanceOf(Map.class);
Map<String, Object> buildInfo = (Map<String, Object>) build;
assertThat(buildInfo).containsOnlyKeys("group", "artifact", "foo"); assertThat(buildInfo).containsOnlyKeys("group", "artifact", "foo");
assertThat(buildInfo.get("foo")).isEqualTo("bar"); assertThat(buildInfo.get("foo")).isEqualTo("bar");
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.boot.actuate.endpoint; package org.springframework.boot.actuate.endpoint;
import java.util.List; import java.util.List;
import java.util.Map;
import org.junit.Test; import org.junit.Test;
...@@ -43,7 +44,7 @@ public class InfoEndpointTests extends AbstractEndpointTests<InfoEndpoint> { ...@@ -43,7 +44,7 @@ public class InfoEndpointTests extends AbstractEndpointTests<InfoEndpoint> {
@Test @Test
public void invoke() throws Exception { public void invoke() throws Exception {
Info actual = getEndpointBean().invoke(); Map<String, Object> actual = getEndpointBean().invoke();
assertThat(actual.get("key1")).isEqualTo("value1"); assertThat(actual.get("key1")).isEqualTo("value1");
} }
......
/*
* Copyright 2012-2016 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.actuate.info;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link Info}.
*
* @author Stephane Nicoll
*/
public class InfoTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void infoIsImmutable() {
Info info = new Info.Builder().withDetail("foo", "bar").build();
this.thrown.expect(UnsupportedOperationException.class);
info.getDetails().clear();
}
@Test
public void infoTakesCopyOfMap() {
Info.Builder builder = new Info.Builder();
builder.withDetail("foo", "bar");
Info build = builder.build();
builder.withDetail("biz", "bar");
assertThat(build.getDetails()).containsOnly(entry("foo", "bar"));
}
}
...@@ -62,7 +62,7 @@ public class ProjectInfoAutoConfiguration { ...@@ -62,7 +62,7 @@ public class ProjectInfoAutoConfiguration {
return new GitProperties(loadFrom(this.properties.getGit().getLocation(), "git")); return new GitProperties(loadFrom(this.properties.getGit().getLocation(), "git"));
} }
@ConditionalOnResource(resources = "${spring.info.build.location:classpath:META-INF/boot/build.properties}") @ConditionalOnResource(resources = "${spring.info.build.location:classpath:META-INF/build-info.properties}")
@ConditionalOnMissingBean @ConditionalOnMissingBean
@Bean @Bean
public BuildProperties buildProperties() throws Exception { public BuildProperties buildProperties() throws Exception {
......
...@@ -59,10 +59,10 @@ public class ProjectInfoProperties { ...@@ -59,10 +59,10 @@ public class ProjectInfoProperties {
public static class Build { public static class Build {
/** /**
* Location of the generated build.properties file. * Location of the generated build-info.properties file.
*/ */
private Resource location = new ClassPathResource( private Resource location = new ClassPathResource(
"META-INF/boot/build.properties"); "META-INF/build-info.properties");
public Resource getLocation() { public Resource getLocation() {
return this.location; return this.location;
......
...@@ -105,7 +105,7 @@ public class ProjectInfoAutoConfigurationTests { ...@@ -105,7 +105,7 @@ public class ProjectInfoAutoConfigurationTests {
@Test @Test
public void buildPropertiesCustomLocation() { public void buildPropertiesCustomLocation() {
load("spring.info.build.location=classpath:/org/springframework/boot/autoconfigure/info/build.properties"); load("spring.info.build.location=classpath:/org/springframework/boot/autoconfigure/info/build-info.properties");
BuildProperties buildProperties = this.context.getBean(BuildProperties.class); BuildProperties buildProperties = this.context.getBean(BuildProperties.class);
assertThat(buildProperties.getGroup()).isEqualTo("com.example.acme"); assertThat(buildProperties.getGroup()).isEqualTo("com.example.acme");
assertThat(buildProperties.getArtifact()).isEqualTo("acme"); assertThat(buildProperties.getArtifact()).isEqualTo("acme");
...@@ -116,7 +116,7 @@ public class ProjectInfoAutoConfigurationTests { ...@@ -116,7 +116,7 @@ public class ProjectInfoAutoConfigurationTests {
@Test @Test
public void buildPropertiesCustomInvalidLocation() { public void buildPropertiesCustomInvalidLocation() {
load("spring.info.build.location=classpath:/org/acme/no-build.properties"); load("spring.info.build.location=classpath:/org/acme/no-build-info.properties");
Map<String, BuildProperties> beans = this.context Map<String, BuildProperties> beans = this.context
.getBeansOfType(BuildProperties.class); .getBeansOfType(BuildProperties.class);
assertThat(beans).hasSize(0); assertThat(beans).hasSize(0);
......
...@@ -86,7 +86,7 @@ content into your application; rather pick only the properties that you need. ...@@ -86,7 +86,7 @@ content into your application; rather pick only the properties that you need.
spring.hazelcast.config= # The location of the configuration file to use to initialize Hazelcast. spring.hazelcast.config= # The location of the configuration file to use to initialize Hazelcast.
# PROJECT INFORMATION ({sc-spring-boot-autoconfigure}/info/ProjectInfoProperties.{sc-ext}[ProjectInfoProperties]) # PROJECT INFORMATION ({sc-spring-boot-autoconfigure}/info/ProjectInfoProperties.{sc-ext}[ProjectInfoProperties])
spring.info.build.location=classpath:META-INF/boot/build.properties # Location of the generated build.properties file. spring.info.build.location=classpath:META-INF/build-info.properties # Location of the generated build-info.properties file.
spring.info.git.location=classpath:git.properties # Location of the generated git.properties file. spring.info.git.location=classpath:git.properties # Location of the generated git.properties file.
# JMX # JMX
...@@ -1015,7 +1015,6 @@ content into your application; rather pick only the properties that you need. ...@@ -1015,7 +1015,6 @@ content into your application; rather pick only the properties that you need.
# INFO CONTRIBUTORS ({sc-spring-boot-actuator}/autoconfigure/InfoContributorProperties.{sc-ext}[InfoContributorProperties]) # INFO CONTRIBUTORS ({sc-spring-boot-actuator}/autoconfigure/InfoContributorProperties.{sc-ext}[InfoContributorProperties])
management.info.build.enabled=true # Enable build info. management.info.build.enabled=true # Enable build info.
management.info.build.mode=simple # Mode to use to expose build information.
management.info.defaults.enabled=true # Enable default info contributors. management.info.defaults.enabled=true # Enable default info contributors.
management.info.env.enabled=true # Enable environment info. management.info.env.enabled=true # Enable environment info.
management.info.git.enabled=true # Enable git info. management.info.git.enabled=true # Enable git info.
......
...@@ -393,7 +393,7 @@ The following `InfoContributors` are auto-configured by Spring Boot when appropr ...@@ -393,7 +393,7 @@ The following `InfoContributors` are auto-configured by Spring Boot when appropr
|Expose git information if a `git.properties` file is available. |Expose git information if a `git.properties` file is available.
|{sc-spring-boot-actuator}/info/BuildInfoContributor.{sc-ext}[`BuildInfoContributor`] |{sc-spring-boot-actuator}/info/BuildInfoContributor.{sc-ext}[`BuildInfoContributor`]
|Expose build information if a `META-INF/boot/build.properties` file is available. |Expose build information if a `META-INF/build-info.properties` file is available.
|=== |===
TIP: It is possible to disable them all using the `management.info.defaults.enabled` TIP: It is possible to disable them all using the `management.info.defaults.enabled`
...@@ -453,19 +453,12 @@ If you want to display the full git information (i.e. the full content of ...@@ -453,19 +453,12 @@ If you want to display the full git information (i.e. the full content of
[[production-ready-application-info-build]] [[production-ready-application-info-build]]
==== Build information ==== Build information
The `info` endpoint can also publish information about your build if a `BuildProperties` The `info` endpoint can also publish information about your build if a `BuildProperties`
bean is available. This happens if a `META-INF/boot/build.properties` file is available bean is available. This happens if a `META-INF/build-info.properties` file is available
in the classpath. in the classpath.
TIP: The Maven and Gradle plugins can both generate that file, see TIP: The Maven and Gradle plugins can both generate that file, see
<<howto.adoc#howto-build-info,Generate build information>> for more details. <<howto.adoc#howto-build-info,Generate build information>> for more details.
If additional properties are present they are not exposed unless configured explicitly:
[source,properties,indent=0]
----
management.info.build.mode=full
----
[[production-ready-application-info-custom]] [[production-ready-application-info-custom]]
==== Writing custom InfoContributors ==== Writing custom InfoContributors
......
...@@ -34,11 +34,11 @@ import org.springframework.boot.loader.tools.BuildPropertiesWriter; ...@@ -34,11 +34,11 @@ 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.properties} file from a * {@link DefaultTask} for generating a {@code build-info.properties} file from a
* {@code Project}. * {@code Project}.
* <p> * <p>
* By default, the {@code build.properties} file is generated in * By default, the {@code build-info.properties} file is generated in
* project.buildDir/resources/main/META-INF/boot. * project.buildDir/resources/main/META-INF.
* </p> * </p>
* *
* @author Andy Wilkinson * @author Andy Wilkinson
...@@ -47,7 +47,7 @@ public class BuildInfo extends DefaultTask { ...@@ -47,7 +47,7 @@ public class BuildInfo extends DefaultTask {
@OutputFile @OutputFile
private File outputFile = getProject().file(new File(getProject().getBuildDir(), private File outputFile = getProject().file(new File(getProject().getBuildDir(),
"resources/main/META-INF/boot/build.properties")); "resources/main/META-INF/build-info.properties"));
@Input @Input
private String projectGroup = getProject().getGroup().toString(); private String projectGroup = getProject().getGroup().toString();
......
...@@ -25,8 +25,8 @@ import java.util.Map; ...@@ -25,8 +25,8 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
/** /**
* A {@code BuildPropertiesWriter} writes the {@code build.properties} for consumption by * A {@code BuildPropertiesWriter} writes the {@code build-info.properties} for
* the Actuator. * consumption by the Actuator.
* *
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Stephane Nicoll * @author Stephane Nicoll
......
...@@ -3,7 +3,7 @@ import org.springframework.boot.maven.Verify ...@@ -3,7 +3,7 @@ import org.springframework.boot.maven.Verify
import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals
import static org.junit.Assert.assertTrue import static org.junit.Assert.assertTrue
def file = new File(basedir, "target/classes/META-INF/boot/build.properties") def file = new File(basedir, "target/classes/META-INF/build-info.properties")
println file.getAbsolutePath() println file.getAbsolutePath()
Properties properties = Verify.verifyBuildInfo(file, Properties properties = Verify.verifyBuildInfo(file,
'org.springframework.boot.maven.it', 'build-info-additional-properties', 'org.springframework.boot.maven.it', 'build-info-additional-properties',
......
...@@ -2,7 +2,7 @@ import org.springframework.boot.maven.Verify ...@@ -2,7 +2,7 @@ import org.springframework.boot.maven.Verify
import static org.junit.Assert.assertTrue import static org.junit.Assert.assertTrue
def file = new File(basedir, "target/classes/META-INF/boot/build.properties") def file = new File(basedir, "target/classes/META-INF/build-info.properties")
println file.getAbsolutePath() println file.getAbsolutePath()
Properties properties = Verify.verifyBuildInfo(file, Properties properties = Verify.verifyBuildInfo(file,
'org.springframework.boot.maven.it', 'build-info', 'org.springframework.boot.maven.it', 'build-info',
......
...@@ -31,7 +31,7 @@ import org.springframework.boot.loader.tools.BuildPropertiesWriter; ...@@ -31,7 +31,7 @@ import org.springframework.boot.loader.tools.BuildPropertiesWriter;
import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails; import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails;
/** /**
* Generate a {@code build.properties} file based the content of the current * Generate a {@code build-info.properties} file based the content of the current
* {@link MavenProject}. * {@link MavenProject}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
...@@ -47,14 +47,14 @@ public class BuildInfoMojo extends AbstractMojo { ...@@ -47,14 +47,14 @@ public class BuildInfoMojo extends AbstractMojo {
private MavenProject project; private MavenProject project;
/** /**
* The location of the generated build.properties. * The location of the generated build-info.properties.
*/ */
@Parameter(defaultValue = "${project.build.outputDirectory}/META-INF/boot/build.properties") @Parameter(defaultValue = "${project.build.outputDirectory}/META-INF/build-info.properties")
private File outputFile; private File outputFile;
/** /**
* Additional properties to store in the build.properties. Each entry is prefixed by * Additional properties to store in the build-info.properties. Each entry is prefixed by
* {@code build.} in the generated build.properties. * {@code build.} in the generated build-info.properties.
*/ */
@Parameter @Parameter
private Map<String, String> additionalProperties; private Map<String, String> additionalProperties;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
2016-03-17 2016-03-17
----- -----
Spring Boot Actuator displays build-related information if a <<<META-INF/boot/build.properties>>> Spring Boot Actuator displays build-related information if a <<<META-INF/build-info.properties>>>
file is present. The <<<build-info>>> goal generates such file with the coordinates of the project file is present. The <<<build-info>>> goal generates such file with the coordinates of the project
and the build time. It also allows you to add an arbitrary number of additional properties: and the build time. It also allows you to add an arbitrary number of additional properties:
...@@ -46,10 +46,10 @@ ...@@ -46,10 +46,10 @@
</project> </project>
--- ---
This configuration will generate a <<<build.properties>>> at the expected location with four This configuration will generate a <<<build-info.properties>>> at the expected location with
additional keys. Note that <<<maven.compiler.source>>> and <<<maven.compiler.target>>> are four additional keys. Note that <<<maven.compiler.source>>> and <<<maven.compiler.target>>>
expected to be regular properties available in the project. They will be interpolated as you are expected to be regular properties available in the project. They will be interpolated as
would expect. you would expect.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment