parent
7395420fa2
commit
1bf334ae0f
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
|
||||
|
||||
/**
|
||||
* A changelog containing differences computed from two repositories of configuration
|
||||
* metadata.
|
||||
*
|
||||
* @param oldVersionNumber the name of the old version
|
||||
* @param newVersionNumber the name of the new version
|
||||
* @param differences the differences
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
record Changelog(String oldVersionNumber, String newVersionNumber, List<Difference> differences) {
|
||||
|
||||
static Changelog of(String oldVersionNumber, ConfigurationMetadataRepository oldMetadata, String newVersionNumber,
|
||||
ConfigurationMetadataRepository newMetadata) {
|
||||
return new Changelog(oldVersionNumber, newVersionNumber, computeDifferences(oldMetadata, newMetadata));
|
||||
}
|
||||
|
||||
static List<Difference> computeDifferences(ConfigurationMetadataRepository oldMetadata,
|
||||
ConfigurationMetadataRepository newMetadata) {
|
||||
List<String> seenIds = new ArrayList<>();
|
||||
List<Difference> differences = new ArrayList<>();
|
||||
for (ConfigurationMetadataProperty oldProperty : oldMetadata.getAllProperties().values()) {
|
||||
String id = oldProperty.getId();
|
||||
seenIds.add(id);
|
||||
ConfigurationMetadataProperty newProperty = newMetadata.getAllProperties().get(id);
|
||||
Difference difference = Difference.compute(oldProperty, newProperty);
|
||||
if (difference != null) {
|
||||
differences.add(difference);
|
||||
}
|
||||
}
|
||||
for (ConfigurationMetadataProperty newProperty : newMetadata.getAllProperties().values()) {
|
||||
if ((!seenIds.contains(newProperty.getId())) && (!newProperty.isDeprecated())) {
|
||||
differences.add(new Difference(DifferenceType.ADDED, null, newProperty));
|
||||
}
|
||||
}
|
||||
return List.copyOf(differences);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;
|
||||
|
||||
/**
|
||||
* Generates a configuration metadata changelog. Requires three arguments:
|
||||
*
|
||||
* <ol>
|
||||
* <li>The path of a directory containing jar files of the old version
|
||||
* <li>The path of a directory containing jar files of the new version
|
||||
* <li>The path of a file to which the asciidoc changelog will be written
|
||||
* </ol>
|
||||
*
|
||||
* The name of each directory will be used as version numbers in generated changelog.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public final class ChangelogGenerator {
|
||||
|
||||
private ChangelogGenerator() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
generate(new File(args[0]), new File(args[1]), new File(args[2]));
|
||||
}
|
||||
|
||||
private static void generate(File oldDir, File newDir, File out) throws IOException {
|
||||
String oldVersionNumber = oldDir.getName();
|
||||
ConfigurationMetadataRepository oldMetadata = buildRepository(oldDir);
|
||||
String newVersionNumber = newDir.getName();
|
||||
ConfigurationMetadataRepository newMetadata = buildRepository(newDir);
|
||||
Changelog changelog = Changelog.of(oldVersionNumber, oldMetadata, newVersionNumber, newMetadata);
|
||||
try (ChangelogWriter writer = new ChangelogWriter(out)) {
|
||||
writer.write(changelog);
|
||||
}
|
||||
System.out.println("%nConfiguration metadata changelog written to '%s'".formatted(out));
|
||||
}
|
||||
|
||||
static ConfigurationMetadataRepository buildRepository(File directory) {
|
||||
ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create();
|
||||
for (File file : directory.listFiles()) {
|
||||
try (JarFile jarFile = new JarFile(file)) {
|
||||
JarEntry metadataEntry = jarFile.getJarEntry("META-INF/spring-configuration-metadata.json");
|
||||
if (metadataEntry != null) {
|
||||
builder.withJsonResource(jarFile.getInputStream(metadataEntry));
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.text.BreakIterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
|
||||
import org.springframework.boot.configurationmetadata.Deprecation;
|
||||
|
||||
/**
|
||||
* Writes a {@link Changelog} using asciidoc markup.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ChangelogWriter implements AutoCloseable {
|
||||
|
||||
private static final Comparator<ConfigurationMetadataProperty> COMPARING_ID = Comparator
|
||||
.comparing(ConfigurationMetadataProperty::getId);
|
||||
|
||||
private final PrintWriter out;
|
||||
|
||||
ChangelogWriter(File out) throws IOException {
|
||||
this(new FileWriter(out));
|
||||
}
|
||||
|
||||
ChangelogWriter(Writer out) {
|
||||
this.out = new PrintWriter(out);
|
||||
}
|
||||
|
||||
void write(Changelog changelog) {
|
||||
String oldVersionNumber = changelog.oldVersionNumber();
|
||||
String newVersionNumber = changelog.newVersionNumber();
|
||||
Map<DifferenceType, List<Difference>> differencesByType = collateByType(changelog);
|
||||
write("Configuration property changes between `%s` and `%s`%n", oldVersionNumber, newVersionNumber);
|
||||
write("%n%n%n== Deprecated in %s%n", newVersionNumber);
|
||||
writeDeprecated(differencesByType.get(DifferenceType.DEPRECATED));
|
||||
write("%n%n%n== Added in %s%n", newVersionNumber);
|
||||
writeAdded(differencesByType.get(DifferenceType.ADDED));
|
||||
write("%n%n%n== Removed in %s%n", newVersionNumber);
|
||||
writeRemoved(differencesByType.get(DifferenceType.DELETED), differencesByType.get(DifferenceType.DEPRECATED));
|
||||
}
|
||||
|
||||
private Map<DifferenceType, List<Difference>> collateByType(Changelog differences) {
|
||||
Map<DifferenceType, List<Difference>> byType = new HashMap<>();
|
||||
for (DifferenceType type : DifferenceType.values()) {
|
||||
byType.put(type, new ArrayList<>());
|
||||
}
|
||||
for (Difference difference : differences.differences()) {
|
||||
byType.get(difference.type()).add(difference);
|
||||
}
|
||||
return byType;
|
||||
}
|
||||
|
||||
private void writeDeprecated(List<Difference> differences) {
|
||||
List<Difference> rows = sortProperties(differences, Difference::newProperty).stream()
|
||||
.filter(this::isDeprecatedInRelease)
|
||||
.collect(Collectors.toList());
|
||||
writeTable("| Key | Replacement | Reason", rows, this::writeDeprecated);
|
||||
}
|
||||
|
||||
private void writeDeprecated(Difference difference) {
|
||||
writeDeprecatedPropertyRow(difference.newProperty());
|
||||
}
|
||||
|
||||
private void writeAdded(List<Difference> differences) {
|
||||
List<Difference> rows = sortProperties(differences, Difference::newProperty);
|
||||
writeTable("| Key | Default value | Description", rows, this::writeAdded);
|
||||
}
|
||||
|
||||
private void writeAdded(Difference difference) {
|
||||
writeRegularPropertyRow(difference.newProperty());
|
||||
}
|
||||
|
||||
private void writeRemoved(List<Difference> deleted, List<Difference> deprecated) {
|
||||
List<Difference> rows = getRemoved(deleted, deprecated);
|
||||
writeTable("| Key | Replacement | Reason", rows, this::writeRemoved);
|
||||
}
|
||||
|
||||
private List<Difference> getRemoved(List<Difference> deleted, List<Difference> deprecated) {
|
||||
List<Difference> result = new ArrayList<>(deleted);
|
||||
deprecated.stream().filter(Predicate.not(this::isDeprecatedInRelease)).forEach(result::remove);
|
||||
return sortProperties(result,
|
||||
(difference) -> getFirstNonNull(difference, Difference::oldProperty, Difference::newProperty));
|
||||
}
|
||||
|
||||
private void writeRemoved(Difference difference) {
|
||||
writeDeprecatedPropertyRow(getFirstNonNull(difference, Difference::newProperty, Difference::oldProperty));
|
||||
}
|
||||
|
||||
private List<Difference> sortProperties(List<Difference> differences,
|
||||
Function<Difference, ConfigurationMetadataProperty> extractor) {
|
||||
return differences.stream().sorted(Comparator.comparing(extractor, COMPARING_ID)).toList();
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
private <T, P> P getFirstNonNull(T t, Function<T, P>... extractors) {
|
||||
return Stream.of(extractors)
|
||||
.map((extractor) -> extractor.apply(t))
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private void writeTable(String header, List<Difference> rows, Consumer<Difference> action) {
|
||||
if (rows.isEmpty()) {
|
||||
write("_None_.%n");
|
||||
}
|
||||
else {
|
||||
writeTableBreak();
|
||||
write(header + "%n%n");
|
||||
for (Iterator<Difference> iterator = rows.iterator(); iterator.hasNext();) {
|
||||
action.accept(iterator.next());
|
||||
write((!iterator.hasNext()) ? null : "%n");
|
||||
}
|
||||
writeTableBreak();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeTableBreak() {
|
||||
write("|======================%n");
|
||||
}
|
||||
|
||||
private void writeRegularPropertyRow(ConfigurationMetadataProperty property) {
|
||||
writeCell(monospace(property.getId()));
|
||||
writeCell(monospace(asString(property.getDefaultValue())));
|
||||
writeCell(property.getShortDescription());
|
||||
}
|
||||
|
||||
private void writeDeprecatedPropertyRow(ConfigurationMetadataProperty property) {
|
||||
Deprecation deprecation = (property.getDeprecation() != null) ? property.getDeprecation() : new Deprecation();
|
||||
writeCell(monospace(property.getId()));
|
||||
writeCell(monospace(deprecation.getReplacement()));
|
||||
writeCell(getFirstSentence(deprecation.getReason()));
|
||||
}
|
||||
|
||||
private String getFirstSentence(String text) {
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
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);
|
||||
}
|
||||
String[] lines = text.split(System.lineSeparator());
|
||||
return lines[0].trim();
|
||||
}
|
||||
|
||||
private String removeSpaceBetweenLine(String text) {
|
||||
String[] lines = text.split(System.lineSeparator());
|
||||
return Arrays.stream(lines).map(String::trim).collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
private boolean isDeprecatedInRelease(Difference difference) {
|
||||
Deprecation deprecation = difference.newProperty().getDeprecation();
|
||||
return (deprecation != null) && (deprecation.getLevel() != Deprecation.Level.ERROR);
|
||||
}
|
||||
|
||||
private String monospace(String value) {
|
||||
return (value != null) ? "`%s`".formatted(value) : null;
|
||||
}
|
||||
|
||||
private void writeCell(String format, Object... args) {
|
||||
write((format != null) ? "| %s%n".formatted(format) : "|%n", args);
|
||||
}
|
||||
|
||||
private void write(String format, Object... args) {
|
||||
if (format != null) {
|
||||
Object[] strings = Arrays.stream(args).map(this::asString).toArray();
|
||||
this.out.append(format.formatted(strings));
|
||||
}
|
||||
}
|
||||
|
||||
private String asString(Object value) {
|
||||
if (value instanceof Object[] array) {
|
||||
return Stream.of(array).map(this::asString).collect(Collectors.joining(", "));
|
||||
}
|
||||
return (value != null) ? value.toString() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.out.close();
|
||||
}
|
||||
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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] + "'");
|
||||
}
|
||||
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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,52 @@
|
||||
/*
|
||||
* 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 org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
|
||||
import org.springframework.boot.configurationmetadata.Deprecation.Level;
|
||||
|
||||
/**
|
||||
* A difference the metadata.
|
||||
*
|
||||
* @param type the type of the difference
|
||||
* @param oldProperty the old property
|
||||
* @param newProperty the new property
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
record Difference(DifferenceType type, ConfigurationMetadataProperty oldProperty,
|
||||
ConfigurationMetadataProperty newProperty) {
|
||||
|
||||
static Difference compute(ConfigurationMetadataProperty oldProperty, ConfigurationMetadataProperty newProperty) {
|
||||
if (newProperty == null) {
|
||||
if (!(oldProperty.isDeprecated() && oldProperty.getDeprecation().getLevel() == Level.ERROR)) {
|
||||
return new Difference(DifferenceType.DELETED, oldProperty, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (newProperty.isDeprecated() && !oldProperty.isDeprecated()) {
|
||||
return new Difference(DifferenceType.DEPRECATED, oldProperty, newProperty);
|
||||
}
|
||||
if (oldProperty.isDeprecated() && oldProperty.getDeprecation().getLevel() == Level.WARNING
|
||||
&& newProperty.isDeprecated() && newProperty.getDeprecation().getLevel() == Level.ERROR) {
|
||||
return new Difference(DifferenceType.DELETED, oldProperty, newProperty);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The type of a difference in the metadata.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
enum DifferenceType {
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* 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,68 @@
|
||||
/*
|
||||
* 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.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ChangelogGenerator}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ChangelogGeneratorTests {
|
||||
|
||||
@TempDir
|
||||
File temp;
|
||||
|
||||
@Test
|
||||
void generateChangeLog() throws IOException {
|
||||
File oldJars = new File(this.temp, "1.0");
|
||||
addJar(oldJars, "sample-1.0.json");
|
||||
File newJars = new File(this.temp, "2.0");
|
||||
addJar(newJars, "sample-2.0.json");
|
||||
File out = new File(this.temp, "changes.adoc");
|
||||
String[] args = new String[] { oldJars.getAbsolutePath(), newJars.getAbsolutePath(), out.getAbsolutePath() };
|
||||
ChangelogGenerator.main(args);
|
||||
assertThat(out).usingCharset(StandardCharsets.UTF_8)
|
||||
.hasSameTextualContentAs(new File("src/test/resources/sample.adoc"));
|
||||
}
|
||||
|
||||
private void addJar(File directory, String filename) throws IOException {
|
||||
directory.mkdirs();
|
||||
try (JarOutputStream out = new JarOutputStream(new FileOutputStream(new File(directory, "sample.jar")))) {
|
||||
out.putNextEntry(new ZipEntry("META-INF/spring-configuration-metadata.json"));
|
||||
try (InputStream in = new FileInputStream("src/test/resources/" + filename)) {
|
||||
in.transferTo(out);
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link Changelog}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ChangelogTests {
|
||||
|
||||
@Test
|
||||
void diffContainsDifferencesBetweenLeftAndRightInputs() {
|
||||
Changelog differences = TestChangelog.load();
|
||||
assertThat(differences).isNotNull();
|
||||
assertThat(differences.oldVersionNumber()).isEqualTo("1.0");
|
||||
assertThat(differences.newVersionNumber()).isEqualTo("2.0");
|
||||
assertThat(differences.differences()).hasSize(4);
|
||||
List<Difference> added = differences.differences()
|
||||
.stream()
|
||||
.filter((difference) -> difference.type() == DifferenceType.ADDED)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(added).hasSize(1);
|
||||
assertProperty(added.get(0).newProperty(), "test.add", String.class, "new");
|
||||
List<Difference> deleted = differences.differences()
|
||||
.stream()
|
||||
.filter((difference) -> difference.type() == DifferenceType.DELETED)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(deleted).hasSize(2)
|
||||
.anySatisfy((entry) -> assertProperty(entry.oldProperty(), "test.delete", String.class, "delete"))
|
||||
.anySatisfy(
|
||||
(entry) -> assertProperty(entry.newProperty(), "test.delete.deprecated", String.class, "delete"));
|
||||
List<Difference> deprecated = differences.differences()
|
||||
.stream()
|
||||
.filter((difference) -> difference.type() == DifferenceType.DEPRECATED)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(deprecated).hasSize(1);
|
||||
assertProperty(deprecated.get(0).oldProperty(), "test.deprecate", String.class, "wrong");
|
||||
assertProperty(deprecated.get(0).newProperty(), "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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.assertj.core.util.Files;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ChangelogWriter}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ChangelogWriterTests {
|
||||
|
||||
@Test
|
||||
void writeChangelog() {
|
||||
StringWriter out = new StringWriter();
|
||||
try (ChangelogWriter writer = new ChangelogWriter(out)) {
|
||||
writer.write(TestChangelog.load());
|
||||
}
|
||||
String expected = Files.contentOf(new File("src/test/resources/sample.adoc"), StandardCharsets.UTF_8);
|
||||
assertThat(out).hasToString(expected);
|
||||
}
|
||||
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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,52 @@
|
||||
/*
|
||||
* 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 org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
|
||||
import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;
|
||||
|
||||
/**
|
||||
* Factory to create test {@link Changelog} instance.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
final class TestChangelog {
|
||||
|
||||
private TestChangelog() {
|
||||
}
|
||||
|
||||
static Changelog load() {
|
||||
ConfigurationMetadataRepository previousRepository = load("sample-1.0.json");
|
||||
ConfigurationMetadataRepository repository = load("sample-2.0.json");
|
||||
return Changelog.of("1.0", previousRepository, "2.0", repository);
|
||||
}
|
||||
|
||||
private static 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,32 @@
|
||||
Configuration property changes between `1.0` and `2.0`
|
||||
|
||||
|
||||
|
||||
== Deprecated in 2.0
|
||||
_None_.
|
||||
|
||||
|
||||
|
||||
== Added in 2.0
|
||||
|======================
|
||||
| Key | Default value | Description
|
||||
|
||||
| `test.add`
|
||||
| `new`
|
||||
| Test add.
|
||||
|======================
|
||||
|
||||
|
||||
|
||||
== Removed in 2.0
|
||||
|======================
|
||||
| Key | Replacement | Reason
|
||||
|
||||
| `test.delete`
|
||||
|
|
||||
|
|
||||
|
||||
| `test.delete.deprecated`
|
||||
| `test.add`
|
||||
| it was just bad
|
||||
|======================
|
Loading…
Reference in New Issue