From e6e799e961c8bdd914b37f0c478a386a708482f2 Mon Sep 17 00:00:00 2001 From: Mahendra Bishnoi Date: Sun, 20 Dec 2020 00:44:46 +0530 Subject: [PATCH 1/3] Add external links to release notes using a property. Fixes gh-46 --- .../ApplicationProperties.java | 42 ++++++++++++++++++- .../ChangelogGenerator.java | 17 ++++++++ .../output-with-multiple-external-link | 5 +++ .../output-with-one-external-link | 3 ++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/io/spring/githubchangeloggenerator/output-with-multiple-external-link create mode 100644 src/test/resources/io/spring/githubchangeloggenerator/output-with-one-external-link diff --git a/src/main/java/io/spring/githubchangeloggenerator/ApplicationProperties.java b/src/main/java/io/spring/githubchangeloggenerator/ApplicationProperties.java index 8eb25ab..8a31485 100644 --- a/src/main/java/io/spring/githubchangeloggenerator/ApplicationProperties.java +++ b/src/main/java/io/spring/githubchangeloggenerator/ApplicationProperties.java @@ -63,14 +63,20 @@ public class ApplicationProperties { */ private final Contributors contributors; + /** + * Settings specific to external links. + */ + private final List externalLinks; + public ApplicationProperties(Repository repository, @DefaultValue("title") MilestoneReference milestoneReference, - List
sections, Issues issues, Contributors contributors) { + List
sections, Issues issues, Contributors contributors, List externalLinks) { Assert.notNull(repository, "Repository must not be null"); this.repository = repository; this.milestoneReference = milestoneReference; this.sections = (sections != null) ? sections : Collections.emptyList(); this.issues = (issues != null) ? issues : new Issues(null, null, null); this.contributors = (contributors != null) ? contributors : new Contributors(null, null); + this.externalLinks = (externalLinks != null) ? externalLinks : Collections.emptyList(); } public Repository getRepository() { @@ -93,6 +99,10 @@ public Contributors getContributors() { return this.contributors; } + public List getExternalLinks() { + return this.externalLinks; + } + /** * Properties for a single changelog section. */ @@ -285,6 +295,36 @@ public Set getNames() { } + /** + * Properties for a single external link. + */ + public static class ExternalLink { + + /** + * Name to be shown for external link. + */ + private final String name; + + /** + * URL for external link. + */ + private final String location; + + public ExternalLink(String name, String location) { + this.name = name; + this.location = location; + } + + public String getName() { + return this.name; + } + + public String getLocation() { + return this.location; + } + + } + public enum IssueSort { /** diff --git a/src/main/java/io/spring/githubchangeloggenerator/ChangelogGenerator.java b/src/main/java/io/spring/githubchangeloggenerator/ChangelogGenerator.java index 5c071c2..fcb5501 100644 --- a/src/main/java/io/spring/githubchangeloggenerator/ChangelogGenerator.java +++ b/src/main/java/io/spring/githubchangeloggenerator/ChangelogGenerator.java @@ -29,6 +29,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import io.spring.githubchangeloggenerator.ApplicationProperties.ExternalLink; import io.spring.githubchangeloggenerator.ApplicationProperties.IssueSort; import io.spring.githubchangeloggenerator.ApplicationProperties.PortedIssue; import io.spring.githubchangeloggenerator.github.payload.Issue; @@ -73,6 +74,8 @@ public class ChangelogGenerator { private final ChangelogSections sections; + private final List externalLinks; + public ChangelogGenerator(GitHubService service, ApplicationProperties properties) { this.service = service; this.repository = properties.getRepository(); @@ -83,6 +86,7 @@ public ChangelogGenerator(GitHubService service, ApplicationProperties propertie this.contributorsTitle = properties.getContributors().getTitle(); this.sections = new ChangelogSections(properties); this.portedIssues = properties.getIssues().getPorts(); + this.externalLinks = properties.getExternalLinks(); } /** @@ -131,6 +135,9 @@ private String generateContent(List issues) { if (!contributors.isEmpty()) { addContributorsContent(content, contributors); } + if (!this.externalLinks.isEmpty()) { + addExternalLinksContent(content, this.externalLinks); + } return content.toString(); } @@ -201,6 +208,16 @@ private String formatContributors(User c) { return String.format("- [@%s](%s)%n", c.getName(), c.getUrl()); } + private void addExternalLinksContent(StringBuilder content, List externalLinks) { + content.append(String.format("## ")); + content.append(String.format("External Links%n%n")); + externalLinks.stream().map(this::formatExternalLinks).forEach(content::append); + } + + private String formatExternalLinks(ExternalLink externalLink) { + return String.format("- [%s](%s)%n", externalLink.getName(), externalLink.getLocation()); + } + private void writeContentToFile(String content, String path) throws IOException { FileCopyUtils.copy(content, new FileWriter(new File(path))); } diff --git a/src/test/resources/io/spring/githubchangeloggenerator/output-with-multiple-external-link b/src/test/resources/io/spring/githubchangeloggenerator/output-with-multiple-external-link new file mode 100644 index 0000000..95b5df6 --- /dev/null +++ b/src/test/resources/io/spring/githubchangeloggenerator/output-with-multiple-external-link @@ -0,0 +1,5 @@ +## External Links + +- [Release Notes Link 1](url1) +- [Release Notes Link 2](url2) +- [Release Notes Link 3](url3) diff --git a/src/test/resources/io/spring/githubchangeloggenerator/output-with-one-external-link b/src/test/resources/io/spring/githubchangeloggenerator/output-with-one-external-link new file mode 100644 index 0000000..3c9e0b9 --- /dev/null +++ b/src/test/resources/io/spring/githubchangeloggenerator/output-with-one-external-link @@ -0,0 +1,3 @@ +## External Links + +- [Release Notes Link 1](url1) From bad5a39e091f40112b7df23f59d94ddfd9be50de Mon Sep 17 00:00:00 2001 From: Mahendra Bishnoi Date: Sun, 20 Dec 2020 00:46:30 +0530 Subject: [PATCH 2/3] Add tests for verifying that external links are generated in required format. Fixes gh-46 --- .../ApplicationPropertiesTests.java | 4 +++ .../ChangelogGeneratorTests.java | 35 +++++++++++++++---- .../ChangelogSectionsTests.java | 15 ++++---- .../test-application.yml | 5 +++ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/test/java/io/spring/githubchangeloggenerator/ApplicationPropertiesTests.java b/src/test/java/io/spring/githubchangeloggenerator/ApplicationPropertiesTests.java index fc2351f..d854daf 100644 --- a/src/test/java/io/spring/githubchangeloggenerator/ApplicationPropertiesTests.java +++ b/src/test/java/io/spring/githubchangeloggenerator/ApplicationPropertiesTests.java @@ -62,6 +62,10 @@ void loadYaml() throws Exception { assertThat(properties.getIssues().getSort()).isEqualTo(IssueSort.TITLE); assertThat(properties.getContributors().getTitle()).isEqualTo("Nice one!"); assertThat(properties.getContributors().getExclude().getNames()).containsExactly("philwebb"); + assertThat(properties.getExternalLinks().get(0).getName()).isEqualTo("Release Notes 1"); + assertThat(properties.getExternalLinks().get(0).getLocation()).isEqualTo("url1"); + assertThat(properties.getExternalLinks().get(1).getName()).isEqualTo("Release Notes 2"); + assertThat(properties.getExternalLinks().get(1).getLocation()).isEqualTo("url2"); } } diff --git a/src/test/java/io/spring/githubchangeloggenerator/ChangelogGeneratorTests.java b/src/test/java/io/spring/githubchangeloggenerator/ChangelogGeneratorTests.java index ba80369..bd65508 100644 --- a/src/test/java/io/spring/githubchangeloggenerator/ChangelogGeneratorTests.java +++ b/src/test/java/io/spring/githubchangeloggenerator/ChangelogGeneratorTests.java @@ -31,6 +31,7 @@ import io.spring.githubchangeloggenerator.ApplicationProperties.Contributors; import io.spring.githubchangeloggenerator.ApplicationProperties.ContributorsExclude; +import io.spring.githubchangeloggenerator.ApplicationProperties.ExternalLink; import io.spring.githubchangeloggenerator.ApplicationProperties.IssueSort; import io.spring.githubchangeloggenerator.ApplicationProperties.Issues; import io.spring.githubchangeloggenerator.ApplicationProperties.IssuesExclude; @@ -139,7 +140,7 @@ void generateWhenHasExcludedContributors() throws Exception { issues.add(newPullRequest("Enhancement 2", "2", Type.ENHANCEMENT, "enhancement-2-url", contributor2)); given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, - new Contributors(null, new ContributorsExclude(Collections.singleton("contributor1")))); + new Contributors(null, new ContributorsExclude(Collections.singleton("contributor1"))), null); this.generator = new ChangelogGenerator(this.service, properties); assertChangelog("23").hasContent(from("output-with-excluded-contributors")); } @@ -153,7 +154,7 @@ void generateWhenHasAllContributorsExcluded() throws Exception { issues.add(newPullRequest("Enhancement 2", "2", Type.ENHANCEMENT, "enhancement-2-url", contributor2)); given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, - new Contributors(null, new ContributorsExclude(Collections.singleton("*")))); + new Contributors(null, new ContributorsExclude(Collections.singleton("*"))), null); this.generator = new ChangelogGenerator(this.service, properties); assertChangelog("23").hasContent(from("output-with-all-contributors-excluded")); } @@ -223,7 +224,7 @@ void generateWhenSectionSortedByTitle() throws Exception { Set labels = Collections.singleton("type: enhancement"); sections.add(new Section("Enhancements", null, IssueSort.TITLE, labels)); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, sections, - new Issues(null, null, null), null); + new Issues(null, null, null), null, null); this.generator = new ChangelogGenerator(this.service, properties); List issues = new ArrayList<>(); issues.add(newIssue("Enhancement c", "1", "enhancement-1-url", Type.ENHANCEMENT)); @@ -239,7 +240,7 @@ void generateWhenAllIssuesSortedByTitle() throws Exception { Set labels = Collections.singleton("type: enhancement"); sections.add(new Section("Enhancements", null, null, labels)); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, sections, - new Issues(IssueSort.TITLE, null, null), null); + new Issues(IssueSort.TITLE, null, null), null, null); this.generator = new ChangelogGenerator(this.service, properties); List issues = new ArrayList<>(); issues.add(newIssue("Enhancement c", "1", "enhancement-1-url", Type.ENHANCEMENT)); @@ -256,18 +257,40 @@ void generateWhenHasCustomContributorsTitle() throws Exception { issues.add(newPullRequest("Bug 1", "1", Type.BUG, "bug-1-url", contributor1)); given(this.service.getIssuesForMilestone(23, REPO)).willReturn(issues); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, - new Contributors(":heart: Teamwork", null)); + new Contributors(":heart: Teamwork", null), null); this.generator = new ChangelogGenerator(this.service, properties); assertChangelog("23").hasContent(from("output-with-custom-contributors-title")); } + @Test + void generateWhenOneExternalLink() throws Exception { + List externalLinks = new ArrayList<>(); + externalLinks.add(new ExternalLink("Release Notes Link 1", "url1")); + ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, null, + externalLinks); + this.generator = new ChangelogGenerator(this.service, properties); + assertChangelog("23").hasContent(from("output-with-one-external-link")); + } + + @Test + void generateWhenMultipleExternalLink() throws Exception { + List externalLinks = new ArrayList<>(); + externalLinks.add(new ExternalLink("Release Notes Link 1", "url1")); + externalLinks.add(new ExternalLink("Release Notes Link 2", "url2")); + externalLinks.add(new ExternalLink("Release Notes Link 3", "url3")); + ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.ID, null, null, null, + externalLinks); + this.generator = new ChangelogGenerator(this.service, properties); + assertChangelog("23").hasContent(from("output-with-multiple-external-link")); + } + private void setupGenerator(MilestoneReference id) { Set labels = new HashSet<>(Arrays.asList("duplicate", "wontfix")); PortedIssue forwardPort = new PortedIssue("status: forward-port", "Forward port of issue #(\\d+)"); PortedIssue cherryPick = new PortedIssue("status: back-port", "Back port of issue #(\\d+)"); Set portedIssues = new HashSet<>(Arrays.asList(forwardPort, cherryPick)); ApplicationProperties properties = new ApplicationProperties(REPO, id, null, - new Issues(null, new IssuesExclude(labels), portedIssues), null); + new Issues(null, new IssuesExclude(labels), portedIssues), null, null); this.generator = new ChangelogGenerator(this.service, properties); } diff --git a/src/test/java/io/spring/githubchangeloggenerator/ChangelogSectionsTests.java b/src/test/java/io/spring/githubchangeloggenerator/ChangelogSectionsTests.java index d5cfe41..8465042 100644 --- a/src/test/java/io/spring/githubchangeloggenerator/ChangelogSectionsTests.java +++ b/src/test/java/io/spring/githubchangeloggenerator/ChangelogSectionsTests.java @@ -46,7 +46,8 @@ void collateWhenNoCustomSectionsUsesDefaultSections() { Issue bug = createIssue("2", "bug"); Issue documentation = createIssue("3", "documentation"); Issue dependencyUpgrade = createIssue("4", "dependency-upgrade"); - ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, null, null, null); + ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, null, null, null, + null); ChangelogSections sections = new ChangelogSections(properties); Map> collated = sections .collate(Arrays.asList(enhancement, bug, documentation, dependencyUpgrade)); @@ -67,7 +68,7 @@ void collateWhenHasCustomSectionsUsesDefinedSections() { Collections.singleton("bug")); List customSections = Arrays.asList(breaksPassivitySection, bugsSection); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, customSections, - null, null); + null, null, null); ChangelogSections sections = new ChangelogSections(properties); Issue bug = createIssue("1", "bug"); Issue nonPassive = createIssue("1", "breaks-passivity"); @@ -79,7 +80,8 @@ void collateWhenHasCustomSectionsUsesDefinedSections() { @Test void collateWhenNoIssuesInSectionExcludesSection() { Issue bug = createIssue("1", "bug"); - ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, null, null, null); + ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, null, null, null, + null); ChangelogSections sections = new ChangelogSections(properties); Map> collated = sections.collate(Collections.singletonList(bug)); Map> bySection = getBySection(collated); @@ -90,7 +92,8 @@ void collateWhenNoIssuesInSectionExcludesSection() { void collateWhenIssueDoesNotMatchAnySectionLabelThenExcludesIssue() { Issue bug = createIssue("1", "bug"); Issue nonPassive = createIssue("2", "non-passive"); - ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, null, null, null); + ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, null, null, null, + null); ChangelogSections sections = new ChangelogSections(properties); Map> collated = sections.collate(Arrays.asList(bug, nonPassive)); Map> bySection = getBySection(collated); @@ -109,7 +112,7 @@ void collateWithDefaultsDoesNotAddIssueToMultipleSections() { Collections.singleton("highlight")); List customSections = Arrays.asList(bugs, highlights); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, customSections, - null, null); + null, null, null); ChangelogSections sections = new ChangelogSections(properties); Map> collated = sections.collate(Arrays.asList(bug, highlight, bugAndHighlight)); Map> bySection = getBySection(collated); @@ -129,7 +132,7 @@ void collateWithGroupsAddsIssuePerGroup() { Collections.singleton("highlight")); List customSections = Arrays.asList(bugs, highlights); ApplicationProperties properties = new ApplicationProperties(REPO, MilestoneReference.TITLE, customSections, - null, null); + null, null, null); ChangelogSections sections = new ChangelogSections(properties); Map> collated = sections.collate(Arrays.asList(bug, highlight, bugAndHighlight)); Map> bySection = getBySection(collated); diff --git a/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml b/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml index 63bf275..22df2da 100644 --- a/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml +++ b/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml @@ -15,3 +15,8 @@ changelog: title: "Nice one!" exclude: names: ["philwebb"] + external_links: + - name: Release Notes 1 + location: url1 + - name: Release Notes 2 + location: url2 \ No newline at end of file From bb4899837400fe8363005521b75a2251f4a52e22 Mon Sep 17 00:00:00 2001 From: Mahendra Bishnoi Date: Sun, 20 Dec 2020 01:08:10 +0530 Subject: [PATCH 3/3] Update readme. Fixes gh-46 --- README.adoc | 11 +++++++++++ .../githubchangeloggenerator/test-application.yml | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.adoc b/README.adoc index 49f195e..206a501 100644 --- a/README.adoc +++ b/README.adoc @@ -73,6 +73,17 @@ changelog: title: "Contributors" ---- +You can add external links such as release notes for quick access using: + +[source,yaml] +---- +changelog: + external_links: + - name: "Release Notes" + location: "https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes" +---- + + ==== Showing Issues in Multiple Sections diff --git a/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml b/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml index 22df2da..b099ad7 100644 --- a/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml +++ b/src/test/resources/io/spring/githubchangeloggenerator/test-application.yml @@ -16,7 +16,7 @@ changelog: exclude: names: ["philwebb"] external_links: - - name: Release Notes 1 - location: url1 - - name: Release Notes 2 - location: url2 \ No newline at end of file + - name: "Release Notes 1" + location: "url1" + - name: "Release Notes 2" + location: "url2" \ No newline at end of file