Automatically supersede existing upgrade issue when running Bomr
Closes gh-25345
This commit is contained in:
parent
017dbe608f
commit
bf33e7ef7e
|
|
@ -23,6 +23,7 @@ import java.io.Reader;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
@ -41,6 +42,7 @@ import org.gradle.api.tasks.options.Option;
|
||||||
import org.springframework.boot.build.bom.BomExtension;
|
import org.springframework.boot.build.bom.BomExtension;
|
||||||
import org.springframework.boot.build.bom.bomr.github.GitHub;
|
import org.springframework.boot.build.bom.bomr.github.GitHub;
|
||||||
import org.springframework.boot.build.bom.bomr.github.GitHubRepository;
|
import org.springframework.boot.build.bom.bomr.github.GitHubRepository;
|
||||||
|
import org.springframework.boot.build.bom.bomr.github.Issue;
|
||||||
import org.springframework.boot.build.bom.bomr.github.Milestone;
|
import org.springframework.boot.build.bom.bomr.github.Milestone;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
|
@ -83,6 +85,7 @@ public class UpgradeBom extends DefaultTask {
|
||||||
"Unknown label(s): " + StringUtils.collectionToCommaDelimitedString(unknownLabels));
|
"Unknown label(s): " + StringUtils.collectionToCommaDelimitedString(unknownLabels));
|
||||||
}
|
}
|
||||||
Milestone milestone = determineMilestone(repository);
|
Milestone milestone = determineMilestone(repository);
|
||||||
|
List<Issue> existingUpgradeIssues = repository.findIssues(issueLabels, milestone);
|
||||||
List<Upgrade> upgrades = new InteractiveUpgradeResolver(
|
List<Upgrade> upgrades = new InteractiveUpgradeResolver(
|
||||||
new MavenMetadataVersionResolver(Arrays.asList("https://repo1.maven.org/maven2/")),
|
new MavenMetadataVersionResolver(Arrays.asList("https://repo1.maven.org/maven2/")),
|
||||||
this.bom.getUpgrade().getPolicy(), getServices().get(UserInputHandler.class))
|
this.bom.getUpgrade().getPolicy(), getServices().get(UserInputHandler.class))
|
||||||
|
|
@ -92,10 +95,22 @@ public class UpgradeBom extends DefaultTask {
|
||||||
UpgradeApplicator upgradeApplicator = new UpgradeApplicator(buildFile, gradleProperties);
|
UpgradeApplicator upgradeApplicator = new UpgradeApplicator(buildFile, gradleProperties);
|
||||||
for (Upgrade upgrade : upgrades) {
|
for (Upgrade upgrade : upgrades) {
|
||||||
String title = "Upgrade to " + upgrade.getLibrary().getName() + " " + upgrade.getVersion();
|
String title = "Upgrade to " + upgrade.getLibrary().getName() + " " + upgrade.getVersion();
|
||||||
System.out.println(title);
|
Issue existingUpgradeIssue = findExistingUpgradeIssue(existingUpgradeIssues, upgrade);
|
||||||
|
if (existingUpgradeIssue != null) {
|
||||||
|
System.out.println(title + " (supersedes #" + existingUpgradeIssue.getNumber() + " "
|
||||||
|
+ existingUpgradeIssue.getTitle() + ")");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.out.println(title);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Path modified = upgradeApplicator.apply(upgrade);
|
Path modified = upgradeApplicator.apply(upgrade);
|
||||||
int issueNumber = repository.openIssue(title, issueLabels, milestone);
|
int issueNumber = repository.openIssue(title,
|
||||||
|
(existingUpgradeIssue != null) ? "Supersedes #" + existingUpgradeIssue.getNumber() : "",
|
||||||
|
issueLabels, milestone);
|
||||||
|
if (existingUpgradeIssue != null) {
|
||||||
|
existingUpgradeIssue.label(Arrays.asList("type: task", "status: superseded"));
|
||||||
|
}
|
||||||
if (new ProcessBuilder().command("git", "add", modified.toFile().getAbsolutePath()).start()
|
if (new ProcessBuilder().command("git", "add", modified.toFile().getAbsolutePath()).start()
|
||||||
.waitFor() != 0) {
|
.waitFor() != 0) {
|
||||||
throw new IllegalStateException("git add failed");
|
throw new IllegalStateException("git add failed");
|
||||||
|
|
@ -114,6 +129,17 @@ public class UpgradeBom extends DefaultTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Issue findExistingUpgradeIssue(List<Issue> existingUpgradeIssues, Upgrade upgrade) {
|
||||||
|
String toMatch = "Upgrade to " + upgrade.getLibrary().getName();
|
||||||
|
for (Issue existingUpgradeIssue : existingUpgradeIssues) {
|
||||||
|
if (existingUpgradeIssue.getTitle().substring(0, existingUpgradeIssue.getTitle().lastIndexOf(' '))
|
||||||
|
.equals(toMatch)) {
|
||||||
|
return existingUpgradeIssue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private GitHub createGitHub() {
|
private GitHub createGitHub() {
|
||||||
Properties bomrProperties = new Properties();
|
Properties bomrProperties = new Properties();
|
||||||
try (Reader reader = new FileReader(new File(System.getProperty("user.home"), ".bomr.properties"))) {
|
try (Reader reader = new FileReader(new File(System.getProperty("user.home"), ".bomr.properties"))) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2021 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.
|
||||||
|
|
@ -29,11 +29,12 @@ public interface GitHubRepository {
|
||||||
* Opens a new issue with the given title. The given {@code labels} will be applied to
|
* Opens a new issue with the given title. The given {@code labels} will be applied to
|
||||||
* the issue and it will be assigned to the given {@code milestone}.
|
* the issue and it will be assigned to the given {@code milestone}.
|
||||||
* @param title the title of the issue
|
* @param title the title of the issue
|
||||||
|
* @param body the body of the issue
|
||||||
* @param labels the labels to apply to the issue
|
* @param labels the labels to apply to the issue
|
||||||
* @param milestone the milestone to assign the issue to
|
* @param milestone the milestone to assign the issue to
|
||||||
* @return the number of the new issue
|
* @return the number of the new issue
|
||||||
*/
|
*/
|
||||||
int openIssue(String title, List<String> labels, Milestone milestone);
|
int openIssue(String title, String body, List<String> labels, Milestone milestone);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the labels in the repository.
|
* Returns the labels in the repository.
|
||||||
|
|
@ -47,4 +48,13 @@ public interface GitHubRepository {
|
||||||
*/
|
*/
|
||||||
List<Milestone> getMilestones();
|
List<Milestone> getMilestones();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds issues that have the given {@code labels} and are assigned to the given
|
||||||
|
* {@code milestone}.
|
||||||
|
* @param labels issue labels
|
||||||
|
* @param milestone assigned milestone
|
||||||
|
* @return the matching issues
|
||||||
|
*/
|
||||||
|
List<Issue> findIssues(List<String> labels, Milestone milestone);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2021 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.boot.build.bom.bomr.github;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal representation of a GitHub issue.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class Issue {
|
||||||
|
|
||||||
|
private final RestTemplate rest;
|
||||||
|
|
||||||
|
private final int number;
|
||||||
|
|
||||||
|
private final String title;
|
||||||
|
|
||||||
|
Issue(RestTemplate rest, int number, String title) {
|
||||||
|
this.rest = rest;
|
||||||
|
this.number = number;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber() {
|
||||||
|
return this.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Labels the issue with the given {@code labels}. Any existing labels are removed.
|
||||||
|
* @param labels the labels to apply to the issue
|
||||||
|
*/
|
||||||
|
public void label(List<String> labels) {
|
||||||
|
Map<String, List<String>> body = Collections.singletonMap("labels", labels);
|
||||||
|
this.rest.put("issues/" + this.number + "/labels", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2021 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.
|
||||||
|
|
@ -40,16 +40,17 @@ final class StandardGitHubRepository implements GitHubRepository {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public int openIssue(String title, List<String> labels, Milestone milestone) {
|
public int openIssue(String title, String body, List<String> labels, Milestone milestone) {
|
||||||
Map<String, Object> body = new HashMap<>();
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
body.put("title", title);
|
requestBody.put("title", title);
|
||||||
if (milestone != null) {
|
if (milestone != null) {
|
||||||
body.put("milestone", milestone.getNumber());
|
requestBody.put("milestone", milestone.getNumber());
|
||||||
}
|
}
|
||||||
if (!labels.isEmpty()) {
|
if (!labels.isEmpty()) {
|
||||||
body.put("labels", labels);
|
requestBody.put("labels", labels);
|
||||||
}
|
}
|
||||||
ResponseEntity<Map> response = this.rest.postForEntity("issues", body, Map.class);
|
requestBody.put("body", body);
|
||||||
|
ResponseEntity<Map> response = this.rest.postForEntity("issues", requestBody, Map.class);
|
||||||
return (Integer) response.getBody().get("number");
|
return (Integer) response.getBody().get("number");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,6 +65,14 @@ final class StandardGitHubRepository implements GitHubRepository {
|
||||||
(milestone) -> new Milestone((String) milestone.get("title"), (Integer) milestone.get("number")));
|
(milestone) -> new Milestone((String) milestone.get("title"), (Integer) milestone.get("number")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Issue> findIssues(List<String> labels, Milestone milestone) {
|
||||||
|
return get(
|
||||||
|
"issues?per_page=100&state=all&labels=" + String.join(",", labels) + "&milestone="
|
||||||
|
+ milestone.getNumber(),
|
||||||
|
(issue) -> new Issue(this.rest, (Integer) issue.get("number"), (String) issue.get("title")));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private <T> List<T> get(String name, Function<Map<String, Object>, T> mapper) {
|
private <T> List<T> get(String name, Function<Map<String, Object>, T> mapper) {
|
||||||
ResponseEntity<List> response = this.rest.getForEntity(name, List.class);
|
ResponseEntity<List> response = this.rest.getForEntity(name, List.class);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue