Skip to content

Commit

Permalink
Merge pull request quarkusio#46452 from aloubyansky/extension-catalog…
Browse files Browse the repository at this point in the history
…s-for-stream

Fix recommended release selection in an archived platform stream
  • Loading branch information
aloubyansky authored Feb 24, 2025
2 parents 8b9acdc + 24fac49 commit 8ff5400
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package io.quarkus.devtools.project.create;

import java.nio.file.Path;
import java.util.List;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder;
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.registry.catalog.PlatformStreamCoords;

public class QuarkusPlatformArchivedStreamSelectionTest extends MultiplePlatformBomsTestBase {

private static final String ACME_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(ACME_PLATFORM_KEY)
// 3.0 STREAM
.newStream("3.0")
// 3.0.5 release
.newRelease("3.0.5")
.quarkusVersion("3.0.5")
// default bom including quarkus-core + essential metadata
.addCoreMember().release()
.newMember("acme-zoo-bom").addExtension("org.acme", "acme-rabbit", "3.0.5")
.release().stream().platform()
// 2.0 STREAM
.newArchivedStream("2.0")
.newRelease("2.0.5")
.quarkusVersion("2.0.5")
// default bom including quarkus-core + essential metadata
.addCoreMember().release()
.newMember("acme-zoo-bom").addExtension("org.acme", "acme-rabbit", "2.0.5")
.release().stream()
.newRelease("2.0.4")
.quarkusVersion("2.0.4")
// default bom including quarkus-core + essential metadata
.addCoreMember().release()
.newMember("acme-zoo-bom").addExtension("org.acme", "acme-rabbit", "2.0.4")
.release().stream()
.newRelease("2.0.3")
.quarkusVersion("2.0.3")
// default bom including quarkus-core + essential metadata
.addCoreMember().release()
.newMember("acme-zoo-bom")
.addExtension("org.acme", "acme-rabbit", "2.0.3")
.addExtension("org.acme", "acme-giraffe", "2.0.3")
.release().stream().platform()
// 1.0 STREAM
.newStream("1.0")
.newRelease("1.0.5")
.quarkusVersion("1.0.5")
// default bom including quarkus-core + essential metadata
.addCoreMember().release()
.newMember("acme-zoo-bom")
.addExtension("org.acme", "acme-rabbit", "1.0.5")
.addExtension("org.acme", "acme-giraffe", "1.0.5")
.registry()
.clientBuilder()
.build();

enableRegistryClient();
}

protected String getMainPlatformKey() {
return ACME_PLATFORM_KEY;
}

@Test
public void testLatestRecommendedStream() throws Exception {
final Path projectDir = newProjectDir("latest-recommended-stream-selection");
createProject(projectDir, List.of("acme-rabbit"));

assertModel(projectDir,
toPlatformBomCoords("acme-zoo-bom"),
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null)),
"3.0.5");
}

@Test
public void testLatestRecommendedMatchingStreamRelease() throws Exception {
final Path projectDir = newProjectDir("latest-recommended-matching-stream");
createProject(projectDir, List.of("acme-rabbit", "acme-giraffe"));

assertModel(projectDir,
toPlatformBomCoords("acme-zoo-bom"),
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null),
ArtifactCoords.jar("org.acme", "acme-giraffe", null)),
"1.0.5");
}

@Test
public void testArchivedStreamSelection() throws Exception {
final Path projectDir = newProjectDir("archived-stream-selection");
createProject(projectDir, new PlatformStreamCoords(ACME_PLATFORM_KEY, "2.0"),
List.of("acme-rabbit"));

assertModel(projectDir,
toPlatformBomCoords("acme-zoo-bom"),
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null)),
"2.0.5");
}

/**
* This one may seem like an edge case. This test makes sure a release that includes an extension
* that was removed in later releases in the same stream still gets selected when that extension
* is requested by a user.
*
* @throws Exception in case of an error
*/
@Test
public void testArchivedMatchingStreamRelease() throws Exception {
final Path projectDir = newProjectDir("archived-stream-selection");
createProject(projectDir, new PlatformStreamCoords(ACME_PLATFORM_KEY, "2.0"),
List.of("acme-rabbit", "acme-giraffe"));

assertModel(projectDir,
toPlatformBomCoords("acme-zoo-bom"),
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null),
ArtifactCoords.jar("org.acme", "acme-giraffe", null)),
"2.0.3");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -326,7 +325,8 @@ void addUpstreamQuarkusVersion(String quarkusVersion) {
}

