diff --git a/spring-cloud-release-tools-core/pom.xml b/spring-cloud-release-tools-core/pom.xml
index f0edbad6..ddd99efa 100644
--- a/spring-cloud-release-tools-core/pom.xml
+++ b/spring-cloud-release-tools-core/pom.xml
@@ -67,16 +67,21 @@
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
com.jcabi
jcabi-github
0.23
+
+ com.github.jknack
+ handlebars
+ 4.0.6
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
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 6406b996..3a917c52 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
@@ -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);
+ }
+ }
}
diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java
new file mode 100644
index 00000000..5cdb7406
--- /dev/null
+++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java
@@ -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);
+ }
+ }
+}
diff --git a/spring-cloud-release-tools-core/src/main/resources/templates/email.hbs b/spring-cloud-release-tools-core/src/main/resources/templates/email.hbs
new file mode 100644
index 00000000..31a9a8d7
--- /dev/null
+++ b/spring-cloud-release-tools-core/src/main/resources/templates/email.hbs
@@ -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,
\ No newline at end of file
diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/ReleaserTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/ReleaserTests.java
index dd8a6186..52dea902 100644
--- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/ReleaserTests.java
+++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/ReleaserTests.java
@@ -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();
+ }
+
}
\ No newline at end of file
diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/template/TemplateGeneratorTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/template/TemplateGeneratorTests.java
new file mode 100644
index 00000000..4137ab18
--- /dev/null
+++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/template/TemplateGeneratorTests.java
@@ -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";
+ }
+}
diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java
index 1ec141cc..df155948 100644
--- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java
+++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java
@@ -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);
}
}
diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java
index c0855ec5..5e21eed3 100644
--- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java
+++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/SpringReleaser.java
@@ -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);
}
}
}
diff --git a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java
index 56428410..62b9db36 100644
--- a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java
+++ b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java
@@ -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() {