Skip to content

Commit 8ff5400

Browse files
authored
Merge pull request #46452 from aloubyansky/extension-catalogs-for-stream
Fix recommended release selection in an archived platform stream
2 parents 8b9acdc + 24fac49 commit 8ff5400

File tree

2 files changed

+180
-37
lines changed

2 files changed

+180
-37
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package io.quarkus.devtools.project.create;
2+
3+
import java.nio.file.Path;
4+
import java.util.List;
5+
6+
import org.junit.jupiter.api.BeforeAll;
7+
import org.junit.jupiter.api.Test;
8+
9+
import io.quarkus.devtools.testing.registry.client.TestRegistryClientBuilder;
10+
import io.quarkus.maven.dependency.ArtifactCoords;
11+
import io.quarkus.registry.catalog.PlatformStreamCoords;
12+
13+
public class QuarkusPlatformArchivedStreamSelectionTest extends MultiplePlatformBomsTestBase {
14+
15+
private static final String ACME_PLATFORM_KEY = "org.acme.platform";
16+
17+
@BeforeAll
18+
public static void setup() throws Exception {
19+
TestRegistryClientBuilder.newInstance()
20+
//.debug()
21+
.baseDir(configDir())
22+
// registry
23+
.newRegistry("registry.acme.org")
24+
// platform key
25+
.newPlatform(ACME_PLATFORM_KEY)
26+
// 3.0 STREAM
27+
.newStream("3.0")
28+
// 3.0.5 release
29+
.newRelease("3.0.5")
30+
.quarkusVersion("3.0.5")
31+
// default bom including quarkus-core + essential metadata
32+
.addCoreMember().release()
33+
.newMember("acme-zoo-bom").addExtension("org.acme", "acme-rabbit", "3.0.5")
34+
.release().stream().platform()
35+
// 2.0 STREAM
36+
.newArchivedStream("2.0")
37+
.newRelease("2.0.5")
38+
.quarkusVersion("2.0.5")
39+
// default bom including quarkus-core + essential metadata
40+
.addCoreMember().release()
41+
.newMember("acme-zoo-bom").addExtension("org.acme", "acme-rabbit", "2.0.5")
42+
.release().stream()
43+
.newRelease("2.0.4")
44+
.quarkusVersion("2.0.4")
45+
// default bom including quarkus-core + essential metadata
46+
.addCoreMember().release()
47+
.newMember("acme-zoo-bom").addExtension("org.acme", "acme-rabbit", "2.0.4")
48+
.release().stream()
49+
.newRelease("2.0.3")
50+
.quarkusVersion("2.0.3")
51+
// default bom including quarkus-core + essential metadata
52+
.addCoreMember().release()
53+
.newMember("acme-zoo-bom")
54+
.addExtension("org.acme", "acme-rabbit", "2.0.3")
55+
.addExtension("org.acme", "acme-giraffe", "2.0.3")
56+
.release().stream().platform()
57+
// 1.0 STREAM
58+
.newStream("1.0")
59+
.newRelease("1.0.5")
60+
.quarkusVersion("1.0.5")
61+
// default bom including quarkus-core + essential metadata
62+
.addCoreMember().release()
63+
.newMember("acme-zoo-bom")
64+
.addExtension("org.acme", "acme-rabbit", "1.0.5")
65+
.addExtension("org.acme", "acme-giraffe", "1.0.5")
66+
.registry()
67+
.clientBuilder()
68+
.build();
69+
70+
enableRegistryClient();
71+
}
72+
73+
protected String getMainPlatformKey() {
74+
return ACME_PLATFORM_KEY;
75+
}
76+
77+
@Test
78+
public void testLatestRecommendedStream() throws Exception {
79+
final Path projectDir = newProjectDir("latest-recommended-stream-selection");
80+
createProject(projectDir, List.of("acme-rabbit"));
81+
82+
assertModel(projectDir,
83+
toPlatformBomCoords("acme-zoo-bom"),
84+
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null)),
85+
"3.0.5");
86+
}
87+
88+
@Test
89+
public void testLatestRecommendedMatchingStreamRelease() throws Exception {
90+
final Path projectDir = newProjectDir("latest-recommended-matching-stream");
91+
createProject(projectDir, List.of("acme-rabbit", "acme-giraffe"));
92+
93+
assertModel(projectDir,
94+
toPlatformBomCoords("acme-zoo-bom"),
95+
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null),
96+
ArtifactCoords.jar("org.acme", "acme-giraffe", null)),
97+
"1.0.5");
98+
}
99+
100+
@Test
101+
public void testArchivedStreamSelection() throws Exception {
102+
final Path projectDir = newProjectDir("archived-stream-selection");
103+
createProject(projectDir, new PlatformStreamCoords(ACME_PLATFORM_KEY, "2.0"),
104+
List.of("acme-rabbit"));
105+
106+
assertModel(projectDir,
107+
toPlatformBomCoords("acme-zoo-bom"),
108+
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null)),
109+
"2.0.5");
110+
}
111+
112+
/**
113+
* This one may seem like an edge case. This test makes sure a release that includes an extension
114+
* that was removed in later releases in the same stream still gets selected when that extension
115+
* is requested by a user.
116+
*
117+
* @throws Exception in case of an error
118+
*/
119+
@Test
120+
public void testArchivedMatchingStreamRelease() throws Exception {
121+
final Path projectDir = newProjectDir("archived-stream-selection");
122+
createProject(projectDir, new PlatformStreamCoords(ACME_PLATFORM_KEY, "2.0"),
123+
List.of("acme-rabbit", "acme-giraffe"));
124+
125+
assertModel(projectDir,
126+
toPlatformBomCoords("acme-zoo-bom"),
127+
List.of(ArtifactCoords.jar("org.acme", "acme-rabbit", null),
128+
ArtifactCoords.jar("org.acme", "acme-giraffe", null)),
129+
"2.0.3");
130+
}
131+
}

