Added email template generation

fixes #12
This commit is contained in:
Marcin Grzejszczak
2017-04-19 14:40:46 +02:00
parent 96c362646b
commit 68456dcb80
9 changed files with 200 additions and 17 deletions

View File

@@ -67,16 +67,21 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-github</artifactId>
<version>0.23</version>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>

View File

@@ -5,6 +5,7 @@ import java.lang.invoke.MethodHandles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
import org.springframework.cloud.release.internal.pom.ProjectPomUpdater;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
@@ -20,12 +21,14 @@ public class Releaser {
private final ProjectPomUpdater projectPomUpdater;
private final ProjectBuilder projectBuilder;
private final ProjectGitUpdater projectGitUpdater;
private final TemplateGenerator templateGenerator;
public Releaser(ProjectPomUpdater projectPomUpdater,
ProjectBuilder projectBuilder, ProjectGitUpdater projectGitUpdater) {
public Releaser(ProjectPomUpdater projectPomUpdater, ProjectBuilder projectBuilder,
ProjectGitUpdater projectGitUpdater, TemplateGenerator templateGenerator) {
this.projectPomUpdater = projectPomUpdater;
this.projectBuilder = projectBuilder;
this.projectGitUpdater = projectGitUpdater;
this.templateGenerator = templateGenerator;
}
public Projects retrieveVersionsFromSCRelease() {
@@ -79,4 +82,13 @@ public class Releaser {
this.projectGitUpdater.closeMilestone(releaseVersion);
log.info("\nSuccessfully closed milestone");
}
public void createEmail(ProjectVersion releaseVersion) {
if (releaseVersion.isSnapshot()) {
log.info("\nWon't send an email for a SNAPSHOT version");
} else {
File email = this.templateGenerator.email();
log.info("\nSuccessfully created email template at location [{}]", email);
}
}
}

View File

@@ -0,0 +1,63 @@
package org.springframework.cloud.release.internal.template;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import org.springframework.cloud.release.internal.ReleaserProperties;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.helper.StringHelpers;
/**
* @author Marcin Grzejszczak
*/
public class TemplateGenerator {
private final String emailTemplate = "/templates/email";
private final File emailOutput = new File("target/email.txt");
private final ReleaserProperties props;
public TemplateGenerator(ReleaserProperties props) {
this.props = props;
}
public File email() {
try {
Template template = uncheckedCompileTemplate();
String releaseVersion = parsedVersion();
String email = template.apply(releaseVersion);
if (emailOutput.exists()) {
emailOutput.delete();
}
if (!emailOutput.createNewFile()) {
throw new IllegalStateException("Couldn't create a file with email template");
}
Files.write(emailOutput.toPath(), email.getBytes());
return emailOutput;
}
catch (IOException e) {
throw new IllegalStateException(e);
}
}
private String parsedVersion() {
String version = this.props.getPom().getBranch();
if (version.startsWith("v")) {
return version.substring(1);
}
return version;
}
private Template uncheckedCompileTemplate() {
try {
Handlebars handlebars = new Handlebars();
handlebars.registerHelper("replace", StringHelpers.replace);
handlebars.registerHelper("capitalizeFirst", StringHelpers.capitalizeFirst);
return handlebars.compile(this.emailTemplate);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}

View File

@@ -0,0 +1,12 @@
Title:
Spring Cloud {{ this }} available
Content:
All,
On behalf of the team and the community, I'm excited to announce Spring Cloud {{ replace this "." " " }} Train release.
link to blog post
link to twitter
Cheers,

View File

@@ -10,6 +10,7 @@ import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
import org.springframework.cloud.release.internal.pom.ProjectPomUpdater;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
@@ -28,6 +29,7 @@ public class ReleaserTests {
@Mock ProjectPomUpdater projectPomUpdater;
@Mock ProjectBuilder projectBuilder;
@Mock ProjectGitUpdater projectGitUpdater;
@Mock TemplateGenerator templateGenerator;
@InjectMocks Releaser releaser;
File pom;
@@ -64,4 +66,18 @@ public class ReleaserTests {
then(this.projectBuilder).should().bumpVersions(anyString());
}
@Test
public void should_not_generate_email_for_snapshot_version() throws Exception {
this.releaser.createEmail(new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT"));
then(this.templateGenerator).should(never()).email();
}
@Test
public void should_generate_email_for_release_version() throws Exception {
this.releaser.createEmail(new ProjectVersion("original", "1.0.0.RELEASE"));
then(this.templateGenerator).should().email();
}
}

View File

@@ -0,0 +1,44 @@
package org.springframework.cloud.release.internal.template;
import java.io.File;
import org.junit.Test;
import org.springframework.cloud.release.internal.ReleaserProperties;
import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Marcin Grzejszczak
*/
public class TemplateGeneratorTests {
@Test
public void should_generate_email_from_template_for_tag_with_v_prefix() {
ReleaserProperties props = new ReleaserProperties();
props.getPom().setBranch("vDalston.RELEASE");
File generatedMail = new TemplateGenerator(props).email();
then(generatedMail).hasContent(expectedEmail());
}
@Test
public void should_generate_email_from_template_for_tag_without_v_prefix() {
ReleaserProperties props = new ReleaserProperties();
props.getPom().setBranch("Dalston.RELEASE");
File generatedMail = new TemplateGenerator(props).email();
then(generatedMail).hasContent(expectedEmail());
}
private String expectedEmail() {
return "Title:\n"
+ "Spring Cloud Dalston.RELEASE available\n\n"
+ "Content:\n"
+ "All,\n" + "\n"
+ "On behalf of the team and the community, I'm excited to announce Spring Cloud Dalston RELEASE Train release.\n"
+ "\n"
+ "link to blog post\n"
+ "link to twitter\n\n"
+ "Cheers,\n";
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.release.internal.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.template.TemplateGenerator;
import org.springframework.cloud.release.internal.project.ProjectBuilder;
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
import org.springframework.cloud.release.internal.pom.ProjectPomUpdater;
@@ -31,6 +32,6 @@ class ReleaserConfiguration {
@Bean SpringReleaser releaser(ReleaserProperties properties) {
ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties);
return new SpringReleaser(new Releaser(pomUpdater, new ProjectBuilder(properties, pomUpdater),
new ProjectGitUpdater(properties)), properties);
new ProjectGitUpdater(properties), new TemplateGenerator(properties)), properties);
}
}

View File

@@ -37,12 +37,12 @@ public class SpringReleaser {
File project = new File(workingDir);
ProjectVersion originalVersion = new ProjectVersion(project);
Projects projects = this.releaser.retrieveVersionsFromSCRelease();
ProjectVersion changedVersion = projects.forFile(project);
ProjectVersion versionFromScRelease = projects.forFile(project);
log.info("\n\n\n=== UPDATING POMS ===\n\nWill run the application "
+ "for root folder [{}]. \n\nPress ENTER to continue {}", workingDir, MSG);
boolean skipPoms = skipStep();
if (!skipPoms) {
changedVersion = this.releaser.updateProjectFromScRelease(project, projects);
versionFromScRelease = this.releaser.updateProjectFromScRelease(project, projects);
}
log.info("\n\n\n=== BUILD PROJECT ===\n\nPress ENTER to build the project {}", MSG);
boolean skipBuild = skipStep();
@@ -52,7 +52,7 @@ public class SpringReleaser {
log.info("\n\n\n=== COMMITTING (ALL) AND PUSHING TAGS (NON-SNAPSHOTS) ===\n\nPress ENTER to commit, tag and push the tag {}", MSG);
boolean skipCommit = skipStep();
if (!skipCommit) {
this.releaser.commitAndPushTags(project, changedVersion);
this.releaser.commitAndPushTags(project, versionFromScRelease);
}
log.info("\n\n\n=== ARTIFACT DEPLOYMENT ===\n\nPress ENTER to deploy the artifacts {}", MSG);
boolean skipDeployment = skipStep();
@@ -62,14 +62,14 @@ public class SpringReleaser {
log.info("\n\n\n=== PUBLISHING DOCS ===\n\nPress ENTER to publish the docs {}", MSG);
boolean skipDocs = skipStep();
if (!skipDocs) {
this.releaser.publishDocs(changedVersion);
this.releaser.publishDocs(versionFromScRelease);
}
if (!changedVersion.isSnapshot()) {
if (!versionFromScRelease.isSnapshot()) {
log.info("\n\n\n=== REVERTING CHANGES & BUMPING VERSION (RELEASE ONLY)===\n\nPress ENTER to go "
+ "back to snapshots and bump originalVersion by patch {}", MSG);
boolean skipRevert = skipStep();
if (!skipRevert) {
this.releaser.rollbackReleaseVersion(project, originalVersion, changedVersion);
this.releaser.rollbackReleaseVersion(project, originalVersion, versionFromScRelease);
}
}
log.info("\n\n\n=== PUSHING CHANGES===\n\nPress ENTER to push the commits {}", MSG);
@@ -77,11 +77,18 @@ public class SpringReleaser {
if (!skipPush) {
this.releaser.pushCurrentBranch(project);
}
if (!changedVersion.isSnapshot()) {
if (!versionFromScRelease.isSnapshot()) {
log.info("\n\n\n=== CLOSING MILESTONE===\n\nPress ENTER to close the milestone at Github {}", MSG);
boolean skipMilestone = skipStep();
if (!skipMilestone) {
this.releaser.closeMilestone(changedVersion);
this.releaser.closeMilestone(versionFromScRelease);
}
}
if (!versionFromScRelease.isSnapshot()) {
log.info("\n\n\n=== CREATING TEMPLATES===\n\nPress ENTER to create email / tweet etc. templates {}", MSG);
boolean skipTemplates = skipStep();
if (!skipTemplates) {
this.releaser.createEmail(versionFromScRelease);
}
}
}

View File

@@ -1,7 +1,9 @@
package org.springframework.cloud.release.internal.spring;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.Iterator;
import org.apache.maven.model.Model;
@@ -14,6 +16,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.cloud.release.internal.Releaser;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.cloud.release.internal.git.GitTestUtils;
import org.springframework.cloud.release.internal.git.ProjectGitUpdater;
import org.springframework.cloud.release.internal.pom.ProjectPomUpdater;
@@ -64,6 +67,11 @@ public class AcceptanceTests {
pomVersionIsEqualTo(project, "1.2.1.BUILD-SNAPSHOT");
pomParentVersionIsEqualTo(project, "1.2.1.BUILD-SNAPSHOT");
then(this.gitUpdater.executed).isTrue();
then(emailTemplate()).exists();
String emailTemplateContents = emailTemplateContents();
then(emailTemplateContents)
.contains("Spring Cloud Camden.SR5 available")
.contains("Spring Cloud Camden SR5 Train release");
}
@Test
@@ -85,6 +93,11 @@ public class AcceptanceTests {
commitIsPresent(iterator, "Update SNAPSHOT to 1.2.0.RC1");
pomVersionIsEqualTo(project, "1.2.0.BUILD-SNAPSHOT");
pomParentVersionIsEqualTo(project, "1.2.0.BUILD-SNAPSHOT");
then(emailTemplate()).exists();
String emailTemplateContents = emailTemplateContents();
then(emailTemplateContents)
.contains("Spring Cloud Dalston.RC1 available")
.contains("Spring Cloud Dalston RC1 Train release");
then(this.gitUpdater.executed).isTrue();
}
@@ -124,13 +137,23 @@ public class AcceptanceTests {
return this.testPomReader.readPom(new File(dir, "pom.xml"));
}
private File emailTemplate() throws URISyntaxException {
return new File("target/email.txt");
}
private String emailTemplateContents() throws URISyntaxException, IOException {
return new String(Files.readAllBytes(emailTemplate().toPath()));
}
private SpringReleaser releaser(File projectFile, String branch, String expectedVersion) throws Exception {
ReleaserProperties properties = releaserProperties(projectFile, branch);
ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties);
ProjectBuilder projectBuilder = new ProjectBuilder(properties, pomUpdater);
TestProjectGitUpdater gitUpdater = new TestProjectGitUpdater(properties,
expectedVersion);
Releaser releaser = new Releaser(pomUpdater, projectBuilder, gitUpdater);
TemplateGenerator templateGenerator = new TemplateGenerator(properties);
Releaser releaser = new Releaser(pomUpdater, projectBuilder, gitUpdater,
templateGenerator);
this.gitUpdater = gitUpdater;
return new SpringReleaser(releaser, properties) {
@Override boolean skipStep() {