Refine changelog generation.

Prefer issue references of pull-request references in case both are present to render the pull request as changelog item.
This commit is contained in:
Mark Paluch
2025-06-13 11:24:08 +02:00
parent 19cfc750b2
commit 7fd9d3c1b7
3 changed files with 44 additions and 18 deletions

View File

@@ -557,14 +557,21 @@ public class GitOperations {
}).collect(Collectors.toList()); }).collect(Collectors.toList());
}); });
return getUniqueTicketReferences(ticketReferences);
}
static List<TicketReference> getUniqueTicketReferences(List<TicketReference> ticketReferences) {
// make TicketReference unique // make TicketReference unique
Set<String> uniqueIds = new HashSet<>(); MultiValueMap<String, TicketReference> collated = new LinkedMultiValueMap<>();
List<TicketReference> uniqueTicketReferences = new ArrayList<>(); List<TicketReference> uniqueTicketReferences = new ArrayList<>();
for (TicketReference reference : ticketReferences) { for (TicketReference reference : ticketReferences) {
if (uniqueIds.add(reference.getId())) { collated.add(reference.getId(), reference);
uniqueTicketReferences.add(reference); }
}
for (Map.Entry<String, List<TicketReference>> entry : collated.entrySet()) {
uniqueTicketReferences.add(getTicketReference(entry));
} }
uniqueTicketReferences.sort(Comparator.<TicketReference> naturalOrder().reversed()); uniqueTicketReferences.sort(Comparator.<TicketReference> naturalOrder().reversed());
@@ -572,6 +579,18 @@ public class GitOperations {
return uniqueTicketReferences; return uniqueTicketReferences;
} }
private static TicketReference getTicketReference(Map.Entry<String, List<TicketReference>> 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, protected ObjectId resolveLowerBoundary(SupportStatus supportStatus, Project project, TrainIteration iteration,
VersionTags tags, Git git, Repository repo) throws IOException, GitAPIException { VersionTags tags, Git git, Repository repo) throws IOException, GitAPIException {

View File

@@ -106,9 +106,9 @@ class ParsedCommitMessage {
} }
} }
List<TicketReference> relatedTickets = parseRelatedTickets(body, List<TicketReference> relatedTickets = parseRelatedTickets(summary, body,
Arrays.asList(gitHubCloseMatcher, gitHubSeeMatcher)); Arrays.asList(gitHubCloseMatcher, gitHubSeeMatcher));
Optional<TicketReference> optionalOriginalPr = parsePullRequestReference(body); Optional<TicketReference> optionalOriginalPr = parsePullRequestReference(summary, body);
if (optionalOriginalPr.isPresent()) { if (optionalOriginalPr.isPresent()) {
@@ -161,6 +161,7 @@ class ParsedCommitMessage {
MatchResult mr = gitHubPrefixMatcher.toMatchResult(); MatchResult mr = gitHubPrefixMatcher.toMatchResult();
if (mr.start(1) == 0) { if (mr.start(1) == 0) {
int summaryStart = findSummaryIndex(summary, mr.end(1)); int summaryStart = findSummaryIndex(summary, mr.end(1));
return Optional.of(new TicketReference(gitHubPrefixMatcher.group(1).toUpperCase(Locale.ROOT), return Optional.of(new TicketReference(gitHubPrefixMatcher.group(1).toUpperCase(Locale.ROOT),
@@ -193,21 +194,22 @@ class ParsedCommitMessage {
return Optional.empty(); return Optional.empty();
} }
protected static Optional<TicketReference> parsePullRequestReference(String body) { protected static Optional<TicketReference> parsePullRequestReference(String summary, String body) {
if (body != null) { if (body != null) {
Matcher prMatcher = ORIGINAL_PULL_REQUEST.matcher(body); Matcher prMatcher = ORIGINAL_PULL_REQUEST.matcher(body);
if (prMatcher.find()) { if (prMatcher.find()) {
return extractTicket(prMatcher.group(1), TicketReference.Reference.PullRequest); return extractTicket(prMatcher.group(1), summary, TicketReference.Reference.PullRequest);
} }
} }
return Optional.empty(); return Optional.empty();
} }
protected static List<TicketReference> parseRelatedTickets(String body, Collection<Matcher> gitHubMatcher) { protected static List<TicketReference> parseRelatedTickets(String summary, String body,
Collection<Matcher> gitHubMatcher) {
List<TicketReference> relatedTickets = new ArrayList<>(); List<TicketReference> relatedTickets = new ArrayList<>();
if (body != null) { if (body != null) {
@@ -218,14 +220,14 @@ class ParsedCommitMessage {
String[] ticketIds = relatedTicketsMatcher.group(1).split(","); String[] ticketIds = relatedTicketsMatcher.group(1).split(",");
for (String ticketId : ticketIds) { 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) { for (Matcher matcher : gitHubMatcher) {
while (matcher.find()) { 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; return relatedTickets;
} }
protected static Optional<TicketReference> extractTicket(String ticketId, TicketReference.Reference reference) { protected static Optional<TicketReference> extractTicket(String ticketId, String summary,
TicketReference.Reference reference) {
if (GITHUB_TICKET.matcher(ticketId.trim()).matches()) { 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()) { 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(); return Optional.empty();

View File

@@ -77,10 +77,9 @@ public class ChangelogGenerator {
private String generateContent(List<ChangeItem> issues, private String generateContent(List<ChangeItem> issues,
BiFunction<ChangelogSection, String, String> sectionContentPostProcessor, boolean includeIssueNumbers) { BiFunction<ChangelogSection, String, String> sectionContentPostProcessor, boolean includeIssueNumbers) {
StringBuilder content = new StringBuilder(); StringBuilder content = new StringBuilder();
addSectionContent(content, addSectionContent(content, this.sections.collate(issues.stream()
this.sections.collate(issues.stream().filter(it -> it.getReference().isIssue() || it.getReference().isRelated()) .filter(it -> it.getReference().isIssue() || it.getReference().isPullRequest() || it.getReference().isRelated())
.map(ChangeItem::getIssue).collect(Collectors.toList())), .map(ChangeItem::getIssue).collect(Collectors.toList())), sectionContentPostProcessor, includeIssueNumbers);
sectionContentPostProcessor, includeIssueNumbers);
Set<GitHubUser> contributors = getContributors(issues); Set<GitHubUser> contributors = getContributors(issues);
if (!contributors.isEmpty()) { if (!contributors.isEmpty()) {
addContributorsContent(content, contributors); addContributorsContent(content, contributors);
@@ -107,6 +106,11 @@ public class ChangelogGenerator {
private String getFormattedIssue(GitHubReadIssue issue, boolean includeIssueNumbers) { private String getFormattedIssue(GitHubReadIssue issue, boolean includeIssueNumbers) {
String title = issue.getTitle(); String title = issue.getTitle();
if (title.endsWith(".")) {
title = title.substring(0, title.length() - 1); // Remove trailing period
}
title = ghUserMentionPattern.matcher(title).replaceAll("$1`$2`"); title = ghUserMentionPattern.matcher(title).replaceAll("$1`$2`");
return includeIssueNumbers ? String.format("- %s %s%n", title, getLinkToIssue(issue)) return includeIssueNumbers ? String.format("- %s %s%n", title, getLinkToIssue(issue))
: String.format("- %s%n", title); : String.format("- %s%n", title);