independent-projects/tools/registry-client/src/main/java/io/quarkus/registry/ExtensionCatalogResolver.java

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import java.net.URL;
66
import java.net.URLClassLoader;
77
import java.util.ArrayList;
8-
import java.util.Arrays;
98
import java.util.Collection;
109
import java.util.Collections;
1110
import java.util.HashMap;
@@ -326,7 +325,8 @@ void addUpstreamQuarkusVersion(String quarkusVersion) {
326325
}
327326

328327
List<RegistryExtensionResolver> getRegistriesForQuarkusCore(String quarkusVersion) {
329-
return registriesByQuarkusCore.computeIfAbsent(quarkusVersion, v -> getRegistriesForQuarkusVersion(v));
328+
return registriesByQuarkusCore.computeIfAbsent(quarkusVersion,
329+
ExtensionCatalogResolver.this::getRegistriesForQuarkusVersion);
330330
}
331331

332332
public int getCompatibilityCode(String quarkusVersion) {
@@ -337,11 +337,7 @@ public int getCompatibilityCode(String quarkusVersion, String upstreamQuarkusVer
337337
Integer i = compatibilityCodes.get(quarkusVersion);
338338
if (i == null) {
339339
if (upstreamQuarkusVersion != null) {
340-
i = compatibilityCodes.get(upstreamQuarkusVersion);
341-
if (i == null) {
342-
i = compatibilityCodes.size();
343-
compatibilityCodes.put(upstreamQuarkusVersion, i);
344-
}
340+
i = compatibilityCodes.computeIfAbsent(upstreamQuarkusVersion, cc -> compatibilityCodes.size());
345341
} else {
346342
i = compatibilityCodes.size();
347343
}
@@ -356,6 +352,16 @@ void appendAllNonPlatformExtensions() throws RegistryResolutionException {
356352
}
357353
}
358354

355+
void addUpstreamExtensionCatalogs(String quarkusCoreVersion, Set<String> processedPlatformKeys)
356+
throws RegistryResolutionException {
357+
collectPlatformExtensions(quarkusCoreVersion, this, processedPlatformKeys);
358+
int i = 0;
359+
while (i < upstreamQuarkusVersions.size()) {
360+
collectPlatformExtensions(upstreamQuarkusVersions.get(i++), this, processedPlatformKeys);
361+
}
362+
upstreamQuarkusVersions.clear();
363+
}
364+
359365
ExtensionCatalog build() throws RegistryResolutionException {
360366
appendAllNonPlatformExtensions();
361367
if (catalogs.isEmpty()) {
@@ -474,12 +480,12 @@ public ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion) throw
474480
}
475481

476482
private ExtensionCatalog resolveExtensionCatalog(String quarkusCoreVersion,
477-
final ExtensionCatalogBuilder catalogBuilder, Set<String> preferredPlatforms)
483+
final ExtensionCatalogBuilder catalogBuilder, Set<String> preferredPlatformKeys)
478484
throws RegistryResolutionException {
479-
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, preferredPlatforms);
485+
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, preferredPlatformKeys);
480486
int i = 0;
481487
while (i < catalogBuilder.upstreamQuarkusVersions.size()) {
482-
collectPlatformExtensions(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatforms);
488+
collectPlatformExtensions(catalogBuilder.upstreamQuarkusVersions.get(i++), catalogBuilder, preferredPlatformKeys);
483489
}
484490
return catalogBuilder.build();
485491
}
@@ -489,11 +495,11 @@ public ExtensionCatalog resolveExtensionCatalog(PlatformStreamCoords streamCoord
489495
ensureRegistriesConfigured();
490496

491497
final PlatformStream stream = findPlatformStreamOrFail(streamCoords);
492-
final List<ExtensionCatalog> catalogs = new ArrayList<>();
498+
ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder();
493499
for (PlatformRelease release : stream.getReleases()) {
494-
catalogs.add(resolveExtensionCatalog(release.getMemberBoms()));
500+
collectExtensionCatalogs(release.getMemberBoms(), catalogBuilder);
495501
}
496-
return CatalogMergeUtility.merge(catalogs);
502+
return catalogBuilder.build();
497503
}
498504

