Update git changelog command to use issue tracker.

See #166
This commit is contained in:
Mark Paluch
2021-01-12 14:49:58 +01:00
parent ebadf0a5ea
commit 7cf21144cd
7 changed files with 69 additions and 27 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.data.release.git;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -28,14 +29,18 @@ import java.util.stream.Stream;
import org.springframework.data.release.CliComponent; import org.springframework.data.release.CliComponent;
import org.springframework.data.release.TimedCommand; import org.springframework.data.release.TimedCommand;
import org.springframework.data.release.issues.Changelog; 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.Ticket;
import org.springframework.data.release.issues.TicketReference; import org.springframework.data.release.issues.TicketReference;
import org.springframework.data.release.issues.Tickets; import org.springframework.data.release.issues.Tickets;
import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.ModuleIteration;
import org.springframework.data.release.model.Project; import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ReleaseTrains; import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train; import org.springframework.data.release.model.Train;
import org.springframework.data.release.model.TrainIteration; import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils; import org.springframework.data.release.utils.ExecutionUtils;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption; import org.springframework.shell.core.annotation.CliOption;
import org.springframework.shell.support.table.Table; import org.springframework.shell.support.table.Table;
@@ -50,6 +55,7 @@ import org.springframework.util.StringUtils;
@RequiredArgsConstructor @RequiredArgsConstructor
class GitCommands extends TimedCommand { class GitCommands extends TimedCommand {
private final PluginRegistry<IssueTracker, Project> trackers;
private final @NonNull GitOperations git; private final @NonNull GitOperations git;
private final @NonNull Executor executor; private final @NonNull Executor executor;
@@ -87,23 +93,33 @@ class GitCommands extends TimedCommand {
TrainIteration previousIteration = git.getPreviousIteration(iteration); TrainIteration previousIteration = git.getPreviousIteration(iteration);
return ExecutionUtils.runAndReturn(executor, iteration, moduleIteration -> { return ExecutionUtils.runAndReturn(executor, iteration, module -> {
List<TicketReference> ticketRefs = git.getTicketReferencesBetween(moduleIteration.getProject(), previousIteration, List<TicketReference> ticketRefs = git.getTicketReferencesBetween(module.getProject(), previousIteration,
iteration); iteration);
return Changelog.of(moduleIteration, toTickets(ticketRefs)); return Changelog.of(module, toTickets(module, ticketRefs));
}).stream() // }).stream() //
.map(Changelog::toString) // .map(changelog -> {
ModuleIteration module = changelog.getModule();
return String.format("%s %s%n%s", module.getModule().getProject().getFullName(), ArtifactVersion.of(module),
changelog.toString(false, " "));
}) //
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
} }
private Tickets toTickets(List<TicketReference> ticketRefs) { private Tickets toTickets(ModuleIteration module, List<TicketReference> ticketReferences) {
return new Tickets( // TODO: Use only associated tracker
ticketRefs.stream().map(it -> new Ticket(it.getId(), it.getMessage(), "", null, null)) List<Ticket> tickets = new ArrayList<>();
.collect(Collectors.toList()));
for (IssueTracker tracker : trackers) {
tickets.addAll(tracker.findTickets(module, ticketReferences).getTickets());
}
return new Tickets(tickets);
} }
/** /**

View File

@@ -54,10 +54,10 @@ class ParsedCommitMessage {
.compile(String.format("(%s|%s)", JIRA_TICKET.pattern(), GITHUB_TICKET.pattern())); .compile(String.format("(%s|%s)", JIRA_TICKET.pattern(), GITHUB_TICKET.pattern()));
private static final Pattern ORIGINAL_PULL_REQUEST = Pattern private static final Pattern ORIGINAL_PULL_REQUEST = Pattern
.compile("Original (?>pull request|PR|pullrequest):(?>\\s+)?" + A_TICKET.pattern(), Pattern.CASE_INSENSITIVE); .compile("Original (?>pull request|PR|pullrequest)[:]*(?>\\s+)?" + A_TICKET.pattern(), Pattern.CASE_INSENSITIVE);
private static final Pattern RELATED_TICKET = Pattern.compile( private static final Pattern RELATED_TICKET = Pattern.compile(
"Related (?>tickets|ticket):(?>\\s+)?((" + A_TICKET.pattern() + "(?>[\\s,]*))+)", Pattern.CASE_INSENSITIVE); "Related (?>tickets|ticket)[:]*(?>\\s+)?((" + A_TICKET.pattern() + "(?>[\\s,]*))+)", Pattern.CASE_INSENSITIVE);
private final String summary; private final String summary;
private final @Nullable String body; private final @Nullable String body;

View File

@@ -16,6 +16,7 @@
package org.springframework.data.release.issues; package org.springframework.data.release.issues;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.util.Date; import java.util.Date;
@@ -34,7 +35,7 @@ import org.springframework.format.datetime.DateFormatter;
@EqualsAndHashCode @EqualsAndHashCode
public class Changelog { public class Changelog {
private final ModuleIteration module; @Getter private final ModuleIteration module;
private final Tickets tickets; private final Tickets tickets;
/* /*
@@ -43,25 +44,35 @@ public class Changelog {
*/ */
@Override @Override
public String toString() { public String toString() {
return toString(true, "");
}
public String toString(boolean header, String indentation) {
ArtifactVersion version = ArtifactVersion.of(module); ArtifactVersion version = ArtifactVersion.of(module);
String headline = String.format("Changes in version %s (%s)", version, String headline = String.format("Changes in version %s (%s)", version,
new DateFormatter("YYYY-MM-dd").print(new Date(), Locale.US)); new DateFormatter("YYYY-MM-dd").print(new Date(), Locale.US));
StringBuilder builder = new StringBuilder(headline).append(IOUtils.LINE_SEPARATOR); StringBuilder builder = new StringBuilder();
for (int i = 0; i < headline.length(); i++) { if (header) {
builder.append("-");
builder.append(indentation).append(headline).append(IOUtils.LINE_SEPARATOR).append(indentation);
for (int i = 0; i < headline.length(); i++) {
builder.append("-");
}
builder.append(IOUtils.LINE_SEPARATOR);
} }
builder.append(IOUtils.LINE_SEPARATOR);
for (Ticket ticket : tickets) { for (Ticket ticket : tickets) {
String summary = ticket.getSummary(); String summary = ticket.getSummary();
builder.append("* ").append(ticket.getId()).append(" - ").append(summary != null ? summary.trim() : ""); builder.append(indentation).append("* ").append(ticket.getId()).append(" - ")
.append(summary != null ? summary.trim() : "");
if (!summary.endsWith(".")) { if (!summary.endsWith(".")) {
builder.append("."); builder.append(".");

View File

@@ -136,8 +136,8 @@ class IssueTrackerCommands extends TimedCommand {
.toString(); .toString();
} }
@CliCommand("tracker changelog") @CliCommand("tracker open-tickets")
public String changelog(@CliOption(key = "", mandatory = true) TrainIteration iteration, // public String openTickets(@CliOption(key = "", mandatory = true) TrainIteration iteration, //
@CliOption(key = "module") String moduleName) { @CliOption(key = "module") String moduleName) {
if (StringUtils.hasText(moduleName)) { if (StringUtils.hasText(moduleName)) {
@@ -145,11 +145,15 @@ class IssueTrackerCommands extends TimedCommand {
Project project = Projects.requiredByName(moduleName); Project project = Projects.requiredByName(moduleName);
ModuleIteration module = iteration.getModule(project); ModuleIteration module = iteration.getModule(project);
return getTrackerFor(module).getChangelogFor(module).toString(); String tickets = getTrackerFor(module).getTicketsFor(module).stream().filter(it -> !it.isResolved())
.collect(Tickets.toTicketsCollector()).toString(false);
return String.format("%s - %s%n%s%n", project.getFullName(), module.getFullVersionString(), tickets);
} }
return ExecutionUtils.runAndReturn(executor, iteration, this::getChangelog).// return ExecutionUtils.runAndReturn(executor, iteration,
stream().map(it -> it.toString()).collect(Collectors.joining("\n")); moduleIteration -> openTickets(iteration, moduleIteration.getModule().getProject().getName())).//
stream().collect(Collectors.joining("\n"));
} }
@CliCommand("tracker close") @CliCommand("tracker close")

View File

@@ -98,11 +98,17 @@ public class Tickets implements Streamable<Ticket> {
*/ */
@Override @Override
public String toString() { public String toString() {
return toString(true);
}
public String toString(boolean header) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(String.format("Train only tickets: %s of %s", tickets.size(), overallTotal)); if (header) {
builder.append(IOUtils.LINE_SEPARATOR); builder.append(String.format("Train only tickets: %s of %s", tickets.size(), overallTotal));
builder.append(IOUtils.LINE_SEPARATOR);
}
builder.append(tickets.stream().map(it -> "\t" + it).collect(Collectors.joining(IOUtils.LINE_SEPARATOR))); builder.append(tickets.stream().map(it -> "\t" + it).collect(Collectors.joining(IOUtils.LINE_SEPARATOR)));
return builder.toString(); return builder.toString();

View File

@@ -593,6 +593,10 @@ class Jira implements JiraConnector {
.filter(it -> it.getId().startsWith(moduleIteration.getProjectKey().getKey())).map(TicketReference::getId) .filter(it -> it.getId().startsWith(moduleIteration.getProjectKey().getKey())).map(TicketReference::getId)
.collect(Collectors.toList()); .collect(Collectors.toList());
if (ids.isEmpty()) {
return new Tickets(Collections.emptyList());
}
Map<String, Object> parameters = newUrlTemplateVariables(); Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("jql", JqlQuery.from(ids)); parameters.put("jql", JqlQuery.from(ids));
parameters.put("fields", "summary,status,resolution,fixVersions"); parameters.put("fields", "summary,status,resolution,fixVersions");

View File

@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.DefaultEdge;
@@ -131,9 +132,9 @@ public class Projects {
public static Optional<Project> byName(String name) { public static Optional<Project> byName(String name) {
return PROJECTS.stream().// return Stream.concat(Stream.of(BOM), PROJECTS.stream()) //
filter(project -> project.getName().equalsIgnoreCase(name) || project.getKey().toString().equals(name)).// .filter(project -> project.getName().equalsIgnoreCase(name) || project.getKey().toString().equals(name))//
findFirst(); .findFirst();
} }
public static Project requiredByName(String name) { public static Project requiredByName(String name) {