From 7fd9d3c1b79b92d01677eae2c0ae22293473c774 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 13 Jun 2025 11:24:08 +0200 Subject: [PATCH] Refine changelog generation. Prefer issue references of pull-request references in case both are present to render the pull request as changelog item. --- .../data/release/git/GitOperations.java | 27 ++++++++++++++++--- .../data/release/git/ParsedCommitMessage.java | 23 +++++++++------- .../issues/github/ChangelogGenerator.java | 12 ++++++--- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/springframework/data/release/git/GitOperations.java b/src/main/java/org/springframework/data/release/git/GitOperations.java index b98a87e..6b4ee1d 100644 --- a/src/main/java/org/springframework/data/release/git/GitOperations.java +++ b/src/main/java/org/springframework/data/release/git/GitOperations.java @@ -557,14 +557,21 @@ public class GitOperations { }).collect(Collectors.toList()); }); + return getUniqueTicketReferences(ticketReferences); + } + + static List getUniqueTicketReferences(List ticketReferences) { + // make TicketReference unique - Set uniqueIds = new HashSet<>(); + MultiValueMap collated = new LinkedMultiValueMap<>(); List uniqueTicketReferences = new ArrayList<>(); for (TicketReference reference : ticketReferences) { - if (uniqueIds.add(reference.getId())) { - uniqueTicketReferences.add(reference); - } + collated.add(reference.getId(), reference); + } + + for (Map.Entry> entry : collated.entrySet()) { + uniqueTicketReferences.add(getTicketReference(entry)); } uniqueTicketReferences.sort(Comparator. naturalOrder().reversed()); @@ -572,6 +579,18 @@ public class GitOperations { return uniqueTicketReferences; } + private static TicketReference getTicketReference(Map.Entry> entry) { + + for (TicketReference ticketReference : entry.getValue()) { + + if (ticketReference.isIssue()) { + return ticketReference; + } + } + + return entry.getValue().get(0); + } + protected ObjectId resolveLowerBoundary(SupportStatus supportStatus, Project project, TrainIteration iteration, VersionTags tags, Git git, Repository repo) throws IOException, GitAPIException { diff --git a/src/main/java/org/springframework/data/release/git/ParsedCommitMessage.java b/src/main/java/org/springframework/data/release/git/ParsedCommitMessage.java index ae2db31..80ca248 100644 --- a/src/main/java/org/springframework/data/release/git/ParsedCommitMessage.java +++ b/src/main/java/org/springframework/data/release/git/ParsedCommitMessage.java @@ -106,9 +106,9 @@ class ParsedCommitMessage { } } - List relatedTickets = parseRelatedTickets(body, + List relatedTickets = parseRelatedTickets(summary, body, Arrays.asList(gitHubCloseMatcher, gitHubSeeMatcher)); - Optional optionalOriginalPr = parsePullRequestReference(body); + Optional optionalOriginalPr = parsePullRequestReference(summary, body); if (optionalOriginalPr.isPresent()) { @@ -161,6 +161,7 @@ class ParsedCommitMessage { MatchResult mr = gitHubPrefixMatcher.toMatchResult(); if (mr.start(1) == 0) { + int summaryStart = findSummaryIndex(summary, mr.end(1)); return Optional.of(new TicketReference(gitHubPrefixMatcher.group(1).toUpperCase(Locale.ROOT), @@ -193,21 +194,22 @@ class ParsedCommitMessage { return Optional.empty(); } - protected static Optional parsePullRequestReference(String body) { + protected static Optional parsePullRequestReference(String summary, String body) { if (body != null) { Matcher prMatcher = ORIGINAL_PULL_REQUEST.matcher(body); if (prMatcher.find()) { - return extractTicket(prMatcher.group(1), TicketReference.Reference.PullRequest); + return extractTicket(prMatcher.group(1), summary, TicketReference.Reference.PullRequest); } } return Optional.empty(); } - protected static List parseRelatedTickets(String body, Collection gitHubMatcher) { + protected static List parseRelatedTickets(String summary, String body, + Collection gitHubMatcher) { List relatedTickets = new ArrayList<>(); if (body != null) { @@ -218,14 +220,14 @@ class ParsedCommitMessage { String[] ticketIds = relatedTicketsMatcher.group(1).split(","); for (String ticketId : ticketIds) { - extractTicket(ticketId.trim(), TicketReference.Reference.Related).ifPresent(relatedTickets::add); + extractTicket(ticketId.trim(), summary, TicketReference.Reference.Related).ifPresent(relatedTickets::add); } } for (Matcher matcher : gitHubMatcher) { while (matcher.find()) { - extractTicket(matcher.group(1), TicketReference.Reference.Related).ifPresent(relatedTickets::add); + extractTicket(matcher.group(1), summary, TicketReference.Reference.Related).ifPresent(relatedTickets::add); } } @@ -234,14 +236,15 @@ class ParsedCommitMessage { return relatedTickets; } - protected static Optional extractTicket(String ticketId, TicketReference.Reference reference) { + protected static Optional extractTicket(String ticketId, String summary, + TicketReference.Reference reference) { if (GITHUB_TICKET.matcher(ticketId.trim()).matches()) { - return Optional.of(new TicketReference(ticketId, null, TicketReference.Style.GitHub, reference)); + return Optional.of(new TicketReference(ticketId, summary, TicketReference.Style.GitHub, reference)); } if (JIRA_TICKET.matcher(ticketId.trim()).matches()) { - return Optional.of(new TicketReference(ticketId, null, TicketReference.Style.Jira, reference)); + return Optional.of(new TicketReference(ticketId, summary, TicketReference.Style.Jira, reference)); } return Optional.empty(); diff --git a/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java b/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java index 6eab94c..beca1ba 100644 --- a/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java +++ b/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java @@ -77,10 +77,9 @@ public class ChangelogGenerator { private String generateContent(List issues, BiFunction sectionContentPostProcessor, boolean includeIssueNumbers) { StringBuilder content = new StringBuilder(); - addSectionContent(content, - this.sections.collate(issues.stream().filter(it -> it.getReference().isIssue() || it.getReference().isRelated()) - .map(ChangeItem::getIssue).collect(Collectors.toList())), - sectionContentPostProcessor, includeIssueNumbers); + addSectionContent(content, this.sections.collate(issues.stream() + .filter(it -> it.getReference().isIssue() || it.getReference().isPullRequest() || it.getReference().isRelated()) + .map(ChangeItem::getIssue).collect(Collectors.toList())), sectionContentPostProcessor, includeIssueNumbers); Set contributors = getContributors(issues); if (!contributors.isEmpty()) { addContributorsContent(content, contributors); @@ -107,6 +106,11 @@ public class ChangelogGenerator { private String getFormattedIssue(GitHubReadIssue issue, boolean includeIssueNumbers) { String title = issue.getTitle(); + + if (title.endsWith(".")) { + title = title.substring(0, title.length() - 1); // Remove trailing period + } + title = ghUserMentionPattern.matcher(title).replaceAll("$1`$2`"); return includeIssueNumbers ? String.format("- %s %s%n", title, getLinkToIssue(issue)) : String.format("- %s%n", title);