499505
protected PlatformStream findPlatformStreamOrFail(PlatformStreamCoords streamCoords)
@@ -556,15 +562,13 @@ protected RegistryResolutionException unknownStreamException(PlatformStreamCoord
556562
break;
557563
}
558564
}
559-
for (Platform platform : platforms.getPlatforms()) {
560-
knownPlatforms.add(platform);
561-
}
565+
knownPlatforms.addAll(platforms.getPlatforms());
562566
}
563567

564568
final StringBuilder buf = new StringBuilder();
565569
if (requestedPlatform != null) {
566570
buf.append("Failed to locate stream ").append(stream.getStreamId())
567-
.append(" in platform " + requestedPlatform.getPlatformKey());
571+
.append(" in platform ").append(requestedPlatform.getPlatformKey());
568572
} else if (knownPlatforms.isEmpty()) {
569573
buf.append("None of the registries provided any platform");
570574
} else {
@@ -582,18 +586,27 @@ protected RegistryResolutionException unknownStreamException(PlatformStreamCoord
582586
return new RegistryResolutionException(buf.toString());
583587
}
584588

585-
@SuppressWarnings("unchecked")
586589
public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> preferredPlatforms)
587590
throws RegistryResolutionException {
588591
if (preferredPlatforms.isEmpty()) {
589592
return resolveExtensionCatalog();
590593
}
591-
592594
final ExtensionCatalogBuilder catalogBuilder = new ExtensionCatalogBuilder();
593-
final Set<String> preferredPlatformKeys = new HashSet<>();
595+
collectExtensionCatalogs(preferredPlatforms, catalogBuilder);
596+
return catalogBuilder.build();
597+
}
598+
599+
@SuppressWarnings("unchecked")
600+
private void collectExtensionCatalogs(Collection<ArtifactCoords> preferredPlatforms, ExtensionCatalogBuilder catalogBuilder)
601+
throws RegistryResolutionException {
602+
final Set<String> preferredPlatformKeys = new HashSet<>(4);
603+
final Set<ArtifactCoords> addedPlatformBoms = new HashSet<>();
594604
String quarkusVersion = null;
595605
int platformIndex = 0;
596606
for (ArtifactCoords bom : preferredPlatforms) {
607+
if (!addedPlatformBoms.add(bom)) {
608+
continue;
609+
}
597610
final List<RegistryExtensionResolver> registries;
598611
try {
599612
registries = filterRegistries(r -> r.checkPlatform(bom));
@@ -657,12 +670,11 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
657670
if (!preferredPlatformKeys.add(platformKey)) {
658671
continue;
659672
}
660-
final Platform.Mutable p = Platform.builder()
661-
.setPlatformKey(platformKey);
673+
final Platform.Mutable platform = Platform.builder().setPlatformKey(platformKey);
662674

663675
final PlatformStream.Mutable stream = PlatformStream.builder()
664676
.setId(String.valueOf(md.getOrDefault("stream", "default")));
665-
p.addStream(stream);
677+
platform.addStream(stream);
666678

667679
final PlatformRelease.Mutable release = PlatformRelease.builder()
668680
.setVersion(PlatformReleaseVersion
@@ -674,14 +686,16 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
674686
o = md.get("members");
675687
if (o != null) {
676688
final Collection<String> col = (Collection<String>) o;
677-
final List<ArtifactCoords> coords = new ArrayList<>(col.size());
689+
final List<ArtifactCoords> memberCatalogs = new ArrayList<>(col.size());
678690
for (String s : col) {
679-
coords.add(ArtifactCoords.fromString(s));
691+
var memberCatalogCoords = ArtifactCoords.fromString(s);
692+
memberCatalogs.add(memberCatalogCoords);
693+
addedPlatformBoms.add(PlatformArtifacts.getBomArtifactForCatalog(memberCatalogCoords));
680694
}
681-
release.setMemberBoms(coords);
695+
release.setMemberBoms(memberCatalogs);
682696
}
683697

684-
collectPlatformExtensions(quarkusVersion, catalogBuilder, registry, platformIndex, p);
698+
collectPlatformExtensions(catalogBuilder, registry, platformIndex, platform);
685699
continue;
686700
}
687701
}
@@ -709,10 +723,8 @@ public ExtensionCatalog resolveExtensionCatalog(Collection<ArtifactCoords> prefe
709723
}
710724
throw new RegistryResolutionException(buf.toString());
711725
}
712-
return catalogBuilder.catalogs.isEmpty() ? null : catalogBuilder.build();
713726
}
714-
return preferredPlatforms.isEmpty() ? catalogBuilder.build()
715-
: resolveExtensionCatalog(quarkusVersion, catalogBuilder, preferredPlatformKeys);
727+
catalogBuilder.addUpstreamExtensionCatalogs(quarkusVersion, preferredPlatformKeys);
716728
}
717729

