From 178305c85409b61a283f101ca888f29978a248f6 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 6 Jul 2026 20:49:14 +0100 Subject: [PATCH] Add support for upgrading dependencies using release train versions --- .../boot/build/bom/BomExtension.java | 35 ++++++++- .../boot/build/bom/Library.java | 34 +++++++-- .../bomr/MavenMetadataVersionResolver.java | 3 +- .../boot/build/bom/bomr/MoveToSnapshots.java | 11 ++- .../bom/bomr/ReleaseTrainVersionResolver.java | 75 +++++++++++++++++++ .../bomr/StandardLibraryUpdateResolver.java | 12 ++- .../boot/build/bom/bomr/UpgradeBom.java | 8 +- .../build/bom/bomr/UpgradeDependencies.java | 51 +++++++++---- .../boot/build/bom/bomr/VersionResolver.java | 4 +- .../bom/bomr/github/GitHubRepository.java | 8 ++ .../build/bom/bomr/github/StandardGitHub.java | 7 +- .../bomr/github/StandardGitHubRepository.java | 15 ++++ .../antora/AntoraAsciidocAttributesTests.java | 5 +- .../boot/build/bom/LibraryTests.java | 9 ++- .../bomr/InteractiveUpgradeResolverTests.java | 2 +- .../bom/bomr/UpgradeApplicatorTests.java | 4 +- .../boot/build/bom/bomr/UpgradeTests.java | 4 +- .../spring-boot-dependencies/build.gradle | 44 +++++------ 18 files changed, 251 insertions(+), 80 deletions(-) create mode 100644 buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/ReleaseTrainVersionResolver.java diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java index 3d4dc4b6d6c..6bc68a37a3f 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; @@ -44,6 +45,7 @@ import org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithH import org.springframework.boot.build.bom.Library.BomAlignment; import org.springframework.boot.build.bom.Library.DependencyVersionAlignment; import org.springframework.boot.build.bom.Library.Exclusion; +import org.springframework.boot.build.bom.Library.FirstParty; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.ImportedBom; import org.springframework.boot.build.bom.Library.LibraryVersion; @@ -113,8 +115,14 @@ public class BomExtension { (version != null) ? version : ""); action.execute(libraryHandler); LibraryVersion libraryVersion = new LibraryVersion(DependencyVersion.parse(libraryHandler.version)); + FirstParty firstParty = null; + if (libraryHandler.firstParty) { + String releaseTrainId = (libraryHandler.releaseTrainId != null) ? libraryHandler.releaseTrainId + : name.replace(' ', '-').toLowerCase(Locale.ROOT); + firstParty = new FirstParty(releaseTrainId); + } addLibrary(new Library(name, libraryHandler.calendarName, libraryVersion, libraryHandler.groups, - libraryHandler.upgradePolicy, libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots, + libraryHandler.upgradePolicy, libraryHandler.prohibitedVersions, firstParty, versionAlignment(libraryHandler), libraryHandler.alignWith.bomAlignment, libraryHandler.linkRootName, libraryHandler.links)); } @@ -205,7 +213,9 @@ public class BomExtension { private final AlignWithHandler alignWith; - private boolean considerSnapshots; + private boolean firstParty = false; + + private String releaseTrainId = null; private String version; @@ -226,8 +236,15 @@ public class BomExtension { this.version = version; } - public void considerSnapshots() { - this.considerSnapshots = true; + public void firstParty() { + this.firstParty = true; + } + + public void firstParty(Action action) { + FirstPartyHandler handler = new FirstPartyHandler(); + action.execute(handler); + this.firstParty = true; + this.releaseTrainId = handler.releaseTrainId; } public void setCalendarName(String calendarName) { @@ -486,6 +503,16 @@ public class BomExtension { } + public static class FirstPartyHandler { + + private String releaseTrainId; + + public void setReleaseTrainId(String releaseTrainId) { + this.releaseTrainId = releaseTrainId; + } + + } + } public static class LinksHandler { diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java index 0e1b335772d..6d8d2ab7534 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java @@ -73,7 +73,7 @@ public class Library { private final List prohibitedVersions; - private final boolean considerSnapshots; + private final FirstParty firstParty; private final VersionAlignment versionAlignment; @@ -94,7 +94,7 @@ public class Library { * @param upgradePolicy the upgrade policy of the library, or {@code null} to use the * containing bom's policy * @param prohibitedVersions version of the library that are prohibited - * @param considerSnapshots whether to consider snapshots + * @param firstParty configuration for a first-party library * @param versionAlignment version alignment, if any, for the library * @param bomAlignment the bom, if any, that this library should align with * @param linkRootName the root name to use when generating link variable or @@ -102,7 +102,7 @@ public class Library { * @param links a list of HTTP links relevant to the library */ public Library(String name, String calendarName, LibraryVersion version, List groups, - UpgradePolicy upgradePolicy, List prohibitedVersions, boolean considerSnapshots, + UpgradePolicy upgradePolicy, List prohibitedVersions, FirstParty firstParty, VersionAlignment versionAlignment, BomAlignment bomAlignment, String linkRootName, Map> links) { this.name = name; @@ -113,7 +113,7 @@ public class Library { : name.toLowerCase(Locale.ENGLISH).replace(' ', '-') + ".version"; this.upgradePolicy = upgradePolicy; this.prohibitedVersions = prohibitedVersions; - this.considerSnapshots = considerSnapshots; + this.firstParty = firstParty; this.versionAlignment = versionAlignment; this.bomAlignment = bomAlignment; this.linkRootName = (linkRootName != null) ? linkRootName : generateLinkRootName(name); @@ -152,8 +152,12 @@ public class Library { return this.prohibitedVersions; } - public boolean isConsiderSnapshots() { - return this.considerSnapshots; + public FirstParty getFirstParty() { + return this.firstParty; + } + + public boolean isFirstParty() { + return this.firstParty != null; } public VersionAlignment getVersionAlignment() { @@ -193,8 +197,8 @@ public class Library { public Library withVersion(LibraryVersion version) { return new Library(this.name, this.calendarName, version, this.groups, this.upgradePolicy, - this.prohibitedVersions, this.considerSnapshots, this.versionAlignment, this.bomAlignment, - this.linkRootName, this.links); + this.prohibitedVersions, this.firstParty, this.versionAlignment, this.bomAlignment, this.linkRootName, + this.links); } /** @@ -695,6 +699,20 @@ public class Library { } + public static class FirstParty { + + private final String releaseTrainId; + + public FirstParty(String releaseTrainId) { + this.releaseTrainId = releaseTrainId; + } + + public String getReleaseTrainId() { + return this.releaseTrainId; + } + + } + public record Link(String rootName, Function factory, List packages) { private static final Pattern PACKAGE_EXPAND = Pattern.compile("^(.*)\\[(.*)\\]$"); 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 c9030510e76..da13e946292 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 @@ -34,6 +34,7 @@ import org.gradle.internal.artifacts.repositories.AuthenticationSupportedInterna import org.w3c.dom.Document; import org.w3c.dom.NodeList; +import org.springframework.boot.build.bom.Library; import org.springframework.boot.build.bom.bomr.version.DependencyVersion; import org.springframework.boot.build.xml.XmlDocument; import org.springframework.http.HttpStatus; @@ -67,7 +68,7 @@ final class MavenMetadataVersionResolver implements VersionResolver { } @Override - public SortedSet resolveVersions(String groupId, String artifactId) { + public SortedSet resolveVersions(String groupId, String artifactId, Library library) { Set versions = new HashSet<>(); for (MavenArtifactRepository repository : this.repositories) { versions.addAll(resolveVersions(groupId, artifactId, repository)); 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 index 44b2e193add..af10d3ce3d5 100644 --- 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 @@ -66,14 +66,17 @@ public abstract class MoveToSnapshots extends UpgradeDependencies { } @Override - protected String commitMessage(Upgrade upgrade, int issueNumber) { - return "Start building against " + upgrade.toRelease().getNameAndVersion() + " snapshots" + "\n\nSee gh-" - + issueNumber; + protected String commitMessage(Upgrade upgrade, Integer issueNumber) { + String message = "Start building against " + upgrade.toRelease().getNameAndVersion() + " snapshots"; + if (issueNumber != null) { + message += "\n\nSee gh-" + issueNumber; + } + return message; } @Override protected boolean eligible(Library library) { - return library.isConsiderSnapshots() && super.eligible(library); + return library.isFirstParty() && super.eligible(library); } @Override diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/ReleaseTrainVersionResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/ReleaseTrainVersionResolver.java new file mode 100644 index 00000000000..2b7e6022b20 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/ReleaseTrainVersionResolver.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-present 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.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import tools.jackson.databind.json.JsonMapper; +import tools.jackson.databind.type.TypeFactory; + +import org.springframework.boot.build.bom.Library; +import org.springframework.boot.build.bom.bomr.github.GitHub; +import org.springframework.boot.build.bom.bomr.version.DependencyVersion; + +/** + * A {@link VersionResolver version resolver} that resolves versions from a release train. + * + * @author Andy Wilkinson + */ +public class ReleaseTrainVersionResolver implements VersionResolver { + + private final Map> versions; + + ReleaseTrainVersionResolver(GitHub gitHub, String releaseTrain) { + this.versions = parseVersions(getRawVersions(gitHub, releaseTrain)); + } + + private static Map> getRawVersions(GitHub gitHub, String releaseTrain) { + String content = gitHub.getRepository("spring-io", "release-train") + .getContent("release-versions.json", releaseTrain); + TypeFactory typeFactory = TypeFactory.createDefaultInstance(); + return JsonMapper.shared() + .readerFor(typeFactory.constructMapLikeType(TreeMap.class, typeFactory.constructType(String.class), + typeFactory.constructCollectionLikeType(ArrayList.class, String.class))) + .readValue(content); + } + + private static Map> parseVersions(Map> rawVersions) { + Map> parsedVersions = new TreeMap<>(); + rawVersions.forEach((project, versions) -> parsedVersions.put(project, + new TreeSet<>(versions.stream().map(DependencyVersion::parse).collect(Collectors.toSet())))); + return parsedVersions; + } + + @Override + public SortedSet resolveVersions(String groupId, String artifactId, Library library) { + if (!library.isFirstParty()) { + return Collections.emptySortedSet(); + } + SortedSet result = this.versions.getOrDefault(library.getFirstParty().getReleaseTrainId(), + Collections.emptySortedSet()); + return result; + } + +} diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java index 851fafb7801..21de96f428e 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java @@ -110,15 +110,13 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver { for (Group group : library.getGroups()) { for (Module module : group.getModules()) { moduleVersions.put(group.getId() + ":" + module.getName(), - getLaterVersionsForModule(group.getId(), module.getName(), library)); + getVersionsForModule(group.getId(), module.getName(), library)); } for (ImportedBom bom : group.getBoms()) { - moduleVersions.put(group.getId() + ":" + bom, - getLaterVersionsForModule(group.getId(), bom.name(), library)); + moduleVersions.put(group.getId() + ":" + bom, getVersionsForModule(group.getId(), bom.name(), library)); } for (String plugin : group.getPlugins()) { - moduleVersions.put(group.getId() + ":" + plugin, - getLaterVersionsForModule(group.getId(), plugin, library)); + moduleVersions.put(group.getId() + ":" + plugin, getVersionsForModule(group.getId(), plugin, library)); } } List versionOptions = new ArrayList<>(); @@ -146,8 +144,8 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver { return missingModules; } - private SortedSet getLaterVersionsForModule(String groupId, String artifactId, Library library) { - return this.versionResolver.resolveVersions(groupId, artifactId); + private SortedSet getVersionsForModule(String groupId, String artifactId, Library library) { + return this.versionResolver.resolveVersions(groupId, artifactId, library); } } 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 682bf9e46bc..541b2db759d 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 @@ -62,8 +62,12 @@ public abstract class UpgradeBom extends UpgradeDependencies { } @Override - protected String commitMessage(Upgrade upgrade, int issueNumber) { - return issueTitle(upgrade) + "\n\nCloses gh-" + issueNumber; + protected String commitMessage(Upgrade upgrade, Integer issueNumber) { + String message = issueTitle(upgrade); + if (issueNumber != null) { + message += "\n\nCloses gh-" + issueNumber; + } + return message; } @Override 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 index db4d4662c80..1c02a17b8bf 100644 --- 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 @@ -92,6 +92,11 @@ public abstract class UpgradeDependencies extends DefaultTask { @Option(option = "milestone", description = "Milestone to which dependency upgrade issues should be assigned") public abstract Property getMilestone(); + @Input + @Optional + @Option(option = "release-train", description = "Release train from which dependency versions should be resolved") + public abstract Property getReleaseTrain(); + @Input @Optional @Option(option = "threads", description = "Number of Threads to use for update resolution") @@ -108,12 +113,18 @@ public abstract class UpgradeDependencies extends DefaultTask { description = "Whether to perform a dry run that doesn't open issues or change the bom") public abstract Property getDryRun(); + @Input + @Optional + @Option(option = "no-issues", description = "Whether to disable issue creation") + public abstract Property getNoIssues(); + @Input abstract ListProperty getRepositoryNames(); @TaskAction void upgradeDependencies() { - GitHubRepository repository = createGitHub().getRepository(this.bom.getUpgrade().getGitHub().getOrganization(), + GitHub gitHub = createGitHub("bomr.github.password"); + GitHubRepository repository = gitHub.getRepository(this.bom.getUpgrade().getGitHub().getOrganization(), this.bom.getUpgrade().getGitHub().getRepository()); List issueLabels = verifyLabels(repository); Milestone milestone = determineMilestone(repository); @@ -138,15 +149,18 @@ public abstract class UpgradeDependencies extends DefaultTask { Issue existingUpgradeIssue = findExistingUpgradeIssue(existingUpgradeIssues, upgrade); try { Path modified = this.upgradeApplicator.apply(upgrade); - String title = issueTitle(upgrade); - String body = issueBody(upgrade, existingUpgradeIssue); - int issueNumber = getOrOpenUpgradeIssue(repository, issueLabels, milestone, title, body, - existingUpgradeIssue); - if (existingUpgradeIssue != null && existingUpgradeIssue.getState() == Issue.State.CLOSED) { - existingUpgradeIssue.label(Arrays.asList("type: task", "status: superseded")); + Integer issueNumber = null; + if (!getNoIssues().getOrElse(Boolean.FALSE)) { + String title = issueTitle(upgrade); + String body = issueBody(upgrade, existingUpgradeIssue); + issueNumber = getOrOpenUpgradeIssue(repository, issueLabels, milestone, title, body, + existingUpgradeIssue); + if (existingUpgradeIssue != null && existingUpgradeIssue.getState() == Issue.State.CLOSED) { + existingUpgradeIssue.label(Arrays.asList("type: task", "status: superseded")); + } + System.out.println(" Issue: " + issueNumber + " - " + title + + getExistingUpgradeIssueMessageDetails(existingUpgradeIssue)); } - System.out.println(" Issue: " + issueNumber + " - " + title - + getExistingUpgradeIssueMessageDetails(existingUpgradeIssue)); if (new ProcessBuilder().command("git", "add", modified.toFile().getAbsolutePath()) .start() .waitFor() != 0) { @@ -156,7 +170,9 @@ public abstract class UpgradeDependencies extends DefaultTask { if (new ProcessBuilder().command("git", "commit", "-m", commitMessage).start().waitFor() != 0) { throw new IllegalStateException("git commit failed"); } - System.out.println(" Commit: " + commitMessage.substring(0, commitMessage.indexOf('\n'))); + int newlineIndex = commitMessage.indexOf('\n'); + System.out.println(" Commit: " + + ((newlineIndex > -1) ? commitMessage.substring(0, newlineIndex) : commitMessage)); } catch (IOException ex) { throw new TaskExecutionException(this, ex); @@ -198,12 +214,12 @@ public abstract class UpgradeDependencies extends DefaultTask { return issueLabels; } - private GitHub createGitHub() { + private GitHub createGitHub(String passwordProperty) { 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"); + String password = bomrProperties.getProperty(passwordProperty); return GitHub.withCredentials(username, password); } catch (IOException ex) { @@ -245,12 +261,19 @@ public abstract class UpgradeDependencies extends DefaultTask { } private LibraryUpdateResolver getLibraryUpdateResolver(Milestone milestone) { - VersionResolver versionResolver = new MavenMetadataVersionResolver(getRepositories()); + VersionResolver versionResolver = getVersionResolver(); LibraryUpdateResolver libraryResolver = new StandardLibraryUpdateResolver(versionResolver, createVersionOptionResolver(milestone)); return new MultithreadedLibraryUpdateResolver(getThreads().get(), libraryResolver); } + private VersionResolver getVersionResolver() { + String releaseTrain = getReleaseTrain().getOrNull(); + return (releaseTrain != null) + ? new ReleaseTrainVersionResolver(createGitHub("bomr.github.release-train-token"), releaseTrain) + : new MavenMetadataVersionResolver(getRepositories()); + } + private Collection getRepositories() { return getRepositoryNames().map(this::asRepositories).get(); } @@ -311,7 +334,7 @@ public abstract class UpgradeDependencies extends DefaultTask { return libraryPredicate.test(library.getName()); } - protected abstract String commitMessage(Upgrade upgrade, int issueNumber); + protected abstract String commitMessage(Upgrade upgrade, Integer issueNumber); protected String issueTitle(Upgrade upgrade) { return "Upgrade to " + upgrade.toRelease().getNameAndVersion(); diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/VersionResolver.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/VersionResolver.java index 63abbf470f3..97bc2e770ae 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/VersionResolver.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/VersionResolver.java @@ -18,6 +18,7 @@ package org.springframework.boot.build.bom.bomr; import java.util.SortedSet; +import org.springframework.boot.build.bom.Library; import org.springframework.boot.build.bom.bomr.version.DependencyVersion; /** @@ -32,8 +33,9 @@ interface VersionResolver { * {@code groupId} and {@code artifactId}. * @param groupId module's group ID * @param artifactId module's artifact ID + * @param library the library to which the module belongs * @return the available versions */ - SortedSet resolveVersions(String groupId, String artifactId); + SortedSet resolveVersions(String groupId, String artifactId, Library library); } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/GitHubRepository.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/GitHubRepository.java index 4c6973e1b57..3eb55f92e4c 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/GitHubRepository.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/GitHubRepository.java @@ -58,4 +58,12 @@ public interface GitHubRepository { */ List findIssues(List labels, Milestone milestone); + /** + * Returns the content of the repository at the given {@code path} and {@code ref}. + * @param path the path in the repository + * @param ref the ref in the repository, typically a branch name + * @return the content, possibly {@code null} + */ + String getContent(String path, String ref); + } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHub.java b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHub.java index dcd9ae5aada..5c249a9cd72 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHub.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHub.java @@ -16,8 +16,6 @@ package org.springframework.boot.build.bom.bomr.github; -import java.util.Base64; - import org.springframework.http.MediaType; import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; import org.springframework.web.client.RestClient; @@ -50,10 +48,7 @@ final class StandardGitHub implements GitHub { .withJsonConverter(new JacksonJsonHttpMessageConverter())) .requestInterceptor((request, body, execution) -> { request.getHeaders().add("User-Agent", StandardGitHub.this.username); - request.getHeaders() - .add("Authorization", "Basic " + Base64.getEncoder() - .encodeToString( - (StandardGitHub.this.username + ":" + StandardGitHub.this.password).getBytes())); + request.getHeaders().add("Authorization", "Bearer " + StandardGitHub.this.password); request.getHeaders().add("Accept", MediaType.APPLICATION_JSON_VALUE); return execution.execute(request, body); }) 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 c766f38ec1b..72e7d46f48a 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 @@ -16,8 +16,10 @@ package org.springframework.boot.build.bom.bomr.github; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.OffsetDateTime; +import java.util.Base64; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -94,6 +96,19 @@ final class StandardGitHubRepository implements GitHubRepository { Issue.State.of((String) issue.get("state")))); } + @Override + @SuppressWarnings("rawtypes") + public String getContent(String path, String ref) { + Map body = this.rest.get().uri("contents/" + path + "?ref=" + ref).retrieve().body(Map.class); + return base64Decode((String) body.get("content")); + + } + + private String base64Decode(String encoded) { + return new String(Base64.getDecoder().decode(encoded.replace("\n", "").getBytes(StandardCharsets.UTF_8)), + StandardCharsets.UTF_8); + } + @SuppressWarnings({ "rawtypes", "unchecked" }) private List get(String name, Function, T> mapper) { ResponseEntity response = this.rest.get().uri(name).retrieve().toEntity(List.class); diff --git a/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java b/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java index b8506232ba7..25a843c203c 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.build.bom.Library; import org.springframework.boot.build.bom.Library.BomAlignment; +import org.springframework.boot.build.bom.Library.FirstParty; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.LibraryVersion; import org.springframework.boot.build.bom.Library.Link; @@ -234,11 +235,11 @@ class AntoraAsciidocAttributesTests { LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3")); List groups = Collections.emptyList(); List prohibitedVersion = Collections.emptyList(); - boolean considerSnapshots = false; + FirstParty firstParty = null; VersionAlignment versionAlignment = null; BomAlignment alignsWithBom = null; String linkRootName = null; - Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots, + Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, firstParty, versionAlignment, alignsWithBom, linkRootName, links); return library; } diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java index 4d35d610a76..eae37d7960e 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java @@ -23,6 +23,7 @@ import java.util.Map; import org.junit.jupiter.api.Test; import org.springframework.boot.build.bom.Library.BomAlignment; +import org.springframework.boot.build.bom.Library.FirstParty; import org.springframework.boot.build.bom.Library.Group; import org.springframework.boot.build.bom.Library.LibraryVersion; import org.springframework.boot.build.bom.Library.Link; @@ -46,12 +47,12 @@ class LibraryTests { LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3")); List groups = Collections.emptyList(); List prohibitedVersion = Collections.emptyList(); - boolean considerSnapshots = false; + FirstParty firstParty = null; VersionAlignment versionAlignment = null; BomAlignment alignsWithBom = null; String linkRootName = null; Map> links = Collections.emptyMap(); - Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots, + Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, firstParty, versionAlignment, alignsWithBom, linkRootName, links); assertThat(library.getLinkRootName()).isEqualTo("spring-framework"); } @@ -63,12 +64,12 @@ class LibraryTests { LibraryVersion version = new LibraryVersion(DependencyVersion.parse("1.2.3")); List groups = Collections.emptyList(); List prohibitedVersion = Collections.emptyList(); - boolean considerSnapshots = false; + FirstParty firstParty = null; VersionAlignment versionAlignment = null; BomAlignment alignsWithBom = null; String linkRootName = "spring-data"; Map> links = Collections.emptyMap(); - Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots, + Library library = new Library(name, calendarName, version, groups, null, prohibitedVersion, firstParty, versionAlignment, alignsWithBom, linkRootName, links); assertThat(library.getLinkRootName()).isEqualTo("spring-data"); } diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java index cc9726bf028..ed05c931fe1 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java @@ -48,7 +48,7 @@ class InteractiveUpgradeResolverTests { List libraries = new ArrayList<>(); DependencyVersion version = DependencyVersion.parse("1.0.0"); LibraryVersion libraryVersion = new LibraryVersion(version); - Library library = new Library("test", null, libraryVersion, null, null, null, false, null, null, null, null); + Library library = new Library("test", null, libraryVersion, null, null, null, null, null, null, null, null); libraries.add(library); List librariesToUpgrade = new ArrayList<>(); librariesToUpgrade.add(library); diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java index d7732ee7233..aa7a8d7e90a 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java @@ -53,7 +53,7 @@ class UpgradeApplicatorTests { File gradleProperties = new File(this.temp, "gradle.properties"); FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties); Library activeMq = new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")), null, - null, null, false, null, null, null, Collections.emptyMap()); + null, null, null, null, null, null, Collections.emptyMap()); new UpgradeApplicator(bom.toPath(), gradleProperties.toPath()) .apply(new Upgrade(activeMq, activeMq.withVersion(new LibraryVersion(DependencyVersion.parse("5.16"))))); String bomContents = Files.readString(bom.toPath()); @@ -67,7 +67,7 @@ class UpgradeApplicatorTests { File gradleProperties = new File(this.temp, "gradle.properties"); FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties); Library kotlin = new Library("Kotlin", null, new LibraryVersion(DependencyVersion.parse("1.3.70")), null, null, - null, false, null, null, null, Collections.emptyMap()); + null, null, null, null, null, Collections.emptyMap()); new UpgradeApplicator(bom.toPath(), gradleProperties.toPath()) .apply(new Upgrade(kotlin, kotlin.withVersion(new LibraryVersion(DependencyVersion.parse("1.4"))))); Properties properties = new Properties(); diff --git a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java index 1220c6b2505..4aebeaaca87 100644 --- a/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java +++ b/buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java @@ -34,7 +34,7 @@ class UpgradeTests { @Test void createToRelease() { Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null, null, - false, null, null, null, null); + null, null, null, null, null); Upgrade upgrade = new Upgrade(from, from.withVersion(new LibraryVersion(DependencyVersion.parse("1.0.1")))); assertThat(upgrade.from().getNameAndVersion()).isEqualTo("Test 1.0.0"); assertThat(upgrade.to().getNameAndVersion()).isEqualTo("Test 1.0.1"); @@ -44,7 +44,7 @@ class UpgradeTests { @Test void createToSnapshot() { Library from = new Library("Test", null, new LibraryVersion(DependencyVersion.parse("1.0.0")), null, null, null, - false, null, null, null, null); + null, null, null, null, null); Upgrade upgrade = new Upgrade(from, from.withVersion(new LibraryVersion(DependencyVersion.parse("1.0.1-SNAPSHOT"))), from.withVersion(new LibraryVersion(DependencyVersion.parse("1.0.1")))); diff --git a/platform/spring-boot-dependencies/build.gradle b/platform/spring-boot-dependencies/build.gradle index afea10864cb..ea85079eaf0 100644 --- a/platform/spring-boot-dependencies/build.gradle +++ b/platform/spring-boot-dependencies/build.gradle @@ -1541,7 +1541,7 @@ bom { } } library("Micrometer", "1.16.6") { - considerSnapshots() + firstParty() group("io.micrometer") { modules = [ "micrometer-registry-stackdriver" { @@ -1564,7 +1564,7 @@ bom { } } library("Micrometer Tracing", "1.6.6") { - considerSnapshots() + firstParty() alignWith { dependencyManagementDeclaredIn("io.micrometer:micrometer-tracing-bom") { excluding { id -> @@ -1852,7 +1852,7 @@ bom { } } library("R2DBC H2", "1.1.0.RELEASE") { - considerSnapshots() + firstParty() group("io.r2dbc") { modules = [ "r2dbc-h2" @@ -1893,7 +1893,7 @@ bom { } } library("R2DBC Pool", "1.0.2.RELEASE") { - considerSnapshots() + firstParty() group("io.r2dbc") { modules = [ "r2dbc-pool" @@ -1905,7 +1905,7 @@ bom { } } library("R2DBC Postgresql", "1.1.2.RELEASE") { - considerSnapshots() + firstParty() group("org.postgresql") { modules = [ "r2dbc-postgresql" @@ -1916,7 +1916,7 @@ bom { } } library("R2DBC Proxy", "1.1.6.RELEASE") { - considerSnapshots() + firstParty() group("io.r2dbc") { modules = [ "r2dbc-proxy" @@ -1927,7 +1927,7 @@ bom { } } library("R2DBC SPI", "1.0.0.RELEASE") { - considerSnapshots() + firstParty() group("io.r2dbc") { modules = [ "r2dbc-spi" @@ -1974,7 +1974,7 @@ bom { } } library("Reactor Bom", "2025.0.6") { - considerSnapshots() + firstParty() calendarName = "Reactor" group("io.projectreactor") { bom("reactor-bom") @@ -2393,7 +2393,7 @@ bom { } } library("Spring AMQP", "4.0.4") { - considerSnapshots() + firstParty() group("org.springframework.amqp") { bom("spring-amqp-bom") } @@ -2408,7 +2408,7 @@ bom { } } library("Spring Batch", "6.0.4") { - considerSnapshots() + firstParty() group("org.springframework.batch") { bom("spring-batch-bom") } @@ -2423,7 +2423,7 @@ bom { } } library("Spring Data Bom", "2025.1.6") { - considerSnapshots() + firstParty() calendarName = "Spring Data Release" group("org.springframework.data") { bom("spring-data-bom") @@ -2435,7 +2435,7 @@ bom { } } library("Spring Framework", "${springFrameworkVersion}") { - considerSnapshots() + firstParty() group("org.springframework") { bom("spring-framework-bom") } @@ -2453,7 +2453,7 @@ bom { } } library("Spring GraphQL", "2.0.4") { - considerSnapshots() + firstParty() group("org.springframework.graphql") { modules = [ "spring-graphql", @@ -2471,7 +2471,7 @@ bom { } } library("Spring HATEOAS", "3.0.4") { - considerSnapshots() + firstParty() group("org.springframework.hateoas") { modules = [ "spring-hateoas" @@ -2488,7 +2488,7 @@ bom { } } library("Spring Integration", "7.0.5") { - considerSnapshots() + firstParty() group("org.springframework.integration") { bom("spring-integration-bom") } @@ -2503,7 +2503,7 @@ bom { } } library("Spring Kafka", "4.0.6") { - considerSnapshots() + firstParty() group("org.springframework.kafka") { modules = [ "spring-kafka", @@ -2521,7 +2521,7 @@ bom { } } library("Spring LDAP", "4.0.4") { - considerSnapshots() + firstParty() group("org.springframework.ldap") { modules = [ "spring-ldap-core", @@ -2541,7 +2541,7 @@ bom { } } library("Spring Pulsar", "2.0.6") { - considerSnapshots() + firstParty() group("org.springframework.pulsar") { bom("spring-pulsar-bom") } @@ -2556,7 +2556,7 @@ bom { } } library("Spring RESTDocs", "4.0.1") { - considerSnapshots() + firstParty() group("org.springframework.restdocs") { bom("spring-restdocs-bom") } @@ -2571,7 +2571,7 @@ bom { } } library("Spring Security", "7.0.6") { - considerSnapshots() + firstParty() group("org.springframework.security") { bom("spring-security-bom") } @@ -2586,7 +2586,7 @@ bom { } } library("Spring Session", "4.0.4") { - considerSnapshots() + firstParty() prohibit { startsWith(["Apple-", "Bean-", "Corn-", "Dragonfruit-"]) because "Spring Session switched to numeric version numbers" @@ -2609,7 +2609,7 @@ bom { } } library("Spring WS", "5.0.2") { - considerSnapshots() + firstParty() group("org.springframework.ws") { bom("spring-ws-bom") }