From 06b7112a2c954b96342d9c308d6aa5c46f93cf45 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Wed, 19 Apr 2017 16:57:56 +0200 Subject: [PATCH] Generates blog post template fixes #11 --- .../cloud/release/internal/Releaser.java | 13 +- .../release/internal/pom/ProjectVersion.java | 14 +- .../template/BlogTemplateGenerator.java | 147 +++++++++++++ .../template/EmailTemplateGenerator.java | 34 +++ .../internal/template/TemplateGenerator.java | 39 ++-- .../src/main/resources/templates/blog.hbs | 84 ++++++++ .../internal/pom/ProjectVersionTests.java | 30 ++- .../template/TemplateGeneratorTests.java | 203 ++++++++++++++++++ .../internal/spring/SpringReleaser.java | 1 + .../internal/spring/AcceptanceTests.java | 22 +- 10 files changed, 564 insertions(+), 23 deletions(-) create mode 100644 spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/BlogTemplateGenerator.java create mode 100644 spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/EmailTemplateGenerator.java create mode 100644 spring-cloud-release-tools-core/src/main/resources/templates/blog.hbs 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 3a917c52..7769e923 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 @@ -64,7 +64,7 @@ public class Releaser { public void rollbackReleaseVersion(File project, ProjectVersion originalVersion, ProjectVersion changedVersion) { this.projectGitUpdater.revertChangesIfApplicable(project, changedVersion); - if (changedVersion.isRelease() && originalVersion.isSnapshot()) { + if ((changedVersion.isRelease() || changedVersion.isServiceRelease()) && originalVersion.isSnapshot()) { this.projectBuilder.bumpVersions(originalVersion.bumpedVersion()); this.projectGitUpdater.commitAfterBumpingVersions(project, originalVersion); log.info("\nSuccessfully reverted the commit and bumped snapshot versions"); @@ -85,10 +85,19 @@ public class Releaser { public void createEmail(ProjectVersion releaseVersion) { if (releaseVersion.isSnapshot()) { - log.info("\nWon't send an email for a SNAPSHOT version"); + log.info("\nWon't create email template for a SNAPSHOT version"); } else { File email = this.templateGenerator.email(); log.info("\nSuccessfully created email template at location [{}]", email); } } + + public void createBlog(ProjectVersion releaseVersion, Projects projects) { + if (releaseVersion.isSnapshot()) { + log.info("\nWon't create blog template for a SNAPSHOT version"); + } else { + File blog = this.templateGenerator.blog(projects); + log.info("\nSuccessfully created blog template at location [{}]", blog); + } + } } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java index 24d291fc..88c0f925 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java @@ -49,8 +49,20 @@ public class ProjectVersion { return this.version.contains("SNAPSHOT"); } + public boolean isRc() { + return this.version.contains("RC"); + } + + public boolean isMilestone() { + return this.version.matches(".*M[0-9]+"); + } + public boolean isRelease() { - return this.version.contains("RELEASE") || this.version.matches(".*.SR[0-9]+"); + return this.version.contains("RELEASE"); + } + + public boolean isServiceRelease() { + return this.version.matches(".*.SR[0-9]+"); } @Override public String toString() { diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/BlogTemplateGenerator.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/BlogTemplateGenerator.java new file mode 100644 index 00000000..22d30e60 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/BlogTemplateGenerator.java @@ -0,0 +1,147 @@ +package org.springframework.cloud.release.internal.template; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.springframework.cloud.release.internal.pom.Projects; +import org.springframework.util.StringUtils; + +import com.github.jknack.handlebars.Template; +import com.google.common.collect.ImmutableMap; + +/** + * @author Marcin Grzejszczak + */ +class BlogTemplateGenerator { + + private static final Pattern RC_PATTERN = Pattern.compile("(.*)(RC)([0-9]+)"); + private static final Pattern MILESTONE_PATTERN = Pattern.compile("(.*)(M)([0-9]+)"); + private static final Pattern SR_PATTERN = Pattern.compile("(.*)(SR)([0-9]+)"); + + private final Template template; + private final String releaseVersion; + private final File blogOutput; + private final Projects projects; + + BlogTemplateGenerator(Template template, String releaseVersion, File blogOutput, + Projects projects) { + this.template = template; + this.releaseVersion = releaseVersion; + this.blogOutput = blogOutput; + this.projects = projects; + } + + File blog() { + try { + // availability - General Availability (RELEASE) / Service Release 1 (SR1) / Milestone 1 (M1) + // releaseName - Dalston + // releaseLink + // - [Maven Central](http://repo1.maven.org/maven2/org/springframework/cloud/spring-cloud-dependencies/Dalston.RELEASE/) + // - [Spring Milestone](https://repo.spring.io/milestone/) repository + // releaseVersion '- Dalston.RELEASE + boolean release = this.releaseVersion.contains("RELEASE"); + boolean nonRelease = !(release || SR_PATTERN.matcher(this.releaseVersion).matches()); + String availability = availability(release); + String releaseName = parsedReleaseName(this.releaseVersion); + String releaseLink = link(nonRelease); + Map map = ImmutableMap.builder() + .put("availability", availability) + .put("releaseName", releaseName) + .put("releaseLink", releaseLink) + .put("releaseVersion", this.releaseVersion) + .put("projects", fromProjects()) + .put("nonRelease", nonRelease) + .build(); + String blog = this.template.apply(map); + Files.write(this.blogOutput.toPath(), blog.getBytes()); + return this.blogOutput; + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private Set fromProjects() { + return this.projects.stream().map(projectVersion -> { + String name = projectVersion.projectName; + String version = projectVersion.version; + String convertedName = Arrays.stream(name.split("-")).map( + StringUtils::capitalize).collect(Collectors.joining(" ")); + return new Tuple(convertedName, version); + }).collect(Collectors.toSet()); + } + + private String parsedReleaseName(String version) { + return version.substring(0, version.indexOf(".")); + } + + private String availability(boolean release) { + Matcher sr = SR_PATTERN.matcher(this.releaseVersion); + Matcher rc = RC_PATTERN.matcher(this.releaseVersion); + Matcher milestone = MILESTONE_PATTERN.matcher(this.releaseVersion); + if (release) { + return "General Availability (RELEASE)"; + } else if (sr.matches()) { + return availabilityText(sr, "Service Release", "SR"); + } else if (rc.matches()) { + return availabilityText(rc, "Release Candidate", "RC"); + } else if (milestone.matches()) { + return availabilityText(milestone, "Milestone", "M"); + } + throw new IllegalStateException("Wrong version [" + this.releaseVersion + "] for a blog post"); + } + + private String availabilityText(Matcher matcher, String text, String shortText) { + String number = matcher.group(3); + return text + " " + number + " (" + shortText + number + ")"; + } + + private String link(boolean nonRelease) { + if (nonRelease) { + return "[Spring Milestone](https://repo.spring.io/milestone/) repository"; + } + return "[Maven Central](http://repo1.maven.org/maven2/org/springframework/cloud/spring-cloud-dependencies/" + this.releaseVersion + "/)"; + } +} + +class Tuple { + private final String name; + private final String version; + + Tuple(String name, String version) { + this.name = name; + this.version = version; + } + + public String getName() { + return name; + } + + public String getVersion() { + return version; + } + + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Tuple tuple = (Tuple) o; + if (name != null ? !name.equals(tuple.name) : tuple.name != null) + return false; + return version != null ? version.equals(tuple.version) : tuple.version == null; + } + + @Override public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (version != null ? version.hashCode() : 0); + return result; + } +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/EmailTemplateGenerator.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/EmailTemplateGenerator.java new file mode 100644 index 00000000..468fbca1 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/EmailTemplateGenerator.java @@ -0,0 +1,34 @@ +package org.springframework.cloud.release.internal.template; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import com.github.jknack.handlebars.Template; + +/** + * @author Marcin Grzejszczak + */ +class EmailTemplateGenerator { + + private final Template template; + private final String releaseVersion; + private final File emailOutput; + + EmailTemplateGenerator(Template template, String releaseVersion, File emailOutput) { + this.template = template; + this.releaseVersion = releaseVersion; + this.emailOutput = emailOutput; + } + + File email() { + try { + String email = this.template.apply(this.releaseVersion); + Files.write(this.emailOutput.toPath(), email.getBytes()); + return this.emailOutput; + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } +} 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 index f4aac098..e3b3c32e 100644 --- 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 @@ -2,9 +2,9 @@ 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 org.springframework.cloud.release.internal.pom.Projects; import com.github.jknack.handlebars.Handlebars; import com.github.jknack.handlebars.Template; @@ -17,7 +17,9 @@ import com.github.jknack.handlebars.io.ClassPathTemplateLoader; public class TemplateGenerator { private static final String EMAIL_TEMPLATE = "email"; + private static final String BLOG_TEMPLATE = "blog"; private final File emailOutput = new File("target/email.txt"); + private final File blogOutput = new File("target/blog.md"); private final ReleaserProperties props; public TemplateGenerator(ReleaserProperties props) { @@ -25,24 +27,33 @@ public class TemplateGenerator { } public File email() { + File emailOutput = file(this.emailOutput); + String releaseVersion = parsedVersion(); + Template template = template(EMAIL_TEMPLATE); + return new EmailTemplateGenerator(template, releaseVersion, emailOutput).email(); + } + + private File file(File file) { try { - Template template = uncheckedCompileTemplate(); - String releaseVersion = parsedVersion(); - String email = template.apply(releaseVersion); - if (emailOutput.exists()) { - emailOutput.delete(); + if (file.exists()) { + file.delete(); } - if (!emailOutput.createNewFile()) { - throw new IllegalStateException("Couldn't create a file with email template"); + if (!file.createNewFile()) { + throw new IllegalStateException("Couldn't create a file [" + file + "]"); } - Files.write(emailOutput.toPath(), email.getBytes()); - return emailOutput; - } - catch (IOException e) { + return file; + } catch (IOException e) { throw new IllegalStateException(e); } } + public File blog(Projects projects) { + File blogOutput = file(this.blogOutput); + String releaseVersion = parsedVersion(); + Template template = template(BLOG_TEMPLATE); + return new BlogTemplateGenerator(template, releaseVersion, blogOutput, projects).blog(); + } + private String parsedVersion() { String version = this.props.getPom().getBranch(); if (version.startsWith("v")) { @@ -51,12 +62,12 @@ public class TemplateGenerator { return version; } - private Template uncheckedCompileTemplate() { + private Template template(String template) { try { Handlebars handlebars = new Handlebars(new ClassPathTemplateLoader("/templates")); handlebars.registerHelper("replace", StringHelpers.replace); handlebars.registerHelper("capitalizeFirst", StringHelpers.capitalizeFirst); - return handlebars.compile(this.EMAIL_TEMPLATE); + return handlebars.compile(template); } catch (IOException e) { throw new IllegalStateException(e); } diff --git a/spring-cloud-release-tools-core/src/main/resources/templates/blog.hbs b/spring-cloud-release-tools-core/src/main/resources/templates/blog.hbs new file mode 100644 index 00000000..701b9919 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/resources/templates/blog.hbs @@ -0,0 +1,84 @@ +On behalf of the community, I am pleased to announce that the {{ availability }} of the [Spring Cloud {{ releaseName }}](https://cloud.spring.io) Release Train is available today. The release can be found in {{ releaseLink }}. You can check out the {{ releaseName }} [release notes for more information](https://github.com/spring-projects/spring-cloud/wiki/Spring-Cloud-{{ releaseName }}-Release-Notes). + +## Notable Changes in the {{ releaseName }} Release Train +{{#each projects}} +### {{ name }} + +Sine text related to project +{{/each}} + +The following modules were updated as part of {{ releaseVersion }}: + +| Module | Version | +|--- |--- | +{{#each projects}}| {{name}} | {{version}} | +{{/each}} + +And, as always, we welcome feedback: either on [GitHub](https://github.com/spring-cloud/), on [Gitter](https://gitter.im/spring-cloud/spring-cloud), on [Stack Overflow](http://stackoverflow.com/questions/tagged/spring-cloud), or on [Twitter](https://twitter.com/SpringCloud). + +To get started with Maven with a BOM (dependency management only) + +``` +{{#if nonRelease}} + + spring-milestones + Spring Milestones + http://repo.spring.io/milestone + + false + + +{{/if}} + + + + org.springframework.cloud + spring-cloud-dependencies + {{ releaseVersion }} + pom + import + + + + + + org.springframework.cloud + spring-cloud-starter-config + + + org.springframework.cloud + spring-cloud-starter-eureka + + ... + +``` + +or with Gradle: + +``` +buildscript { + dependencies { + classpath "io.spring.gradle:dependency-management-plugin:1.0.0.RELEASE" + } +} + +{{#if nonRelease}}repositories { + maven { + url 'http://repo.spring.io/milestone' + } +}{{/if}} + +apply plugin: "io.spring.dependency-management" + +dependencyManagement { + imports { + mavenBom 'org.springframework.cloud:spring-cloud-dependencies:{{ releaseVersion }}' + } +} + +dependencies { + compile 'org.springframework.cloud:spring-cloud-starter-config' + compile 'org.springframework.cloud:spring-cloud-starter-eureka' + ... +} +``` diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java index 853a10b7..020b2f43 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java @@ -114,7 +114,35 @@ public class ProjectVersionTests { public void should_return_true_for_service_release_versions() { String version = "1.0.1.SR1"; - then(projectVersion(version).isRelease()).isTrue(); + then(projectVersion(version).isServiceRelease()).isTrue(); + } + + @Test + public void should_return_true_when_checking_milestone_version_against_milestone() { + String version = "1.0.1.M1"; + + then(projectVersion(version).isMilestone()).isTrue(); + } + + @Test + public void should_return_false_when_checking_milestone_version_against_non_milestone() { + String version = "1.0.1.RC1"; + + then(projectVersion(version).isMilestone()).isFalse(); + } + + @Test + public void should_return_true_when_checking_rc_version_against_rc() { + String version = "1.0.1.RC3"; + + then(projectVersion(version).isRc()).isTrue(); + } + + @Test + public void should_return_false_when_checking_rc_version_against_non_rc() { + String version = "1.0.1.M1"; + + then(projectVersion(version).isRc()).isFalse(); } private ProjectVersion projectVersion(String version) { 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 index 4137ab18..19392ec0 100644 --- 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 @@ -1,9 +1,14 @@ package org.springframework.cloud.release.internal.template; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashSet; import org.junit.Test; import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; import static org.assertj.core.api.BDDAssertions.then; @@ -16,6 +21,7 @@ public class TemplateGeneratorTests { 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()); @@ -25,11 +31,208 @@ public class TemplateGeneratorTests { 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()); } + @Test + public void should_generate_blog_from_template_for_tag_with_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("vDalston.RELEASE"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.RELEASE")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.RELEASE")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("General Availability (RELEASE) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.RELEASE \t|") + .contains("Dalston.RELEASE") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'"); + } + + @Test + public void should_generate_blog_from_template_for_tag_without_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("Dalston.RELEASE"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.RELEASE")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.RELEASE")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("General Availability (RELEASE) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.RELEASE \t|") + .contains("Dalston.RELEASE") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'"); + } + + @Test + public void should_generate_sr_blog_from_template_for_tag_with_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("vDalston.SR1"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.RELEASE")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.RELEASE")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("Service Release 1 (SR1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.RELEASE \t|") + .contains("Dalston.SR1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.SR1'"); + } + + @Test + public void should_generate_sr_blog_from_template_for_tag_without_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("Dalston.SR1"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.RELEASE")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.RELEASE")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("Service Release 1 (SR1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.RELEASE \t|") + .contains("Dalston.SR1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.SR1'"); + } + + @Test + public void should_generate_milestone_blog_from_template_for_tag_with_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("vDalston.M1"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.M1")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.M1")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("Milestone 1 (M1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.M1 \t|") + .contains("spring-milestones") + .contains("url 'http://repo.spring.io/milestone'") + .contains("Dalston.M1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.M1'"); + } + + @Test + public void should_generate_milestone_blog_from_template_for_tag_without_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("Dalston.M1"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.M1")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.M1")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("Milestone 1 (M1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.M1 \t|") + .contains("spring-milestones") + .contains("url 'http://repo.spring.io/milestone'") + .contains("Dalston.M1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.M1'"); + } + + @Test + public void should_generate_rc_blog_from_template_for_tag_with_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("vDalston.RC1"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.RC1")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.RC1")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("Release Candidate 1 (RC1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.RC1 \t|") + .contains("spring-milestones") + .contains("url 'http://repo.spring.io/milestone'") + .contains("Dalston.RC1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RC1'"); + } + + @Test + public void should_generate_rc_blog_from_template_for_tag_without_v_prefix_release() + throws IOException { + ReleaserProperties props = new ReleaserProperties(); + props.getPom().setBranch("Dalston.RC1"); + Projects projects = new Projects( + new HashSet() {{ + add(new ProjectVersion("spring-cloud-sleuth", "1.0.0.RC1")); + add(new ProjectVersion("spring-cloud-consul", "1.0.1.RC1")); + }} + ); + + File generatedBlog = new TemplateGenerator(props).blog(projects); + + then(content(generatedBlog)) + .contains("Release Candidate 1 (RC1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]") + .contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth \t| 1.0.0.RC1 \t|") + .contains("spring-milestones") + .contains("url 'http://repo.spring.io/milestone'") + .contains("Dalston.RC1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RC1'"); + } + + private String content(File file) throws IOException { + return new String(Files.readAllBytes(file.toPath())); + } + private String expectedEmail() { return "Title:\n" + "Spring Cloud Dalston.RELEASE available\n\n" 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 5e21eed3..34928dca 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 @@ -89,6 +89,7 @@ public class SpringReleaser { boolean skipTemplates = skipStep(); if (!skipTemplates) { this.releaser.createEmail(versionFromScRelease); + this.releaser.createBlog(versionFromScRelease, projects); } } } 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 62b9db36..a7d8ea7e 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 @@ -68,10 +68,12 @@ public class AcceptanceTests { pomParentVersionIsEqualTo(project, "1.2.1.BUILD-SNAPSHOT"); then(this.gitUpdater.executed).isTrue(); then(emailTemplate()).exists(); - String emailTemplateContents = emailTemplateContents(); - then(emailTemplateContents) + then(emailTemplateContents()) .contains("Spring Cloud Camden.SR5 available") .contains("Spring Cloud Camden SR5 Train release"); + then(blogTemplate()).exists(); + then(blogTemplateContents()) + .contains("I am pleased to announce that the Service Release 5 (SR5)"); } @Test @@ -93,12 +95,14 @@ 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(this.gitUpdater.executed).isTrue(); then(emailTemplate()).exists(); - String emailTemplateContents = emailTemplateContents(); - then(emailTemplateContents) + then(emailTemplateContents()) .contains("Spring Cloud Dalston.RC1 available") .contains("Spring Cloud Dalston RC1 Train release"); - then(this.gitUpdater.executed).isTrue(); + then(blogTemplate()).exists(); + then(blogTemplateContents()) + .contains("I am pleased to announce that the Release Candidate 1 (RC1)"); } private Iterable listOfCommits(File project) throws GitAPIException { @@ -145,6 +149,14 @@ public class AcceptanceTests { return new String(Files.readAllBytes(emailTemplate().toPath())); } + private File blogTemplate() throws URISyntaxException { + return new File("target/blog.md"); + } + + private String blogTemplateContents() throws URISyntaxException, IOException { + return new String(Files.readAllBytes(blogTemplate().toPath())); + } + private SpringReleaser releaser(File projectFile, String branch, String expectedVersion) throws Exception { ReleaserProperties properties = releaserProperties(projectFile, branch); ProjectPomUpdater pomUpdater = new ProjectPomUpdater(properties);