diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 8b928caa835..31559c058b9 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -28,6 +28,7 @@ dependencies { testImplementation("org.assertj:assertj-core:3.11.1") testImplementation("org.apache.logging.log4j:log4j-core:2.12.1") testImplementation("org.junit.jupiter:junit-jupiter:5.6.0") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } checkstyle { diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/AsciidocBuilder.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Asciidoc.java similarity index 81% rename from buildSrc/src/main/java/org/springframework/boot/build/context/properties/AsciidocBuilder.java rename to buildSrc/src/main/java/org/springframework/boot/build/context/properties/Asciidoc.java index 305da3abcfe..fdf81f92fc9 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/AsciidocBuilder.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Asciidoc.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -21,36 +21,36 @@ package org.springframework.boot.build.context.properties; * * @author Phillip Webb */ -class AsciidocBuilder { +class Asciidoc { private final StringBuilder content; - AsciidocBuilder() { + Asciidoc() { this.content = new StringBuilder(); } - AsciidocBuilder appendKey(Object... items) { + Asciidoc appendWithHardLineBreaks(Object... items) { for (Object item : items) { appendln("`+", item, "+` +"); } return this; } - AsciidocBuilder newLine() { - return append(System.lineSeparator()); - } - - AsciidocBuilder appendln(Object... items) { + Asciidoc appendln(Object... items) { return append(items).newLine(); } - AsciidocBuilder append(Object... items) { + Asciidoc append(Object... items) { for (Object item : items) { this.content.append(item); } return this; } + Asciidoc newLine() { + return append(System.lineSeparator()); + } + @Override public String toString() { return this.content.toString(); diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundConfigurationTableEntry.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundConfigurationTableEntry.java deleted file mode 100644 index decd79af38a..00000000000 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundConfigurationTableEntry.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.build.context.properties; - -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Stream; - -/** - * Table entry regrouping a list of configuration properties sharing the same description. - * - * @author Brian Clozel - */ -class CompoundConfigurationTableEntry extends ConfigurationTableEntry { - - private final Set configurationKeys; - - private final String description; - - CompoundConfigurationTableEntry(String key, String description) { - this.key = key; - this.description = description; - this.configurationKeys = new TreeSet<>(); - } - - void addConfigurationKeys(ConfigurationProperty... properties) { - Stream.of(properties).map(ConfigurationProperty::getName).forEach(this.configurationKeys::add); - } - - @Override - void write(AsciidocBuilder builder) { - builder.append("|[[" + this.key + "]]<<" + this.key + ","); - this.configurationKeys.forEach(builder::appendKey); - builder.appendln(">>"); - builder.newLine().appendln("|").appendln("|+++", this.description, "+++"); - } - -} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java new file mode 100644 index 00000000000..d322ce10629 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.build.context.properties; + +import java.util.Set; +import java.util.TreeSet; + +/** + * Table row regrouping a list of configuration properties sharing the same description. + * + * @author Brian Clozel + * @author Phillip Webb + */ +class CompoundRow extends Row { + + private final Set propertyNames; + + private final String description; + + CompoundRow(Snippet snippet, String prefix, String description) { + super(snippet, prefix); + this.description = description; + this.propertyNames = new TreeSet<>(); + } + + void addProperty(ConfigurationProperty property) { + this.propertyNames.add(property.getDisplayName()); + } + + @Override + void write(Asciidoc asciidoc) { + asciidoc.append("|"); + asciidoc.append("[[" + getAnchor() + "]]"); + asciidoc.append("<<" + getAnchor() + ","); + this.propertyNames.forEach(asciidoc::appendWithHardLineBreaks); + asciidoc.appendln(">>"); + asciidoc.appendln("|+++", this.description, "+++"); + asciidoc.appendln("|"); + } + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationMetadataDocumentWriter.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationMetadataDocumentWriter.java deleted file mode 100644 index f5661073221..00000000000 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationMetadataDocumentWriter.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.build.context.properties; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.gradle.api.file.FileCollection; - -/** - * Write Asciidoc documents with configuration properties listings. - * - * @author Brian Clozel - * @since 2.0.0 - */ -public class ConfigurationMetadataDocumentWriter { - - public void writeDocument(Path outputDirectory, DocumentOptions options, FileCollection metadataFiles) - throws IOException { - assertValidOutputDirectory(outputDirectory); - if (!Files.exists(outputDirectory)) { - Files.createDirectory(outputDirectory); - } - List tables = createConfigTables(ConfigurationProperties.fromFiles(metadataFiles), options); - for (ConfigurationTable table : tables) { - writeConfigurationTable(table, outputDirectory); - } - } - - private void assertValidOutputDirectory(Path outputDirPath) { - if (outputDirPath == null) { - throw new IllegalArgumentException("output path should not be null"); - } - if (Files.exists(outputDirPath) && !Files.isDirectory(outputDirPath)) { - throw new IllegalArgumentException("output path already exists and is not a directory"); - } - } - - private List createConfigTables(Map metadataProperties, - DocumentOptions options) { - List tables = new ArrayList<>(); - List unmappedKeys = metadataProperties.values().stream().filter((property) -> !property.isDeprecated()) - .map(ConfigurationProperty::getName).collect(Collectors.toList()); - Map overrides = getOverrides(metadataProperties, unmappedKeys, - options); - options.getMetadataSections().forEach((id, keyPrefixes) -> tables - .add(createConfigTable(metadataProperties, unmappedKeys, overrides, id, keyPrefixes))); - if (!unmappedKeys.isEmpty()) { - throw new IllegalStateException( - "The following keys were not written to the documentation: " + String.join(", ", unmappedKeys)); - } - if (!overrides.isEmpty()) { - throw new IllegalStateException("The following keys were not written to the documentation: " - + String.join(", ", overrides.keySet())); - } - return tables; - } - - private Map getOverrides( - Map metadataProperties, List unmappedKeys, DocumentOptions options) { - Map overrides = new HashMap<>(); - options.getOverrides().forEach((keyPrefix, description) -> { - CompoundConfigurationTableEntry entry = new CompoundConfigurationTableEntry(keyPrefix, description); - List matchingKeys = unmappedKeys.stream().filter((key) -> key.startsWith(keyPrefix)) - .collect(Collectors.toList()); - for (String matchingKey : matchingKeys) { - entry.addConfigurationKeys(metadataProperties.get(matchingKey)); - } - overrides.put(keyPrefix, entry); - unmappedKeys.removeAll(matchingKeys); - }); - return overrides; - } - - private ConfigurationTable createConfigTable(Map metadataProperties, - List unmappedKeys, Map overrides, String id, - List keyPrefixes) { - ConfigurationTable table = new ConfigurationTable(id); - for (String keyPrefix : keyPrefixes) { - List matchingOverrides = overrides.keySet().stream() - .filter((overrideKey) -> overrideKey.startsWith(keyPrefix)).collect(Collectors.toList()); - matchingOverrides.forEach((match) -> table.addEntry(overrides.remove(match))); - } - List matchingKeys = unmappedKeys.stream() - .filter((key) -> keyPrefixes.stream().anyMatch(key::startsWith)).collect(Collectors.toList()); - for (String matchingKey : matchingKeys) { - ConfigurationProperty property = metadataProperties.get(matchingKey); - table.addEntry(new SingleConfigurationTableEntry(property)); - } - unmappedKeys.removeAll(matchingKeys); - return table; - } - - private void writeConfigurationTable(ConfigurationTable table, Path outputDirectory) throws IOException { - Path outputFilePath = outputDirectory.resolve(table.getId() + ".adoc"); - Files.deleteIfExists(outputFilePath); - Files.createFile(outputFilePath); - try (OutputStream outputStream = Files.newOutputStream(outputFilePath)) { - outputStream.write(table.toAsciidocTable().getBytes(StandardCharsets.UTF_8)); - } - } - -} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperties.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperties.java index 3b9baab566a..56278dcb5c3 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperties.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperties.java @@ -17,14 +17,13 @@ package org.springframework.boot.build.context.properties; import java.io.File; -import java.io.FileReader; import java.io.IOException; -import java.io.Reader; import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; +import java.util.stream.Stream; import com.fasterxml.jackson.databind.ObjectMapper; @@ -33,35 +32,40 @@ import com.fasterxml.jackson.databind.ObjectMapper; * {@code META-INF/spring-configuration-metadata.json} files. * * @author Andy Wilkinson + * @author Phillip Webb */ final class ConfigurationProperties { - private ConfigurationProperties() { + private final Map byName; + private ConfigurationProperties(List properties) { + Map byName = new LinkedHashMap<>(); + for (ConfigurationProperty property : properties) { + byName.put(property.getName(), property); + } + this.byName = Collections.unmodifiableMap(byName); + } + + ConfigurationProperty get(String propertyName) { + return this.byName.get(propertyName); + } + + Stream stream() { + return this.byName.values().stream(); } @SuppressWarnings("unchecked") - static Map fromFiles(Iterable files) { - List configurationProperties = new ArrayList<>(); + static ConfigurationProperties fromFiles(Iterable files) { try { ObjectMapper objectMapper = new ObjectMapper(); + List properties = new ArrayList<>(); for (File file : files) { - try (Reader reader = new FileReader(file)) { - Map json = objectMapper.readValue(file, Map.class); - List> properties = (List>) json.get("properties"); - for (Map property : properties) { - String name = (String) property.get("name"); - String type = (String) property.get("type"); - Object defaultValue = property.get("defaultValue"); - String description = (String) property.get("description"); - boolean deprecated = property.containsKey("deprecated"); - configurationProperties - .add(new ConfigurationProperty(name, type, defaultValue, description, deprecated)); - } + Map json = objectMapper.readValue(file, Map.class); + for (Map property : (List>) json.get("properties")) { + properties.add(ConfigurationProperty.fromJsonProperties(property)); } } - return configurationProperties.stream() - .collect(Collectors.toMap(ConfigurationProperty::getName, Function.identity())); + return new ConfigurationProperties(properties); } catch (IOException ex) { throw new RuntimeException("Failed to load configuration metadata", ex); diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperty.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperty.java index 3ea50d2d94b..bdf5fc7788f 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperty.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperty.java @@ -1,5 +1,5 @@ /* - * Copyright 2019-2020 the original author or authors. + * Copyright 2019-2021 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. @@ -16,12 +16,14 @@ package org.springframework.boot.build.context.properties; +import java.util.Map; + /** * A configuration property. * * @author Andy Wilkinson */ -public class ConfigurationProperty { +class ConfigurationProperty { private final String name; @@ -45,23 +47,27 @@ public class ConfigurationProperty { this.deprecated = deprecated; } - public String getName() { + String getName() { return this.name; } - public String getType() { + String getDisplayName() { + return (getType() != null && getType().startsWith("java.util.Map")) ? getName() + ".*" : getName(); + } + + String getType() { return this.type; } - public Object getDefaultValue() { + Object getDefaultValue() { return this.defaultValue; } - public String getDescription() { + String getDescription() { return this.description; } - public boolean isDeprecated() { + boolean isDeprecated() { return this.deprecated; } @@ -70,4 +76,13 @@ public class ConfigurationProperty { return "ConfigurationProperty [name=" + this.name + ", type=" + this.type + "]"; } + static ConfigurationProperty fromJsonProperties(Map property) { + String name = (String) property.get("name"); + String type = (String) property.get("type"); + Object defaultValue = property.get("defaultValue"); + String description = (String) property.get("description"); + boolean deprecated = property.containsKey("deprecated"); + return new ConfigurationProperty(name, type, defaultValue, description, deprecated); + } + } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java index 9969dbd1132..1ea7b3dcf43 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java @@ -28,12 +28,13 @@ import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; -import org.springframework.boot.build.context.properties.DocumentOptions.Builder; +import org.springframework.boot.build.context.properties.Snippet.Config; /** * {@link Task} used to document auto-configuration classes. * * @author Andy Wilkinson + * @author Phillip Webb */ public class DocumentConfigurationProperties extends DefaultTask { @@ -62,42 +63,159 @@ public class DocumentConfigurationProperties extends DefaultTask { @TaskAction void documentConfigurationProperties() throws IOException { - Builder builder = DocumentOptions.builder(); - builder.addSection("core") - .withKeyPrefixes("debug", "trace", "logging", "spring.aop", "spring.application", - "spring.autoconfigure", "spring.banner", "spring.beaninfo", "spring.codec", "spring.config", - "spring.info", "spring.jmx", "spring.lifecycle", "spring.main", "spring.messages", "spring.pid", - "spring.profiles", "spring.quartz", "spring.reactor", "spring.task", - "spring.mandatory-file-encoding", "info", "spring.output.ansi.enabled") - .addSection("mail").withKeyPrefixes("spring.mail", "spring.sendgrid").addSection("cache") - .withKeyPrefixes("spring.cache").addSection("server").withKeyPrefixes("server").addSection("web") - .withKeyPrefixes("spring.hateoas", "spring.http", "spring.servlet", "spring.jersey", "spring.mvc", - "spring.netty", "spring.resources", "spring.session", "spring.web", "spring.webflux") - .addSection("json").withKeyPrefixes("spring.jackson", "spring.gson").addSection("rsocket") - .withKeyPrefixes("spring.rsocket").addSection("templating") - .withKeyPrefixes("spring.freemarker", "spring.groovy", "spring.mustache", "spring.thymeleaf") - .addOverride("spring.groovy.template.configuration", "See GroovyMarkupConfigurer") - .addSection("security").withKeyPrefixes("spring.security").addSection("data-migration") - .withKeyPrefixes("spring.flyway", "spring.liquibase", "spring.sql.init").addSection("data") - .withKeyPrefixes("spring.couchbase", "spring.elasticsearch", "spring.h2", "spring.influx", - "spring.ldap", "spring.mongodb", "spring.neo4j", "spring.redis", "spring.dao", "spring.data", - "spring.datasource", "spring.jooq", "spring.jdbc", "spring.jpa", "spring.r2dbc") - .addOverride("spring.datasource.oracleucp", - "Oracle UCP specific settings bound to an instance of Oracle UCP's PoolDataSource") - .addOverride("spring.datasource.dbcp2", - "Commons DBCP2 specific settings bound to an instance of DBCP2's BasicDataSource") - .addOverride("spring.datasource.tomcat", - "Tomcat datasource specific settings bound to an instance of Tomcat JDBC's DataSource") - .addOverride("spring.datasource.hikari", - "Hikari specific settings bound to an instance of Hikari's HikariDataSource") - .addSection("transaction").withKeyPrefixes("spring.jta", "spring.transaction").addSection("integration") - .withKeyPrefixes("spring.activemq", "spring.artemis", "spring.batch", "spring.integration", - "spring.jms", "spring.kafka", "spring.rabbitmq", "spring.hazelcast", "spring.webservices") - .addSection("actuator").withKeyPrefixes("management").addSection("devtools") - .withKeyPrefixes("spring.devtools").addSection("testing").withKeyPrefixes("spring.test"); - DocumentOptions options = builder.build(); - new ConfigurationMetadataDocumentWriter().writeDocument(this.outputDir.toPath(), options, - this.configurationPropertyMetadata); + Snippets snippets = new Snippets(this.configurationPropertyMetadata); + snippets.add("application-properties.core", "Core Properties", this::corePrefixes); + snippets.add("application-properties.cache", "Cache Properties", this::cachePrefixes); + snippets.add("application-properties.mail", "Mail Properties", this::mailPrefixes); + snippets.add("application-properties.json", "JSON Properties", this::jsonPrefixes); + snippets.add("application-properties.data", "Data Properties", this::dataPrefixes); + snippets.add("application-properties.transaction", "Transaction Properties", this::transactionPrefixes); + snippets.add("application-properties.data-migration", "Data Migration Properties", this::dataMigrationPrefixes); + snippets.add("application-properties.integration", "Integration Properties", this::integrationPrefixes); + snippets.add("application-properties.web", "Web Properties", this::webPrefixes); + snippets.add("application-properties.templating", "Templating Properties", this::templatePrefixes); + snippets.add("application-properties.server", "Server Properties", this::serverPrefixes); + snippets.add("application-properties.security", "Security Properties", this::securityPrefixes); + snippets.add("application-properties.rsocket", "RSocket Properties", this::rsocketPrefixes); + snippets.add("application-properties.actuator", "Actuator Properties", this::actuatorPrefixes); + snippets.add("application-properties.devtools", "Devtools Properties", this::devtoolsPrefixes); + snippets.add("application-properties.testing", "Testing Properties", this::testingPrefixes); + snippets.writeTo(this.outputDir.toPath()); + } + + private void corePrefixes(Config config) { + config.accept("debug"); + config.accept("trace"); + config.accept("logging"); + config.accept("spring.aop"); + config.accept("spring.application"); + config.accept("spring.autoconfigure"); + config.accept("spring.banner"); + config.accept("spring.beaninfo"); + config.accept("spring.codec"); + config.accept("spring.config"); + config.accept("spring.info"); + config.accept("spring.jmx"); + config.accept("spring.lifecycle"); + config.accept("spring.main"); + config.accept("spring.messages"); + config.accept("spring.pid"); + config.accept("spring.profiles"); + config.accept("spring.quartz"); + config.accept("spring.reactor"); + config.accept("spring.task"); + config.accept("spring.mandatory-file-encoding"); + config.accept("info"); + config.accept("spring.output.ansi.enabled"); + } + + private void cachePrefixes(Config config) { + config.accept("spring.cache"); + } + + private void mailPrefixes(Config config) { + config.accept("spring.mail"); + config.accept("spring.sendgrid"); + } + + private void jsonPrefixes(Config config) { + config.accept("spring.jackson"); + config.accept("spring.gson"); + } + + private void dataPrefixes(Config config) { + config.accept("spring.couchbase"); + config.accept("spring.elasticsearch"); + config.accept("spring.h2"); + config.accept("spring.influx"); + config.accept("spring.ldap"); + config.accept("spring.mongodb"); + config.accept("spring.neo4j"); + config.accept("spring.redis"); + config.accept("spring.dao"); + config.accept("spring.data"); + config.accept("spring.datasource"); + config.accept("spring.jooq"); + config.accept("spring.jdbc"); + config.accept("spring.jpa"); + config.accept("spring.r2dbc"); + config.accept("spring.datasource.oracleucp", + "Oracle UCP specific settings bound to an instance of Oracle UCP's PoolDataSource"); + config.accept("spring.datasource.dbcp2", + "Commons DBCP2 specific settings bound to an instance of DBCP2's BasicDataSource"); + config.accept("spring.datasource.tomcat", + "Tomcat datasource specific settings bound to an instance of Tomcat JDBC's DataSource"); + config.accept("spring.datasource.hikari", + "Hikari specific settings bound to an instance of Hikari's HikariDataSource"); + + } + + private void transactionPrefixes(Config prefix) { + prefix.accept("spring.jta"); + prefix.accept("spring.transaction"); + } + + private void dataMigrationPrefixes(Config prefix) { + prefix.accept("spring.flyway"); + prefix.accept("spring.liquibase"); + prefix.accept("spring.sql.init"); + } + + private void integrationPrefixes(Config prefix) { + prefix.accept("spring.activemq"); + prefix.accept("spring.artemis"); + prefix.accept("spring.batch"); + prefix.accept("spring.integration"); + prefix.accept("spring.jms"); + prefix.accept("spring.kafka"); + prefix.accept("spring.rabbitmq"); + prefix.accept("spring.hazelcast"); + prefix.accept("spring.webservices"); + } + + private void webPrefixes(Config prefix) { + prefix.accept("spring.hateoas"); + prefix.accept("spring.http"); + prefix.accept("spring.servlet"); + prefix.accept("spring.jersey"); + prefix.accept("spring.mvc"); + prefix.accept("spring.netty"); + prefix.accept("spring.resources"); + prefix.accept("spring.session"); + prefix.accept("spring.web"); + prefix.accept("spring.webflux"); + } + + private void templatePrefixes(Config prefix) { + prefix.accept("spring.freemarker"); + prefix.accept("spring.groovy"); + prefix.accept("spring.mustache"); + prefix.accept("spring.thymeleaf"); + prefix.accept("spring.groovy.template.configuration", "See GroovyMarkupConfigurer"); + } + + private void serverPrefixes(Config prefix) { + prefix.accept("server"); + } + + private void securityPrefixes(Config prefix) { + prefix.accept("spring.security"); + } + + private void rsocketPrefixes(Config prefix) { + prefix.accept("spring.rsocket"); + } + + private void actuatorPrefixes(Config prefix) { + prefix.accept("management"); + } + + private void devtoolsPrefixes(Config prefix) { + prefix.accept("spring.devtools"); + } + + private void testingPrefixes(Config prefix) { + prefix.accept("spring.test"); } } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentOptions.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentOptions.java deleted file mode 100644 index 53fc4adec3f..00000000000 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentOptions.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.build.context.properties; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Options for generating documentation for configuration properties. - * - * @author Brian Clozel - * @since 2.0.0 - */ -public final class DocumentOptions { - - private final Map> metadataSections; - - private final Map overrides; - - private DocumentOptions(Map> metadataSections, Map overrides) { - this.metadataSections = metadataSections; - this.overrides = overrides; - } - - Map> getMetadataSections() { - return this.metadataSections; - } - - Map getOverrides() { - return this.overrides; - } - - static Builder builder() { - return new Builder(); - } - - /** - * Builder for DocumentOptions. - */ - public static class Builder { - - Map> metadataSections = new HashMap<>(); - - Map overrides = new HashMap<>(); - - SectionSpec addSection(String name) { - return new SectionSpec(this, name); - } - - Builder addOverride(String keyPrefix, String description) { - this.overrides.put(keyPrefix, description); - return this; - } - - DocumentOptions build() { - return new DocumentOptions(this.metadataSections, this.overrides); - } - - } - - /** - * Configuration for a documentation section listing properties for a specific theme. - */ - public static class SectionSpec { - - private final String name; - - private final Builder builder; - - SectionSpec(Builder builder, String name) { - this.builder = builder; - this.name = name; - } - - Builder withKeyPrefixes(String... keyPrefixes) { - this.builder.metadataSections.put(this.name, Arrays.asList(keyPrefixes)); - return this.builder; - } - - } - -} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationTableEntry.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Row.java similarity index 59% rename from buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationTableEntry.java rename to buildSrc/src/main/java/org/springframework/boot/build/context/properties/Row.java index a0ebc3361b6..1b01421b019 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationTableEntry.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Row.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -17,20 +17,22 @@ package org.springframework.boot.build.context.properties; /** - * Abstract class for entries in {@link ConfigurationTable}. + * Abstract class for rows in {@link Table}. * * @author Brian Clozel + * @author Phillip Webb */ -abstract class ConfigurationTableEntry implements Comparable { +abstract class Row implements Comparable { - protected String key; + private final Snippet snippet; - String getKey() { - return this.key; + private final String id; + + protected Row(Snippet snippet, String id) { + this.snippet = snippet; + this.id = id; } - abstract void write(AsciidocBuilder builder); - @Override public boolean equals(Object obj) { if (this == obj) { @@ -39,18 +41,24 @@ abstract class ConfigurationTableEntry implements Comparable>"); - writeDefaultValue(builder); - writeDescription(builder); - builder.appendln(); + void write(Asciidoc asciidoc) { + asciidoc.append("|"); + asciidoc.append("[[" + getAnchor() + "]]"); + asciidoc.appendln("<<" + getAnchor() + ",`+", this.displayName, "+`>>"); + writeDescription(asciidoc); + writeDefaultValue(asciidoc); } - private void writeDefaultValue(AsciidocBuilder builder) { + private void writeDescription(Asciidoc builder) { + if (this.description == null || this.description.isEmpty()) { + builder.appendln("|"); + } + else { + String cleanedDescription = this.description.replace("|", "\\|").replace("<", "<").replace(">", ">"); + builder.appendln("|+++", cleanedDescription, "+++"); + } + } + + private void writeDefaultValue(Asciidoc builder) { String defaultValue = (this.defaultValue != null) ? this.defaultValue : ""; if (defaultValue.isEmpty()) { builder.appendln("|"); @@ -72,14 +81,4 @@ class SingleConfigurationTableEntry extends ConfigurationTableEntry { } } - private void writeDescription(AsciidocBuilder builder) { - if (this.description == null || this.description.isEmpty()) { - builder.append("|"); - } - else { - String cleanedDescription = this.description.replace("|", "\\|").replace("<", "<").replace(">", ">"); - builder.append("|+++", cleanedDescription, "+++"); - } - } - } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippet.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippet.java new file mode 100644 index 00000000000..a7493d0bbf9 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippet.java @@ -0,0 +1,102 @@ +/* + * Copyright 2021-2021 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 + * + * https://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.build.context.properties; + +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * A configuration properties snippet. + * + * @author Brian Clozed + * @author Phillip Webb + */ +class Snippet { + + private final String anchor; + + private final String title; + + private final Set prefixes; + + private final Map overrides; + + Snippet(String anchor, String title, Consumer config) { + Set prefixes = new LinkedHashSet<>(); + Map overrides = new LinkedHashMap<>(); + if (config != null) { + config.accept(new Config() { + + @Override + public void accept(String prefix) { + prefixes.add(prefix); + } + + @Override + public void accept(String prefix, String description) { + overrides.put(prefix, description); + } + + }); + } + this.anchor = anchor; + this.title = title; + this.prefixes = prefixes; + this.overrides = overrides; + } + + String getAnchor() { + return this.anchor; + } + + String getTitle() { + return this.title; + } + + void forEachPrefix(Consumer action) { + this.prefixes.forEach(action); + } + + void forEachOverride(BiConsumer action) { + this.overrides.forEach(action); + } + + /** + * Callback to configure the snippet. + */ + interface Config { + + /** + * Accept the given prefix using the meta-data description. + * @param prefix the prefix to accept + */ + void accept(String prefix); + + /** + * Accept the given prefix with a defined description. + * @param prefix the prefix to accept + * @param description the description to use + */ + void accept(String prefix, String description); + + } + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java new file mode 100644 index 00000000000..8daffd1e2b7 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java @@ -0,0 +1,129 @@ +/* + * Copyright 2021-2021 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 + * + * https://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.build.context.properties; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.gradle.api.file.FileCollection; + +/** + * Configuration properties snippets. + * + * @author Brian Clozed + * @author Phillip Webb + */ +class Snippets { + + private final ConfigurationProperties properties; + + private final List snippets = new ArrayList<>(); + + Snippets(FileCollection configurationPropertyMetadata) { + this.properties = ConfigurationProperties.fromFiles(configurationPropertyMetadata); + } + + void add(String anchor, String title, Consumer config) { + this.snippets.add(new Snippet(anchor, title, config)); + } + + void writeTo(Path outputDirectory) throws IOException { + createDirectory(outputDirectory); + Set remaining = this.properties.stream().filter((property) -> !property.isDeprecated()) + .map(ConfigurationProperty::getName).collect(Collectors.toSet()); + for (Snippet snippet : this.snippets) { + Set written = writeSnippet(outputDirectory, snippet, remaining); + remaining.removeAll(written); + } + if (!remaining.isEmpty()) { + throw new IllegalStateException( + "The following keys were not written to the documentation: " + String.join(", ", remaining)); + } + } + + private Set writeSnippet(Path outputDirectory, Snippet snippet, Set remaining) throws IOException { + Table table = new Table(); + Set added = new HashSet<>(); + snippet.forEachOverride((prefix, description) -> { + CompoundRow row = new CompoundRow(snippet, prefix, description); + remaining.stream().filter((candidate) -> candidate.startsWith(prefix)).forEach((name) -> { + if (added.add(name)) { + row.addProperty(this.properties.get(name)); + } + }); + table.addRow(row); + }); + snippet.forEachPrefix((prefix) -> { + remaining.stream().filter((candidate) -> candidate.startsWith(prefix)).forEach((name) -> { + if (added.add(name)) { + table.addRow(new SingleRow(snippet, this.properties.get(name))); + } + }); + }); + Asciidoc asciidoc = getAsciidoc(snippet, table); + writeAsciidoc(outputDirectory, snippet, asciidoc); + return added; + } + + private Asciidoc getAsciidoc(Snippet snippet, Table table) { + Asciidoc asciidoc = new Asciidoc(); + asciidoc.appendln("[[" + snippet.getAnchor() + "]]"); + asciidoc.appendln("== ", snippet.getTitle()); + table.write(asciidoc); + return asciidoc; + } + + private void writeAsciidoc(Path outputDirectory, Snippet snippet, Asciidoc asciidoc) throws IOException { + String[] parts = (snippet.getAnchor()).split("\\."); + Path path = outputDirectory; + for (int i = 0; i < parts.length; i++) { + String name = (i < parts.length - 1) ? parts[i] : parts[i] + ".adoc"; + path = path.resolve(name); + } + createDirectory(path.getParent()); + Files.deleteIfExists(path); + try (OutputStream outputStream = Files.newOutputStream(path)) { + outputStream.write(asciidoc.toString().getBytes(StandardCharsets.UTF_8)); + } + } + + private void createDirectory(Path path) throws IOException { + assertValidOutputDirectory(path); + if (!Files.exists(path)) { + Files.createDirectory(path); + } + } + + private void assertValidOutputDirectory(Path path) { + if (path == null) { + throw new IllegalArgumentException("Directory path should not be null"); + } + if (Files.exists(path) && !Files.isDirectory(path)) { + throw new IllegalArgumentException("Path already exists and is not a directory"); + } + } + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationTable.java b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Table.java similarity index 54% rename from buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationTable.java rename to buildSrc/src/main/java/org/springframework/boot/build/context/properties/Table.java index 87bd0d05368..16b58ec989a 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationTable.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/context/properties/Table.java @@ -16,7 +16,6 @@ package org.springframework.boot.build.context.properties; -import java.util.Arrays; import java.util.Set; import java.util.TreeSet; @@ -25,36 +24,24 @@ import java.util.TreeSet; * * @author Brian Clozel */ -class ConfigurationTable { +class Table { - private final String id; + private final Set rows = new TreeSet<>(); - private final Set entries; - - ConfigurationTable(String id) { - this.id = id; - this.entries = new TreeSet<>(); + void addRow(Row row) { + this.rows.add(row); } - String getId() { - return this.id; - } - - void addEntry(ConfigurationTableEntry... entries) { - this.entries.addAll(Arrays.asList(entries)); - } - - String toAsciidocTable() { - AsciidocBuilder builder = new AsciidocBuilder(); - builder.appendln("[cols=\"4,3,3\", options=\"header\"]"); - builder.appendln("|==="); - builder.appendln("|Key|Default Value|Description"); - builder.appendln(); - this.entries.forEach((entry) -> { - entry.write(builder); - builder.appendln(); + void write(Asciidoc asciidoc) { + asciidoc.appendln("[cols=\"4,3,3\", options=\"header\"]"); + asciidoc.appendln("|==="); + asciidoc.appendln("|Name|Description|Default Value"); + asciidoc.appendln(); + this.rows.forEach((entry) -> { + entry.write(asciidoc); + asciidoc.appendln(); }); - return builder.appendln("|===").toString(); + asciidoc.appendln("|==="); } } diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundConfigurationTableEntryTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundConfigurationTableEntryTests.java deleted file mode 100644 index 5e7476c30ed..00000000000 --- a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundConfigurationTableEntryTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.build.context.properties; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link CompoundConfigurationTableEntry}. - * - * @author Brian Clozel - */ -public class CompoundConfigurationTableEntryTests { - - private static final String NEWLINE = System.lineSeparator(); - - @Test - void simpleProperty() { - ConfigurationProperty firstProp = new ConfigurationProperty("spring.test.first", "java.lang.String"); - ConfigurationProperty secondProp = new ConfigurationProperty("spring.test.second", "java.lang.String"); - ConfigurationProperty thirdProp = new ConfigurationProperty("spring.test.third", "java.lang.String"); - CompoundConfigurationTableEntry entry = new CompoundConfigurationTableEntry("spring.test", - "This is a description."); - entry.addConfigurationKeys(firstProp, secondProp, thirdProp); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test]]<>" + NEWLINE + NEWLINE - + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - -} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java new file mode 100644 index 00000000000..5945f5c6a71 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.build.context.properties; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CompoundRow}. + * + * @author Brian Clozel + */ +public class CompoundRowTests { + + private static final String NEWLINE = System.lineSeparator(); + + private static final Snippet SNIPPET = new Snippet("my", "title", null); + + @Test + void simpleProperty() { + CompoundRow row = new CompoundRow(SNIPPET, "spring.test", "This is a description."); + row.addProperty(new ConfigurationProperty("spring.test.first", "java.lang.String")); + row.addProperty(new ConfigurationProperty("spring.test.second", "java.lang.String")); + row.addProperty(new ConfigurationProperty("spring.test.third", "java.lang.String")); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test]]<>" + NEWLINE + + "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesTests.java index 0169bce623c..7ab586bc681 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesTests.java @@ -18,7 +18,6 @@ package org.springframework.boot.build.context.properties; import java.io.File; import java.util.Arrays; -import java.util.Map; import org.junit.jupiter.api.Test; @@ -33,7 +32,7 @@ class ConfigurationPropertiesTests { @Test void whenJsonHasAnIntegerDefaultValueThenItRemainsAnIntegerWhenRead() { - Map properties = ConfigurationProperties + ConfigurationProperties properties = ConfigurationProperties .fromFiles(Arrays.asList(new File("src/test/resources/spring-configuration-metadata.json"))); assertThat(properties.get("example.counter").getDefaultValue()).isEqualTo(0); } diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationTableTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationTableTests.java deleted file mode 100644 index 436aff1628f..00000000000 --- a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationTableTests.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-2021 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 - * - * https://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.build.context.properties; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link ConfigurationTable}. - * - * @author Brian Clozel - */ -public class ConfigurationTableTests { - - private static final String NEWLINE = System.lineSeparator(); - - @Test - void simpleTable() { - ConfigurationTable table = new ConfigurationTable("test"); - ConfigurationProperty first = new ConfigurationProperty("spring.test.prop", "java.lang.String", "something", - "This is a description.", false); - ConfigurationProperty second = new ConfigurationProperty("spring.test.other", "java.lang.String", "other value", - "This is another description.", false); - table.addEntry(new SingleConfigurationTableEntry(first)); - table.addEntry(new SingleConfigurationTableEntry(second)); - assertThat(table.toAsciidocTable()).isEqualTo("[cols=\"4,3,3\", options=\"header\"]" + NEWLINE + "|===" - + NEWLINE + "|Key|Default Value|Description" + NEWLINE + NEWLINE - + "|[[spring.test.other]]<>" + NEWLINE + "|`+other value+`" - + NEWLINE + "|+++This is another description.+++" + NEWLINE + NEWLINE - + "|[[spring.test.prop]]<>" + NEWLINE + "|`+something+`" - + NEWLINE + "|+++This is a description.+++" + NEWLINE + NEWLINE + "|===" + NEWLINE); - } - -} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleConfigurationTableEntryTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleConfigurationTableEntryTests.java deleted file mode 100644 index c232d845e7a..00000000000 --- a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleConfigurationTableEntryTests.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2012-2020 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 - * - * https://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.build.context.properties; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link SingleConfigurationTableEntry}. - * - * @author Brian Clozel - */ -public class SingleConfigurationTableEntryTests { - - private static final String NEWLINE = System.lineSeparator(); - - @Test - void simpleProperty() { - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", "something", - "This is a description.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test.prop]]<>" - + NEWLINE + "|`+something+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - - @Test - void noDefaultValue() { - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", null, - "This is a description.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test.prop]]<>" - + NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - - @Test - void defaultValueWithPipes() { - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", - "first|second", "This is a description.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test.prop]]<>" - + NEWLINE + "|`+first\\|second+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - - @Test - void defaultValueWithBackslash() { - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", - "first\\second", "This is a description.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test.prop]]<>" - + NEWLINE + "|`+first\\\\second+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - - @Test - void descriptionWithPipe() { - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", null, - "This is a description with a | pipe.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test.prop]]<>" - + NEWLINE + "|" + NEWLINE + "|+++This is a description with a \\| pipe.+++" + NEWLINE); - } - - @Test - void mapProperty() { - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", - "java.util.Map", null, "This is a description.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo("|[[spring.test.prop]]<>" - + NEWLINE + "|" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - - @Test - void listProperty() { - String[] defaultValue = new String[] { "first", "second", "third" }; - ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", - "java.util.List", defaultValue, "This is a description.", false); - SingleConfigurationTableEntry entry = new SingleConfigurationTableEntry(property); - AsciidocBuilder builder = new AsciidocBuilder(); - entry.write(builder); - assertThat(builder.toString()).isEqualTo( - "|[[spring.test.prop]]<>" + NEWLINE + "|`+first," + NEWLINE - + "second," + NEWLINE + "third+`" + NEWLINE + "|+++This is a description.+++" + NEWLINE); - } - -} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java new file mode 100644 index 00000000000..9bfcd8b86e4 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.build.context.properties; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SingleRow}. + * + * @author Brian Clozel + */ +public class SingleRowTests { + + private static final String NEWLINE = System.lineSeparator(); + + private static final Snippet SNIPPET = new Snippet("my", "title", null); + + @Test + void simpleProperty() { + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", "something", + "This is a description.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<>" + + NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+something+`" + NEWLINE); + } + + @Test + void noDefaultValue() { + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", null, + "This is a description.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<>" + + NEWLINE + "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE); + } + + @Test + void defaultValueWithPipes() { + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", + "first|second", "This is a description.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<>" + + NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first\\|second+`" + NEWLINE); + } + + @Test + void defaultValueWithBackslash() { + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", + "first\\second", "This is a description.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<>" + + NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first\\\\second+`" + NEWLINE); + } + + @Test + void descriptionWithPipe() { + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", "java.lang.String", null, + "This is a description with a | pipe.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<>" + + NEWLINE + "|+++This is a description with a \\| pipe.+++" + NEWLINE + "|" + NEWLINE); + } + + @Test + void mapProperty() { + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", + "java.util.Map", null, "This is a description.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()) + .isEqualTo("|[[my.spring.test.prop]]<>" + NEWLINE + + "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE); + } + + @Test + void listProperty() { + String[] defaultValue = new String[] { "first", "second", "third" }; + ConfigurationProperty property = new ConfigurationProperty("spring.test.prop", + "java.util.List", defaultValue, "This is a description.", false); + SingleRow row = new SingleRow(SNIPPET, property); + Asciidoc asciidoc = new Asciidoc(); + row.write(asciidoc); + assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<>" + + NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first," + NEWLINE + "second," + NEWLINE + + "third+`" + NEWLINE); + } + +} diff --git a/buildSrc/src/test/java/org/springframework/boot/build/context/properties/TableTests.java b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/TableTests.java new file mode 100644 index 00000000000..5ec6eb6d4c0 --- /dev/null +++ b/buildSrc/src/test/java/org/springframework/boot/build/context/properties/TableTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.build.context.properties; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link Table}. + * + * @author Brian Clozel + */ +public class TableTests { + + private static final String NEWLINE = System.lineSeparator(); + + private static final Snippet SNIPPET = new Snippet("my", "title", null); + + @Test + void simpleTable() { + Table table = new Table(); + table.addRow(new SingleRow(SNIPPET, new ConfigurationProperty("spring.test.prop", "java.lang.String", + "something", "This is a description.", false))); + table.addRow(new SingleRow(SNIPPET, new ConfigurationProperty("spring.test.other", "java.lang.String", + "other value", "This is another description.", false))); + Asciidoc asciidoc = new Asciidoc(); + table.write(asciidoc); + // @formatter:off + assertThat(asciidoc.toString()).isEqualTo( + "[cols=\"4,3,3\", options=\"header\"]" + NEWLINE + + "|===" + NEWLINE + + "|Name|Description|Default Value" + NEWLINE + NEWLINE + + "|[[my.spring.test.other]]<>" + NEWLINE + + "|+++This is another description.+++" + NEWLINE + + "|`+other value+`" + NEWLINE + NEWLINE + + "|[[my.spring.test.prop]]<>" + NEWLINE + + "|+++This is a description.+++" + NEWLINE + + "|`+something+`" + NEWLINE + NEWLINE + + "|===" + NEWLINE); + // @formatter:on + } + +} diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index dc20d8abfe4..8c3e6dcdc7f 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -218,7 +218,7 @@ task documentVersionProperties(type: org.springframework.boot.build.constraints. task documentConfigurationProperties(type: org.springframework.boot.build.context.properties.DocumentConfigurationProperties) { configurationPropertyMetadata = configurations.configurationProperties - outputDir = file("${buildDir}/docs/generated/application-properties/documented-application-properties/") + outputDir = file("${buildDir}/docs/generated/") } tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties index 9110ffaaa88..f1c56c0503f 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties @@ -762,3 +762,19 @@ executable-jar-alternatives=executable-jar.alternatives dependency-versions=dependency-versions dependency-versions-coordinates=dependency-versions.coordinates dependency-versions-properties=dependency-versions.properties +core-properties=application-properties.core +cache-properties=application-properties.cache +mail-properties=application-properties.mail +json-properties=application-properties.json +data-properties=application-properties.data +transaction-properties=application-properties.transaction +data-migration-properties=application-properties.data-migration +integration-properties=application-properties.integration +web-properties=application-properties.web +templating-properties=application-properties.templating +server-properties=application-properties.server +security-properties=application-properties.security +rsocket-properties=application-properties.rsocket +actuator-properties=application-properties.actuator +devtools-properties=application-properties.devtools +testing-properties=application-properties.testing diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties.adoc index 7a9710ecf9d..e66a5236477 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties.adoc @@ -1,6 +1,6 @@ [appendix] [[application-properties]] -= Common Application properties += Common Application Properties include::attributes.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/actuator.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/actuator.adoc deleted file mode 100644 index 3839fe3fde1..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/actuator.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.actuator]] -== Actuator Properties [[actuator-properties]] -include::documented-application-properties/actuator.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/cache.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/cache.adoc deleted file mode 100644 index b7b94177a39..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/cache.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.cache]] -== Cache Properties [[cache-properties]] -include::documented-application-properties/cache.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/core.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/core.adoc deleted file mode 100644 index 53e5caef770..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/core.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.core]] -== Core Properties [[core-properties]] -include::documented-application-properties/core.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/data-migration.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/data-migration.adoc deleted file mode 100644 index 892b5b41e13..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/data-migration.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.data-migration]] -== Data Migration Properties [[data-migration-properties]] -include::documented-application-properties/data-migration.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/data.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/data.adoc deleted file mode 100644 index ce856891337..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/data.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.data]] -== Data Properties [[data-properties]] -include::documented-application-properties/data.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/devtools.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/devtools.adoc deleted file mode 100644 index 4a6966aeb9a..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/devtools.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.devtools]] -== Devtools Properties [[devtools-properties]] -include::documented-application-properties/devtools.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/integration.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/integration.adoc deleted file mode 100644 index 409416e23cf..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/integration.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.integration]] -== Integration Properties [[integration-properties]] -include::documented-application-properties/integration.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/json.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/json.adoc deleted file mode 100644 index 5ae84a18744..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/json.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.json]] -== JSON Properties [[json-properties]] -include::documented-application-properties/json.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/mail.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/mail.adoc deleted file mode 100644 index 8c93a6d828a..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/mail.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.mail]] -== Mail Properties [[mail-properties]] -include::documented-application-properties/mail.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/rsocket.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/rsocket.adoc deleted file mode 100644 index 4c83b0bd268..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/rsocket.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.rsocket]] -== RSocket Properties [[rsocket-properties]] -include::documented-application-properties/rsocket.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/security.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/security.adoc deleted file mode 100644 index 8d20e4e49bf..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/security.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.security]] -== Security Properties [[security-properties]] -include::documented-application-properties/security.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/server.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/server.adoc deleted file mode 100644 index 0302e188190..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/server.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.server]] -== Server Properties [[server-properties]] -include::documented-application-properties/server.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/templating.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/templating.adoc deleted file mode 100644 index cc6fdea1989..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/templating.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.templating]] -== Templating Properties [[templating-properties]] -include::documented-application-properties/templating.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/testing.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/testing.adoc deleted file mode 100644 index bb5b918f973..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/testing.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.testing]] -== Testing Properties [[testing-properties]] -include::documented-application-properties/testing.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/transaction.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/transaction.adoc deleted file mode 100644 index 7c5cb713480..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/transaction.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.transaction]] -== Transaction Properties [[transaction-properties]] -include::documented-application-properties/transaction.adoc[] diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/web.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/web.adoc deleted file mode 100644 index f9567ca2c49..00000000000 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/application-properties/web.adoc +++ /dev/null @@ -1,3 +0,0 @@ -[[application-properties.web]] -== Web Properties [[web-properties]] -include::documented-application-properties/web.adoc[]