diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java index 39e94996ac..4fffec4562 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -37,6 +37,7 @@ import org.springframework.boot.build.DeployedPlugin; import org.springframework.boot.build.MavenRepositoryPlugin; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.Module; +import org.springframework.boot.build.bom.bomr.MoveToSnapshots; import org.springframework.boot.build.bom.bomr.UpgradeBom; /** @@ -63,6 +64,7 @@ public class BomPlugin implements Plugin { project); project.getTasks().create("bomrCheck", CheckBom.class, bom); project.getTasks().create("bomrUpgrade", UpgradeBom.class, bom); + project.getTasks().create("moveToSnapshots", MoveToSnapshots.class, bom); new PublishingCustomizer(project, bom).customize(); } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java index 34a48d26c2..8f938b755e 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java @@ -17,6 +17,7 @@ package org.springframework.boot.build.bom.bomr; import java.io.StringReader; +import java.net.URI; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -49,13 +50,13 @@ final class MavenMetadataVersionResolver implements VersionResolver { private final RestTemplate rest; - private final Collection repositoryUrls; + private final Collection repositoryUrls; - MavenMetadataVersionResolver(Collection repositoryUrls) { + MavenMetadataVersionResolver(Collection repositoryUrls) { this(new RestTemplate(Collections.singletonList(new StringHttpMessageConverter())), repositoryUrls); } - MavenMetadataVersionResolver(RestTemplate restTemplate, Collection repositoryUrls) { + MavenMetadataVersionResolver(RestTemplate restTemplate, Collection repositoryUrls) { this.rest = restTemplate; this.repositoryUrls = repositoryUrls; } @@ -63,15 +64,15 @@ final class MavenMetadataVersionResolver implements VersionResolver { @Override public SortedSet resolveVersions(String groupId, String artifactId) { Set versions = new HashSet<>(); - for (String repositoryUrl : this.repositoryUrls) { + for (URI repositoryUrl : this.repositoryUrls) { versions.addAll(resolveVersions(groupId, artifactId, repositoryUrl)); } return versions.stream().map(DependencyVersion::parse).collect(Collectors.toCollection(TreeSet::new)); } - private Set resolveVersions(String groupId, String artifactId, String repositoryUrl) { + private Set resolveVersions(String groupId, String artifactId, URI repositoryUrl) { Set versions = new HashSet<>(); - String url = repositoryUrl + "/" + groupId.replace('.', '/') + "/" + artifactId + "/maven-metadata.xml"; + URI url = repositoryUrl.resolve(groupId.replace('.', '/') + "/" + artifactId + "/maven-metadata.xml"); try { String metadata = this.rest.getForObject(url, String.class); Document metadataDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder() diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java new file mode 100644 index 0000000000..322ecd5011 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java @@ -0,0 +1,60 @@ +/* + * Copyright 2021-2023 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; + +import java.net.URI; + +import javax.inject.Inject; + +import org.gradle.api.Task; + +import org.springframework.boot.build.bom.BomExtension; + +/** + * A {@link Task} to move to snapshot dependencies. + * + * @author Andy Wilkinson + */ +public abstract class MoveToSnapshots extends UpgradeDependencies { + + private final URI REPOSITORY_URI = URI.create("https://repo.spring.io/snapshot/"); + + @Inject + public MoveToSnapshots(BomExtension bom) { + super(bom); + getRepositoryUris().add(this.REPOSITORY_URI); + } + + @Override + protected String issueTitle(Upgrade upgrade) { + String snapshotVersion = upgrade.getVersion().toString(); + String releaseVersion = snapshotVersion.substring(0, snapshotVersion.length() - "-SNAPSHOT".length()); + return "Upgrade to " + upgrade.getLibrary().getName() + " " + releaseVersion; + } + + @Override + protected String commitMessage(Upgrade upgrade, int issueNumber) { + return "Start building against " + upgrade.getLibrary().getName() + " " + releaseVersion(upgrade) + " snapshots" + + "\n\nSee gh-" + issueNumber; + } + + private String releaseVersion(Upgrade upgrade) { + String snapshotVersion = upgrade.getVersion().toString(); + return snapshotVersion.substring(0, snapshotVersion.length() - "-SNAPSHOT".length()); + } + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java index 2a00ab5556..16e4dbdc06 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java @@ -16,40 +16,14 @@ package org.springframework.boot.build.bom.bomr; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; -import java.util.function.Predicate; -import java.util.regex.Pattern; +import java.net.URI; import javax.inject.Inject; -import org.gradle.api.DefaultTask; -import org.gradle.api.InvalidUserDataException; import org.gradle.api.Task; import org.gradle.api.artifacts.repositories.MavenArtifactRepository; -import org.gradle.api.internal.tasks.userinput.UserInputHandler; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.TaskExecutionException; -import org.gradle.api.tasks.options.Option; import org.springframework.boot.build.bom.BomExtension; -import org.springframework.boot.build.bom.Library; -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.Issue; -import org.springframework.boot.build.bom.bomr.github.Milestone; -import org.springframework.util.StringUtils; /** * {@link Task} to upgrade the libraries managed by a bom. @@ -57,161 +31,27 @@ import org.springframework.util.StringUtils; * @author Andy Wilkinson * @author Moritz Halbritter */ -public class UpgradeBom extends DefaultTask { - - private final Set repositoryUrls = new LinkedHashSet<>(); - - private final BomExtension bom; - - private String milestone; - - private String libraries; - - private int threads = 2; +public abstract class UpgradeBom extends UpgradeDependencies { @Inject public UpgradeBom(BomExtension bom) { - this.bom = bom; + super(bom); getProject().getRepositories().withType(MavenArtifactRepository.class, (repository) -> { - String repositoryUrl = repository.getUrl().toString(); - if (!repositoryUrl.endsWith("snapshot")) { - this.repositoryUrls.add(repositoryUrl); + URI repositoryUrl = repository.getUrl(); + if (!repositoryUrl.toString().endsWith("snapshot")) { + getRepositoryUris().add(repositoryUrl); } }); } - @Option(option = "milestone", description = "Milestone to which dependency upgrade issues should be assigned") - public void setMilestone(String milestone) { - this.milestone = milestone; - } - - @Option(option = "threads", description = "Number of Threads to use for update resolution") - public void setThreads(String threads) { - this.threads = Integer.parseInt(threads); - } - - @Input - public String getMilestone() { - return this.milestone; - } - - @Option(option = "libraries", description = "Regular expression that identifies the libraries to upgrade") - public void setLibraries(String libraries) { - this.libraries = libraries; - } - - @Input - @org.gradle.api.tasks.Optional - public String getLibraries() { - return this.libraries; - } - - @TaskAction - @SuppressWarnings("deprecation") - void upgradeDependencies() { - GitHubRepository repository = createGitHub().getRepository(this.bom.getUpgrade().getGitHub().getOrganization(), - this.bom.getUpgrade().getGitHub().getRepository()); - Set availableLabels = repository.getLabels(); - List issueLabels = this.bom.getUpgrade().getGitHub().getIssueLabels(); - if (!availableLabels.containsAll(issueLabels)) { - List unknownLabels = new ArrayList<>(issueLabels); - unknownLabels.removeAll(availableLabels); - throw new InvalidUserDataException( - "Unknown label(s): " + StringUtils.collectionToCommaDelimitedString(unknownLabels)); - } - Milestone milestone = determineMilestone(repository); - List existingUpgradeIssues = repository.findIssues(issueLabels, milestone); - List upgrades = new InteractiveUpgradeResolver(getServices().get(UserInputHandler.class), - new MultithreadedLibraryUpdateResolver(new MavenMetadataVersionResolver(this.repositoryUrls), - this.bom.getUpgrade().getPolicy(), this.threads)) - .resolveUpgrades(matchingLibraries(this.libraries), this.bom.getLibraries()); - Path buildFile = getProject().getBuildFile().toPath(); - Path gradleProperties = new File(getProject().getRootProject().getProjectDir(), "gradle.properties").toPath(); - UpgradeApplicator upgradeApplicator = new UpgradeApplicator(buildFile, gradleProperties); - for (Upgrade upgrade : upgrades) { - String title = "Upgrade to " + upgrade.getLibrary().getName() + " " + upgrade.getVersion(); - Issue existingUpgradeIssue = findExistingUpgradeIssue(existingUpgradeIssues, upgrade); - if (existingUpgradeIssue != null) { - System.out.println(title + " (supersedes #" + existingUpgradeIssue.getNumber() + " " - + existingUpgradeIssue.getTitle() + ")"); - } - else { - System.out.println(title); - } - try { - Path modified = upgradeApplicator.apply(upgrade); - 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() - .waitFor() != 0) { - throw new IllegalStateException("git add failed"); - } - if (new ProcessBuilder().command("git", "commit", "-m", title + "\n\nCloses gh-" + issueNumber).start() - .waitFor() != 0) { - throw new IllegalStateException("git commit failed"); - } - } - catch (IOException ex) { - throw new TaskExecutionException(this, ex); - } - catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - } - - private List matchingLibraries(String pattern) { - if (pattern == null) { - return this.bom.getLibraries(); - } - Predicate libraryPredicate = Pattern.compile(pattern).asPredicate(); - List matchingLibraries = this.bom.getLibraries().stream() - .filter((library) -> libraryPredicate.test(library.getName())).toList(); - if (matchingLibraries.isEmpty()) { - throw new InvalidUserDataException("No libraries matched '" + pattern + "'"); - } - return matchingLibraries; - } - - private Issue findExistingUpgradeIssue(List 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() { - Properties bomrProperties = new Properties(); - try (Reader reader = new FileReader(new File(System.getProperty("user.home"), ".bomr.properties"))) { - bomrProperties.load(reader); - String username = bomrProperties.getProperty("bomr.github.username"); - String password = bomrProperties.getProperty("bomr.github.password"); - return GitHub.withCredentials(username, password); - } - catch (IOException ex) { - throw new InvalidUserDataException("Failed to load .bomr.properties from user home", ex); - } + @Override + protected String issueTitle(Upgrade upgrade) { + return "Upgrade to " + upgrade.getLibrary().getName() + " " + upgrade.getVersion(); } - private Milestone determineMilestone(GitHubRepository repository) { - if (this.milestone == null) { - return null; - } - List milestones = repository.getMilestones(); - Optional matchingMilestone = milestones.stream() - .filter((milestone) -> milestone.getName().equals(this.milestone)).findFirst(); - if (!matchingMilestone.isPresent()) { - throw new InvalidUserDataException("Unknown milestone: " + this.milestone); - } - return matchingMilestone.get(); + @Override + protected String commitMessage(Upgrade upgrade, int issueNumber) { + return issueTitle(upgrade) + "\n\nCloses gh-" + issueNumber; } } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java new file mode 100644 index 0000000000..359355a1ba --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java @@ -0,0 +1,222 @@ +/* + * Copyright 2012-2023 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; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.net.URI; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +import javax.inject.Inject; + +import org.gradle.api.DefaultTask; +import org.gradle.api.InvalidUserDataException; +import org.gradle.api.internal.tasks.userinput.UserInputHandler; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.TaskExecutionException; +import org.gradle.api.tasks.options.Option; + +import org.springframework.boot.build.bom.BomExtension; +import org.springframework.boot.build.bom.Library; +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.Issue; +import org.springframework.boot.build.bom.bomr.github.Milestone; +import org.springframework.util.StringUtils; + +/** + * Base class for tasks that upgrade dependencies in a bom. + * + * @author Andy Wilkinson + * @author Moritz Halbritter + */ +public abstract class UpgradeDependencies extends DefaultTask { + + private final BomExtension bom; + + @Inject + public UpgradeDependencies(BomExtension bom) { + this.bom = bom; + getThreads().convention(2); + } + + @Input + @Option(option = "milestone", description = "Milestone to which dependency upgrade issues should be assigned") + public abstract Property getMilestone(); + + @Input + @Optional + @Option(option = "threads", description = "Number of Threads to use for update resolution") + public abstract Property getThreads(); + + @Input + @Optional + @Option(option = "libraries", description = "Regular expression that identifies the libraries to upgrade") + public abstract Property getLibraries(); + + @Input + abstract ListProperty getRepositoryUris(); + + @TaskAction + void upgradeDependencies() { + GitHubRepository repository = createGitHub().getRepository(this.bom.getUpgrade().getGitHub().getOrganization(), + this.bom.getUpgrade().getGitHub().getRepository()); + List issueLabels = verifyLabels(repository); + Milestone milestone = determineMilestone(repository); + List upgrades = resolveUpgrades(); + applyUpgrades(repository, issueLabels, milestone, upgrades); + } + + private void applyUpgrades(GitHubRepository repository, List issueLabels, Milestone milestone, + List upgrades) { + Path buildFile = getProject().getBuildFile().toPath(); + Path gradleProperties = new File(getProject().getRootProject().getProjectDir(), "gradle.properties").toPath(); + UpgradeApplicator upgradeApplicator = new UpgradeApplicator(buildFile, gradleProperties); + List existingUpgradeIssues = repository.findIssues(issueLabels, milestone); + for (Upgrade upgrade : upgrades) { + String title = issueTitle(upgrade); + Issue existingUpgradeIssue = findExistingUpgradeIssue(existingUpgradeIssues, upgrade); + if (existingUpgradeIssue != null) { + if (existingUpgradeIssue.getState() == Issue.State.CLOSED) { + System.out.println(title + " (supersedes #" + existingUpgradeIssue.getNumber() + " " + + existingUpgradeIssue.getTitle() + ")"); + } + else { + System.out.println(title + " (completes existing upgrade)"); + } + } + else { + System.out.println(title); + } + try { + Path modified = upgradeApplicator.apply(upgrade); + int issueNumber; + if (existingUpgradeIssue != null && existingUpgradeIssue.getState() == Issue.State.OPEN) { + issueNumber = existingUpgradeIssue.getNumber(); + } + else { + issueNumber = repository.openIssue(title, + (existingUpgradeIssue != null) ? "Supersedes #" + existingUpgradeIssue.getNumber() : "", + issueLabels, milestone); + if (existingUpgradeIssue != null && existingUpgradeIssue.getState() == Issue.State.CLOSED) { + existingUpgradeIssue.label(Arrays.asList("type: task", "status: superseded")); + } + } + if (new ProcessBuilder().command("git", "add", modified.toFile().getAbsolutePath()).start() + .waitFor() != 0) { + throw new IllegalStateException("git add failed"); + } + if (new ProcessBuilder().command("git", "commit", "-m", commitMessage(upgrade, issueNumber)).start() + .waitFor() != 0) { + throw new IllegalStateException("git commit failed"); + } + } + catch (IOException ex) { + throw new TaskExecutionException(this, ex); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + + private List verifyLabels(GitHubRepository repository) { + Set availableLabels = repository.getLabels(); + List issueLabels = this.bom.getUpgrade().getGitHub().getIssueLabels(); + if (!availableLabels.containsAll(issueLabels)) { + List unknownLabels = new ArrayList<>(issueLabels); + unknownLabels.removeAll(availableLabels); + throw new InvalidUserDataException( + "Unknown label(s): " + StringUtils.collectionToCommaDelimitedString(unknownLabels)); + } + return issueLabels; + } + + private GitHub createGitHub() { + Properties bomrProperties = new Properties(); + try (Reader reader = new FileReader(new File(System.getProperty("user.home"), ".bomr.properties"))) { + bomrProperties.load(reader); + String username = bomrProperties.getProperty("bomr.github.username"); + String password = bomrProperties.getProperty("bomr.github.password"); + return GitHub.withCredentials(username, password); + } + catch (IOException ex) { + throw new InvalidUserDataException("Failed to load .bomr.properties from user home", ex); + } + } + + private Milestone determineMilestone(GitHubRepository repository) { + List milestones = repository.getMilestones(); + java.util.Optional matchingMilestone = milestones.stream() + .filter((milestone) -> milestone.getName().equals(getMilestone().get())).findFirst(); + if (!matchingMilestone.isPresent()) { + throw new InvalidUserDataException("Unknown milestone: " + getMilestone().get()); + } + return matchingMilestone.get(); + } + + private Issue findExistingUpgradeIssue(List 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; + } + + @SuppressWarnings("deprecation") + private List resolveUpgrades() { + List upgrades = new InteractiveUpgradeResolver(getServices().get(UserInputHandler.class), + new MultithreadedLibraryUpdateResolver(new MavenMetadataVersionResolver(getRepositoryUris().get()), + this.bom.getUpgrade().getPolicy(), getThreads().get())).resolveUpgrades( + matchingLibraries(getLibraries().getOrNull()), this.bom.getLibraries()); + return upgrades; + } + + private List matchingLibraries(String pattern) { + if (pattern == null) { + return this.bom.getLibraries(); + } + Predicate libraryPredicate = Pattern.compile(pattern).asPredicate(); + List matchingLibraries = this.bom.getLibraries().stream() + .filter((library) -> libraryPredicate.test(library.getName())).toList(); + if (matchingLibraries.isEmpty()) { + throw new InvalidUserDataException("No libraries matched '" + pattern + "'"); + } + return matchingLibraries; + } + + protected abstract String issueTitle(Upgrade upgrade); + + protected abstract String commitMessage(Upgrade upgrade, int issueNumber); + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/Issue.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/Issue.java index c19b223d3d..262e1efc07 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/Issue.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/Issue.java @@ -35,10 +35,13 @@ public class Issue { private final String title; - Issue(RestTemplate rest, int number, String title) { + private final State state; + + Issue(RestTemplate rest, int number, String title, State state) { this.rest = rest; this.number = number; this.title = title; + this.state = state; } public int getNumber() { @@ -49,6 +52,10 @@ public class Issue { return this.title; } + public State getState() { + return this.state; + } + /** * Labels the issue with the given {@code labels}. Any existing labels are removed. * @param labels the labels to apply to the issue @@ -58,4 +65,30 @@ public class Issue { this.rest.put("issues/" + this.number + "/labels", body); } + public enum State { + + /** + * The issue is open. + */ + OPEN, + + /** + * The issue is closed. + */ + CLOSED; + + static State of(String state) { + if ("open".equals(state)) { + return OPEN; + } + if ("closed".equals(state)) { + return CLOSED; + } + else { + throw new IllegalArgumentException("Unknown state '" + state + "'"); + } + } + + } + } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHubRepository.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHubRepository.java index 24f7bbee97..28027e2c88 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHubRepository.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHubRepository.java @@ -84,7 +84,8 @@ final class StandardGitHubRepository implements GitHubRepository { 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"))); + (issue) -> new Issue(this.rest, (Integer) issue.get("number"), (String) issue.get("title"), + Issue.State.of((String) issue.get("state")))); } @SuppressWarnings({ "rawtypes", "unchecked" })