718730
public void clearRegistryCache() throws RegistryResolutionException {
@@ -736,7 +748,7 @@ private void appendNonPlatformExtensions(
736748
}
737749
}
738750

739-
public void appendNonPlatformExtensions(RegistryExtensionResolver registry, ExtensionCatalogBuilder catalogBuilder,
751+
private void appendNonPlatformExtensions(RegistryExtensionResolver registry, ExtensionCatalogBuilder catalogBuilder,
740752
String quarkusVersion) throws RegistryResolutionException {
741753
final ExtensionCatalog.Mutable nonPlatformCatalog = registry.resolveNonPlatformExtensions(quarkusVersion);
742754
if (nonPlatformCatalog == null) {
@@ -766,7 +778,7 @@ private int getRegistryIndex(String registryId) {
766778
}
767779

768780
private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
769-
Set<String> processedPlatforms)
781+
Set<String> processedPlatformKeys)
770782
throws RegistryResolutionException {
771783
final List<RegistryExtensionResolver> quarkusVersionRegistries = catalogBuilder
772784
.getRegistriesForQuarkusCore(quarkusCoreVersion);
@@ -780,18 +792,18 @@ private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatal
780792
if (platforms.isEmpty()) {
781793
continue;
782794
}
783-
int platformIndex = processedPlatforms.size();
795+
int platformIndex = processedPlatformKeys.size();
784796
for (Platform p : platforms) {
785-
if (processedPlatforms.contains(p.getPlatformKey())) {
797+
if (processedPlatformKeys.contains(p.getPlatformKey())) {
786798
continue;
787799
}
788800
++platformIndex;
789-
collectPlatformExtensions(quarkusCoreVersion, catalogBuilder, registry, platformIndex, p);
801+
collectPlatformExtensions(catalogBuilder, registry, platformIndex, p);
790802
}
791803
}
792804
}
793805

794-
private void collectPlatformExtensions(String quarkusCoreVersion, ExtensionCatalogBuilder catalogBuilder,
806+
private void collectPlatformExtensions(ExtensionCatalogBuilder catalogBuilder,
795807
RegistryExtensionResolver registry, int platformIndex,
796808
Platform p) throws RegistryResolutionException {
797809

@@ -880,6 +892,6 @@ private List<RegistryExtensionResolver> filterRegistries(Function<RegistryExtens
880892
throw new ExclusiveProviderConflictException(conflicts);
881893
}
882894

883-
return exclusiveProvider == null ? filtered == null ? registries : filtered : Arrays.asList(exclusiveProvider);
895+
return exclusiveProvider == null ? filtered == null ? registries : filtered : List.of(exclusiveProvider);
884896
}
885897
}

0 commit comments

Comments
 (0)