List<RegistryExtensionResolver> getRegistriesForQuarkusCore(String quarkusVersion) {
return registriesByQuarkusCore.computeIfAbsent(quarkusVersion, v -> getRegistriesForQuarkusVersion(v));
return registriesByQuarkusCore.computeIfAbsent(quarkusVersion,
ExtensionCatalogResolver.this::getRegistriesForQuarkusVersion);
}

public int getCompatibilityCode(String quarkusVersion) {
Expand All @@ -337,11 +337,7 @@ public int getCompatibilityCode(String quarkusVersion, String upstreamQuarkusVer
Integer i = compatibilityCodes.get(quarkusVersion);
if (i == null) {
if (upstreamQuarkusVersion != null) {
i = compatibilityCodes.get(upstreamQuarkusVersion);
if (i == null) {
i = compatibilityCodes.size();
compatibilityCodes.put(upstreamQuarkusVersion, i);
}
i = compatibilityCodes.computeIfAbsent(upstreamQuarkusVersion, cc -> compatibilityCodes.size());
} else {
i = compatibilityCodes.size();
}
Expand All @@ -356,6 +352,16 @@ void appendAllNonPlatformExtensions() throws RegistryResolutionException {
}
}

void addUpstreamExtensionCatalogs(String quarkusCoreVersion, Set<String> processedPlatformKeys)
throws RegistryResolutionException {
collectPlatformExtensions(quarkusCoreVersion, this, processedPlatformKeys);
int i = 0;
while (i < upstreamQuarkusVersions.size()) {
collectPlatformExtensions(upstreamQuarkusVersions.get(i++), this, processedPlatformKeys);
}
upstreamQuarkusVersions.clear();
}

ExtensionCatalog build() throws RegistryResolutionException {
appendAllNonPlatformExtensions();
if (catalogs.isEmpty()) {
Expand Down Expand Up @@ -474,12 +480,12 @@ public ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion) throw
}

private ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion,
final ExtensionCatalogBuilder catalogBuilder, Set<String> preferredPlatforms)
final ExtensionCatalogBuilder catalogBuilder, Set<String> preferredPlatformKeys)
throws RegistryResolutionException {
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, preferredPlatforms);
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, preferredPlatformKeys);
int i = 0;
while (i < catalogBuilder.upstreamQuarkusVersions.size()) {
collectPlatformExtensions(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatforms);
collectPlatformExtensions(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatformKeys);
}
return catalogBuilder.build();
}
Expand All @@ -489,11 +495,11 @@ public ExtensionCatalog resolveExtensionCatalog(PlatformStreamCoords streamCoord
ensureRegistriesConfigured();

final PlatformStream stream = findPlatformStreamOrFail(streamCoords);
final List<ExtensionCatalog> catalogs = new ArrayList<>();
ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder();
for (PlatformRelease release : stream.getReleases()) {
catalogs.add(resolveExtensionCatalog(release.getMemberBoms()));
collectExtensionCatalogs(release.getMemberBoms(), catalogBuilder);
}
return CatalogMergeUtility.merge(catalogs);
return catalogBuilder.build();
}

protected PlatformStream findPlatformStreamOrFail(PlatformStreamCoords streamCoords)
Expand Down Expand Up @@ -556,15 +562,13 @@ protected RegistryResolutionException unknownStreamException(PlatformStreamCoord
break;
}
}
for (Platform platform : platforms.getPlatforms()) {
knownPlatforms.add(platform);
}
knownPlatforms.addAll(platforms.getPlatforms());
}

final StringBuilder buf = new StringBuilder();
if (requestedPlatform != null) {
buf.append("Failed to locate stream ").append(stream.getStreamId())
.append(" in platform " + requestedPlatform.getPlatformKey());
.append(" in platform ").append(requestedPlatform.getPlatformKey());
} else if (knownPlatforms.isEmpty()) {
buf.append("None of the registries provided any platform");
} else {
Expand All @@ -582,18 +586,27 @@ protected RegistryResolutionException unknownStreamException(PlatformStreamCoord
return new RegistryResolutionException(buf.toString());
}

@SuppressWarnings("unchecked")
public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> preferredPlatforms)
throws RegistryResolutionException {
if (preferredPlatforms.isEmpty()) {
return resolveExtensionCatalog();
}

final ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder();
final Set<String> preferredPlatformKeys = new HashSet<>();
collectExtensionCatalogs(preferredPlatforms, catalogBuilder);
return catalogBuilder.build();
}

