Skip to content

Commit da86c81

Browse files
committed
Use complete artifact keys instead of G:A when checking whether dependency has been visited
1 parent bac6022 commit da86c81

File tree

8 files changed

+154
-81
lines changed

8 files changed

+154
-81
lines changed

devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java

Lines changed: 96 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -241,18 +241,36 @@ private static void collectDestinationDirs(Collection<SourceDir> sources, final
241241
private void collectExtensionDependencies(Project project, Configuration deploymentConfiguration,
242242
ApplicationModelBuilder modelBuilder) {
243243
final ResolvedConfiguration rc = deploymentConfiguration.getResolvedConfiguration();
244+
final Set<ArtifactKey> processedDeps = new HashSet<>();
244245
for (var dep : rc.getFirstLevelModuleDependencies()) {
245-
processDeploymentDependency(project, dep, modelBuilder, false);
246+
processDeploymentDependency(project, dep, modelBuilder, false, processedDeps);
246247
}
247248
}
248249

249250
private static void processDeploymentDependency(Project project, ResolvedDependency resolvedDep,
250-
ApplicationModelBuilder modelBuilder, boolean clearReloadableFlag) {
251-
boolean processChildren = false;
252-
for (var a : resolvedDep.getModuleArtifacts()) {
253-
ResolvedDependencyBuilder dep = modelBuilder.getDependency(getKey(a));
251+
ApplicationModelBuilder modelBuilder, boolean clearReloadableFlag, Set<ArtifactKey> processedDeps) {
252+
final Set<ResolvedArtifact> resolvedArtifacts = resolvedDep.getModuleArtifacts();
253+
boolean processChildren = resolvedArtifacts.isEmpty();
254+
for (var a : resolvedArtifacts) {
255+
final ArtifactKey artifactKey = getKey(a);
256+
if (!processedDeps.add(artifactKey)) {
257+
continue;
258+
}
259+
processChildren = true;
260+
ResolvedDependencyBuilder dep = modelBuilder.getDependency(artifactKey);
254261
if (dep == null) {
255-
if (a.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier projectComponentIdentifier) {
262+
if (isApplicationRoot(modelBuilder, artifactKey)) {
263+
// An application root artifact may be found among the dependencies in a could of cases:
264+
// test fixtures in an application project and as a deployment module in an extension project
265+
// running deployment module tests.
266+
// In case of test fixtures, the root artifact does not have to be added to the model as a dependency,
267+
// it can simply be skipped.
268+
// In case of a deployment test, it has to be added as a dependency, since otherwise, the deployment
269+
// module will appear to be missing.
270+
// This part here looks like a hack but appears to work for both cases so far.
271+
dep = modelBuilder.getApplicationArtifact();
272+
} else if (a.getId()
273+
.getComponentIdentifier() instanceof ProjectComponentIdentifier projectComponentIdentifier) {
256274
var includedBuild = ToolingUtils.includedBuild(project,
257275
projectComponentIdentifier.getBuild().getBuildPath());
258276
final Project projectDep;
@@ -297,22 +315,26 @@ private static void processDeploymentDependency(Project project, ResolvedDepende
297315
}
298316
}
299317
if (dep != null) {
300-
if (!dep.isDeploymentCp()) {
301-
dep.setDeploymentCp();
302-
processChildren = true;
318+
if (dep.isRuntimeExtensionArtifact()) {
319+
clearReloadableFlag = true;
303320
}
321+
dep.setDeploymentCp();
304322
if (clearReloadableFlag) {
305323
dep.clearFlag(DependencyFlags.RELOADABLE);
306324
}
307325
}
308326
}
309327
if (processChildren) {
310328
for (var child : resolvedDep.getChildren()) {
311-
processDeploymentDependency(project, child, modelBuilder, clearReloadableFlag);
329+
processDeploymentDependency(project, child, modelBuilder, clearReloadableFlag, processedDeps);
312330
}
313331
}
314332
}
315333

334+
private static boolean isApplicationRoot(ApplicationModelBuilder modelBuilder, ArtifactKey artifactKey) {
335+
return modelBuilder.getApplicationArtifact().getKey().equals(artifactKey);
336+
}
337+
316338
private static ResolvedDependencyBuilder addArtifactDependency(Project project, ApplicationModelBuilder modelBuilder,
317339
ResolvedArtifact a) {
318340
ResolvedDependencyBuilder dep = modelBuilder.getDependency(getKey(a));
@@ -350,9 +372,7 @@ private void collectDependencies(ResolvedConfiguration configuration, Resolvable
350372

351373
final Set<File> artifactFiles = getArtifactFilesOrNull(configuration, dependencies);
352374
for (ResolvedDependency d : configuration.getFirstLevelModuleDependencies()) {
353-
collectDependencies(d, workspaceDiscovery, project, artifactFiles, new HashSet<>(),
354-
modelBuilder,
355-
wsModule,
375+
collectDependencies(d, workspaceDiscovery, project, artifactFiles, modelBuilder, wsModule,
356376
(byte) (COLLECT_TOP_EXTENSION_RUNTIME_NODES | COLLECT_DIRECT_DEPS | COLLECT_RELOADABLE_MODULES));
357377
}
358378

@@ -403,86 +423,94 @@ private static Set<File> getArtifactFilesOrNull(ResolvedConfiguration configurat
403423
}
404424

405425
private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency resolvedDep, boolean workspaceDiscovery,
406-
Project project, Set<File> artifactFiles, Set<ArtifactKey> processedModules, ApplicationModelBuilder modelBuilder,
426+
Project project, Set<File> artifactFiles, ApplicationModelBuilder modelBuilder,
407427
WorkspaceModule.Mutable parentModule,
408428
byte flags) {
409429
WorkspaceModule.Mutable projectModule = null;
410-
for (ResolvedArtifact a : resolvedDep.getModuleArtifacts()) {
430+
final Set<ResolvedArtifact> resolvedArtifacts = resolvedDep.getModuleArtifacts();
431+
boolean processChildren = resolvedArtifacts.isEmpty();
432+
for (ResolvedArtifact a : resolvedArtifacts) {
411433
if (!isDependency(a)) {
412434
continue;
413435
}
414-
var depBuilder = modelBuilder.getDependency(getKey(a));
415-
if (depBuilder != null) {
416-
if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) {
417-
depBuilder.setDirect(true);
418-
}
436+
final ArtifactKey artifactKey = getKey(a);
437+
if (isApplicationRoot(modelBuilder, artifactKey)) {
419438
continue;
420439
}
421-
final ArtifactCoords depCoords = getArtifactCoords(a);
422-
depBuilder = ResolvedDependencyBuilder.newInstance()
423-
.setCoords(depCoords)
424-
.setRuntimeCp();
425-
if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) {
426-
depBuilder.setDirect(true);
427-
flags = clearFlag(flags, COLLECT_DIRECT_DEPS);
428-
}
429-
if (parentModule != null) {
430-
parentModule.addDependency(new ArtifactDependency(depCoords));
431-
}
432-
433-
PathCollection paths = null;
434-
if (workspaceDiscovery && a.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier compId) {
435-
Project projectDep = project.getRootProject().findProject(compId.getProjectPath());
440+
var depBuilder = modelBuilder.getDependency(artifactKey);
441+
if (depBuilder == null) {
442+
processChildren = true;
443+
final ArtifactCoords depCoords = getArtifactCoords(a);
444+
depBuilder = ResolvedDependencyBuilder.newInstance()
445+
.setCoords(depCoords)
446+
.setRuntimeCp();
447+
if (parentModule != null) {
448+
parentModule.addDependency(new ArtifactDependency(depCoords));
449+
}
436450

437-
final String classifier = a.getClassifier();
438-
if (classifier == null || classifier.isEmpty()) {
439-
final IncludedBuild includedBuild = ToolingUtils.includedBuild(project.getRootProject(),
440-
compId.getBuild().getBuildPath());
441-
if (includedBuild != null) {
442-
if (includedBuild instanceof IncludedBuildInternal ib) {
443-
projectDep = ToolingUtils.includedBuildProject(ib, compId.getProjectPath());
444-
}
445-
if (projectDep != null) {
446-
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
451+
PathCollection paths = null;
452+
if (workspaceDiscovery && a.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier compId) {
453+
Project projectDep = project.getRootProject().findProject(compId.getProjectPath());
454+
455+
final String classifier = a.getClassifier();
456+
if (classifier == null || classifier.isEmpty()) {
457+
final IncludedBuild includedBuild = ToolingUtils.includedBuild(project.getRootProject(),
458+
compId.getBuild().getBuildPath());
459+
if (includedBuild != null) {
460+
if (includedBuild instanceof IncludedBuildInternal ib) {
461+
projectDep = ToolingUtils.includedBuildProject(ib, compId.getProjectPath());
462+
}
463+
if (projectDep != null) {
464+
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
465+
} else {
466+
final PathList.Builder pathBuilder = PathList.builder();
467+
addSubstitutedProject(pathBuilder, includedBuild.getProjectDir());
468+
paths = pathBuilder.build();
469+
}
447470
} else {
448-
final PathList.Builder pathBuilder = PathList.builder();
449-
addSubstitutedProject(pathBuilder, includedBuild.getProjectDir());
450-
paths = pathBuilder.build();
471+
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
451472
}
452473
} else {
453474
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
454475
}
455-
} else {
456-
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
457476
}
458-
}
459477

460-
depBuilder.setResolvedPaths(paths == null ? PathList.of(a.getFile().toPath()) : paths);
461-
if (processQuarkusDependency(depBuilder, modelBuilder)) {
462-
if (isFlagOn(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES)) {
478+
depBuilder.setResolvedPaths(paths == null ? PathList.of(a.getFile().toPath()) : paths);
479+
if (processQuarkusDependency(depBuilder, modelBuilder)) {
480+
flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
481+
}
482+
modelBuilder.addDependency(depBuilder);
483+
if (projectModule == null && depBuilder.getWorkspaceModule() != null) {
484+
projectModule = depBuilder.getWorkspaceModule().mutable();
485+
}
486+
487+
if (artifactFiles != null) {
488+
artifactFiles.add(a.getFile());
489+
}
490+
}
491+
if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) {
492+
depBuilder.setDirect(true);
493+
flags = clearFlag(flags, COLLECT_DIRECT_DEPS);
494+
}
495+
if (depBuilder.isRuntimeExtensionArtifact()) {
496+
if (isFlagOn(flags, COLLECT_RELOADABLE_MODULES)) {
497+
flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
498+
processChildren = true;
499+
}
500+
if (isFlagOn(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES)
501+
&& !depBuilder.isFlagSet(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT)) {
463502
depBuilder.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT);
464503
flags = clearFlag(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES);
465504
}
466-
flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
467505
}
468506
if (!isFlagOn(flags, COLLECT_RELOADABLE_MODULES)) {
469507
depBuilder.clearFlag(DependencyFlags.RELOADABLE);
470508
}
471-
modelBuilder.addDependency(depBuilder);
472-
if (projectModule == null && depBuilder.getWorkspaceModule() != null) {
473-
projectModule = depBuilder.getWorkspaceModule().mutable();
474-
}
475-
476-
if (artifactFiles != null) {
477-
artifactFiles.add(a.getFile());
478-
}
479509
}
480510

481-
processedModules.add(ArtifactKey.ga(resolvedDep.getModuleGroup(), resolvedDep.getModuleName()));
482-
for (org.gradle.api.artifacts.ResolvedDependency child : resolvedDep.getChildren()) {
483-
if (!processedModules.contains(ArtifactKey.ga(child.getModuleGroup(), child.getModuleName()))) {
484-
collectDependencies(child, workspaceDiscovery, project, artifactFiles, processedModules,
485-
modelBuilder, projectModule, flags);
511+
if (processChildren) {
512+
for (org.gradle.api.artifacts.ResolvedDependency child : resolvedDep.getChildren()) {
513+
collectDependencies(child, workspaceDiscovery, project, artifactFiles, modelBuilder, projectModule, flags);
486514
}
487515
}
488516
}

integration-tests/gradle/src/main/resources/basic-composite-build-extension-project/application/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ dependencies {
1818
implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
1919
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2020
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
21-
implementation 'io.quarkus:quarkus-resteasy'
22-
implementation ('org.acme.libs:libraryB')
23-
implementation ('org.acme.libs:libraryA')
24-
implementation ('org.acme.extensions:example-extension')
21+
implementation 'io.quarkus:quarkus-rest'
22+
implementation 'org.acme.libs:libraryB'
23+
implementation 'org.acme.libs:libraryA'
24+
implementation 'org.acme.extensions:example-extension'
2525

2626
}
2727

integration-tests/gradle/src/main/resources/basic-composite-build-extension-project/libraries/libraryA/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repositories {
1515

1616
dependencies {
1717
implementation platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
18-
implementation ("${quarkusPlatformGroupId}:quarkus-arc:${quarkusPlatformVersion}")
18+
implementation 'io.quarkus:quarkus-arc'
1919
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2020
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
2121
}

integration-tests/gradle/src/main/resources/basic-composite-build-extension-project/libraries/libraryB/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repositories {
1515

1616
dependencies {
1717
implementation platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
18-
implementation ("${quarkusPlatformGroupId}:quarkus-arc:${quarkusPlatformVersion}")
18+
implementation 'io.quarkus:quarkus-arc'
1919
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2020
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
2121
implementation project(':libraryA')

integration-tests/gradle/src/main/resources/basic-composite-build-project/application/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ dependencies {
1818
implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
1919
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2020
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
21-
implementation 'io.quarkus:quarkus-resteasy'
22-
implementation ('org.acme.libs:libraryB')
23-
implementation ('org.acme.libs:libraryA')
21+
implementation 'io.quarkus:quarkus-rest'
22+
implementation 'org.acme.libs:libraryB'
23+
implementation 'org.acme.libs:libraryA'
2424

2525
}
2626

integration-tests/gradle/src/main/resources/basic-composite-build-project/libraries/libraryA/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repositories {
1515

1616
dependencies {
1717
implementation platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
18-
implementation ("${quarkusPlatformGroupId}:quarkus-arc:${quarkusPlatformVersion}")
18+
implementation 'io.quarkus:quarkus-arc'
1919
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2020
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
2121
}

integration-tests/gradle/src/main/resources/basic-composite-build-project/libraries/libraryB/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repositories {
1515

1616
dependencies {
1717
implementation platform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
18-
implementation ("${quarkusPlatformGroupId}:quarkus-arc:${quarkusPlatformVersion}")
18+
implementation 'io.quarkus:quarkus-arc'
1919
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2020
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
2121
implementation project(':libraryA')

integration-tests/gradle/src/test/java/io/quarkus/gradle/TestFixtureMultiModuleTest.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,61 @@
44

55
import java.io.File;
66
import java.io.IOException;
7-
import java.net.URISyntaxException;
7+
import java.io.ObjectInputStream;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
import java.util.HashMap;
11+
import java.util.Map;
812

913
import org.junit.jupiter.api.Test;
1014

15+
import io.quarkus.bootstrap.model.ApplicationModel;
16+
import io.quarkus.bootstrap.util.BootstrapUtils;
17+
import io.quarkus.maven.dependency.ArtifactKey;
18+
1119
public class TestFixtureMultiModuleTest extends QuarkusGradleWrapperTestBase {
1220

1321
@Test
14-
public void testTaskShouldUseTestFixtures() throws IOException, URISyntaxException, InterruptedException {
22+
public void testTaskShouldUseTestFixtures() throws Exception {
1523
final File projectDir = getProjectDir("test-fixtures-multi-module");
1624
final BuildResult result = runGradleWrapper(projectDir, "clean", "test");
1725
assertThat(BuildResult.isSuccessful(result.getTasks().get(":application:test"))).isTrue();
26+
27+
final Path testModelDat = projectDir.toPath().resolve("application").resolve("build").resolve("quarkus")
28+
.resolve("application-model").resolve("quarkus-app-test-model.dat");
29+
assertThat(testModelDat).exists();
30+
final ApplicationModel model = deserializeAppModel(testModelDat);
31+
final Map<ArtifactKey, String> actualDepFlags = new HashMap<>();
32+
for (var dep : model.getDependencies()) {
33+
if (dep.getGroupId().equals("my-groupId")) {
34+
actualDepFlags.put(dep.getKey(), BootstrapUtils.toTextFlags(dep.getFlags()));
35+
}
36+
}
37+
assertThat(actualDepFlags).containsExactlyInAnyOrderEntriesOf(Map.of(
38+
ArtifactKey.fromString("my-groupId:library-1::jar"),
39+
"runtime-cp, deployment-cp, workspace-module, reloadable",
40+
ArtifactKey.fromString("my-groupId:library-1:test-fixtures:jar"),
41+
"runtime-cp, deployment-cp, workspace-module, reloadable",
42+
ArtifactKey.fromString("my-groupId:library-2::jar"),
43+
"direct, runtime-cp, deployment-cp, workspace-module, reloadable",
44+
ArtifactKey.fromString("my-groupId:library-2:test-fixtures:jar"),
45+
"direct, runtime-cp, deployment-cp, workspace-module, reloadable",
46+
ArtifactKey.fromString("my-groupId:static-init-library::jar"),
47+
"runtime-cp, deployment-cp, workspace-module, reloadable"));
48+
}
49+
50+
/**
51+
* Copied from ToolingUtils
52+
*
53+
* @param path application model dat file
54+
* @return deserialized ApplicationModel
55+
* @throws IOException in case of a failure to read the model
56+
*/
57+
private static ApplicationModel deserializeAppModel(Path path) throws IOException {
58+
try (ObjectInputStream out = new ObjectInputStream(Files.newInputStream(path))) {
59+
return (ApplicationModel) out.readObject();
60+
} catch (ClassNotFoundException e) {
61+
throw new RuntimeException(e);
62+
}
1863
}
1964
}

0 commit comments

Comments
 (0)