11 changed files with 686 additions and 0 deletions
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
plugins { |
||||
id "java" |
||||
id "org.springframework.boot.conventions" |
||||
} |
||||
|
||||
description = "Spring Boot Configuration Metadata Changelog Generator" |
||||
|
||||
configurations { |
||||
oldMetadata |
||||
newMetadata |
||||
} |
||||
|
||||
dependencies { |
||||
implementation(enforcedPlatform(project(":spring-boot-project:spring-boot-dependencies"))) |
||||
implementation(project(":spring-boot-project:spring-boot-tools:spring-boot-configuration-metadata")) |
||||
|
||||
testImplementation(enforcedPlatform(project(":spring-boot-project:spring-boot-dependencies"))) |
||||
testImplementation("org.assertj:assertj-core") |
||||
testImplementation("org.junit.jupiter:junit-jupiter") |
||||
} |
||||
|
||||
if (project.hasProperty("oldVersion") && project.hasProperty("newVersion")) { |
||||
dependencies { |
||||
["spring-boot", |
||||
"spring-boot-actuator", |
||||
"spring-boot-actuator-autoconfigure", |
||||
"spring-boot-autoconfigure", |
||||
"spring-boot-devtools", |
||||
"spring-boot-test-autoconfigure"].each { |
||||
oldMetadata("org.springframework.boot:$it:$oldVersion") |
||||
newMetadata("org.springframework.boot:$it:$newVersion") |
||||
} |
||||
} |
||||
|
||||
def prepareOldMetadata = tasks.register("prepareOldMetadata", Sync) { |
||||
from(configurations.oldMetadata) |
||||
if (project.hasProperty("oldVersion")) { |
||||
destinationDir = project.file("build/configuration-metadata-diff/$oldVersion") |
||||
} |
||||
} |
||||
|
||||
def prepareNewMetadata = tasks.register("prepareNewMetadata", Sync) { |
||||
from(configurations.newMetadata) |
||||
if (project.hasProperty("newVersion")) { |
||||
destinationDir = project.file("build/configuration-metadata-diff/$newVersion") |
||||
} |
||||
} |
||||
|
||||
tasks.register("generate", JavaExec) { |
||||
inputs.files(prepareOldMetadata, prepareNewMetadata) |
||||
outputs.file(project.file("build/configuration-metadata-changelog.adoc")) |
||||
classpath = sourceSets.main.runtimeClasspath |
||||
mainClass = 'org.springframework.boot.configurationmetadata.changelog.ConfigurationMetadataChangelogGenerator' |
||||
if (project.hasProperty("oldVersion") && project.hasProperty("newVersion")) { |
||||
args = [project.file("build/configuration-metadata-diff/$oldVersion"), project.file("build/configuration-metadata-diff/$newVersion"), project.file("build/configuration-metadata-changelog.adoc")] |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.configurationmetadata.changelog; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileWriter; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Generates a configuration metadata changelog. Requires three arguments: |
||||
* |
||||
* <ol> |
||||
* <li>The path of a directory containing jar files from which the old metadata will be |
||||
* extracted |
||||
* <li>The path of a directory containing jar files from which the new metadata will be |
||||
* extracted |
||||
* <li>The path of a file to which the changelog will be written |
||||
* </ol> |
||||
* |
||||
* The name of each directory will be used to name the old and new metadata in the |
||||
* generated changelog |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
final class ConfigurationMetadataChangelogGenerator { |
||||
|
||||
private ConfigurationMetadataChangelogGenerator() { |
||||
|
||||
} |
||||
|
||||
public static void main(String[] args) throws IOException { |
||||
ConfigurationMetadataDiff diff = ConfigurationMetadataDiff.of( |
||||
NamedConfigurationMetadataRepository.from(new File(args[0])), |
||||
NamedConfigurationMetadataRepository.from(new File(args[1]))); |
||||
try (ConfigurationMetadataChangelogWriter writer = new ConfigurationMetadataChangelogWriter( |
||||
new FileWriter(new File(args[2])))) { |
||||
writer.write(diff); |
||||
} |
||||
System.out.println("\nConfiguration metadata changelog written to '" + args[2] + "'"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,204 @@
@@ -0,0 +1,204 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.configurationmetadata.changelog; |
||||
|
||||
import java.io.PrintWriter; |
||||
import java.io.Writer; |
||||
import java.text.BreakIterator; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.function.Function; |
||||
import java.util.stream.Collectors; |
||||
import java.util.stream.Stream; |
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; |
||||
import org.springframework.boot.configurationmetadata.Deprecation; |
||||
import org.springframework.boot.configurationmetadata.changelog.ConfigurationMetadataDiff.Difference; |
||||
import org.springframework.boot.configurationmetadata.changelog.ConfigurationMetadataDiff.Difference.Type; |
||||
|
||||
/** |
||||
* Writes a configuration metadata changelog from a {@link ConfigurationMetadataDiff}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class ConfigurationMetadataChangelogWriter implements AutoCloseable { |
||||
|
||||
private final PrintWriter out; |
||||
|
||||
ConfigurationMetadataChangelogWriter(Writer out) { |
||||
this.out = new PrintWriter(out); |
||||
} |
||||
|
||||
void write(ConfigurationMetadataDiff diff) { |
||||
this.out.append(String.format("Configuration property changes between `%s` and " + "`%s`%n", diff.leftName(), |
||||
diff.rightName())); |
||||
this.out.append(System.lineSeparator()); |
||||
this.out.append(String.format("== Deprecated in `%s`%n", diff.rightName())); |
||||
Map<Type, List<Difference>> differencesByType = differencesByType(diff); |
||||
writeDeprecatedProperties(differencesByType.get(Type.DEPRECATED)); |
||||
this.out.append(System.lineSeparator()); |
||||
this.out.append(String.format("== New in `%s`%n", diff.rightName())); |
||||
writeAddedProperties(differencesByType.get(Type.ADDED)); |
||||
this.out.append(System.lineSeparator()); |
||||
this.out.append(String.format("== Removed in `%s`%n", diff.rightName())); |
||||
writeRemovedProperties(differencesByType.get(Type.DELETED), differencesByType.get(Type.DEPRECATED)); |
||||
} |
||||
|
||||
private Map<Type, List<Difference>> differencesByType(ConfigurationMetadataDiff diff) { |
||||
Map<Type, List<Difference>> differencesByType = new HashMap<>(); |
||||
for (Type type : Type.values()) { |
||||
differencesByType.put(type, new ArrayList<>()); |
||||
} |
||||
for (Difference difference : diff.differences()) { |
||||
differencesByType.get(difference.type()).add(difference); |
||||
} |
||||
return differencesByType; |
||||
} |
||||
|
||||
private void writeDeprecatedProperties(List<Difference> differences) { |
||||
if (differences.isEmpty()) { |
||||
this.out.append(String.format("None.%n")); |
||||
} |
||||
else { |
||||
List<Difference> properties = sortProperties(differences, Difference::right).stream() |
||||
.filter(this::isDeprecatedInRelease) |
||||
.collect(Collectors.toList()); |
||||
this.out.append(String.format("|======================%n")); |
||||
this.out.append(String.format("|Key |Replacement |Reason%n")); |
||||
properties.forEach((diff) -> { |
||||
ConfigurationMetadataProperty property = diff.right(); |
||||
writeDeprecatedProperty(property); |
||||
}); |
||||
this.out.append(String.format("|======================%n")); |
||||
} |
||||
this.out.append(String.format("%n%n")); |
||||
} |
||||
|
||||
private boolean isDeprecatedInRelease(Difference difference) { |
||||
return difference.right().getDeprecation() != null |
||||
&& Deprecation.Level.ERROR != difference.right().getDeprecation().getLevel(); |
||||
} |
||||
|
||||
private void writeAddedProperties(List<Difference> differences) { |
||||
if (differences.isEmpty()) { |
||||
this.out.append(String.format("None.%n")); |
||||
} |
||||
else { |
||||
List<Difference> properties = sortProperties(differences, Difference::right); |
||||
this.out.append(String.format("|======================%n")); |
||||
this.out.append(String.format("|Key |Default value |Description%n")); |
||||
properties.forEach((diff) -> writeRegularProperty(diff.right())); |
||||
this.out.append(String.format("|======================%n")); |
||||
} |
||||
this.out.append(String.format("%n%n")); |
||||
} |
||||
|
||||
private void writeRemovedProperties(List<Difference> deleted, List<Difference> deprecated) { |
||||
List<Difference> removed = getRemovedProperties(deleted, deprecated); |
||||
if (removed.isEmpty()) { |
||||
this.out.append(String.format("None.%n")); |
||||
} |
||||
else { |
||||
this.out.append(String.format("|======================%n")); |
||||
this.out.append(String.format("|Key |Replacement |Reason%n")); |
||||
removed.forEach((property) -> writeDeprecatedProperty( |
||||
(property.right() != null) ? property.right() : property.left())); |
||||
this.out.append(String.format("|======================%n")); |
||||
} |
||||
} |
||||
|
||||
private List<Difference> getRemovedProperties(List<Difference> deleted, List<Difference> deprecated) { |
||||
List<Difference> properties = new ArrayList<>(deleted); |
||||
properties.addAll(deprecated.stream().filter((p) -> !isDeprecatedInRelease(p)).collect(Collectors.toList())); |
||||
return sortProperties(properties, |
||||
(difference) -> (difference.left() != null) ? difference.left() : difference.right()); |
||||
} |
||||
|
||||
private void writeRegularProperty(ConfigurationMetadataProperty property) { |
||||
this.out.append("|`").append(property.getId()).append("` |"); |
||||
if (property.getDefaultValue() != null) { |
||||
this.out.append("`").append(defaultValueToString(property.getDefaultValue())).append("`"); |
||||
} |
||||
this.out.append(" |"); |
||||
if (property.getDescription() != null) { |
||||
this.out.append(property.getShortDescription()); |
||||
} |
||||
this.out.append(System.lineSeparator()); |
||||
} |
||||
|
||||
private void writeDeprecatedProperty(ConfigurationMetadataProperty property) { |
||||
Deprecation deprecation = (property.getDeprecation() != null) ? property.getDeprecation() : new Deprecation(); |
||||
this.out.append("|`").append(property.getId()).append("` |"); |
||||
if (deprecation.getReplacement() != null) { |
||||
this.out.append("`").append(deprecation.getReplacement()).append("`"); |
||||
} |
||||
this.out.append(" |"); |
||||
if (deprecation.getReason() != null) { |
||||
this.out.append(getFirstSentence(deprecation.getReason())); |
||||
} |
||||
this.out.append(System.lineSeparator()); |
||||
} |
||||
|
||||
private String getFirstSentence(String text) { |
||||
int dot = text.indexOf('.'); |
||||
if (dot != -1) { |
||||
BreakIterator breakIterator = BreakIterator.getSentenceInstance(Locale.US); |
||||
breakIterator.setText(text); |
||||
String sentence = text.substring(breakIterator.first(), breakIterator.next()).trim(); |
||||
return removeSpaceBetweenLine(sentence); |
||||
} |
||||
else { |
||||
String[] lines = text.split(System.lineSeparator()); |
||||
return lines[0].trim(); |
||||
} |
||||
} |
||||
|
||||
private static String removeSpaceBetweenLine(String text) { |
||||
String[] lines = text.split(System.lineSeparator()); |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (String line : lines) { |
||||
sb.append(line.trim()).append(" "); |
||||
} |
||||
return sb.toString().trim(); |
||||
} |
||||
|
||||
private List<Difference> sortProperties(List<Difference> properties, |
||||
Function<Difference, ConfigurationMetadataProperty> property) { |
||||
List<Difference> sorted = new ArrayList<>(properties); |
||||
sorted.sort((o1, o2) -> property.apply(o1).getId().compareTo(property.apply(o2).getId())); |
||||
return sorted; |
||||
} |
||||
|
||||
private static String defaultValueToString(Object defaultValue) { |
||||
if (defaultValue instanceof Object[]) { |
||||
return Stream.of((Object[]) defaultValue).map(Object::toString).collect(Collectors.joining(", ")); |
||||
} |
||||
else { |
||||
return defaultValue.toString(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void close() { |
||||
this.out.close(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.configurationmetadata.changelog; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; |
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; |
||||
import org.springframework.boot.configurationmetadata.Deprecation.Level; |
||||
import org.springframework.boot.configurationmetadata.changelog.ConfigurationMetadataDiff.Difference.Type; |
||||
|
||||
/** |
||||
* A diff of two repositories of configuration metadata. |
||||
* |
||||
* @param leftName the name of the left-hand side of the diff |
||||
* @param rightName the name of the right-hand side of the diff |
||||
* @param differences the differences |
||||
* @author Stephane Nicoll |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
record ConfigurationMetadataDiff(String leftName, String rightName, List<Difference> differences) { |
||||
|
||||
static ConfigurationMetadataDiff of(NamedConfigurationMetadataRepository left, |
||||
NamedConfigurationMetadataRepository right) { |
||||
return new ConfigurationMetadataDiff(left.getName(), right.getName(), differences(left, right)); |
||||
} |
||||
|
||||
private static List<Difference> differences(ConfigurationMetadataRepository left, |
||||
ConfigurationMetadataRepository right) { |
||||
List<Difference> differences = new ArrayList<>(); |
||||
List<String> matches = new ArrayList<>(); |
||||
Map<String, ConfigurationMetadataProperty> leftProperties = left.getAllProperties(); |
||||
Map<String, ConfigurationMetadataProperty> rightProperties = right.getAllProperties(); |
||||
for (ConfigurationMetadataProperty leftProperty : leftProperties.values()) { |
||||
String id = leftProperty.getId(); |
||||
matches.add(id); |
||||
ConfigurationMetadataProperty rightProperty = rightProperties.get(id); |
||||
if (rightProperty == null) { |
||||
if (!(leftProperty.isDeprecated() && leftProperty.getDeprecation().getLevel() == Level.ERROR)) { |
||||
differences.add(new Difference(Type.DELETED, leftProperty, null)); |
||||
} |
||||
} |
||||
else if (rightProperty.isDeprecated() && !leftProperty.isDeprecated()) { |
||||
differences.add(new Difference(Type.DEPRECATED, leftProperty, rightProperty)); |
||||
} |
||||
else if (leftProperty.isDeprecated() && leftProperty.getDeprecation().getLevel() == Level.WARNING |
||||
&& rightProperty.isDeprecated() && rightProperty.getDeprecation().getLevel() == Level.ERROR) { |
||||
differences.add(new Difference(Type.DELETED, leftProperty, rightProperty)); |
||||
} |
||||
} |
||||
for (ConfigurationMetadataProperty rightProperty : rightProperties.values()) { |
||||
if ((!matches.contains(rightProperty.getId())) && (!rightProperty.isDeprecated())) { |
||||
differences.add(new Difference(Type.ADDED, null, rightProperty)); |
||||
} |
||||
} |
||||
return differences; |
||||
} |
||||
|
||||
/** |
||||
* A difference in the metadata. |
||||
* |
||||
* @param type the type of the difference |
||||
* @param left the left-hand side of the difference |
||||
* @param right the right-hand side of the difference |
||||
*/ |
||||
static record Difference(Type type, ConfigurationMetadataProperty left, ConfigurationMetadataProperty right) { |
||||
|
||||
/** |
||||
* The type of a difference in the metadata. |
||||
*/ |
||||
enum Type { |
||||
|
||||
/** |
||||
* The entry has been added. |
||||
*/ |
||||
ADDED, |
||||
|
||||
/** |
||||
* The entry has been made deprecated. It may or may not still exist in the |
||||
* previous version. |
||||
*/ |
||||
DEPRECATED, |
||||
|
||||
/** |
||||
* The entry has been deleted. |
||||
*/ |
||||
DELETED |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,80 @@
@@ -0,0 +1,80 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.configurationmetadata.changelog; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
import java.util.jar.JarEntry; |
||||
import java.util.jar.JarFile; |
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataGroup; |
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; |
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; |
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; |
||||
|
||||
/** |
||||
* A {@link ConfigurationMetadataRepository} with a name. |
||||
* |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class NamedConfigurationMetadataRepository implements ConfigurationMetadataRepository { |
||||
|
||||
private final String name; |
||||
|
||||
private final ConfigurationMetadataRepository delegate; |
||||
|
||||
NamedConfigurationMetadataRepository(String name, ConfigurationMetadataRepository delegate) { |
||||
this.name = name; |
||||
this.delegate = delegate; |
||||
} |
||||
|
||||
/** |
||||
* The name of the metadata held in the repository. |
||||
* @return the name of the metadata |
||||
*/ |
||||
String getName() { |
||||
return this.name; |
||||
} |
||||
|
||||
@Override |
||||
public Map<String, ConfigurationMetadataGroup> getAllGroups() { |
||||
return this.delegate.getAllGroups(); |
||||
} |
||||
|
||||
@Override |
||||
public Map<String, ConfigurationMetadataProperty> getAllProperties() { |
||||
return this.delegate.getAllProperties(); |
||||
} |
||||
|
||||
static NamedConfigurationMetadataRepository from(File metadataDir) { |
||||
ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create(); |
||||
for (File jar : metadataDir.listFiles()) { |
||||
try (JarFile jarFile = new JarFile(jar)) { |
||||
JarEntry jsonMetadata = jarFile.getJarEntry("META-INF/spring-configuration-metadata.json"); |
||||
if (jsonMetadata != null) { |
||||
builder.withJsonResource(jarFile.getInputStream(jsonMetadata)); |
||||
} |
||||
} |
||||
catch (IOException ex) { |
||||
throw new RuntimeException(ex); |
||||
} |
||||
} |
||||
return new NamedConfigurationMetadataRepository(metadataDir.getName(), builder.build()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
/* |
||||
* Copyright 2012-2023 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. |
||||
*/ |
||||
|
||||
/** |
||||
* Spring Boot configuration metadata changelog generator. |
||||
*/ |
||||
package org.springframework.boot.configurationmetadata.changelog; |
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
/* |
||||
* Copyright 2012-2023 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.configurationmetadata.changelog; |
||||
|
||||
import java.io.FileInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.List; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; |
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; |
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; |
||||
import org.springframework.boot.configurationmetadata.changelog.ConfigurationMetadataDiff.Difference; |
||||
import org.springframework.boot.configurationmetadata.changelog.ConfigurationMetadataDiff.Difference.Type; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link ConfigurationMetadataDiff}. |
||||
* |
||||
* @author Stephane Nicoll |
||||
* @author Andy Wilkinson |
||||
*/ |
||||
class ConfigurationMetadataDiffTests { |
||||
|
||||
@Test |
||||
void diffContainsDifferencesBetweenLeftAndRightInputs() { |
||||
NamedConfigurationMetadataRepository left = new NamedConfigurationMetadataRepository("1.0", |
||||
load("sample-1.0.json")); |
||||
NamedConfigurationMetadataRepository right = new NamedConfigurationMetadataRepository("2.0", |
||||
load("sample-2.0.json")); |
||||
ConfigurationMetadataDiff diff = ConfigurationMetadataDiff.of(left, right); |
||||
assertThat(diff).isNotNull(); |
||||
assertThat(diff.leftName()).isEqualTo("1.0"); |
||||
assertThat(diff.rightName()).isEqualTo("2.0"); |
||||
assertThat(diff.differences()).hasSize(4); |
||||
List<Difference> added = diff.differences() |
||||
.stream() |
||||
.filter((difference) -> difference.type() == Type.ADDED) |
||||
.collect(Collectors.toList()); |
||||
assertThat(added).hasSize(1); |
||||
assertProperty(added.get(0).right(), "test.add", String.class, "new"); |
||||
List<Difference> deleted = diff.differences() |
||||
.stream() |
||||
.filter((difference) -> difference.type() == Type.DELETED) |
||||
.collect(Collectors.toList()); |
||||
assertThat(deleted).hasSize(2) |
||||
.anySatisfy((entry) -> assertProperty(entry.left(), "test.delete", String.class, "delete")) |
||||
.anySatisfy((entry) -> assertProperty(entry.right(), "test.delete.deprecated", String.class, "delete")); |
||||
List<Difference> deprecated = diff.differences() |
||||
.stream() |
||||
.filter((difference) -> difference.type() == Type.DEPRECATED) |
||||
.collect(Collectors.toList()); |
||||
assertThat(deprecated).hasSize(1); |
||||
assertProperty(deprecated.get(0).left(), "test.deprecate", String.class, "wrong"); |
||||
assertProperty(deprecated.get(0).right(), "test.deprecate", String.class, "wrong"); |
||||
} |
||||
|
||||
private void assertProperty(ConfigurationMetadataProperty property, String id, Class<?> type, Object defaultValue) { |
||||
assertThat(property).isNotNull(); |
||||
assertThat(property.getId()).isEqualTo(id); |
||||
assertThat(property.getType()).isEqualTo(type.getName()); |
||||
assertThat(property.getDefaultValue()).isEqualTo(defaultValue); |
||||
} |
||||
|
||||
private ConfigurationMetadataRepository load(String filename) { |
||||
try (InputStream inputStream = new FileInputStream("src/test/resources/" + filename)) { |
||||
return ConfigurationMetadataRepositoryJsonBuilder.create(inputStream).build(); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new RuntimeException(ex); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
{ |
||||
"properties": [ |
||||
{ |
||||
"name": "test.equal", |
||||
"type": "java.lang.String", |
||||
"description": "Test equality.", |
||||
"defaultValue": "test" |
||||
}, |
||||
{ |
||||
"name": "test.deprecate", |
||||
"type": "java.lang.String", |
||||
"description": "Test deprecate.", |
||||
"defaultValue": "wrong" |
||||
}, |
||||
{ |
||||
"name": "test.delete", |
||||
"type": "java.lang.String", |
||||
"description": "Test delete.", |
||||
"defaultValue": "delete" |
||||
}, |
||||
{ |
||||
"name": "test.delete.deprecated", |
||||
"type": "java.lang.String", |
||||
"description": "Test delete deprecated.", |
||||
"defaultValue": "delete", |
||||
"deprecation": { |
||||
"level": "warning" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
{ |
||||
"properties": [ |
||||
{ |
||||
"name": "test.add", |
||||
"type": "java.lang.String", |
||||
"description": "Test add.", |
||||
"defaultValue": "new" |
||||
}, |
||||
{ |
||||
"name": "test.equal", |
||||
"type": "java.lang.String", |
||||
"description": "Test equality.", |
||||
"defaultValue": "test" |
||||
}, |
||||
{ |
||||
"name": "test.deprecate", |
||||
"type": "java.lang.String", |
||||
"description": "Test deprecate.", |
||||
"defaultValue": "wrong", |
||||
"deprecation": { |
||||
"level": "error" |
||||
} |
||||
}, |
||||
{ |
||||
"name": "test.delete.deprecated", |
||||
"type": "java.lang.String", |
||||
"description": "Test delete deprecated.", |
||||
"defaultValue": "delete", |
||||
"deprecation": { |
||||
"level": "error" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
Loading…
Reference in new issue