diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java index 919586a2ab..52d5092de2 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * 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. @@ -23,13 +23,11 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import liquibase.integration.spring.SpringLiquibase; import org.flywaydb.core.Flyway; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.actuate.endpoint.AutoConfigurationReportEndpoint; import org.springframework.boot.actuate.endpoint.BeansEndpoint; import org.springframework.boot.actuate.endpoint.ConfigurationPropertiesReportEndpoint; @@ -59,6 +57,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.info.GitInfo; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.bind.PropertiesConfigurationFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -67,8 +66,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.StandardEnvironment; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; /** @@ -90,6 +87,9 @@ public class EndpointAutoConfiguration { @Autowired private InfoPropertiesConfiguration properties; + @Autowired(required = false) + private GitInfo gitInfo; + @Autowired(required = false) private HealthAggregator healthAggregator = new OrderedHealthAggregator(); @@ -125,9 +125,8 @@ public class EndpointAutoConfiguration { public InfoEndpoint infoEndpoint() throws Exception { LinkedHashMap info = new LinkedHashMap(); info.putAll(this.properties.infoMap()); - GitInfo gitInfo = this.properties.gitInfo(); - if (gitInfo.getBranch() != null) { - info.put("git", gitInfo); + if (this.gitInfo != null && this.gitInfo.getBranch() != null) { + info.put("git", this.gitInfo); } return new InfoEndpoint(info); } @@ -219,21 +218,6 @@ public class EndpointAutoConfiguration { @Autowired private final ConfigurableEnvironment environment = new StandardEnvironment(); - @Value("${spring.git.properties:classpath:git.properties}") - private Resource gitProperties; - - public GitInfo gitInfo() throws Exception { - PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( - new GitInfo()); - factory.setTargetName("git"); - Properties properties = new Properties(); - if (this.gitProperties.exists()) { - properties = PropertiesLoaderUtils.loadProperties(this.gitProperties); - } - factory.setProperties(properties); - return factory.getObject(); - } - public Map infoMap() throws Exception { PropertiesConfigurationFactory> factory = new PropertiesConfigurationFactory>( new LinkedHashMap()); @@ -244,49 +228,4 @@ public class EndpointAutoConfiguration { } - public static class GitInfo { - - private String branch; - - private final Commit commit = new Commit(); - - public String getBranch() { - return this.branch; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public Commit getCommit() { - return this.commit; - } - - public static class Commit { - - private String id; - - private String time; - - public String getId() { - return this.id == null ? "" - : (this.id.length() > 7 ? this.id.substring(0, 7) : this.id); - } - - public void setId(String id) { - this.id = id; - } - - public String getTime() { - return this.time; - } - - public void setTime(String time) { - this.time = time; - } - - } - - } - } diff --git a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 15d38abf94..fd726b13c2 100644 --- a/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -126,7 +126,10 @@ { "name": "spring.git.properties", "type": "java.lang.String", - "description": "Resource reference to a generated git info properties file." + "description": "Resource reference to a generated git info properties file.", + "deprecation": { + "replacement": "spring.info.git.location" + } }, { "name": "spring.pid.file", diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index e00ccf892b..0b89c82090 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -40,6 +40,7 @@ import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.metrics.Metric; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration; +import org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.test.EnvironmentTestUtils; @@ -140,7 +141,7 @@ public class EndpointAutoConfigurationTests { public void testInfoEndpointConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, "info.foo:bar"); - this.context.register(EndpointAutoConfiguration.class); + this.context.register(ProjectInfoAutoConfiguration.class, EndpointAutoConfiguration.class); this.context.refresh(); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); assertThat(endpoint).isNotNull(); @@ -152,7 +153,7 @@ public class EndpointAutoConfigurationTests { public void testNoGitProperties() throws Exception { this.context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(this.context, - "spring.git.properties:classpath:nonexistent"); + "spring.info.git.location:classpath:nonexistent"); this.context.register(EndpointAutoConfiguration.class); this.context.refresh(); InfoEndpoint endpoint = this.context.getBean(InfoEndpoint.class); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/GitInfo.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/GitInfo.java new file mode 100644 index 0000000000..804394c943 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/GitInfo.java @@ -0,0 +1,69 @@ +/* + * 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.autoconfigure.info; + +/** + * Provide git-related information such as commit id and time. + * + * @author Dave Syer + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class GitInfo { + + private String branch; + + private final Commit commit = new Commit(); + + public String getBranch() { + return this.branch; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public Commit getCommit() { + return this.commit; + } + + public static class Commit { + + private String id; + + private String time; + + public String getId() { + return this.id == null ? "" + : (this.id.length() > 7 ? this.id.substring(0, 7) : this.id); + } + + public void setId(String id) { + this.id = id; + } + + public String getTime() { + return this.time; + } + + public void setTime(String time) { + this.time = time; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfiguration.java new file mode 100644 index 0000000000..546c29418e --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfiguration.java @@ -0,0 +1,90 @@ +/* + * 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.autoconfigure.info; + +import java.util.Properties; + +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.bind.PropertiesConfigurationFactory; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.PropertyResolver; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for various project information. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration +@EnableConfigurationProperties(ProjectInfoProperties.class) +public class ProjectInfoAutoConfiguration { + + @Configuration + @Conditional(GitResourceAvailableCondition.class) + protected static class GitInfoAutoConfiguration { + + @ConditionalOnMissingBean + @Bean + public GitInfo gitInfo(ProjectInfoProperties properties) throws Exception { + PropertiesConfigurationFactory factory = new PropertiesConfigurationFactory( + new GitInfo()); + factory.setTargetName("git"); + Properties gitInfoProperties = PropertiesLoaderUtils + .loadProperties(properties.getGit().getLocation()); + factory.setProperties(gitInfoProperties); + return factory.getObject(); + } + + } + + + static class GitResourceAvailableCondition extends SpringBootCondition { + + private final ResourceLoader defaultResourceLoader = new DefaultResourceLoader(); + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + ResourceLoader loader = context.getResourceLoader() == null + ? this.defaultResourceLoader : context.getResourceLoader(); + PropertyResolver propertyResolver = context.getEnvironment(); + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(propertyResolver, "spring.info.git."); + String location = resolver.getProperty("location"); + if (location == null) { + resolver = new RelaxedPropertyResolver(propertyResolver, "spring.git."); + location = resolver.getProperty("properties"); + if (location == null) { + location = "classpath:git.properties"; + } + } + boolean match = loader.getResource(location).exists(); + return new ConditionOutcome(match, "Git info " + (match ? "found" : "not found") + " at " + location); + } + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoProperties.java new file mode 100644 index 0000000000..03f19bf0a8 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoProperties.java @@ -0,0 +1,70 @@ +/* + * 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.autoconfigure.info; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.io.Resource; + +/** + * Configuration properties for project information. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@ConfigurationProperties("spring.info") +public class ProjectInfoProperties { + + private final Git git = new Git(); + + public Git getGit() { + return this.git; + } + + + /** + * Make sure that the "spring.git.properties" legacy key is used by default. + * @param defaultGitLocation the default git location to use + */ + @Autowired + void setDefaultGitLocation(@Value("${spring.git.properties:classpath:git.properties}") Resource defaultGitLocation) { + getGit().setLocation(defaultGitLocation); + } + + + /** + * Git specific info properties. + */ + public static class Git { + + /** + * Location of the generated git info properties file. + */ + private Resource location; + + public Resource getLocation() { + return this.location; + } + + public void setLocation(Resource location) { + this.location = location; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfigurationTests.java new file mode 100644 index 0000000000..8ba75f37a4 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfigurationTests.java @@ -0,0 +1,117 @@ +/* + * 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.autoconfigure.info; + +import java.util.Map; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ProjectInfoAutoConfiguration}. + * + * @author Stephane Nicoll + */ +public class ProjectInfoAutoConfigurationTests { + + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void gitInfoUnavailableIfResourceNotAvailable() { + load(); + Map beans = this.context + .getBeansOfType(GitInfo.class); + assertThat(beans).hasSize(0); + } + + @Test + public void gitLocationTakesPrecedenceOverLegacyKey() { + load("spring.info.git.location=classpath:/org/springframework/boot/autoconfigure/info/git.properties", + "spring.git.properties=classpath:/org/springframework/boot/autoconfigure/info/git-no-data.properties"); + GitInfo gitInfo = this.context.getBean(GitInfo.class); + assertGitInfo(gitInfo); + } + + @Test + public void gitLegacyKeyIsUsedAsFallback() { + load("spring.git.properties=classpath:/org/springframework/boot/autoconfigure/info/git.properties"); + GitInfo gitInfo = this.context.getBean(GitInfo.class); + assertGitInfo(gitInfo); + } + + @Test + public void gitInfoWithNoData() { + load("spring.info.git.location=classpath:/org/springframework/boot/autoconfigure/info/git-no-data.properties"); + GitInfo gitInfo = this.context.getBean(GitInfo.class); + assertThat(gitInfo.getBranch()).isNull(); + } + + @Test + public void gitInfoFallbackWithGitInfoBean() { + load(CustomGitInfoConfiguration.class, + "spring.info.git.location=classpath:/org/springframework/boot/autoconfigure/info/git.properties"); + GitInfo gitInfo = this.context.getBean(GitInfo.class); + assertThat(gitInfo).isSameAs(this.context.getBean("customGitInfo")); + } + + private void assertGitInfo(GitInfo gitInfo) { + assertThat(gitInfo.getBranch()).isNull(); + assertThat(gitInfo.getCommit().getId()).isEqualTo("f95038e"); + assertThat(gitInfo.getCommit().getTime()).isEqualTo("2016-03-03T10:02:00+0100"); + } + + private void load(String... environment) { + load(null, environment); + } + + private void load(Class config, String... environment) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + if (config != null) { + context.register(config); + } + context.register(PropertyPlaceholderAutoConfiguration.class, + ProjectInfoAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(context, environment); + context.refresh(); + this.context = context; + } + + @Configuration + static class CustomGitInfoConfiguration { + + @Bean + public GitInfo customGitInfo() { + return new GitInfo(); + } + } +} diff --git a/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git-no-data.properties b/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git-no-data.properties new file mode 100644 index 0000000000..74d0a43fcc --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git-no-data.properties @@ -0,0 +1 @@ +foo=bar diff --git a/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git.properties b/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git.properties new file mode 100644 index 0000000000..2f49e6f821 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git.properties @@ -0,0 +1,4 @@ +git.commit.user.email=john@example.com +git.commit.id=f95038ec09e29d8f91982fd1cbcc0f3b131b1d0a +git.commit.user.name=John Smith +git.commit.time=2016-03-03T10\:02\:00+0100 diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 354aeb9a99..94dd7e1899 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -79,6 +79,9 @@ content into your application; rather pick only the properties that you need. # HAZELCAST ({sc-spring-boot-autoconfigure}/hazelcast/HazelcastProperties.{sc-ext}[HazelcastProperties]) 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]) + spring.info.git.location=classpath:git.properties # Location of the generated git info properties file + # JMX spring.jmx.default-domain= # JMX domain name. spring.jmx.enabled=true # Expose management beans to the JMX domain. @@ -904,9 +907,6 @@ content into your application; rather pick only the properties that you need. shell.telnet.enabled=false # Enable CRaSH telnet support. Enabled by default if the TelnetPlugin is available. shell.telnet.port=5000 # Telnet port. - # GIT INFO - spring.git.properties= # Resource reference to a generated git info properties file. - # METRICS EXPORT ({sc-spring-boot-actuator}/metrics/export/MetricExportProperties.{sc-ext}[MetricExportProperties]) spring.metrics.export.aggregate.key-pattern= # Pattern that tells the aggregator what to do with the keys from the source repository. spring.metrics.export.aggregate.prefix= # Prefix for global repository if active.