#162 - Attach label/component to IssueTracker.createTicket(…).

This commit is contained in:
Mark Paluch
2020-11-23 08:50:26 +01:00
parent e1f220fe25
commit 2777a349bc
17 changed files with 268 additions and 141 deletions

View File

@@ -51,6 +51,7 @@ import org.springframework.shell.support.table.Table;
public class DependencyCommands extends TimedCommand { public class DependencyCommands extends TimedCommand {
public static final String BUILD_PROPERTIES = "dependency-upgrade-build.properties"; public static final String BUILD_PROPERTIES = "dependency-upgrade-build.properties";
DependencyOperations operations; DependencyOperations operations;
GitOperations git; GitOperations git;
Logger logger; Logger logger;

View File

@@ -134,7 +134,7 @@ public class DependencyOperations {
ModuleIteration module = iteration.getModule(project); ModuleIteration module = iteration.getModule(project);
logger.log(module, "Creating upgrade ticket for %s", upgradeTicketSummary); logger.log(module, "Creating upgrade ticket for %s", upgradeTicketSummary);
tracker.createTicket(module, upgradeTicketSummary); tracker.createTicket(module, upgradeTicketSummary, IssueTracker.TicketType.DependencyUpgrade);
} }
}); });
} }

View File

@@ -101,9 +101,10 @@ public interface IssueTracker extends Plugin<Project> {
* *
* @param module must not be {@literal null}. * @param module must not be {@literal null}.
* @param text the text to use. * @param text the text to use.
* @param ticketType the ticket type.
* @return the created ticket. * @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. * Assigns the ticket to the current user.
@@ -173,4 +174,8 @@ public interface IssueTracker extends Plugin<Project> {
* @return * @return
*/ */
Tickets findTickets(ModuleIteration moduleIteration, List<TicketReference> ticketReferences); Tickets findTickets(ModuleIteration moduleIteration, List<TicketReference> ticketReferences);
enum TicketType {
Task, DependencyUpgrade;
}
} }

View File

@@ -131,7 +131,8 @@ class IssueTrackerCommands extends TimedCommand {
@CliOption(key = "text", mandatory = true) String text) { @CliOption(key = "text", mandatory = true) String text) {
return iteration.stream().// 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(); .toString();
} }

View File