@SuppressWarnings("unchecked")
private void collectExtensionCatalogs(Collection<ArtifactCoords> preferredPlatforms, ExtensionCatalogBuilder catalogBuilder)
throws RegistryResolutionException {
final Set<String> preferredPlatformKeys = new HashSet<>(4);
final Set<ArtifactCoords> addedPlatformBoms = new HashSet<>();
String quarkusVersion = null;
int platformIndex = 0;
for (ArtifactCoords bom : preferredPlatforms) {
if (!addedPlatformBoms.add(bom)) {
continue;
}
final List<RegistryExtensionResolver> registries;
try {
registries = filterRegistries(r -> r.checkPlatform(bom));
Expand Down Expand Up @@ -657,12 +670,11 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
if (!preferredPlatformKeys.add(platformKey)) {
continue;
}
final Platform.Mutable p = Platform.builder()
.setPlatformKey(platformKey);
final Platform.Mutable platform = Platform.builder().setPlatformKey(platformKey);

final PlatformStream.Mutable stream = PlatformStream.builder()
.setId(String.valueOf(md.getOrDefault("stream", "default")));
p.addStream(stream);
platform.addStream(stream);

final PlatformRelease.Mutable release = PlatformRelease.builder()
.setVersion(PlatformReleaseVersion
Expand All @@ -674,14 +686,16 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
o = md.get("members");
if (o != null) {
final Collection<String> col = (Collection<String>) o;
final List<ArtifactCoords> coords = new ArrayList<>(col.size());
final List<ArtifactCoords> memberCatalogs = new ArrayList<>(col.size());
for (String s : col) {
coords.add(ArtifactCoords.fromString(s));
var memberCatalogCoords = ArtifactCoords.fromString(s);
memberCatalogs.add(memberCatalogCoords);
addedPlatformBoms.add(PlatformArtifacts.getBomArtifactForCatalog(memberCatalogCoords));
}
release.setMemberBoms(coords);
release.setMemberBoms(memberCatalogs);
}

collectPlatformExtensions(quarkusVersion, catalogBuilder, registry, platformIndex, p);
collectPlatformExtensions(catalogBuilder, registry, platformIndex, platform);
continue;
}
}
Expand Down Expand Up @@ -709,10 +723,8 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
}
throw new RegistryResolutionException(buf.toString());
}
return catalogBuilder.catalogs.isEmpty() ? null : catalogBuilder.build();
}
return preferredPlatforms.isEmpty() ? catalogBuilder.build()
: resolveExtensionCatalog(quarkusVersion, catalogBuilder, preferredPlatformKeys);
catalogBuilder.addUpstreamExtensionCatalogs(quarkusVersion, preferredPlatformKeys);
}

public void clearRegistryCache() throws RegistryResolutionException {
Expand All @@ -736,7 +748,7 @@ private void appendNonPlatformExtensions(
}
}

public void appendNonPlatformExtensions(RegistryExtensionResolver registry, ExtensionCatalogBuilder catalogBuilder,
private void appendNonPlatformExtensions(RegistryExtensionResolver registry, ExtensionCatalogBuilder catalogBuilder,
String quarkusVersion) throws RegistryResolutionException {
final ExtensionCatalog.Mutable nonPlatformCatalog = registry.resolveNonPlatformExtensions(quarkusVersion);
if (nonPlatformCatalog == null) {
Expand Down Expand Up @@ -766,7 +778,7 @@ private int getRegistryIndex(String registryId) {
}

private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
Set<String> processedPlatforms)
Set<String> processedPlatformKeys)
throws RegistryResolutionException {
final List<RegistryExtensionResolver> quarkusVersionRegistries = catalogBuilder
.getRegistriesForQuarkusCore(quarkusCoreVersion);
Expand All @@ -780,18 +792,18 @@ private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatal
if (platforms.isEmpty()) {
continue;
}
int platformIndex = processedPlatforms.size();
int platformIndex = processedPlatformKeys.size();
for (Platform p : platforms) {
if (processedPlatforms.contains(p.getPlatformKey())) {
if (processedPlatformKeys.contains(p.getPlatformKey())) {
continue;
}
++platformIndex;
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, registry, platformIndex, p);
collectPlatformExtensions(catalogBuilder, registry, platformIndex, p);
}
}
}

private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
private void collectPlatformExtensions(ExtensionCatalogBuilder catalogBuilder,
RegistryExtensionResolver registry, int platformIndex,
Platform p) throws RegistryResolutionException {

Expand Down Expand Up @@ -880,6 +892,6 @@ private List<RegistryExtensionResolver> filterRegistries(Function<RegistryExtens
throw new ExclusiveProviderConflictException(conflicts);
}

return exclusiveProvider == null ? filtered == null ? registries : filtered : Arrays.asList(exclusiveProvider);
return exclusiveProvider == null ? filtered == null ? registries : filtered : List.of(exclusiveProvider);
}
}

0 comments on commit 8ff5400

Please sign in to comment.