Use configured IssueTracker for changelog ticket lookup.

Also, use plain ticket Id's for lookup and reorder methods.

See #168.
This commit is contained in:
Mark Paluch
2021-02-17 14:20:47 +01:00
parent 5330dcd89a
commit b55a68e6c6
7 changed files with 89 additions and 79 deletions

View File

@@ -114,12 +114,12 @@ class GitCommands extends TimedCommand {
private Tickets toTickets(ModuleIteration module, List<TicketReference> ticketReferences) {
// TODO: Use only associated tracker
List<Ticket> tickets = new ArrayList<>();
IssueTracker issueTracker = trackers.getRequiredPluginFor(module.getProject(),
() -> String.format("No issue tracker found for project %s!", module.getProject()));
for (IssueTracker tracker : trackers) {
tickets.addAll(tracker.findTickets(module, ticketReferences).getTickets());
}
List<String> ticketIds = ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList());
List<Ticket> tickets = new ArrayList<>(issueTracker.findTickets(module, ticketIds).getTickets());
return new Tickets(tickets);
}

View File

@@ -17,6 +17,7 @@ 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;
@@ -81,6 +82,17 @@ public interface IssueTracker extends Plugin<Project> {
*/
Collection<Ticket> findTickets(Project project, Collection<String> ticketIds);
/**
* Query the issue tracker for multiple {@link Ticket#id ticket Ids}. Tickets that are not found are not returned. The
* implementation ensures to resolve only references that match the issue tracker scheme this issue tracker is
* responsible for.
*
* @param moduleIteration must not be {@literal null}.
* @param ticketReferences must not be {@literal null}.
* @return
*/
Tickets findTickets(ModuleIteration moduleIteration, Collection<String> ticketIds);
/**
* Creates a release version if release version is missing.
*
@@ -155,7 +167,8 @@ public interface IssueTracker extends Plugin<Project> {
*/
default Changelog getChangelogFor(ModuleIteration module, List<TicketReference> ticketReferences) {
Tickets tickets = findTickets(module, ticketReferences);
Tickets tickets = findTickets(module,
ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList()));
return Changelog.of(module, tickets);
}
@@ -174,17 +187,6 @@ public interface IssueTracker extends Plugin<Project> {
*/
void closeTicket(ModuleIteration module, Ticket ticket);
/**
* Resolve a {@link List} of {@link TicketReference}s to {@link Tickets} for a given {@link ModuleIteration}. The
* implementation ensures to resolve only references that match the issue tracker scheme this issue tracker is
* responsible for.
*
* @param moduleIteration must not be {@literal null}.
* @param ticketReferences must not be {@literal null}.
* @return
*/
Tickets findTickets(ModuleIteration moduleIteration, List<TicketReference> ticketReferences);
enum TicketType {
Task, DependencyUpgrade;
}

View File

@@ -40,13 +40,13 @@ 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.model.ArtifactVersion;
import org.springframework.data.release.model.DocumentationMetadata;
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.Projects;
import org.springframework.data.release.model.Tracker;
import org.springframework.data.release.model.TrainIteration;
import org.springframework.data.release.utils.ExecutionUtils;
@@ -147,6 +147,13 @@ class GitHub extends GitHubSupport implements IssueTracker {
return tickets;
}
@Override
public Tickets findTickets(ModuleIteration moduleIteration, Collection<String> ticketIds) {
return findGitHubIssues(moduleIteration, ticketIds).stream().map(GitHub::toTicket)
.collect(Tickets.toTicketsCollector());
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.jira.IssueTracker#getChangelogFor(org.springframework.data.release.model.ModuleIteration)
@@ -464,14 +471,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
close(module, ticket);
}
@Override
public Tickets findTickets(ModuleIteration moduleIteration, List<TicketReference> ticketReferences) {
return findGitHubIssues(moduleIteration, ticketReferences).stream().map(GitHub::toTicket)
.collect(Tickets.toTicketsCollector());
}
List<GitHubReadIssue> findGitHubIssues(ModuleIteration moduleIteration, List<TicketReference> ticketReferences) {
List<GitHubReadIssue> findGitHubIssues(ModuleIteration moduleIteration, Collection<String> ticketIds) {
logger.log(moduleIteration, "Looking up GitHub issues from milestone …");
@@ -480,9 +480,9 @@ class GitHub extends GitHubSupport implements IssueTracker {
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
logger.log(moduleIteration, "Resolving GitHub issues …");
logger.log(moduleIteration, "Looking up GitHub issues …");
Collection<GitHubReadIssue> foundIssues = ExecutionUtils.runAndReturn(executorService,
Streamable.of(() -> ticketReferences.stream().filter(it -> it.getId().startsWith("#"))),
Streamable.of(() -> ticketIds.stream().filter(it -> it.startsWith("#"))),
ticketReference -> getTicket(issues, repositoryName, ticketReference));
List<GitHubReadIssue> gitHubIssues = foundIssues.stream().filter(it -> {
@@ -490,19 +490,19 @@ class GitHub extends GitHubSupport implements IssueTracker {
return !ticket.isReleaseTicketFor(moduleIteration) && !ticket.isReleaseTicket();
}).collect(Collectors.toList());
logger.log(moduleIteration, "Resolved %s tickets.", gitHubIssues.size());
logger.log(moduleIteration, "Found %s tickets.", gitHubIssues.size());
return gitHubIssues;
}
private GitHubReadIssue getTicket(Map<String, GitHubReadIssue> cache, String repositoryName,
TicketReference reference) {
String ticketId) {
if (cache.containsKey(reference.getId())) {
return cache.get(reference.getId());
if (cache.containsKey(ticketId)) {
return cache.get(ticketId);
}
return findTicket(repositoryName, reference.getId());
return findTicket(repositoryName, ticketId);
}
private Tickets getTicketsFor(ModuleIteration moduleIteration, boolean forCurrentUser) {
@@ -541,11 +541,11 @@ class GitHub extends GitHubSupport implements IssueTracker {
* @param module
* @param ticketReferences
*/
public void createOrUpdateRelease(ModuleIteration module, List<TicketReference> ticketReferences) {
public void createOrUpdateRelease(ModuleIteration module, List<String> ticketIds) {
logger.log(module, "Preparing GitHub Release …");
List<GitHubReadIssue> gitHubIssues = findGitHubIssues(module, ticketReferences);
List<GitHubReadIssue> gitHubIssues = findGitHubIssues(module, ticketIds);
ArtifactVersion version = ArtifactVersion.of(module);
DocumentationMetadata documentation = DocumentationMetadata.of(module.getProject(), version);
@@ -554,7 +554,13 @@ class GitHub extends GitHubSupport implements IssueTracker {
String releaseBody = generator.generate(gitHubIssues, (changelogSection, s) -> s);
String documentationLinks = getDocumentationLinks(module, documentation);
createOrUpdateRelease(module, String.format("## :green_book: Links%n%s%n%s%n", documentationLinks, releaseBody));
if (module.getProject() == Projects.BOM || module.getProject() == Projects.BUILD) {
// We don't ship Javadoc/reference doc for build and BOM
createOrUpdateRelease(module, String.format("%s%n", documentationLinks, releaseBody));
} else {
createOrUpdateRelease(module, String.format("## :green_book: Links%n%s%n%s%n", documentationLinks, releaseBody));
}
logger.log(module, "GitHub Release up to date");
}

View File

@@ -22,6 +22,7 @@ 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;
@@ -63,11 +64,11 @@ class GitHubCommands extends TimedCommand {
git.push(iteration);
git.pushTags(iteration.getTrain());
createOrUpdateLabels(iteration);
createOrUpdateRelease(iteration);
}
@CliCommand(value = "github create release")
public void createOrUpdateLabels(@CliOption(key = "", mandatory = true) TrainIteration iteration) {
public void createOrUpdateRelease(@CliOption(key = "", mandatory = true) TrainIteration iteration) {
TrainIteration previousIteration = git.getPreviousIteration(iteration);
@@ -75,8 +76,8 @@ class GitHubCommands extends TimedCommand {
if (it.getProject().getTracker() == Tracker.GITHUB) {
List<TicketReference> ticketReferences = git.getTicketReferencesBetween(it.getProject(), previousIteration,
iteration);
List<String> ticketReferences = git.getTicketReferencesBetween(it.getProject(), previousIteration, iteration)
.stream().map(TicketReference::getId).collect(Collectors.toList());
gitHub.createOrUpdateRelease(it, ticketReferences);
}
});

View File

@@ -31,7 +31,6 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.release.issues.Changelog;
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.jira.JiraIssue.Fields;
import org.springframework.data.release.issues.jira.JiraIssue.Resolution;
@@ -137,6 +136,8 @@ class Jira implements JiraConnector {
return Collections.emptyList();
}
logger.log(project, "Retrieving up JIRA issues…");
JqlQuery query = JqlQuery.from(ticketIds).and(" resolution is not EMPTY");
Map<String, Object> parameters = newUrlTemplateVariables();
@@ -147,11 +148,40 @@ class Jira implements JiraConnector {
JiraIssues issues = operations.exchange(SEARCH_TEMPLATE, HttpMethod.GET, null, JiraIssues.class, parameters)
.getBody();
logger.log(project, "Found %s tickets.", issues.getIssues().size());
return issues.stream().//
map(this::toTicket).//
collect(Collectors.toList());
}
@Override
public Tickets findTickets(ModuleIteration moduleIteration, Collection<String> ticketIds) {
List<String> ids = ticketIds.stream().filter(it -> it.startsWith(moduleIteration.getProjectKey().getKey()))
.collect(Collectors.toList());
if (ids.isEmpty()) {
return new Tickets(Collections.emptyList());
}
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("jql", JqlQuery.from(ids));
parameters.put("fields", "summary,status,resolution,fixVersions");
parameters.put("startAt", 0);
logger.log(moduleIteration, "Retrieving up JIRA issues…");
JiraIssues issues = operations.getForObject(SEARCH_TEMPLATE, JiraIssues.class, parameters);
Tickets tickets = issues.stream().map(this::toTicket).filter(it -> {
return it.isReleaseTicketFor(moduleIteration) || !it.isReleaseTicket();
}).collect(Tickets.toTicketsCollector());
logger.log(moduleIteration, "Found %s tickets.", tickets.getOverallTotal());
return tickets;
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.jira.IssueTracker#getTicketsFor(org.springframework.data.release.model.TrainIteration)
@@ -586,34 +616,6 @@ class Jira implements JiraConnector {
return project.uses(Tracker.JIRA);
}
@Override
public Tickets findTickets(ModuleIteration moduleIteration, List<TicketReference> ticketReferences) {
List<String> ids = ticketReferences.stream()
.filter(it -> it.getId().startsWith(moduleIteration.getProjectKey().getKey())).map(TicketReference::getId)
.collect(Collectors.toList());
if (ids.isEmpty()) {
return new Tickets(Collections.emptyList());
}
Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("jql", JqlQuery.from(ids));
parameters.put("fields", "summary,status,resolution,fixVersions");
parameters.put("startAt", 0);
logger.log(moduleIteration, "Resolving JIRA issues…");
JiraIssues issues = operations.getForObject(SEARCH_TEMPLATE, JiraIssues.class, parameters);
Tickets tickets = issues.stream().map(this::toTicket).filter(it -> {
return it.isReleaseTicketFor(moduleIteration) || !it.isReleaseTicket();
}).collect(Tickets.toTicketsCollector());
logger.log(moduleIteration, "Resolved %s tickets.", tickets.getOverallTotal());
return tickets;
}
protected JiraComponents getJiraComponents(ProjectKey projectKey) {
HttpHeaders headers = new HttpHeaders();

View File

@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import org.springframework.data.release.git.GitOperations;
import org.springframework.data.release.io.Workspace;
@@ -118,15 +119,10 @@ public class ReleaseOperations {
protected Changelog getChangelog(TrainIteration iteration, TrainIteration previousIteration, ModuleIteration module,
IssueTracker issueTracker) {
List<TicketReference> ticketReferences = git.getTicketReferencesBetween(module.getProject(), previousIteration,
iteration);
List<String> ticketIds = git.getTicketReferencesBetween(module.getProject(), previousIteration, iteration).stream()
.map(TicketReference::getId).collect(Collectors.toList());
// TODO: Use only associated tracker
List<Ticket> tickets = new ArrayList<>();
for (IssueTracker tracker : trackers) {
tickets.addAll(tracker.findTickets(module, ticketReferences).getTickets());
}
List<Ticket> tickets = new ArrayList<>(issueTracker.findTickets(module, ticketIds).getTickets());
return Changelog.of(module, new Tickets(tickets));
}

View File

@@ -18,6 +18,7 @@ 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;
@@ -56,7 +57,8 @@ class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests {
List<TicketReference> ticketReferences = gitOperations.getTicketReferencesBetween(Projects.MONGO_DB, from, to);
IssueTracker tracker = trackers.getRequiredPluginFor(Projects.MONGO_DB);
Tickets tickets = tracker.findTickets(to.getModule(Projects.MONGO_DB), ticketReferences);
Tickets tickets = tracker.findTickets(to.getModule(Projects.MONGO_DB),
ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList()));
assertThat(tickets).hasSize(15);
}
@@ -70,7 +72,8 @@ class ReleaseOperationsIntegrationTests extends AbstractIntegrationTests {
List<TicketReference> ticketReferences = gitOperations.getTicketReferencesBetween(Projects.R2DBC, from, to);
IssueTracker tracker = trackers.getRequiredPluginFor(Projects.R2DBC);
Tickets tickets = tracker.findTickets(to.getModule(Projects.R2DBC), ticketReferences);
Tickets tickets = tracker.findTickets(to.getModule(Projects.R2DBC),
ticketReferences.stream().map(TicketReference::getId).collect(Collectors.toList()));
assertThat(tickets).hasSize(22);
}