@@ -61,12 +61,12 @@ public class ChangelogGenerator {
* @param issues the issues to generate the changelog for * @param issues the issues to generate the changelog for
* @param sectionContentPostProcessor the postprocessor for a changelog section * @param sectionContentPostProcessor the postprocessor for a changelog section
*/ */
public String generate(List<GitHubIssue> issues, public String generate(List<GitHubReadIssue> issues,
BiFunction<ChangelogSection, String, String> sectionContentPostProcessor) { BiFunction<ChangelogSection, String, String> sectionContentPostProcessor) {
return generateContent(issues, sectionContentPostProcessor); return generateContent(issues, sectionContentPostProcessor);
} }
private boolean isExcluded(GitHubIssue issue) { private boolean isExcluded(GitHubReadIssue issue) {
return issue.getLabels().stream().anyMatch(this::isExcluded); return issue.getLabels().stream().anyMatch(this::isExcluded);
} }
@@ -74,7 +74,7 @@ public class ChangelogGenerator {
return this.excludeLabels.contains(label.getName()); return this.excludeLabels.contains(label.getName());
} }
private String generateContent(List<GitHubIssue> issues, private String generateContent(List<GitHubReadIssue> issues,
BiFunction<ChangelogSection, String, String> sectionContentPostProcessor) { BiFunction<ChangelogSection, String, String> sectionContentPostProcessor) {
StringBuilder content = new StringBuilder(); StringBuilder content = new StringBuilder();
addSectionContent(content, this.sections.collate(issues), sectionContentPostProcessor); addSectionContent(content, this.sections.collate(issues), sectionContentPostProcessor);
@@ -85,7 +85,7 @@ public class ChangelogGenerator {
return content.toString(); return content.toString();
} }
private void addSectionContent(StringBuilder result, Map<ChangelogSection, List<GitHubIssue>> sectionIssues, private void addSectionContent(StringBuilder result, Map<ChangelogSection, List<GitHubReadIssue>> sectionIssues,
BiFunction<ChangelogSection, String, String> sectionContentPostProcessor) { BiFunction<ChangelogSection, String, String> sectionContentPostProcessor) {
sectionIssues.forEach((section, issues) -> { 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(); String title = issue.getTitle();
title = ghUserMentionPattern.matcher(title).replaceAll("$1`$2`"); title = ghUserMentionPattern.matcher(title).replaceAll("$1`$2`");
return String.format("- %s %s%n", title, getLinkToIssue(issue)); return String.format("- %s %s%n", title, getLinkToIssue(issue));
@@ -112,11 +112,11 @@ public class ChangelogGenerator {
return "[" + issue.getId() + "]" + "(" + issue.getUrl() + ")"; return "[" + issue.getId() + "]" + "(" + issue.getUrl() + ")";
} }
private Set<GitHubUser> getContributors(List<GitHubIssue> issues) { private Set<GitHubUser> getContributors(List<GitHubReadIssue> issues) {
if (this.excludeContributors.contains("*")) { if (this.excludeContributors.contains("*")) {
return Collections.emptySet(); 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()); .filter(this::isIncludedContributor).collect(Collectors.toSet());
} }

View File

@@ -52,7 +52,7 @@ class ChangelogSection {
return this.group; return this.group;
} }
boolean isMatchFor(GitHubIssue issue) { boolean isMatchFor(GitHubReadIssue issue) {
for (String candidate : this.labels) { for (String candidate : this.labels) {
for (Label label : issue.getLabels()) { for (Label label : issue.getLabels()) {
if (label.getName().contains(candidate)) { if (label.getName().contains(candidate)) {

View File

@@ -52,12 +52,12 @@ class ChangelogSections {
this.sections = DEFAULT_SECTIONS; this.sections = DEFAULT_SECTIONS;
} }
Map<ChangelogSection, List<GitHubIssue>> collate(List<GitHubIssue> issues) { Map<ChangelogSection, List<GitHubReadIssue>> collate(List<GitHubReadIssue> issues) {
SortedMap<ChangelogSection, List<GitHubIssue>> collated = new TreeMap<>( SortedMap<ChangelogSection, List<GitHubReadIssue>> collated = new TreeMap<>(
Comparator.comparing(this.sections::indexOf)); Comparator.comparing(this.sections::indexOf));
for (GitHubIssue issue : issues) { for (GitHubReadIssue issue : issues) {
List<ChangelogSection> sections = getSections(issue); List<ChangelogSection> sections = getSections(issue);
for (ChangelogSection section : sections) { for (ChangelogSection section : sections) {
collated.computeIfAbsent(section, (key) -> new ArrayList<>()); collated.computeIfAbsent(section, (key) -> new ArrayList<>());
@@ -67,7 +67,7 @@ class ChangelogSections {
return collated; return collated;
} }
private List<ChangelogSection> getSections(GitHubIssue issue) { private List<ChangelogSection> getSections(GitHubReadIssue issue) {
List<ChangelogSection> result = new ArrayList<>(); List<ChangelogSection> result = new ArrayList<>();
Set<String> groupClaimes = new HashSet<>(); Set<String> groupClaimes = new HashSet<>();
for (ChangelogSection section : this.sections) { for (ChangelogSection section : this.sections) {

View File

@@ -41,7 +41,6 @@ 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.issues.github.GitHubIssue.Milestone;
import org.springframework.data.release.model.ArtifactVersion; import org.springframework.data.release.model.ArtifactVersion;
import org.springframework.data.release.model.DocumentationMetadata; import org.springframework.data.release.model.DocumentationMetadata;
import org.springframework.data.release.model.Iteration; 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 String RELEASE_BY_ID_URI_TEMPLATE = "/repos/spring-projects/{repoName}/releases/{id}";
private static final ParameterizedTypeReference<List<Milestone>> MILESTONES_TYPE = new ParameterizedTypeReference<List<Milestone>>() {}; private static final ParameterizedTypeReference<List<Milestone>> MILESTONES_TYPE = new ParameterizedTypeReference<List<Milestone>>() {};
private static final ParameterizedTypeReference<List<GitHubIssue>> ISSUES_TYPE = new ParameterizedTypeReference<List<GitHubIssue>>() {}; private static final ParameterizedTypeReference<List<GitHubReadIssue>> ISSUES_TYPE = new ParameterizedTypeReference<List<GitHubReadIssue>>() {};
private static final ParameterizedTypeReference<GitHubIssue> ISSUE_TYPE = new ParameterizedTypeReference<GitHubIssue>() {}; private static final ParameterizedTypeReference<GitHubReadIssue> ISSUE_TYPE = new ParameterizedTypeReference<GitHubReadIssue>() {};
private static final Map<TicketType, Label> 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 Logger logger;
private final GitHubProperties properties; private final GitHubProperties properties;
private final ExecutorService executorService; private final ExecutorService executorService;
public GitHub(@Qualifier("tracker") RestTemplateBuilder templateBuilder, Logger logger, GitHubProperties properties, public GitHub(@Qualifier("tracker") RestTemplateBuilder templateBuilder, Logger logger, GitHubProperties properties,
ExecutorService executorService) { ExecutorService executorService) {
@@ -129,7 +137,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
ticketIds.forEach(ticketId -> { ticketIds.forEach(ticketId -> {
GitHubIssue ticket = findTicket(repositoryName, ticketId); GitHubReadIssue ticket = findTicket(repositoryName, ticketId);
if (ticket != null) { if (ticket != null) {
tickets.add(toTicket(ticket)); tickets.add(toTicket(ticket));
} }
@@ -214,7 +222,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
parameters.put("repoName", repositoryName); parameters.put("repoName", repositoryName);
operations.exchange(MILESTONES_URI_TEMPLATE, HttpMethod.POST, operations.exchange(MILESTONES_URI_TEMPLATE, HttpMethod.POST,
new HttpEntity<Object>(githubMilestone.toMilestone(), httpHeaders), GitHubIssue.Milestone.class, parameters); new HttpEntity<Object>(githubMilestone.toMilestone(), httpHeaders), Milestone.class, parameters);
} }
/* /*
@@ -243,29 +251,31 @@ class GitHub extends GitHubSupport implements IssueTracker {
logger.log(moduleIteration, "Creating release ticket…"); logger.log(moduleIteration, "Creating release ticket…");
doCreateTicket(moduleIteration, Tracker.releaseTicketSummary(moduleIteration)); doCreateTicket(moduleIteration, Tracker.releaseTicketSummary(moduleIteration), TicketType.Task);
} }
@Override @Override
public Ticket createTicket(ModuleIteration moduleIteration, String text) { public Ticket createTicket(ModuleIteration moduleIteration, String text, TicketType ticketType) {
logger.log(moduleIteration, "Creating ticket…"); logger.log(moduleIteration, "Creating ticket…");
return doCreateTicket(moduleIteration, text); return doCreateTicket(moduleIteration, text, ticketType);
} }
private Ticket doCreateTicket(ModuleIteration moduleIteration, String text) { private Ticket doCreateTicket(ModuleIteration moduleIteration, String text, TicketType ticketType) {
HttpHeaders httpHeaders = new HttpHeaders();
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName(); String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
Milestone milestone = getMilestone(moduleIteration, repositoryName); 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<String, Object> parameters = newUrlTemplateVariables(); Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("repoName", repositoryName); parameters.put("repoName", repositoryName);
GitHubIssue body = operations.exchange(ISSUES_URI_TEMPLATE, HttpMethod.POST, GitHubReadIssue body = operations.exchange(ISSUES_URI_TEMPLATE, HttpMethod.POST,
new HttpEntity<Object>(gitHubIssue, httpHeaders), GitHubIssue.class, parameters).getBody(); new HttpEntity<Object>(gitHubIssue), GitHubReadIssue.class, parameters).getBody();
return toTicket(body); return toTicket(body);
} }
@@ -300,9 +310,9 @@ class GitHub extends GitHubSupport implements IssueTracker {
parameters.put("repoName", repositoryName); parameters.put("repoName", repositoryName);
parameters.put("id", stripHash(releaseTicketFor)); 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(); new HttpEntity<>(edit, new HttpHeaders()), ISSUE_TYPE, parameters).getBody();
return toTicket(response); return toTicket(response);
@@ -328,12 +338,12 @@ class GitHub extends GitHubSupport implements IssueTracker {
Assert.notNull(module, "ModuleIteration must not be null."); Assert.notNull(module, "ModuleIteration must not be null.");
Ticket releaseTicketFor = getReleaseTicketFor(module); Ticket releaseTicketFor = getReleaseTicketFor(module);
GitHubIssue response = close(module, releaseTicketFor); GitHubReadIssue response = close(module, releaseTicketFor);
return toTicket(response); return toTicket(response);
} }
private GitHubIssue close(ModuleIteration module, Ticket ticket) { private GitHubReadIssue close(ModuleIteration module, Ticket ticket) {
String repositoryName = GitProject.of(module.getProject()).getRepositoryName(); String repositoryName = GitProject.of(module.getProject()).getRepositoryName();
@@ -341,7 +351,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
parameters.put("repoName", repositoryName); parameters.put("repoName", repositoryName);
parameters.put("id", stripHash(ticket)); 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, return operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.PATCH,
new HttpEntity<>(edit, new HttpHeaders()), ISSUE_TYPE, parameters).getBody(); 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()), doWithPaging(MILESTONE_URI, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()),
MILESTONES_TYPE, milestones -> { MILESTONES_TYPE, milestones -> {
Optional<GitHubIssue.Milestone> milestone = milestones.stream(). // Optional<Milestone> milestone = milestones.stream(). //
filter(m -> m.matches(moduleIteration)). // filter(m -> m.matches(moduleIteration)). //
findFirst(). // findFirst(). //
map(m -> { map(m -> {
@@ -448,21 +458,21 @@ class GitHub extends GitHubSupport implements IssueTracker {
.collect(Tickets.toTicketsCollector()); .collect(Tickets.toTicketsCollector());
} }
List<GitHubIssue> findGitHubIssues(ModuleIteration moduleIteration, List<TicketReference> ticketReferences) { List<GitHubReadIssue> findGitHubIssues(ModuleIteration moduleIteration, List<TicketReference> ticketReferences) {
logger.log(moduleIteration, "Looking up GitHub issues from milestone …"); logger.log(moduleIteration, "Looking up GitHub issues from milestone …");
Map<String, GitHubIssue> issues = getIssuesFor(moduleIteration, false, true) Map<String, GitHubReadIssue> issues = getIssuesFor(moduleIteration, false, true)
.collect(Collectors.toMap(GitHubIssue::getId, Function.identity())); .collect(Collectors.toMap(GitHubIssue::getId, Function.identity()));
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName(); String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
logger.log(moduleIteration, "Resolving GitHub issues …"); logger.log(moduleIteration, "Resolving GitHub issues …");
Collection<GitHubIssue> foundIssues = ExecutionUtils.runAndReturn(executorService, Collection<GitHubReadIssue> foundIssues = ExecutionUtils.runAndReturn(executorService,
Streamable.of(() -> ticketReferences.stream().filter(it -> it.getId().startsWith("#"))), Streamable.of(() -> ticketReferences.stream().filter(it -> it.getId().startsWith("#"))),
ticketReference -> getTicket(issues, repositoryName, ticketReference)); ticketReference -> getTicket(issues, repositoryName, ticketReference));
List<GitHubIssue> gitHubIssues = foundIssues.stream().filter(it -> { List<GitHubReadIssue> gitHubIssues = foundIssues.stream().filter(it -> {
Ticket ticket = toTicket(it); Ticket ticket = toTicket(it);
return !ticket.isReleaseTicketFor(moduleIteration) && !ticket.isReleaseTicket(); return !ticket.isReleaseTicketFor(moduleIteration) && !ticket.isReleaseTicket();
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@@ -472,7 +482,8 @@ class GitHub extends GitHubSupport implements IssueTracker {
return gitHubIssues; return gitHubIssues;
} }
private GitHubIssue getTicket(Map<String, GitHubIssue> cache, String repositoryName, TicketReference reference) { private GitHubReadIssue getTicket(Map<String, GitHubReadIssue> cache, String repositoryName,
TicketReference reference) {
if (cache.containsKey(reference.getId())) { if (cache.containsKey(reference.getId())) {
return cache.get(reference.getId()); return cache.get(reference.getId());
@@ -493,7 +504,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
* @param ticketId * @param ticketId
* @return * @return
*/ */
private GitHubIssue findTicket(String repositoryName, String ticketId) { private GitHubReadIssue findTicket(String repositoryName, String ticketId) {
Map<String, Object> parameters = newUrlTemplateVariables(); Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("repoName", repositoryName); parameters.put("repoName", repositoryName);
@@ -503,7 +514,6 @@ class GitHub extends GitHubSupport implements IssueTracker {
return operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.GET, return operations.exchange(ISSUE_BY_ID_URI_TEMPLATE, HttpMethod.GET,
new HttpEntity<>(new HttpHeaders()), ISSUE_TYPE, parameters).getBody(); new HttpEntity<>(new HttpHeaders()), ISSUE_TYPE, parameters).getBody();
} catch (HttpStatusCodeException e) { } catch (HttpStatusCodeException e) {
if (e.getStatusCode() == HttpStatus.NOT_FOUND) { if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
@@ -522,7 +532,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
logger.log(module, "Preparing GitHub Release …"); logger.log(module, "Preparing GitHub Release …");
List<GitHubIssue> gitHubIssues = findGitHubIssues(module, ticketReferences); List<GitHubReadIssue> gitHubIssues = findGitHubIssues(module, ticketReferences);
ArtifactVersion version = ArtifactVersion.of(module); ArtifactVersion version = ArtifactVersion.of(module);
DocumentationMetadata documentation = DocumentationMetadata.of(module.getProject(), version); DocumentationMetadata documentation = DocumentationMetadata.of(module.getProject(), version);
@@ -608,7 +618,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
parameters); parameters);
} }
private Stream<GitHubIssue> getIssuesFor(ModuleIteration moduleIteration, boolean forCurrentUser, private Stream<GitHubReadIssue> getIssuesFor(ModuleIteration moduleIteration, boolean forCurrentUser,
boolean ignoreMissingMilestone) { boolean ignoreMissingMilestone) {
String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName(); String repositoryName = GitProject.of(moduleIteration.getProject()).getRepositoryName();
@@ -619,7 +629,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
return Stream.empty(); return Stream.empty();
} }
GitHubIssue.Milestone milestone = optionalMilestone.orElseThrow(() -> noSuchMilestone(moduleIteration)); Milestone milestone = optionalMilestone.orElseThrow(() -> noSuchMilestone(moduleIteration));
Map<String, Object> parameters = newUrlTemplateVariables(); Map<String, Object> parameters = newUrlTemplateVariables();
parameters.put("repoName", repositoryName); parameters.put("repoName", repositoryName);
@@ -634,9 +644,9 @@ class GitHub extends GitHubSupport implements IssueTracker {
return getForIssues(ISSUES_BY_MILESTONE_URI_TEMPLATE, parameters); return getForIssues(ISSUES_BY_MILESTONE_URI_TEMPLATE, parameters);
} }
private Stream<GitHubIssue> getForIssues(String template, Map<String, Object> parameters) { private Stream<GitHubReadIssue> getForIssues(String template, Map<String, Object> parameters) {
List<GitHubIssue> issues = new ArrayList<>(); List<GitHubReadIssue> issues = new ArrayList<>();
doWithPaging(template, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()), ISSUES_TYPE, doWithPaging(template, HttpMethod.GET, parameters, new HttpEntity<>(new HttpHeaders()), ISSUES_TYPE,
tickets -> { tickets -> {
issues.addAll(tickets); issues.addAll(tickets);
@@ -661,7 +671,7 @@ class GitHub extends GitHubSupport implements IssueTracker {
} }
private static Ticket toTicket(GitHubIssue issue) { 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()));
} }
} }

View File

@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * 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 * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,100 +15,24 @@
*/ */
package org.springframework.data.release.issues.github; 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 * @author Mark Paluch
*/ */
@Value public interface GitHubIssue {
class GitHubIssue implements Comparable<GitHubIssue> {
String number, title, state, url; String getNumber();
GitHubUser user;
List<Object> assignees;
String htmlUrl;
Object milestone;
PullRequest pullRequest;
List<Label> labels;
public GitHubIssue(String number, String title, String state, String url, GitHubUser user, List<Object> assignees, default String getId() {
@JsonProperty("html_url") String htmlUrl, Object milestone, @JsonProperty("pull_request") PullRequest pullRequest, return getNumber() == null ? null : "#".concat(getNumber());
List<Label> labels) {
this.number = number;
this.title = title;
this.state = state;
this.url = url;
this.user = user;
this.assignees = assignees;
this.htmlUrl = htmlUrl;
this.milestone = milestone;
this.pullRequest = pullRequest;
this.labels = labels;
} }
public static GitHubIssue of(String title, Milestone milestone) { String getTitle();
return new GitHubIssue(null, title, null, null, null, null, null, milestone.number, null, null);
}
public static GitHubIssue assignedTo(String username) { String getState();
Assert.hasText(username, "Username must not be null or empty!");
return new GitHubIssue(null, null, null, null, null, Collections.singletonList(username), null, null, null, null);
}
public GitHubIssue close() {
return new GitHubIssue(this.number, this.title, "closed", null, null, this.assignees, null, this.milestone, null,
null);
}
public String getId() {
return number == null ? null : "#".concat(number);
}
@Override
public int compareTo(GitHubIssue o) {
int number = this.number != null ? Integer.parseInt(this.number) : -1;
int other = o.number != null ? Integer.parseInt(o.number) : -1;
return Integer.compare(number, other);
}
/** /**
* @author Oliver Gierke * @return HTML URL.
* @author Mark Paluch
*/ */
@Value String getUrl();
static class Milestone {
Long number;
String title, description, state;
public static Milestone of(String title, String description) {
return new Milestone(null, title, description, null);
}
public boolean matches(ModuleIteration moduleIteration) {
return title.contains(moduleIteration.getShortVersionString());
}
@JsonIgnore
public boolean isOpen() {
return "open".equals(state);
}
public Milestone markReleased() {
return new Milestone(number, null, null, "closed");
}
}
} }

View File

@@ -17,7 +17,6 @@ package org.springframework.data.release.issues.github;
import lombok.Value; import lombok.Value;
import org.springframework.data.release.issues.github.GitHubIssue.Milestone;
import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.ModuleIteration;
/** /**

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2014-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
*
* 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 java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Read-representation of a GitHub issue.
*
* @author Oliver Gierke
* @author Mark Paluch
*/
@Value
class GitHubReadIssue implements Comparable<GitHubReadIssue>, GitHubIssue {
String number, title, state, url;
GitHubUser user;
List<GitHubUser> assignees;
Milestone milestone;
PullRequest pullRequest;
List<Label> labels;
public GitHubReadIssue(String number, String title, String state, @JsonProperty("html_url") String url,
GitHubUser user, List<GitHubUser> assignees, Milestone milestone,
@JsonProperty("pull_request") PullRequest pullRequest, List<Label> labels) {
this.number = number;
this.title = title;
this.state = state;
this.url = url;
this.user = user;
this.assignees = assignees;
this.milestone = milestone;
this.pullRequest = pullRequest;
this.labels = labels;
}
@Override
public int compareTo(GitHubReadIssue o) {
int number = this.number != null ? Integer.parseInt(this.number) : -1;
int other = o.number != null ? Integer.parseInt(o.number) : -1;
return Integer.compare(number, other);
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2014-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
*
* 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.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.With;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.util.Assert;
/**
* @author Oliver Gierke
* @author Mark Paluch
*/
@Value
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@With
class GitHubWriteIssue implements GitHubIssue {
String number, title, state;
List<Object> assignees;
Long milestone;
List<String> labels;
@Override
public String getUrl() {
return null;
}
public static GitHubWriteIssue of(String title, Milestone milestone) {
return new GitHubWriteIssue(null, title, null, null, milestone.getNumber(), null);
}
public static GitHubWriteIssue assignedTo(String username) {
Assert.hasText(username, "Username must not be null or empty!");
return new GitHubWriteIssue(null, null, null, Collections.singletonList(username), null, null);
}
public GitHubWriteIssue close() {
return new GitHubWriteIssue(this.number, this.title, "closed", this.assignees, null, null);
}
public GitHubWriteIssue withLabel(String labelName) {
List<String> labels = new ArrayList<>(this.labels == null ? Collections.emptyList() : this.labels);
labels.add(labelName);
return withLabels(labels);
}
}

View File

@@ -33,7 +33,12 @@ import org.springframework.data.util.Streamable;
* *
* @author Mark Paluch * @author Mark Paluch
*/ */
public class LabelConfiguration implements Streamable<Label> { class LabelConfiguration implements Streamable<Label> {
public static final Label TYPE_DEPENDENCY_UPGRADE = LabelFactories.TYPE_LABEL.apply("dependency-upgrade",
"A dependency upgrade");
public static final Label TYPE_TASK = LabelFactories.TYPE_LABEL.apply("task", "A general task");
private final Set<Label> labels; private final Set<Label> labels;
@@ -131,11 +136,11 @@ public class LabelConfiguration implements Streamable<Label> {
configurer.register(LabelFactories.TYPE_LABEL, "blocker", "An issue that is blocking us from releasing"); configurer.register(LabelFactories.TYPE_LABEL, "blocker", "An issue that is blocking us from releasing");
configurer.register(LabelFactories.TYPE_LABEL, "bug", "A general bug"); configurer.register(LabelFactories.TYPE_LABEL, "bug", "A general bug");
configurer.register(LabelFactories.TYPE_LABEL, "dependency-upgrade", "A dependency upgrade"); configurer.register(TYPE_DEPENDENCY_UPGRADE);
configurer.register(LabelFactories.TYPE_LABEL, "documentation", "A documentation update"); configurer.register(LabelFactories.TYPE_LABEL, "documentation", "A documentation update");
configurer.register(LabelFactories.TYPE_LABEL, "enhancement", "A general enhancement"); configurer.register(LabelFactories.TYPE_LABEL, "enhancement", "A general enhancement");
configurer.register(LabelFactories.TYPE_LABEL, "regression", "A regression from a previous release"); configurer.register(LabelFactories.TYPE_LABEL, "regression", "A regression from a previous release");
configurer.register(LabelFactories.TYPE_LABEL, "task", "A general task"); configurer.register(TYPE_TASK);
}); });
return configuration; return configuration;

View File

@@ -0,0 +1,50 @@
/*
* 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
*
* 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.model.ModuleIteration;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* @author Oliver Gierke
* @author Mark Paluch
*/
@Value
class Milestone {
Long number;
String title, description, state;
public static Milestone of(String title, String description) {
return new Milestone(null, title, description, null);
}
public boolean matches(ModuleIteration moduleIteration) {
return title.contains(moduleIteration.getShortVersionString());
}
@JsonIgnore
public boolean isOpen() {
return "open".equals(state);
}
public Milestone markReleased() {
return new Milestone(number, null, null, "closed");
}
}

View File

@@ -317,7 +317,7 @@ class Jira implements JiraConnector {
} }
@Override @Override
public Ticket createTicket(ModuleIteration moduleIteration, String text) { public Ticket createTicket(ModuleIteration moduleIteration, String text, TicketType ticketType) {
Assert.notNull(moduleIteration, "ModuleIteration must not be null."); Assert.notNull(moduleIteration, "ModuleIteration must not be null.");

View File

@@ -156,7 +156,8 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests {
github.createReleaseTicket(BUILD_HOPPER_RC1); github.createReleaseTicket(BUILD_HOPPER_RC1);
verify(postRequestedFor(urlPathMatching(ISSUES_URI)) verify(postRequestedFor(urlPathMatching(ISSUES_URI))
.withRequestBody(equalToJson("{\"title\":\"Release 1.8 RC1 (Hopper)\",\"milestone\":45}"))); .withRequestBody(
equalToJson("{\"title\":\"Release 1.8 RC1 (Hopper)\",\"milestone\":45,\"labels\":[ \"type: task\" ]}")));
} }
@Test // #5 @Test // #5

View File

@@ -25,11 +25,10 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest; import org.springframework.boot.test.autoconfigure.json.JsonTest;
import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.json.JacksonTester;
import org.springframework.data.release.issues.github.GitHubIssue.Milestone;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
/** /**
* Unit tests for {@link GitHubIssue}. * Unit tests for {@link GitHubWriteIssue}.
* *
* @author Mark Paluch * @author Mark Paluch
*/ */