Added docs publishing

This commit is contained in:
Marcin Grzejszczak
2017-03-09 16:32:10 +01:00
parent bb3f6c1888
commit fb60676638
8 changed files with 268 additions and 122 deletions

View File

@@ -2,11 +2,10 @@ package org.springframework.cloud.release.internal;
import java.io.File;
import java.lang.invoke.MethodHandles;
import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.builder.ProjectBuilder;
import org.springframework.cloud.release.internal.project.Project;
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
import org.springframework.cloud.release.internal.pom.ProjectUpdater;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
@@ -23,20 +22,19 @@ public class Releaser {
private final ReleaserProperties properties;
private final ProjectUpdater projectUpdater;
private final ProjectBuilder projectBuilder;
private final Project project;
private final ProjectGitUpdater projectGitUpdater;
public Releaser(ReleaserProperties properties, ProjectUpdater projectUpdater,
ProjectBuilder projectBuilder, ProjectGitUpdater projectGitUpdater) {
Project project, ProjectGitUpdater projectGitUpdater) {
this.properties = properties;
this.projectUpdater = projectUpdater;
this.projectBuilder = projectBuilder;
this.project = project;
this.projectGitUpdater = projectGitUpdater;
}
public void release() {
String workingDir = StringUtils.hasText(this.properties.getWorkingDir()) ?
this.properties.getWorkingDir() : System.getProperty("user.dir");
String workingDir = this.properties.getWorkingDir();
File project = new File(workingDir);
log.info("\n\n\n=== UPDATING POMS ===\n\nWill run the application "
+ "for root folder [{}]. \n\nPress ENTER to continue {}", workingDir, MSG);
@@ -49,7 +47,7 @@ public class Releaser {
log.info("\n\n\n=== BUILD PROJECT ===\n\nPress ENTER to build the project {}", MSG);
boolean skipBuild = skipStep();
if (!skipBuild) {
this.projectBuilder.build();
this.project.build();
log.info("\nProject was successfully built");
}
log.info("\n\n\n=== COMMITTING AND PUSHING TAGS ===\n\nPress ENTER to commit, tag and push the tag {}", MSG);
@@ -57,6 +55,16 @@ public class Releaser {
if (!skipCommit) {
this.projectGitUpdater.commitAndTagIfApplicable(project, version);
}
log.info("\n\n\n=== ARTIFACT DEPLOYMENT ===\n\nPress ENTER to deploy the artifacts {}", MSG);
boolean skipDeployment = skipStep();
if (!skipDeployment) {
this.project.deploy();
}
log.info("\n\n\n=== PUBLISHING DOCS ===\n\nPress ENTER to deploy the artifacts {}", MSG);
boolean skipDocs = skipStep();
if (!skipDocs) {
this.project.publishDocs();
}
}
boolean skipStep() {

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.release.internal;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
import edu.emory.mathcs.backport.java.util.Arrays;
@@ -37,6 +38,8 @@ public class ReleaserProperties {
private Pom pom = new Pom();
private Docs docs = new Docs();
private Maven maven = new Maven();
public static class Git {
@@ -102,6 +105,18 @@ public class ReleaserProperties {
}
}
public static class Docs {
private String ghPagesUrl = "https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/ghpages.sh";
public String getGhPagesUrl() {
return this.ghPagesUrl;
}
public void setGhPagesUrl(String ghPagesUrl) {
this.ghPagesUrl = ghPagesUrl;
}
}
public static class Maven {
/**
@@ -115,7 +130,16 @@ public class ReleaserProperties {
private String deployCommand = "./mvnw deploy -DskipTests -Pfast";
/**
* Max wait time in minutes for the build to finish
* Command to be executed to deploy a built project
*/
private String[] publishDocsCommands = {
"wget https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/ghpages.sh -O target/gh-pages.sh",
"chmod +x target/gh-pages.sh",
"./target/gh-pages.sh"
};
/**
* Max wait time in minutes for the process to finish
*/
private long waitTimeInMinutes = 20;
@@ -142,10 +166,19 @@ public class ReleaserProperties {
public void setDeployCommand(String deployCommand) {
this.deployCommand = deployCommand;
}
public String[] getPublishDocsCommands() {
return this.publishDocsCommands;
}
public void setPublishDocsCommands(String[] publishDocsCommands) {
this.publishDocsCommands = publishDocsCommands;
}
}
public String getWorkingDir() {
return this.workingDir;
return StringUtils.hasText(this.workingDir) ?
this.workingDir : System.getProperty("user.dir");
}
public void setWorkingDir(String workingDir) {
@@ -160,6 +193,14 @@ public class ReleaserProperties {
this.git = git;
}
public Docs getDocs() {
return this.docs;
}
public void setDocs(Docs docs) {
this.docs = docs;
}
public Pom getPom() {
return this.pom;
}

View File

@@ -173,14 +173,6 @@ class PomUpdater {
return changes;
}
private boolean relativePathIsSet(Model model) {
return model.getParent() != null && StringUtils.hasText(model.getParent().getRelativePath());
}
private String parentName(Model model) {
return model.getParent() != null ? model.getParent().getArtifactId() : "";
}
private String groupId(Model model) {
if (StringUtils.hasText(model.getGroupId())) {
return model.getGroupId();
@@ -318,8 +310,7 @@ class PropertyStorer {
void setPropertyVersionIfApplicable(Project project) {
String propertyName = propertyName(project);
if (setPropertyVersion(propertyName, project.version)) {
log.info(" Updating property " + propertyName);
log.info(" to version " + project.version);
log.info("Updating property [" + propertyName + "] to version [" + project.version + "]");
}
}

View File

@@ -1,4 +1,4 @@
package org.springframework.cloud.release.internal.builder;
package org.springframework.cloud.release.internal.project;
import java.io.File;
import java.io.IOException;
@@ -13,24 +13,23 @@ 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 {
public class Project {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final ReleaserProperties properties;
private final ProcessExecutor executor;
public ProjectBuilder(ReleaserProperties properties) {
public Project(ReleaserProperties properties) {
this.properties = properties;
this.executor = new ProcessExecutor(properties);
}
ProjectBuilder(ReleaserProperties properties, ProcessExecutor executor) {
Project(ReleaserProperties properties, ProcessExecutor executor) {
this.properties = properties;
this.executor = executor;
}
@@ -38,8 +37,7 @@ public class ProjectBuilder {
public void build() {
try {
String[] commands = this.properties.getMaven().getBuildCommand().split(" ");
long waitTimeInMinutes = this.properties.getMaven().getWaitTimeInMinutes();
this.executor.runCommand(commands, waitTimeInMinutes);
runCommand(commands);
assertNoHtmlFilesContainUnresolvedTags();
log.info("No HTML files from docs contain unresolved tags");
} catch (Exception e) {
@@ -48,8 +46,7 @@ public class ProjectBuilder {
}
private void assertNoHtmlFilesContainUnresolvedTags() {
String workingDir = StringUtils.hasText(this.properties.getWorkingDir()) ?
this.properties.getWorkingDir() : System.getProperty("user.dir");
String workingDir = this.properties.getWorkingDir();
try {
Files.walkFileTree(new File(workingDir).toPath(), new HtmlFileWalker());
}
@@ -59,7 +56,30 @@ public class ProjectBuilder {
}
public void deploy() {
try {
String[] commands = this.properties.getMaven().getDeployCommand().split(" ");
runCommand(commands);
log.info("The project has successfully been deployed");
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
private void runCommand(String[] commands) {
long waitTimeInMinutes = this.properties.getMaven().getWaitTimeInMinutes();
this.executor.runCommand(commands, waitTimeInMinutes);
}
public void publishDocs() {
try {
for (String command : this.properties.getMaven().getPublishDocsCommands()) {
String[] commands = command.split(" ");
runCommand(commands);
}
log.info("The docs got published successfully");
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
@@ -74,8 +94,7 @@ class ProcessExecutor {
void runCommand(String[] commands, long waitTimeInMinutes) {
try {
String workingDir = StringUtils.hasText(this.properties.getWorkingDir()) ?
this.properties.getWorkingDir() : System.getProperty("user.dir");
String workingDir = this.properties.getWorkingDir();
log.info("Will run the build via {} and wait for result for [{}] minutes", commands, waitTimeInMinutes);
ProcessBuilder builder = builder(commands, workingDir);
Process process = builder.start();
@@ -83,7 +102,7 @@ class ProcessExecutor {
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");
throw new IllegalStateException("Process waiting time of [" + waitTimeInMinutes + "] minutes exceeded");
}
}
catch (InterruptedException | IOException e) {

View File

@@ -0,0 +1,28 @@
package org.springframework.cloud.release.internal;
import org.junit.Test;
import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Marcin Grzejszczak
*/
public class ReleaserPropertiesTests {
@Test
public void should_return_provided_working_dir_when_it_was_set() throws Exception {
String workingDir = "foo";
ReleaserProperties properties = new ReleaserProperties();
properties.setWorkingDir(workingDir);
then(properties.getWorkingDir()).isEqualTo(workingDir);
}
@Test
public void should_return_current_working_dir_when_it_was_not_previously_set() throws Exception {
ReleaserProperties properties = new ReleaserProperties();
then(properties.getWorkingDir()).isNotEmpty();
}
}

View File

@@ -1,88 +0,0 @@
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.getMaven().setBuildCommand("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.getMaven().setBuildCommand("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.getMaven().setBuildCommand("sleep 1");
properties.getMaven().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()));
}
}

View File

@@ -0,0 +1,147 @@
package org.springframework.cloud.release.internal.project;
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.getMaven().setBuildCommand("ls -al");
properties.setWorkingDir(file("/projects/builder/resolved").getPath());
Project builder = new Project(properties, executor(properties));
builder.build();
then(asString(file("/projects/builder/resolved/resolved.log")))
.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.getMaven().setBuildCommand("ls -al");
properties.setWorkingDir(file("/projects/builder/unresolved").getPath());
Project builder = new Project(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.getMaven().setBuildCommand("sleep 1");
properties.getMaven().setWaitTimeInMinutes(0);
properties.setWorkingDir(file("/projects/builder/unresolved").getPath());
Project builder = new Project(properties, executor(properties));
thenThrownBy(builder::build).hasMessageContaining("Process waiting time of [0] minutes exceeded");
}
@Test
public void should_successfully_execute_a_deploy_command() throws Exception {
ReleaserProperties properties = new ReleaserProperties();
properties.getMaven().setDeployCommand("ls -al");
properties.setWorkingDir(file("/projects/builder/resolved").getPath());
Project builder = new Project(properties, executor(properties));
builder.deploy();
then(asString(file("/projects/builder/resolved/resolved.log")))
.contains("file.txt");
}
@Test
public void should_throw_exception_when_deploy_command_took_too_long_to_execute() throws Exception {
ReleaserProperties properties = new ReleaserProperties();
properties.getMaven().setDeployCommand("sleep 1");
properties.getMaven().setWaitTimeInMinutes(0);
properties.setWorkingDir(file("/projects/builder/unresolved").getPath());
Project builder = new Project(properties, executor(properties));
thenThrownBy(builder::deploy).hasMessageContaining("Process waiting time of [0] minutes exceeded");
}
@Test
public void should_successfully_execute_a_publish_docs_command() throws Exception {
ReleaserProperties properties = new ReleaserProperties();
properties.getMaven().setPublishDocsCommands(new String[] { "ls -al", "ls -al" });
properties.setWorkingDir(file("/projects/builder/resolved").getPath());
TestProcessExecutor executor = executor(properties);
Project builder = new Project(properties, executor);
builder.publishDocs();
then(asString(file("/projects/builder/resolved/resolved.log")))
.contains("file.txt");
then(executor.counter).isEqualTo(2);
}
@Test
public void should_throw_exception_when_publish_docs_command_took_too_long_to_execute() throws Exception {
ReleaserProperties properties = new ReleaserProperties();
properties.getMaven().setPublishDocsCommands(new String[] { "ls -al", "ls -al" });
properties.getMaven().setWaitTimeInMinutes(0);
properties.setWorkingDir(file("/projects/builder/unresolved").getPath());
Project builder = new Project(properties, executor(properties));
thenThrownBy(builder::publishDocs).hasMessageContaining("Process waiting time of [0] minutes exceeded");
}
private TestProcessExecutor executor(ReleaserProperties properties) {
return new TestProcessExecutor(properties);
}
class TestProcessExecutor extends ProcessExecutor {
int counter = 0;
TestProcessExecutor(ReleaserProperties properties) {
super(properties);
}
@Override ProcessBuilder builder(String[] commands, String workingDir) {
counter++;
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()));
}
}

View File

@@ -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.builder.ProjectBuilder;
import org.springframework.cloud.release.internal.project.Project;
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
import org.springframework.cloud.release.internal.pom.ProjectUpdater;
import org.springframework.context.annotation.Bean;
@@ -30,6 +30,6 @@ class ReleaserConfiguration {
@Bean Releaser releaser(ReleaserProperties properties) {
return new Releaser(properties, new ProjectUpdater(properties),
new ProjectBuilder(properties), new ProjectGitUpdater());
new Project(properties), new ProjectGitUpdater());
}
}