Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix recommended release selection in an archived platform stream #46452

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
Loading