diff --git a/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java b/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java index 960fed7744b6..b66a60edfbea 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java @@ -21,7 +21,12 @@ 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.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.gradle.api.DefaultTask; @@ -52,6 +57,11 @@ public class ApplicationRunner extends DefaultTask { private final Property expectedLogging = getProject().getObjects().property(String.class); + private final Property applicationJar = getProject().getObjects().property(String.class) + .convention("/opt/apps/myapp.jar"); + + private final Map normalizations = new HashMap<>(); + private FileCollection classpath; @OutputFile @@ -83,6 +93,25 @@ public Property getExpectedLogging() { return this.expectedLogging; } + @Input + Map getNormalizations() { + return this.normalizations; + } + + @Input + public Property getApplicationJar() { + return this.applicationJar; + } + + public void normalizeTomcatPort() { + this.normalizations.put("(Tomcat started on port\\(s\\): )[\\d]+( \\(http\\))", "$18080$2"); + this.normalizations.put("(Tomcat initialized with port\\(s\\): )[\\d]+( \\(http\\))", "$18080$2"); + } + + public void normalizeLiveReloadPort() { + this.normalizations.put("(LiveReload server is running on port )[\\d]+", "$135729"); + } + @TaskAction void runApplication() throws IOException { List command = new ArrayList<>(); @@ -98,6 +127,7 @@ void runApplication() throws IOException { .start(); awaitLogging(process); process.destroy(); + normalizeLogging(); } private void awaitLogging(Process process) { @@ -126,4 +156,57 @@ private List outputLines() { } } + private void normalizeLogging() { + List outputLines = outputLines(); + List normalizedLines = normalize(outputLines); + Path outputPath = this.output.get().getAsFile().toPath(); + try { + Files.write(outputPath, normalizedLines); + } + catch (IOException ex) { + throw new RuntimeException("Failed to write normalized lines of output to '" + outputPath + "'", ex); + } + } + + private List normalize(List lines) { + List normalizedLines = lines; + Map normalizations = new HashMap<>(this.normalizations); + normalizations.put("(Starting .* using Java .* on ).*( with PID [\\d]+ \\().*( started by ).*( in ).*(\\))", + "$1myhost$2" + this.applicationJar.get() + "$3myuser$4/opt/apps/$5"); + for (Entry normalization : normalizations.entrySet()) { + Pattern pattern = Pattern.compile(normalization.getKey()); + normalizedLines = normalize(normalizedLines, pattern, normalization.getValue()); + } + return normalizedLines; + } + + private List normalize(List lines, Pattern pattern, String replacement) { + boolean matched = false; + List normalizedLines = new ArrayList<>(); + for (String line : lines) { + Matcher matcher = pattern.matcher(line); + StringBuffer transformed = new StringBuffer(); + while (matcher.find()) { + matched = true; + matcher.appendReplacement(transformed, replacement); + } + matcher.appendTail(transformed); + normalizedLines.add(transformed.toString()); + } + if (!matched) { + reportUnmatchedNormalization(lines, pattern); + } + return normalizedLines; + } + + private void reportUnmatchedNormalization(List lines, Pattern pattern) { + StringBuilder message = new StringBuilder( + "'" + pattern + "' did not match any of the following lines of output:"); + message.append(String.format("%n")); + for (String line : lines) { + message.append(String.format("%s%n", line)); + } + throw new IllegalStateException(message.toString()); + } + } diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index 06bdadb66c7c..473f59c9eff7 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -278,6 +278,8 @@ task runRemoteSpringApplicationExample(type: org.springframework.boot.build.docs args = ["https://myapp.example.com", "--spring.devtools.remote.secret=secret", "--spring.devtools.livereload.port=0"] output = file("$buildDir/example-output/remote-spring-application.txt") expectedLogging = "Started RemoteSpringApplication in " + applicationJar = "/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/${project.version}/spring-boot-devtools-${project.version}.jar" + normalizeLiveReloadPort() } task runSpringApplicationExample(type: org.springframework.boot.build.docs.ApplicationRunner) { @@ -286,6 +288,7 @@ task runSpringApplicationExample(type: org.springframework.boot.build.docs.Appli args = ["--server.port=0"] output = file("$buildDir/example-output/spring-application.txt") expectedLogging = "Started MyApplication in " + normalizeTomcatPort() } task runLoggingFormatExample(type: org.springframework.boot.build.docs.ApplicationRunner) { @@ -294,6 +297,7 @@ task runLoggingFormatExample(type: org.springframework.boot.build.docs.Applicati args = ["--spring.main.banner-mode=off", "--server.port=0"] output = file("$buildDir/example-output/logging-format.txt") expectedLogging = "Started MyApplication in " + normalizeTomcatPort() } tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) {