diff --git a/src/main/java/org/springframework/data/release/git/GitCommands.java b/src/main/java/org/springframework/data/release/git/GitCommands.java index 3615049..d93f9fb 100644 --- a/src/main/java/org/springframework/data/release/git/GitCommands.java +++ b/src/main/java/org/springframework/data/release/git/GitCommands.java @@ -119,8 +119,7 @@ class GitCommands extends TimedCommand { IssueTracker issueTracker = trackers.getRequiredPluginFor(module.getSupportedProject(), () -> String.format("No issue tracker found for project %s!", module.getSupportedProject())); - List ticketIds = ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList()); - + List ticketIds = ticketReferences.stream().filter(TicketReference::isIssue).collect(Collectors.toList()); List tickets = new ArrayList<>(issueTracker.findTickets(module, ticketIds).getTickets()); return new Tickets(tickets); 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 0d1b16d..8428d07 100644 --- a/src/main/java/org/springframework/data/release/git/GitOperations.java +++ b/src/main/java/org/springframework/data/release/git/GitOperations.java @@ -68,7 +68,6 @@ import org.springframework.data.release.issues.Ticket; import org.springframework.data.release.issues.TicketReference; import org.springframework.data.release.issues.TicketStatus; import org.springframework.data.release.model.*; -import org.springframework.data.release.model.Module; import org.springframework.data.release.utils.ExecutionUtils; import org.springframework.data.release.utils.Logger; import org.springframework.data.util.Pair; @@ -435,7 +434,10 @@ public class GitOperations { .filter(branch -> branch.isIssueBranch(project.getProject().getTracker()))// .collect(Collectors.toMap(Branch::toString, branch -> branch)); - Collection tickets = tracker.findTickets(project, ticketIds.keySet()); + Collection tickets = tracker.findTickets(project, + ticketIds.keySet().stream() + .map(it -> TicketReference.ofTicket(it, TicketReference.Style.GitHub)) + .collect(Collectors.toList())); return TicketBranches .from(tickets.stream().collect(Collectors.toMap(ticket -> ticketIds.get(ticket.getId()), ticket -> ticket))); @@ -495,7 +497,7 @@ public class GitOperations { return Stream.empty(); } - return Stream.of(message.getTicketReference()); + return message.getTicketReferences().stream(); }).collect(Collectors.toList()); }); 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 d5d6124..b5a494e 100644 --- a/src/main/java/org/springframework/data/release/git/ParsedCommitMessage.java +++ b/src/main/java/org/springframework/data/release/git/ParsedCommitMessage.java @@ -19,6 +19,8 @@ import lombok.Getter; import lombok.ToString; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Optional; @@ -45,7 +47,10 @@ class ParsedCommitMessage { private static final Pattern GITHUB_TICKET = Pattern.compile("((?>#|gh-)\\d+)"); private static final Pattern GITHUB_CLOSE_SYNTAX = Pattern.compile( - "(?>closes|closed|close|fixes|fixed|fix|resolves|resolved|resolve|see|related to)[\\s:]*((?>#|gh-)\\d+)", + "(?>closes|closed|close|fixes|fixed|fix|resolves|resolved|resolve)[\\s:]*((?>#|gh-)\\d+)", + Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + + private static final Pattern GITHUB_SEE_SYNTAX = Pattern.compile("(?>see|related to)[\\s:]*((?>#|gh-)\\d+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); private static final Pattern GITHUB_PREFIX_SYNTAX = Pattern.compile("^(#\\d+)"); @@ -82,7 +87,8 @@ class ParsedCommitMessage { } // Closes (gh-nnn|#nnn) syntax - Matcher gitHubMatcher = GITHUB_CLOSE_SYNTAX.matcher(summary + "\n" + body); + Matcher gitHubCloseMatcher = GITHUB_CLOSE_SYNTAX.matcher(summary + "\n" + body); + Matcher gitHubSeeMatcher = GITHUB_SEE_SYNTAX.matcher(summary + "\n" + body); // #nnn syntax Optional gitHubTicket = tryParseGitHubTicketReference(summary); @@ -90,12 +96,17 @@ class ParsedCommitMessage { if (gitHubTicket.isPresent()) { ticketReference = gitHubTicket.get(); } else { - if (gitHubMatcher.find()) { - ticketReference = new TicketReference(gitHubMatcher.group(1), summary, TicketReference.Style.GitHub); + if (gitHubCloseMatcher.find()) { + ticketReference = new TicketReference(gitHubCloseMatcher.group(1), summary, TicketReference.Style.GitHub, + TicketReference.Reference.Ticket); + } else if (gitHubSeeMatcher.find()) { + ticketReference = new TicketReference(gitHubSeeMatcher.group(1), summary, TicketReference.Style.GitHub, + TicketReference.Reference.Ticket); } } - List relatedTickets = parseRelatedTickets(body, gitHubMatcher); + List relatedTickets = parseRelatedTickets(body, + Arrays.asList(gitHubCloseMatcher, gitHubSeeMatcher)); Optional optionalOriginalPr = parsePullRequestReference(body); if (optionalOriginalPr.isPresent()) { @@ -148,7 +159,8 @@ class ParsedCommitMessage { int summaryStart = findSummaryIndex(summary, mr.end(1)); return Optional.of(new TicketReference(gitHubPrefixMatcher.group(1).toUpperCase(Locale.ROOT), - summaryStart > -1 ? summary.substring(summaryStart) : summary, TicketReference.Style.GitHub)); + summaryStart > -1 ? summary.substring(summaryStart) : summary, TicketReference.Style.GitHub, + TicketReference.Reference.Ticket)); } } @@ -168,7 +180,8 @@ class ParsedCommitMessage { int summaryStart = findSummaryIndex(summary, mr.end(1)); return Optional.of(new TicketReference(jiraMatcher.group(1).toUpperCase(Locale.ROOT), - summaryStart > -1 ? summary.substring(summaryStart) : summary, TicketReference.Style.Jira)); + summaryStart > -1 ? summary.substring(summaryStart) : summary, TicketReference.Style.Jira, + TicketReference.Reference.Ticket)); } } @@ -182,14 +195,14 @@ class ParsedCommitMessage { Matcher prMatcher = ORIGINAL_PULL_REQUEST.matcher(body); if (prMatcher.find()) { - return extractTicket(prMatcher.group(1)); + return extractTicket(prMatcher.group(1), TicketReference.Reference.PullRequest); } } return Optional.empty(); } - protected static List parseRelatedTickets(String body, Matcher gitHubMatcher) { + protected static List parseRelatedTickets(String body, Collection gitHubMatcher) { List relatedTickets = new ArrayList<>(); if (body != null) { @@ -200,26 +213,30 @@ class ParsedCommitMessage { String ticketIds[] = relatedTicketsMatcher.group(1).split(","); for (String ticketId : ticketIds) { - extractTicket(ticketId).ifPresent(relatedTickets::add); + extractTicket(ticketId, TicketReference.Reference.Related).ifPresent(relatedTickets::add); } } - while (gitHubMatcher.find()) { - extractTicket(gitHubMatcher.group(1)).ifPresent(relatedTickets::add); + for (Matcher matcher : gitHubMatcher) { + + while (matcher.find()) { + extractTicket(matcher.group(1), TicketReference.Reference.Related).ifPresent(relatedTickets::add); + } } + } return relatedTickets; } - protected static Optional extractTicket(String ticketId) { + protected static Optional extractTicket(String ticketId, TicketReference.Reference reference) { if (JIRA_TICKET.matcher(ticketId.trim()).matches()) { - return Optional.of(new TicketReference(ticketId.trim(), null, TicketReference.Style.Jira)); + return Optional.of(new TicketReference(ticketId.trim(), null, TicketReference.Style.Jira, reference)); } if (GITHUB_TICKET.matcher(ticketId.trim()).matches()) { - return Optional.of(new TicketReference(ticketId.trim(), null, TicketReference.Style.GitHub)); + return Optional.of(new TicketReference(ticketId.trim(), null, TicketReference.Style.GitHub, reference)); } return Optional.empty(); @@ -242,4 +259,19 @@ class ParsedCommitMessage { return -1; } + public List getTicketReferences() { + + List references = new ArrayList<>(); + if (getTicketReference() != null) { + references.add(getTicketReference()); + } + + references.addAll(getRelatedTickets()); + + if (getPullRequestReference() != null) { + references.add(getPullRequestReference()); + } + + return references; + } } diff --git a/src/main/java/org/springframework/data/release/issues/IssueTracker.java b/src/main/java/org/springframework/data/release/issues/IssueTracker.java index 99b7899..23ae965 100644 --- a/src/main/java/org/springframework/data/release/issues/IssueTracker.java +++ b/src/main/java/org/springframework/data/release/issues/IssueTracker.java @@ -17,10 +17,11 @@ package org.springframework.data.release.issues; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; +import org.springframework.data.release.model.Iteration; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.SupportedProject; +import org.springframework.data.release.model.Train; import org.springframework.data.release.model.TrainIteration; import org.springframework.plugin.core.Plugin; @@ -78,7 +79,7 @@ public interface IssueTracker extends Plugin { * @param ticketIds collection of {@link Ticket#id ticket Ids}, must not be {@literal null}. * @return */ - Collection findTickets(SupportedProject project, Collection ticketIds); + Collection findTickets(SupportedProject project, Collection ticketIds); /** * Query the issue tracker for multiple {@link Ticket#id ticket Ids}. Tickets that are not found are not returned. The @@ -89,7 +90,7 @@ public interface IssueTracker extends Plugin { * @param ticketReferences must not be {@literal null}. * @return */ - Tickets findTickets(ModuleIteration moduleIteration, Collection ticketIds); + Tickets findTickets(ModuleIteration moduleIteration, Collection ticketIds); /** * Creates a release version if release version is missing. @@ -165,8 +166,7 @@ public interface IssueTracker extends Plugin { */ default Changelog getChangelogFor(ModuleIteration module, List ticketReferences) { - Tickets tickets = findTickets(module, - ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList())); + Tickets tickets = findTickets(module, ticketReferences); return Changelog.of(module, tickets); } diff --git a/src/main/java/org/springframework/data/release/issues/TicketReference.java b/src/main/java/org/springframework/data/release/issues/TicketReference.java index 939756b..ac2392c 100644 --- a/src/main/java/org/springframework/data/release/issues/TicketReference.java +++ b/src/main/java/org/springframework/data/release/issues/TicketReference.java @@ -26,11 +26,17 @@ public class TicketReference implements Comparable { String id; String message; Style style; + Reference reference; - public TicketReference(String id, String message, Style style) { + public TicketReference(String id, String message, Style style, Reference reference) { this.id = normalize(id); this.message = message; this.style = style; + this.reference = reference; + } + + public static TicketReference ofTicket(String number, Style style) { + return new TicketReference(number, "", style, Reference.Ticket); } private static String normalize(String id) { @@ -52,7 +58,19 @@ public class TicketReference implements Comparable { return id.compareToIgnoreCase(o.id); } + public boolean isIssue() { + return getReference() == Reference.Ticket; + } + + public boolean isPullRequest() { + return getReference() == Reference.PullRequest; + } + public enum Style { - GitHub, Jira; + GitHub, Jira + } + + public enum Reference { + Ticket, Related, PullRequest } } diff --git a/src/main/java/org/springframework/data/release/issues/github/ChangeItem.java b/src/main/java/org/springframework/data/release/issues/github/ChangeItem.java new file mode 100644 index 0000000..8220761 --- /dev/null +++ b/src/main/java/org/springframework/data/release/issues/github/ChangeItem.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.issues.github; + +import lombok.Value; + +import org.springframework.data.release.issues.Ticket; +import org.springframework.data.release.issues.TicketReference; + +/** + * @author Mark Paluch + */ +@Value +public class ChangeItem { + TicketReference reference; + GitHubReadIssue issue; +} 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 f502d97..8c706c7 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 @@ -38,7 +38,6 @@ import org.springframework.stereotype.Component; * @author Madhura Bhave * @author Phillip Webb */ -@Component public class ChangelogGenerator { private static final Pattern ghUserMentionPattern = Pattern.compile("(^|[^\\w`])(@[\\w-]+)"); @@ -52,7 +51,7 @@ public class ChangelogGenerator { private final ChangelogSections sections; public ChangelogGenerator() { - this.excludeLabels = new HashSet<>(Arrays.asList("type: task")); + this.excludeLabels = new HashSet<>(Collections.singletonList("type: task")); this.excludeContributors = new LinkedHashSet<>(); this.contributorsTitle = null; this.sections = new ChangelogSections(); @@ -65,7 +64,7 @@ public class ChangelogGenerator { * @param sectionContentPostProcessor the postprocessor for a changelog section * @param includeIssueNumbers whether to include issue numbers */ - public String generate(List issues, + public String generate(List issues, BiFunction sectionContentPostProcessor, boolean includeIssueNumbers) { return generateContent(issues, sectionContentPostProcessor, includeIssueNumbers); } @@ -78,10 +77,12 @@ public class ChangelogGenerator { return this.excludeLabels.contains(label.getName()); } - private String generateContent(List issues, + private String generateContent(List issues, BiFunction sectionContentPostProcessor, boolean includeIssueNumbers) { StringBuilder content = new StringBuilder(); - addSectionContent(content, this.sections.collate(issues), sectionContentPostProcessor, includeIssueNumbers); + addSectionContent(content, + this.sections.collate(issues.stream().filter(it -> it.getReference().isIssue()).map(ChangeItem::getIssue).collect(Collectors.toList())), + sectionContentPostProcessor, includeIssueNumbers); Set contributors = getContributors(issues); if (!contributors.isEmpty()) { addContributorsContent(content, contributors); @@ -98,10 +99,10 @@ public class ChangelogGenerator { StringBuilder content = new StringBuilder(); - content.append((content.length() != 0) ? String.format("%n") : ""); - content.append("## ").append(section).append(String.format("%n%n")); + content.append("## ").append(section).append(String.format("%n")); issues.stream().map(issue -> getFormattedIssue(issue, includeIssueNumbers)).forEach(content::append); + result.append((result.length() != 0) ? String.format("%n") : ""); result.append(sectionContentPostProcessor.apply(section, content.toString())); }); } @@ -117,12 +118,16 @@ public class ChangelogGenerator { return "[" + issue.getId() + "]" + "(" + issue.getUrl() + ")"; } - private Set getContributors(List issues) { + private Set getContributors(List issues) { if (this.excludeContributors.contains("*")) { return Collections.emptySet(); } - return issues.stream().filter((issue) -> issue.getPullRequest() != null).map(GitHubReadIssue::getUser) - .filter(this::isIncludedContributor).collect(Collectors.toSet()); + return issues.stream() + .filter(item -> item.getReference().isPullRequest() || item.getIssue().getPullRequest() != null) // + .map(ChangeItem::getIssue) // + .map(GitHubReadIssue::getUser) // + .filter(this::isIncludedContributor) // + .collect(Collectors.toSet()); } private boolean isIncludedContributor(GitHubUser user) { @@ -132,7 +137,7 @@ public class ChangelogGenerator { private void addContributorsContent(StringBuilder content, Set contributors) { content.append(String.format("%n## ")); content.append((this.contributorsTitle != null) ? this.contributorsTitle : ":heart: Contributors"); - content.append(String.format("%n%nWe'd like to thank all the contributors who worked on this release!%n%n")); + content.append(String.format("%nWe'd like to thank all the contributors who worked on this release!%n%n")); contributors.stream().map(this::formatContributors).forEach(content::append); } diff --git a/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java b/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java index 4ff7e10..25e3412 100644 --- a/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java +++ b/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java @@ -28,7 +28,7 @@ import org.springframework.util.CollectionUtils; * * @author Phillip Webb */ -class ChangelogSection { +public class ChangelogSection { private final String title; diff --git a/src/main/java/org/springframework/data/release/issues/github/GitHub.java b/src/main/java/org/springframework/data/release/issues/github/GitHub.java index ee82105..6c5ea18 100644 --- a/src/main/java/org/springframework/data/release/issues/github/GitHub.java +++ b/src/main/java/org/springframework/data/release/issues/github/GitHub.java @@ -34,6 +34,7 @@ import org.springframework.data.release.git.VersionTags; import org.springframework.data.release.issues.Changelog; import org.springframework.data.release.issues.IssueTracker; import org.springframework.data.release.issues.Ticket; +import org.springframework.data.release.issues.TicketReference; import org.springframework.data.release.issues.Tickets; import org.springframework.data.release.issues.github.GitHubWorkflows.GitHubWorkflow; import org.springframework.data.release.model.ArtifactVersion; @@ -130,14 +131,14 @@ public class GitHub extends GitHubSupport implements IssueTracker { */ @Override @Cacheable("tickets") - public Collection findTickets(SupportedProject project, Collection ticketIds) { + public Collection findTickets(SupportedProject project, Collection ticketIds) { String repositoryName = GitProject.of(project).getRepositoryName(); List tickets = new ArrayList<>(); ticketIds.forEach(ticketId -> { - GitHubReadIssue ticket = findTicket(repositoryName, ticketId); + GitHubReadIssue ticket = findTicket(repositoryName, ticketId.getId()); if (ticket != null) { tickets.add(toTicket(ticket)); } @@ -147,9 +148,9 @@ public class GitHub extends GitHubSupport implements IssueTracker { } @Override - public Tickets findTickets(ModuleIteration moduleIteration, Collection ticketIds) { + public Tickets findTickets(ModuleIteration moduleIteration, Collection ticketIds) { - return findGitHubIssues(moduleIteration, ticketIds).stream().map(GitHub::toTicket) + return findGitHubIssues(moduleIteration, ticketIds).stream().map(ChangeItem::getIssue).map(GitHub::toTicket) .collect(Tickets.toTicketsCollector()); } @@ -491,7 +492,7 @@ public class GitHub extends GitHubSupport implements IssueTracker { close(module, ticket); } - List findGitHubIssues(ModuleIteration moduleIteration, Collection ticketIds) { + List findGitHubIssues(ModuleIteration moduleIteration, Collection ticketIds) { logger.log(moduleIteration, "Looking up GitHub issues from milestone …"); @@ -501,19 +502,19 @@ public class GitHub extends GitHubSupport implements IssueTracker { String repositoryName = GitProject.of(moduleIteration).getRepositoryName(); logger.log(moduleIteration, "Looking up GitHub issues …"); - Collection foundIssues = ticketIds.stream().filter(it -> it.startsWith("#")).flatMap(it -> { + Collection foundIssues = ticketIds.stream().filter(it -> it.getId().startsWith("#")).flatMap(it -> { - GitHubReadIssue ticket = getTicket(issues, repositoryName, it); + GitHubReadIssue ticket = getTicket(issues, repositoryName, it.getId()); if (ticket != null) { - return Stream.of(ticket); + return Stream.of(new ChangeItem(it, ticket)); } return Stream.empty(); }).collect(Collectors.toList()); - List gitHubIssues = foundIssues.stream().filter(it -> { - Ticket ticket = toTicket(it); + List gitHubIssues = foundIssues.stream().filter(it -> { + Ticket ticket = toTicket(it.getIssue()); return !ticket.isReleaseTicketFor(moduleIteration) && !ticket.isReleaseTicket(); }).collect(Collectors.toList()); @@ -563,16 +564,20 @@ public class GitHub extends GitHubSupport implements IssueTracker { } } - /** - * @param iteration - * @param module - * @param ticketIds - */ - public void createOrUpdateRelease(TrainIteration iteration, ModuleIteration module, List ticketIds) { + public void createOrUpdateRelease(ModuleIteration module, List ticketIds) { logger.log(module, "Preparing GitHub Release …"); - List gitHubIssues = findGitHubIssues(module, ticketIds); + String releaseMarkdown = createReleaseMarkdown(module, ticketIds); + + createOrUpdateRelease(module, releaseMarkdown); + + logger.log(module, "GitHub Release up to date"); + } + + public String createReleaseMarkdown(ModuleIteration module, List ticketIds) { + + List gitHubIssues = findGitHubIssues(module, ticketIds); ArtifactVersion version = ArtifactVersion.of(module); DocumentationMetadata documentation = DocumentationMetadata.of(module, version, false); @@ -580,26 +585,26 @@ public class GitHub extends GitHubSupport implements IssueTracker { ChangelogGenerator generator = new ChangelogGenerator(); generator.getExcludeContributors().addAll(properties.getTeam()); - boolean generateLinks = !iteration.isCommercial(); + boolean generateLinks = !module.isCommercial(); String releaseBody = generator.generate(gitHubIssues, (changelogSection, s) -> s, generateLinks); String documentationLinks = getDocumentationLinks(module, documentation); + String releaseMarkdown; if (module.getProject() == Projects.BOM || module.getProject() == Projects.BUILD) { // We don't ship Javadoc/reference doc for build and BOM if (module.getProject() == Projects.BOM) { - String participatingModules = createParticipatingModules(iteration); + String participatingModules = createParticipatingModules(module.getTrainIteration()); - createOrUpdateRelease(module, - String.format("## :shipit: Participating Modules%n%n%s%n%s%n", participatingModules, releaseBody)); + releaseMarkdown = String.format("## :shipit: Participating Modules%n%n%s%n%s%n", participatingModules, + releaseBody); } else { - createOrUpdateRelease(module, String.format("%s%n", documentationLinks, releaseBody)); + releaseMarkdown = String.format("%s%n", documentationLinks); } } else { - createOrUpdateRelease(module, String.format("## :green_book: Links%n%s%n%s%n", documentationLinks, releaseBody)); + releaseMarkdown = String.format("## :green_book: Links%n%s%n%s%n", documentationLinks, releaseBody); } - - logger.log(module, "GitHub Release up to date"); + return releaseMarkdown; } private String createParticipatingModules(TrainIteration iteration) { @@ -696,8 +701,7 @@ public class GitHub extends GitHubSupport implements IssueTracker { String referenceDocUrl = documentation.getReferenceDocUrl(); String apiDocUrl = documentation.getApiDocUrl(); - String reference = String.format("* [%s %s Reference documentation](%s)", - module.getProject().getFullName(), + String reference = String.format("* [%s %s Reference documentation](%s)", module.getProject().getFullName(), module.getVersion().toString(), referenceDocUrl); String apidoc = String.format("* [%s %s Javadoc](%s)", module.getProject().getFullName(), diff --git a/src/main/java/org/springframework/data/release/issues/github/GitHubCommands.java b/src/main/java/org/springframework/data/release/issues/github/GitHubCommands.java index ea0d1ac..d72503c 100644 --- a/src/main/java/org/springframework/data/release/issues/github/GitHubCommands.java +++ b/src/main/java/org/springframework/data/release/issues/github/GitHubCommands.java @@ -22,7 +22,6 @@ import lombok.experimental.FieldDefaults; import java.util.List; import java.util.concurrent.Executor; -import java.util.stream.Collectors; import org.springframework.data.release.CliComponent; import org.springframework.data.release.TimedCommand; @@ -30,6 +29,7 @@ import org.springframework.data.release.git.GitOperations; import org.springframework.data.release.issues.IssueTracker; import org.springframework.data.release.issues.TicketReference; import org.springframework.data.release.model.Iteration; +import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Project; import org.springframework.data.release.model.SupportStatus; import org.springframework.data.release.model.SupportedProject; @@ -59,8 +59,8 @@ public class GitHubCommands extends TimedCommand { @CliCommand(value = "github update labels") public void createOrUpdateLabels(@CliOption(key = "", mandatory = true) Project project, @CliOption(key = "commercial", mandatory = false) Boolean commercial) { - gitHubLabels.createOrUpdateLabels(SupportedProject.of(project, - commercial == null || !commercial ? SupportStatus.OSS : SupportStatus.COMMERCIAL)); + gitHubLabels.createOrUpdateLabels( + SupportedProject.of(project, commercial == null || !commercial ? SupportStatus.OSS : SupportStatus.COMMERCIAL)); } @CliCommand(value = "github push") @@ -74,27 +74,50 @@ public class GitHubCommands extends TimedCommand { git.push(new TrainIteration(iteration.getTrain(), Iteration.SR1)); } - createOrUpdateRelease(iteration); + createOrUpdateRelease(iteration, null); }, 2); } @CliCommand(value = "github create release") - public void createOrUpdateRelease(@CliOption(key = "", mandatory = true) TrainIteration iteration) { + public void createOrUpdateRelease(@CliOption(key = "", mandatory = true) TrainIteration iteration, + @CliOption(key = "project") Project project) { TrainIteration previousIteration = git.getPreviousIteration(iteration); + if (project != null) { + + ModuleIteration module = iteration.getModule(project); + createOrUpdateRelease(module, previousIteration); + return; + } + ExecutionUtils.run(executor, iteration, it -> { if (it.getSupportedProject().getProject().getTracker() == Tracker.GITHUB) { - - List ticketReferences = git - .getTicketReferencesBetween(it.getSupportedProject(), previousIteration, iteration).stream() - .map(TicketReference::getId).collect(Collectors.toList()); - gitHub.createOrUpdateRelease(iteration, it, ticketReferences); + createOrUpdateRelease(it, previousIteration); } }); } + @CliCommand(value = "github preview release") + public String previewRelease(@CliOption(key = "", mandatory = true) TrainIteration iteration, + @CliOption(key = "project", mandatory = true) Project project) { + + TrainIteration previousIteration = git.getPreviousIteration(iteration); + ModuleIteration module = iteration.getModule(project); + + List ticketReferences = git.getTicketReferencesBetween(module.getSupportedProject(), + previousIteration, module.getTrainIteration()); + + return gitHub.createReleaseMarkdown(module, ticketReferences); + } + + private void createOrUpdateRelease(ModuleIteration module, TrainIteration previousIteration) { + List ticketReferences = git.getTicketReferencesBetween(module.getSupportedProject(), + previousIteration, module.getTrainIteration()); + gitHub.createOrUpdateRelease(module, ticketReferences); + } + public void triggerAntoraWorkflow(Project project) { gitHub.triggerAntoraWorkflow(project); } diff --git a/src/test/java/org/springframework/data/release/issues/github/GitHubIssueTrackerIntegrationTests.java b/src/test/java/org/springframework/data/release/issues/github/GitHubIssueTrackerIntegrationTests.java index 4165b9c..e22c5a1 100644 --- a/src/test/java/org/springframework/data/release/issues/github/GitHubIssueTrackerIntegrationTests.java +++ b/src/test/java/org/springframework/data/release/issues/github/GitHubIssueTrackerIntegrationTests.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.AbstractIntegrationTests; import org.springframework.data.release.WireMockExtension; import org.springframework.data.release.issues.Ticket; +import org.springframework.data.release.issues.TicketReference; import org.springframework.data.release.model.Iteration; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Projects; @@ -80,7 +81,7 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests { mockGetIssueWith("issue.json", 233); Collection tickets = github.findTickets(LATEST.getSupportedProject(Projects.BUILD), - Collections.singletonList("233")); + Collections.singletonList(TicketReference.ofTicket("233", TicketReference.Style.GitHub))); assertThat(tickets).hasSize(1); } @@ -89,7 +90,7 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests { void ignoresUnknownTicketsByTicketId() { Collection tickets = github.findTickets(LATEST.getSupportedProject(Projects.BUILD), - Collections.singletonList("123")); + Collections.singletonList(TicketReference.ofTicket("233", TicketReference.Style.GitHub))); assertThat(tickets).isEmpty(); } diff --git a/src/test/java/org/springframework/data/release/misc/ReleaseOperationsIntegrationTests.java b/src/test/java/org/springframework/data/release/misc/ReleaseOperationsIntegrationTests.java index 5a332e6..6542f9a 100644 --- a/src/test/java/org/springframework/data/release/misc/ReleaseOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/release/misc/ReleaseOperationsIntegrationTests.java @@ -18,10 +18,10 @@ package org.springframework.data.release.misc; import static org.assertj.core.api.Assertions.*; import java.util.List; -import java.util.stream.Collectors; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.AbstractIntegrationTests; import org.springframework.data.release.git.GitOperations; @@ -58,8 +58,7 @@ class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests { List ticketReferences = gitOperations.getTicketReferencesBetween(project, from, to); IssueTracker tracker = trackers.getRequiredPluginFor(project); - Tickets tickets = tracker.findTickets(to.getModule(Projects.MONGO_DB), - ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList())); + Tickets tickets = tracker.findTickets(to.getModule(Projects.MONGO_DB), ticketReferences); assertThat(tickets).hasSize(15); } @@ -75,8 +74,7 @@ class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests { List ticketReferences = gitOperations.getTicketReferencesBetween(project, from, to); IssueTracker tracker = trackers.getRequiredPluginFor(project); - Tickets tickets = tracker.findTickets(to.getModule(Projects.R2DBC), - ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList())); + Tickets tickets = tracker.findTickets(to.getModule(Projects.R2DBC), ticketReferences); assertThat(tickets).hasSize(22); }