From 2f3343e9a29b5188aa042da4616d66098c7c775f Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Thu, 9 Mar 2017 09:50:47 +0100 Subject: [PATCH] build -> builder package --- .../cloud/release/internal/Releaser.java | 2 +- .../internal/builder/ProjectBuilder.java | 120 ++++++++++++++++++ .../internal/builder/ProjectBuilderTests.java | 88 +++++++++++++ .../release/spring/ReleaserConfiguration.java | 2 +- 4 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/builder/ProjectBuilder.java create mode 100644 spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/builder/ProjectBuilderTests.java diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java index d50905ad..8bd0b564 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java @@ -6,7 +6,7 @@ import java.lang.invoke.MethodHandles; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.cloud.release.internal.build.ProjectBuilder; +import org.springframework.cloud.release.internal.builder.ProjectBuilder; import org.springframework.cloud.release.internal.pom.ProjectUpdater; import org.springframework.util.StringUtils; diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/builder/ProjectBuilder.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/builder/ProjectBuilder.java new file mode 100644 index 00000000..18f3f65d --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/builder/ProjectBuilder.java @@ -0,0 +1,120 @@ +package org.springframework.cloud.release.internal.builder; + +import java.io.File; +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.util.StringUtils; + +/** + * @author Marcin Grzejszczak + */ +public class ProjectBuilder { + + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private final ReleaserProperties properties; + private final ProcessExecutor executor; + + public ProjectBuilder(ReleaserProperties properties) { + this.properties = properties; + this.executor = new ProcessExecutor(properties); + } + + ProjectBuilder(ReleaserProperties properties, ProcessExecutor executor) { + this.properties = properties; + this.executor = executor; + } + + public void build() { + try { + String[] commands = this.properties.getBuild().getCommand().split(" "); + long waitTimeInMinutes = this.properties.getBuild().getWaitTimeInMinutes(); + this.executor.runCommand(commands, waitTimeInMinutes); + assertNoHtmlFilesContainUnresolvedTags(); + log.info("No HTML files from docs contain unresolved tags"); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private void assertNoHtmlFilesContainUnresolvedTags() { + String workingDir = StringUtils.hasText(this.properties.getWorkingDir()) ? + this.properties.getWorkingDir() : System.getProperty("user.dir"); + try { + Files.walkFileTree(new File(workingDir).toPath(), new HtmlFileWalker()); + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } + + public void deploy() { + + } +} + +class ProcessExecutor { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private final ReleaserProperties properties; + + ProcessExecutor(ReleaserProperties properties) { + this.properties = properties; + } + + void runCommand(String[] commands, long waitTimeInMinutes) { + try { + String workingDir = StringUtils.hasText(this.properties.getWorkingDir()) ? + this.properties.getWorkingDir() : System.getProperty("user.dir"); + log.info("Will run the build via {} and wait for result for [{}] minutes", commands, waitTimeInMinutes); + ProcessBuilder builder = builder(commands, workingDir); + Process process = builder.start(); + boolean finished = process.waitFor(waitTimeInMinutes, TimeUnit.MINUTES); + if (!finished) { + log.error("The build hasn't managed to finish in [{}] minutes", waitTimeInMinutes); + process.destroyForcibly(); + throw new IllegalStateException("Build waiting time of [" + waitTimeInMinutes + "] minutes exceeded"); + } + } + catch (InterruptedException | IOException e) { + throw new IllegalStateException(e); + } + } + + ProcessBuilder builder(String[] commands, String workingDir) { + return new ProcessBuilder(commands) + .directory(new File(workingDir)) + .inheritIO(); + } +} + +class HtmlFileWalker extends SimpleFileVisitor { + + private static final String HTML_EXTENSION = ".html"; + + @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attr) { + File file = path.toFile(); + if (file.getName().endsWith(HTML_EXTENSION) && asString(file).contains("Unresolved")) { + throw new IllegalStateException("File [" + file + "] contains a tag that wasn't resolved properly"); + } + return FileVisitResult.CONTINUE; + } + private String asString(File file) { + try { + return new String(Files.readAllBytes(file.toPath())); + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/builder/ProjectBuilderTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/builder/ProjectBuilderTests.java new file mode 100644 index 00000000..bab5fb3a --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/builder/ProjectBuilderTests.java @@ -0,0 +1,88 @@ +package org.springframework.cloud.release.internal.builder; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; + +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.springframework.cloud.release.internal.ReleaserProperties; + +import static org.assertj.core.api.BDDAssertions.then; +import static org.assertj.core.api.BDDAssertions.thenThrownBy; + +/** + * @author Marcin Grzejszczak + */ +public class ProjectBuilderTests { + + @Before + public void checkOs() { + Assume.assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")); + } + + @Test + public void should_successfully_execute_a_command_when_after_running_there_is_no_html_file_with_unresolved_tag() throws Exception { + ReleaserProperties properties = new ReleaserProperties(); + properties.getBuild().setCommand("ls -al"); + properties.setWorkingDir(file("/projects/builder/resolved").getPath()); + ProjectBuilder builder = new ProjectBuilder(properties, executor(properties)); + + builder.build(); + + then(asString(file("/projects/builder/resolved/resolved.log"))) + .contains("total 0") + .contains("file.txt"); + } + + @Test + public void should_throw_exception_when_after_running_there_is_an_html_file_with_unresolved_tag() throws Exception { + ReleaserProperties properties = new ReleaserProperties(); + properties.getBuild().setCommand("ls -al"); + properties.setWorkingDir(file("/projects/builder/unresolved").getPath()); + ProjectBuilder builder = new ProjectBuilder(properties, executor(properties)); + + thenThrownBy(builder::build).hasMessageContaining("contains a tag that wasn't resolved properly"); + } + + @Test + public void should_throw_exception_when_command_took_too_long_to_execute() throws Exception { + ReleaserProperties properties = new ReleaserProperties(); + properties.getBuild().setCommand("sleep 1"); + properties.getBuild().setWaitTimeInMinutes(0); + properties.setWorkingDir(file("/projects/builder/unresolved").getPath()); + ProjectBuilder builder = new ProjectBuilder(properties, executor(properties)); + + thenThrownBy(builder::build).hasMessageContaining("Build waiting time of [0] minutes exceeded"); + } + + private ProcessExecutor executor(ReleaserProperties properties) { + return new ProcessExecutor(properties) { + @Override ProcessBuilder builder(String[] commands, String workingDir) { + return super.builder(commands, workingDir) + .redirectOutput(file("/projects/builder/resolved/resolved.log")); + } + }; + } + + private File file(String relativePath) { + try { + File root = new File(ProjectBuilderTests.class.getResource("/").toURI()); + File file = new File(root, relativePath); + if (!file.exists()) { + file.createNewFile(); + } + return file; + } + catch (IOException | URISyntaxException e) { + throw new IllegalStateException(e); + } + } + + private String asString(File file) throws IOException { + return new String(Files.readAllBytes(file.toPath())); + } + +} \ No newline at end of file diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/spring/ReleaserConfiguration.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/spring/ReleaserConfiguration.java index 006fb8df..5c4d54a9 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/spring/ReleaserConfiguration.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/spring/ReleaserConfiguration.java @@ -18,7 +18,7 @@ package org.springframework.cloud.release.spring; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.release.internal.Releaser; import org.springframework.cloud.release.internal.ReleaserProperties; -import org.springframework.cloud.release.internal.build.ProjectBuilder; +import org.springframework.cloud.release.internal.builder.ProjectBuilder; import org.springframework.cloud.release.internal.pom.ProjectUpdater; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;