From 2777a349bc84e36064ad2d56d5b5370bda0e1d02 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 23 Nov 2020 08:50:26 +0100 Subject: [PATCH] =?UTF-8?q?#162=20-=20Attach=20label/component=20to=20Issu?= =?UTF-8?q?eTracker.createTicket(=E2=80=A6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dependency/DependencyCommands.java | 1 + .../dependency/DependencyOperations.java | 2 +- .../data/release/issues/IssueTracker.java | 7 +- .../release/issues/IssueTrackerCommands.java | 3 +- .../issues/github/ChangelogGenerator.java | 14 +-- .../issues/github/ChangelogSection.java | 2 +- .../issues/github/ChangelogSections.java | 8 +- .../data/release/issues/github/GitHub.java | 74 +++++++------- .../release/issues/github/GitHubIssue.java | 96 ++----------------- .../issues/github/GitHubMilestone.java | 1 - .../issues/github/GitHubReadIssue.java | 63 ++++++++++++ .../issues/github/GitHubWriteIssue.java | 69 +++++++++++++ .../issues/github/LabelConfiguration.java | 11 ++- .../data/release/issues/github/Milestone.java | 50 ++++++++++ .../data/release/issues/jira/Jira.java | 2 +- .../GitHubIssueTrackerIntegrationTests.java | 3 +- .../issues/github/GitHubIssueUnitTests.java | 3 +- 17 files changed, 268 insertions(+), 141 deletions(-) create mode 100644 release-tools/src/main/java/org/springframework/data/release/issues/github/GitHubReadIssue.java create mode 100644 release-tools/src/main/java/org/springframework/data/release/issues/github/GitHubWriteIssue.java create mode 100644 release-tools/src/main/java/org/springframework/data/release/issues/github/Milestone.java diff --git a/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyCommands.java b/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyCommands.java index 00ef9a8..cf60c8a 100644 --- a/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyCommands.java +++ b/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyCommands.java @@ -51,6 +51,7 @@ import org.springframework.shell.support.table.Table; public class DependencyCommands extends TimedCommand { public static final String BUILD_PROPERTIES = "dependency-upgrade-build.properties"; + DependencyOperations operations; GitOperations git; Logger logger; diff --git a/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyOperations.java b/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyOperations.java index 30c16c4..bc9f9ec 100644 --- a/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyOperations.java +++ b/release-tools/src/main/java/org/springframework/data/release/dependency/DependencyOperations.java @@ -134,7 +134,7 @@ public class DependencyOperations { ModuleIteration module = iteration.getModule(project); logger.log(module, "Creating upgrade ticket for %s", upgradeTicketSummary); - tracker.createTicket(module, upgradeTicketSummary); + tracker.createTicket(module, upgradeTicketSummary, IssueTracker.TicketType.DependencyUpgrade); } }); } diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/IssueTracker.java b/release-tools/src/main/java/org/springframework/data/release/issues/IssueTracker.java index 58c7ff1..34fb3b8 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/IssueTracker.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/IssueTracker.java @@ -101,9 +101,10 @@ public interface IssueTracker extends Plugin { * * @param module must not be {@literal null}. * @param text the text to use. + * @param ticketType the ticket type. * @return the created ticket. */ - Ticket createTicket(ModuleIteration module, String text); + Ticket createTicket(ModuleIteration module, String text, TicketType ticketType); /** * Assigns the ticket to the current user. @@ -173,4 +174,8 @@ public interface IssueTracker extends Plugin { * @return */ Tickets findTickets(ModuleIteration moduleIteration, List ticketReferences); + + enum TicketType { + Task, DependencyUpgrade; + } } diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/IssueTrackerCommands.java b/release-tools/src/main/java/org/springframework/data/release/issues/IssueTrackerCommands.java index 2528c3d..586c6d4 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/IssueTrackerCommands.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/IssueTrackerCommands.java @@ -131,7 +131,8 @@ class IssueTrackerCommands extends TimedCommand { @CliOption(key = "text", mandatory = true) String text) { return iteration.stream().// - map(module -> getTrackerFor(module).createTicket(module, text)).collect(Tickets.toTicketsCollector()) + map(module -> getTrackerFor(module).createTicket(module, text, IssueTracker.TicketType.Task)) + .collect(Tickets.toTicketsCollector()) .toString(); } diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java b/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java index 39f7241..ab09eea 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogGenerator.java @@ -61,12 +61,12 @@ public class ChangelogGenerator { * @param issues the issues to generate the changelog for * @param sectionContentPostProcessor the postprocessor for a changelog section */ - public String generate(List issues, + public String generate(List issues, BiFunction sectionContentPostProcessor) { return generateContent(issues, sectionContentPostProcessor); } - private boolean isExcluded(GitHubIssue issue) { + private boolean isExcluded(GitHubReadIssue issue) { return issue.getLabels().stream().anyMatch(this::isExcluded); } @@ -74,7 +74,7 @@ public class ChangelogGenerator { return this.excludeLabels.contains(label.getName()); } - private String generateContent(List issues, + private String generateContent(List issues, BiFunction sectionContentPostProcessor) { StringBuilder content = new StringBuilder(); addSectionContent(content, this.sections.collate(issues), sectionContentPostProcessor); @@ -85,7 +85,7 @@ public class ChangelogGenerator { return content.toString(); } - private void addSectionContent(StringBuilder result, Map> sectionIssues, + private void addSectionContent(StringBuilder result, Map> sectionIssues, BiFunction sectionContentPostProcessor) { sectionIssues.forEach((section, issues) -> { @@ -102,7 +102,7 @@ public class ChangelogGenerator { }); } - private String getFormattedIssue(GitHubIssue issue) { + private String getFormattedIssue(GitHubReadIssue issue) { String title = issue.getTitle(); title = ghUserMentionPattern.matcher(title).replaceAll("$1`$2`"); return String.format("- %s %s%n", title, getLinkToIssue(issue)); @@ -112,11 +112,11 @@ 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(GitHubIssue::getUser) + return issues.stream().filter((issue) -> issue.getPullRequest() != null).map(GitHubReadIssue::getUser) .filter(this::isIncludedContributor).collect(Collectors.toSet()); } diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java b/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java index f974821..0ecf614 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSection.java @@ -52,7 +52,7 @@ class ChangelogSection { return this.group; } - boolean isMatchFor(GitHubIssue issue) { + boolean isMatchFor(GitHubReadIssue issue) { for (String candidate : this.labels) { for (Label label : issue.getLabels()) { if (label.getName().contains(candidate)) { diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSections.java b/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSections.java index 6ae2bc7..5369a04 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSections.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/github/ChangelogSections.java @@ -52,12 +52,12 @@ class ChangelogSections { this.sections = DEFAULT_SECTIONS; } - Map> collate(List issues) { + Map> collate(List issues) { - SortedMap> collated = new TreeMap<>( + SortedMap> collated = new TreeMap<>( Comparator.comparing(this.sections::indexOf)); - for (GitHubIssue issue : issues) { + for (GitHubReadIssue issue : issues) { List sections = getSections(issue); for (ChangelogSection section : sections) { collated.computeIfAbsent(section, (key) -> new ArrayList<>()); @@ -67,7 +67,7 @@ class ChangelogSections { return collated; } - private List getSections(GitHubIssue issue) { + private List getSections(GitHubReadIssue issue) { List result = new ArrayList<>(); Set groupClaimes = new HashSet<>(); for (ChangelogSection section : this.sections) { diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHub.java b/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHub.java index 9ac8087..025b1da 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHub.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHub.java @@ -41,7 +41,6 @@ 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.GitHubIssue.Milestone; import org.springframework.data.release.model.ArtifactVersion; import org.springframework.data.release.model.DocumentationMetadata; import org.springframework.data.release.model.Iteration; @@ -79,13 +78,22 @@ class GitHub extends GitHubSupport implements IssueTracker { private static final String RELEASE_BY_ID_URI_TEMPLATE = "/repos/spring-projects/{repoName}/releases/{id}"; private static final ParameterizedTypeReference> MILESTONES_TYPE = new ParameterizedTypeReference>() {}; - private static final ParameterizedTypeReference> ISSUES_TYPE = new ParameterizedTypeReference>() {}; - private static final ParameterizedTypeReference ISSUE_TYPE = new ParameterizedTypeReference() {}; + private static final ParameterizedTypeReference> ISSUES_TYPE = new ParameterizedTypeReference>() {}; + private static final ParameterizedTypeReference ISSUE_TYPE = new ParameterizedTypeReference() {}; + + private static final Map TICKET_LABELS = new HashMap<>(); + + static { + + TICKET_LABELS.put(TicketType.Task, LabelConfiguration.TYPE_TASK); + TICKET_LABELS.put(TicketType.DependencyUpgrade, LabelConfiguration.TYPE_DEPENDENCY_UPGRADE); + } private final Logger logger; private final GitHubProperties properties; private final ExecutorService executorService; + public GitHub(@Qualifier("tracker") RestTemplateBuilder templateBuilder, Logger logger, GitHubProperties properties, ExecutorService executorService) { @@ -129,7 +137,7 @@ class GitHub extends GitHubSupport implements IssueTracker { ticketIds.forEach(ticketId -> { - GitHubIssue ticket = findTicket(repositoryName, ticketId); + GitHubReadIssue ticket = findTicket(repositoryName, ticketId); if (ticket != null) { tickets.add(toTicket(ticket)); } @@ -214,7 +222,7 @@ class GitHub extends GitHubSupport implements IssueTracker { parameters.put("repoName", repositoryName); operations.exchange(MILESTONES_URI_TEMPLATE, HttpMethod.POST, - new HttpEntity(githubMilestone.toMilestone(), httpHeaders), GitHubIssue.Milestone.class, parameters); + new HttpEntity(githubMilestone.toMilestone(), httpHeaders), Milestone.class, parameters); } /* @@ -243,29 +251,31 @@ class GitHub extends GitHubSupport implements IssueTracker { logger.log(moduleIteration, "Creating release ticket…"); - doCreateTicket(moduleIteration, Tracker.releaseTicketSummary(moduleIteration)); + doCreateTicket(moduleIteration, Tracker.releaseTicketSummary(moduleIteration), TicketType.Task); } @Override - public Ticket createTicket(ModuleIteration moduleIteration, String text) { + public Ticket createTicket(ModuleIteration moduleIteration, String text, TicketType ticketType) { logger.log(moduleIteration, "Creating ticket…"); - return doCreateTicket(moduleIteration, text); + return doCreateTicket(moduleIteration, text, ticketType); } - private Ticket doCreateTicket(ModuleIteration moduleIteration, String text) { - HttpHeaders httpHeaders = new HttpHeaders(); + private Ticket doCreateTicket(ModuleIteration moduleIteration, String text, TicketType ticketType) { String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName(); Milestone milestone = getMilestone(moduleIteration, repositoryName); - GitHubIssue gitHubIssue = GitHubIssue.of(text, milestone); + + Label label = TICKET_LABELS.get(ticketType); + + GitHubWriteIssue gitHubIssue = GitHubWriteIssue.of(text, milestone).withLabel(label.getName()); Map parameters = newUrlTemplateVariables(); parameters.put("repoName", repositoryName); - GitHubIssue body = operations.exchange(ISSUES_URI_TEMPLATE, HttpMethod.POST, - new HttpEntity(gitHubIssue, httpHeaders), GitHubIssue.class, parameters).getBody(); + GitHubReadIssue body = operations.exchange(ISSUES_URI_TEMPLATE, HttpMethod.POST, + new HttpEntity(gitHubIssue), GitHubReadIssue.class, parameters).getBody(); return toTicket(body); } @@ -300,9 +310,9 @@ class GitHub extends GitHubSupport implements IssueTracker { parameters.put("repoName", repositoryName); parameters.put("id", stripHash(releaseTicketFor)); - GitHubIssue edit = GitHubIssue.assignedTo(properties.getUsername()); + GitHubWriteIssue edit = GitHubWriteIssue.assignedTo(properties.getUsername()); - GitHubIssue response = operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.PATCH, + GitHubReadIssue response = operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.PATCH, new HttpEntity<>(edit, new HttpHeaders()), ISSUE_TYPE, parameters).getBody(); return toTicket(response); @@ -328,12 +338,12 @@ class GitHub extends GitHubSupport implements IssueTracker { Assert.notNull(module, "ModuleIteration must not be null."); Ticket releaseTicketFor = getReleaseTicketFor(module); - GitHubIssue response = close(module, releaseTicketFor); + GitHubReadIssue response = close(module, releaseTicketFor); return toTicket(response); } - private GitHubIssue close(ModuleIteration module, Ticket ticket) { + private GitHubReadIssue close(ModuleIteration module, Ticket ticket) { String repositoryName = GitProject.of(module.getProject()).getRepositoryName(); @@ -341,7 +351,7 @@ class GitHub extends GitHubSupport implements IssueTracker { parameters.put("repoName", repositoryName); parameters.put("id", stripHash(ticket)); - GitHubIssue edit = GitHubIssue.assignedTo(properties.getUsername()).close(); + GitHubWriteIssue edit = GitHubWriteIssue.assignedTo(properties.getUsername()).close(); return operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.PATCH, new HttpEntity<>(edit, new HttpHeaders()), ISSUE_TYPE, parameters).getBody(); @@ -372,7 +382,7 @@ class GitHub extends GitHubSupport implements IssueTracker { doWithPaging(MILESTONE_URI, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()), MILESTONES_TYPE, milestones -> { - Optional milestone = milestones.stream(). // + Optional milestone = milestones.stream(). // filter(m -> m.matches(moduleIteration)). // findFirst(). // map(m -> { @@ -448,21 +458,21 @@ class GitHub extends GitHubSupport implements IssueTracker { .collect(Tickets.toTicketsCollector()); } - List findGitHubIssues(ModuleIteration moduleIteration, List ticketReferences) { + List findGitHubIssues(ModuleIteration moduleIteration, List ticketReferences) { logger.log(moduleIteration, "Looking up GitHub issues from milestone …"); - Map issues = getIssuesFor(moduleIteration, false, true) + Map issues = getIssuesFor(moduleIteration, false, true) .collect(Collectors.toMap(GitHubIssue::getId, Function.identity())); String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName(); logger.log(moduleIteration, "Resolving GitHub issues …"); - Collection foundIssues = ExecutionUtils.runAndReturn(executorService, + Collection foundIssues = ExecutionUtils.runAndReturn(executorService, Streamable.of(() -> ticketReferences.stream().filter(it -> it.getId().startsWith("#"))), ticketReference -> getTicket(issues, repositoryName, ticketReference)); - List gitHubIssues = foundIssues.stream().filter(it -> { + List gitHubIssues = foundIssues.stream().filter(it -> { Ticket ticket = toTicket(it); return !ticket.isReleaseTicketFor(moduleIteration) && !ticket.isReleaseTicket(); }).collect(Collectors.toList()); @@ -472,7 +482,8 @@ class GitHub extends GitHubSupport implements IssueTracker { return gitHubIssues; } - private GitHubIssue getTicket(Map cache, String repositoryName, TicketReference reference) { + private GitHubReadIssue getTicket(Map cache, String repositoryName, + TicketReference reference) { if (cache.containsKey(reference.getId())) { return cache.get(reference.getId()); @@ -493,7 +504,7 @@ class GitHub extends GitHubSupport implements IssueTracker { * @param ticketId * @return */ - private GitHubIssue findTicket(String repositoryName, String ticketId) { + private GitHubReadIssue findTicket(String repositoryName, String ticketId) { Map parameters = newUrlTemplateVariables(); parameters.put("repoName", repositoryName); @@ -503,7 +514,6 @@ class GitHub extends GitHubSupport implements IssueTracker { return operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), ISSUE_TYPE, parameters).getBody(); - } catch (HttpStatusCodeException e) { if (e.getStatusCode() == HttpStatus.NOT_FOUND) { @@ -522,7 +532,7 @@ class GitHub extends GitHubSupport implements IssueTracker { logger.log(module, "Preparing GitHub Release …"); - List gitHubIssues = findGitHubIssues(module, ticketReferences); + List gitHubIssues = findGitHubIssues(module, ticketReferences); ArtifactVersion version = ArtifactVersion.of(module); DocumentationMetadata documentation = DocumentationMetadata.of(module.getProject(), version); @@ -608,7 +618,7 @@ class GitHub extends GitHubSupport implements IssueTracker { parameters); } - private Stream getIssuesFor(ModuleIteration moduleIteration, boolean forCurrentUser, + private Stream getIssuesFor(ModuleIteration moduleIteration, boolean forCurrentUser, boolean ignoreMissingMilestone) { String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName(); @@ -619,7 +629,7 @@ class GitHub extends GitHubSupport implements IssueTracker { return Stream.empty(); } - GitHubIssue.Milestone milestone = optionalMilestone.orElseThrow(() -> noSuchMilestone(moduleIteration)); + Milestone milestone = optionalMilestone.orElseThrow(() -> noSuchMilestone(moduleIteration)); Map parameters = newUrlTemplateVariables(); parameters.put("repoName", repositoryName); @@ -634,9 +644,9 @@ class GitHub extends GitHubSupport implements IssueTracker { return getForIssues(ISSUES_BY_MILESTONE_URI_TEMPLATE, parameters); } - private Stream getForIssues(String template, Map parameters) { + private Stream getForIssues(String template, Map parameters) { - List issues = new ArrayList<>(); + List issues = new ArrayList<>(); doWithPaging(template, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()), ISSUES_TYPE, tickets -> { issues.addAll(tickets); @@ -661,7 +671,7 @@ class GitHub extends GitHubSupport implements IssueTracker { } private static Ticket toTicket(GitHubIssue issue) { - return new Ticket(issue.getId(), issue.getTitle(), issue.getHtmlUrl(), new GithubTicketStatus(issue.getState())); + return new Ticket(issue.getId(), issue.getTitle(), issue.getUrl(), new GithubTicketStatus(issue.getState())); } } diff --git a/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHubIssue.java b/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHubIssue.java index 2e08eb4..5c3522a 100644 --- a/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHubIssue.java +++ b/release-tools/src/main/java/org/springframework/data/release/issues/github/GitHubIssue.java @@ -1,11 +1,11 @@ /* - * Copyright 2014-2020 the original author or authors. + * Copyright 2020 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 * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -15,100 +15,24 @@ */ package org.springframework.data.release.issues.github; -import lombok.Value; - -import java.util.Collections; -import java.util.List; - -import org.springframework.data.release.model.ModuleIteration; -import org.springframework.util.Assert; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - /** - * @author Oliver Gierke * @author Mark Paluch */ -@Value -class GitHubIssue implements Comparable { +public interface GitHubIssue { - String number, title, state, url; - GitHubUser user; - List assignees; - String htmlUrl; - Object milestone; - PullRequest pullRequest; - List