diff --git a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java index 03b6f91c4d47b..74936a9ea295a 100644 --- a/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java +++ b/independent-projects/tools/devtools-testing/src/main/java/io/quarkus/devtools/testing/registry/client/TestRegistryClientBuilder.java @@ -572,7 +572,7 @@ private static void persistPlatformCatalog(PlatformCatalog catalog, Path dir) { } } - static Path getRegistryMemberCatalogPath(Path registryDir, ArtifactCoords bom) { + public static Path getRegistryMemberCatalogPath(Path registryDir, ArtifactCoords bom) { return getMemberCatalogPath(registryDir.resolve("members"), bom); } @@ -605,7 +605,7 @@ static Path getRegistryDescriptorPath(Path registryDir) { return registryDir.resolve("config.json"); } - static Path getRegistryDir(Path baseDir, String registryId) { + public static Path getRegistryDir(Path baseDir, String registryId) { return baseDir.resolve(registryId); } diff --git a/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/project/create/ExtensionCatalogFromProvidedPlatformsTest.java b/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/project/create/ExtensionCatalogFromProvidedPlatformsTest.java new file mode 100644 index 0000000000000..94156f51b8dde --- /dev/null +++ b/independent-projects/tools/devtools-testing/src/test/java/io/quarkus/devtools/project/create/ExtensionCatalogFromProvidedPlatformsTest.java @@ -0,0 +1,114 @@ +package io.quarkus.devtools.project.create; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.quarkus.bootstrap.resolver.maven.workspace.ModelUtils; +import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder; +import io.quarkus.maven.ArtifactCoords; +import io.quarkus.registry.ExtensionCatalogResolver; +import io.quarkus.registry.catalog.ExtensionCatalog; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.stream.Collectors; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.assertj.core.util.Arrays; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ExtensionCatalogFromProvidedPlatformsTest extends MultiplePlatformBomsTestBase { + + private static final String MAIN_PLATFORM_KEY = "org.acme.platform"; + + @BeforeAll + public static void setup() throws Exception { + TestRegistryClientBuilder.newInstance() + //.debug() + .baseDir(configDir()) + // registry + .newRegistry("registry.acme.org") + // platform key + .newPlatform(MAIN_PLATFORM_KEY) + // 2.0 STREAM + .newStream("2.0") + // 2.0.4 release + .newRelease("2.0.4") + .quarkusVersion("2.2.2") + // default bom including quarkus-core + essential metadata + .addCoreMember() + // foo platform member + .newMember("acme-foo-bom").addExtension("acme-foo").release() + .stream().platform() + // 1.0 STREAM + .newStream("1.0") + // 1.0.1 release + .newRelease("1.0.1") + .quarkusVersion("1.1.2") + .addCoreMember() + .newMember("acme-foo-bom").addExtension("acme-foo").release() + .newMember("acme-baz-bom").addExtension("acme-baz").release() + .registry() + .newNonPlatformCatalog("1.1.2") + .addExtension("org.acme", "acme-quarkus-other", "5.5.5") + .registry() + .clientBuilder() + .build(); + + enableRegistryClient(); + + // install 1.0.0 version which is not recommended by the registry any more + installNotRecommendedVersion("1.0.1", "1.0.0", "acme-foo-bom"); + installNotRecommendedVersion("1.0.1", "1.0.0", "acme-baz-bom"); + installNotRecommendedVersion("1.0.1", "1.0.0", "quarkus-bom"); + } + + private static void installNotRecommendedVersion(String baseRecommendedVersion, String nonRecommendedVersion, + String memberArtifactId) throws IOException { + Path repoDir = TestRegistryClientBuilder.getMavenRepoDir(configDir()); + Path p = repoDir; + for (String s : MAIN_PLATFORM_KEY.split("\\.")) { + p = p.resolve(s); + } + final Path groupIdDir = p; + + p = groupIdDir.resolve(memberArtifactId).resolve(baseRecommendedVersion) + .resolve(memberArtifactId + "-" + baseRecommendedVersion + ".pom"); + final Model model = ModelUtils.readModel(p); + model.setVersion(nonRecommendedVersion); + for (Dependency d : model.getDependencyManagement().getDependencies()) { + if (baseRecommendedVersion.equals(d.getVersion())) { + d.setVersion(nonRecommendedVersion); + } + } + p = p.getParent().getParent().resolve(nonRecommendedVersion) + .resolve(memberArtifactId + "-" + nonRecommendedVersion + ".pom"); + Files.createDirectories(p.getParent()); + ModelUtils.persistModel(p, model); + + p = TestRegistryClientBuilder.getRegistryMemberCatalogPath( + TestRegistryClientBuilder.getRegistryDir(configDir(), "registry.acme.org"), + new ArtifactCoords(MAIN_PLATFORM_KEY, memberArtifactId, null, "pom", baseRecommendedVersion)); + final String jsonContent = Files.readString(p).replace(baseRecommendedVersion, nonRecommendedVersion); + String jsonName = p.getFileName().toString().replace(baseRecommendedVersion, nonRecommendedVersion); + Files.writeString(p.getParent().resolve(jsonName), jsonContent); + } + + protected String getMainPlatformKey() { + return MAIN_PLATFORM_KEY; + } + + @Test + public void test() throws Exception { + final ExtensionCatalog catalog = ExtensionCatalogResolver.builder().build().resolveExtensionCatalog( + Collections.singletonList(ArtifactCoords.fromString(MAIN_PLATFORM_KEY + ":acme-baz-bom::pom:1.0.0"))); + assertThat(Arrays.asList(new ArtifactCoords[] { + ArtifactCoords.fromString("io.quarkus:quarkus-core:1.1.2"), + ArtifactCoords.fromString(MAIN_PLATFORM_KEY + ":acme-foo:1.0.0"), + ArtifactCoords.fromString(MAIN_PLATFORM_KEY + ":acme-baz:1.0.0"), + ArtifactCoords.fromString("org.acme:acme-quarkus-other:5.5.5") + })).isEqualTo( + catalog.getExtensions().stream().map(e -> e.getArtifact()).collect(Collectors.toList())); + } +} diff --git a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java index fdaaa7e0586f8..78268b40bf0f4 100644 --- a/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java +++ b/independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java @@ -310,6 +310,7 @@ private class ExtensionCatalogBuilder { private final List catalogs = new ArrayList<>(); final Map> registriesByQuarkusCore = new HashMap<>(); private final Map compatibilityCodes = new LinkedHashMap<>(); + final List upstreamQuarkusVersions = new ArrayList<>(1); void addCatalog(ExtensionCatalog c) { catalogs.add(c); @@ -399,10 +400,9 @@ public ExtensionCatalog resolveExtensionCatalog() throws RegistryResolutionExcep private void addOriginPreference(final ExtensionCatalog ec, OriginPreference originPreference) { Map metadata = ec.getMetadata(); if (metadata.isEmpty()) { - metadata = new HashMap<>(); + metadata = new HashMap<>(1); ((JsonExtensionCatalog) ec).setMetadata(metadata); } - metadata.put("origin-preference", originPreference); } @@ -416,17 +416,16 @@ public ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion) throw throw new RegistryResolutionException("No registries configured"); } - return resolveExtensionCatalog(quarkusCoreVersion, new ExtensionCatalogBuilder(), Collections.emptyMap()); + return resolveExtensionCatalog(quarkusCoreVersion, new ExtensionCatalogBuilder(), Collections.emptySet()); } private ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion, - final ExtensionCatalogBuilder catalogBuilder, Map preferredPlatforms) + final ExtensionCatalogBuilder catalogBuilder, Set preferredPlatforms) throws RegistryResolutionException { - final List upstreamQuarkusVersions = new ArrayList<>(1); - collectPlatforms(quarkusCoreVersion, catalogBuilder, upstreamQuarkusVersions, preferredPlatforms); + collectPlatforms(quarkusCoreVersion, catalogBuilder, preferredPlatforms); int i = 0; - while (i < upstreamQuarkusVersions.size()) { - collectPlatforms(upstreamQuarkusVersions.get(i++), catalogBuilder, upstreamQuarkusVersions, preferredPlatforms); + while (i < catalogBuilder.upstreamQuarkusVersions.size()) { + collectPlatforms(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatforms); } return catalogBuilder.build(); } @@ -528,17 +527,17 @@ public ExtensionCatalog resolveExtensionCatalog(StreamCoords streamCoords) throw } @SuppressWarnings("unchecked") - public ExtensionCatalog resolveExtensionCatalog(Collection platforms) + public ExtensionCatalog resolveExtensionCatalog(Collection preferredPlatforms) throws RegistryResolutionException { - if (platforms.isEmpty()) { + if (preferredPlatforms.isEmpty()) { return resolveExtensionCatalog(); } final ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder(); - final Map preferredPlatforms = new LinkedHashMap<>(); + final Set preferredPlatformKeys = new HashSet<>(); String quarkusVersion = null; int platformIndex = 0; - for (ArtifactCoords bom : platforms) { + for (ArtifactCoords bom : preferredPlatforms) { final List registries; try { registries = filterRegistries(r -> r.checkPlatform(bom)); @@ -554,8 +553,30 @@ public ExtensionCatalog resolveExtensionCatalog(Collection platf throw new RuntimeException(buf.toString()); } - final ExtensionCatalog catalog = resolvePlatformExtensions(bom, registries); + if (registries.isEmpty()) { + log.warn("None of the configured registries recognizes platform %s", bom); + continue; + } + + ExtensionCatalog catalog = null; + RegistryExtensionResolver registry = null; + for (int i = 0; i < registries.size(); ++i) { + registry = registries.get(i); + try { + catalog = registry.resolvePlatformExtensions(bom); + break; + } catch (RegistryResolutionException e) { + } + } + if (catalog == null) { + final StringBuilder buf = new StringBuilder(); + buf.append("Failed to resolve platform ").append(bom).append(" using the following registries: "); + buf.append(registries.get(0).getId()); + for (int i = 1; i < registries.size(); ++i) { + buf.append(", ").append(registries.get(i++)); + } + log.warn(buf.toString()); continue; } @@ -571,12 +592,11 @@ public ExtensionCatalog resolveExtensionCatalog(Collection platf o = md.get("platform-key"); if (o != null && o instanceof String) { final String platformKey = o.toString(); - if (preferredPlatforms.containsKey(platformKey)) { + if (!preferredPlatformKeys.add(platformKey)) { continue; } final JsonPlatform p = new JsonPlatform(); p.setPlatformKey(platformKey); - preferredPlatforms.put(platformKey, p); final JsonPlatformStream stream = new JsonPlatformStream(); stream.setId(String.valueOf(md.getOrDefault("stream", "default"))); @@ -598,20 +618,21 @@ public ExtensionCatalog resolveExtensionCatalog(Collection platf } release.setMemberBoms(coords); } + + collectPlatforms(quarkusVersion, catalogBuilder, registry, platformIndex, + p); continue; } } } - - catalogBuilder.addCatalog(catalog); - final OriginPreference originPreference = new OriginPreference(0, ++platformIndex, 1, 1, catalogBuilder.getCompatibilityCode(quarkusVersion)); addOriginPreference(catalog, originPreference); + catalogBuilder.addCatalog(catalog); } return preferredPlatforms.isEmpty() ? catalogBuilder.build() - : resolveExtensionCatalog(quarkusVersion, catalogBuilder, preferredPlatforms); + : resolveExtensionCatalog(quarkusVersion, catalogBuilder, preferredPlatformKeys); } public void clearRegistryCache() throws RegistryResolutionException { @@ -627,27 +648,6 @@ private void ensureRegistriesConfigured() throws RegistryResolutionException { } } - private ExtensionCatalog resolvePlatformExtensions(ArtifactCoords bom, List registries) { - if (registries.isEmpty()) { - log.debug("None of the configured registries recognizes platform %s", bom); - return null; - } - for (RegistryExtensionResolver registry : registries) { - try { - return registry.resolvePlatformExtensions(bom); - } catch (RegistryResolutionException e) { - } - } - final StringBuilder buf = new StringBuilder(); - buf.append("Failed to resolve platform ").append(bom).append(" using the following registries: "); - buf.append(registries.get(0).getId()); - for (int i = 1; i < registries.size(); ++i) { - buf.append(", ").append(registries.get(i++)); - } - log.warn(buf.toString()); - return null; - } - private void appendNonPlatformExtensions( ExtensionCatalogBuilder catalogBuilder, String quarkusVersion) throws RegistryResolutionException { @@ -684,9 +684,8 @@ private int getRegistryIndex(String registryId) { throw new IllegalStateException(buf.toString()); } - private void collectPlatforms(String quarkusCoreVersion, - ExtensionCatalogBuilder catalogBuilder, - Collection upstreamQuarkusVersions, Map preferredPlatforms) + private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder, + Set preferredPlatforms) throws RegistryResolutionException { final List quarkusVersionRegistries = catalogBuilder .getRegistriesForQuarkusCore(quarkusCoreVersion); @@ -700,25 +699,19 @@ private void collectPlatforms(String quarkusCoreVersion, if (platforms.isEmpty()) { continue; } - int platformIndex = 0; - for (Platform p : preferredPlatforms.values()) { - ++platformIndex; - collectPlatforms(quarkusCoreVersion, catalogBuilder, upstreamQuarkusVersions, registry, platformIndex, - p); - } + int platformIndex = preferredPlatforms.size(); for (Platform p : platforms) { - if (preferredPlatforms.containsKey(p.getPlatformKey())) { + if (preferredPlatforms.contains(p.getPlatformKey())) { continue; } ++platformIndex; - collectPlatforms(quarkusCoreVersion, catalogBuilder, upstreamQuarkusVersions, registry, platformIndex, - p); + collectPlatforms(quarkusCoreVersion, catalogBuilder, registry, platformIndex, p); } } } private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder, - Collection upstreamQuarkusVersions, RegistryExtensionResolver registry, int platformIndex, + RegistryExtensionResolver registry, int platformIndex, Platform p) throws RegistryResolutionException { for (PlatformStream s : p.getStreams()) { int releaseIndex = 0; @@ -741,10 +734,9 @@ private void collectPlatforms(String quarkusCoreVersion, ExtensionCatalogBuilder } final String upstreamQuarkusVersion = r.getUpstreamQuarkusCoreVersion(); - if (upstreamQuarkusVersion != null) { - if (!upstreamQuarkusVersions.contains(upstreamQuarkusVersion)) { - upstreamQuarkusVersions.add(upstreamQuarkusVersion); - } + if (upstreamQuarkusVersion != null + && !catalogBuilder.upstreamQuarkusVersions.contains(upstreamQuarkusVersion)) { + catalogBuilder.upstreamQuarkusVersions.add(upstreamQuarkusVersion); } } }