Skip to content

Commit eb4bf6d

Browse files
authored
Merge pull request #50253 from aloubyansky/GradleApplicationModelBuilder-complete-keys
Make test-fixture sources available to continuous testing
2 parents 86d4b6b + 1ed554b commit eb4bf6d

File tree

10 files changed

+180
-93
lines changed

10 files changed

+180
-93
lines changed

devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusDev.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,16 @@ private boolean classesExist() {
411411
return false;
412412
}
413413

414+
/**
415+
* Returns launch mode for the target application model.
416+
*
417+
* @return launch mode for the target application model
418+
*/
419+
@Internal
420+
protected LaunchMode getLaunchMode() {
421+
return LaunchMode.DEVELOPMENT;
422+
}
423+
414424
private DevModeCommandLine newLauncher(final AnalyticsService analyticsService) throws Exception {
415425
final Project project = getProject();
416426
final JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
@@ -466,7 +476,7 @@ private DevModeCommandLine newLauncher(final AnalyticsService analyticsService)
466476

467477
builder.sourceEncoding(getSourceEncoding());
468478

469-
final ApplicationModel appModel = extension().getApplicationModel(LaunchMode.DEVELOPMENT);
479+
final ApplicationModel appModel = extension().getApplicationModel(getLaunchMode());
470480
builder.extensionDevModeConfig(appModel.getExtensionDevModeConfig())
471481
.extensionDevModeJvmOptionFilter(extensionJvmOptions);
472482

@@ -538,7 +548,8 @@ private DevModeCommandLine newLauncher(final AnalyticsService analyticsService)
538548
serializedModel.toFile().deleteOnExit();
539549
builder.jvmArgs("-D" + BootstrapConstants.SERIALIZED_APP_MODEL + "=" + serializedModel.toAbsolutePath());
540550

541-
final ApplicationModel testAppModel = extension().getApplicationModel(LaunchMode.TEST);
551+
final ApplicationModel testAppModel = getLaunchMode().equals(LaunchMode.TEST) ? appModel
552+
: extension().getApplicationModel(LaunchMode.TEST);
542553
final Path serializedTestModel = ToolingUtils.serializeAppModel(testAppModel, this, true);
543554
serializedTestModel.toFile().deleteOnExit();
544555
builder.jvmArgs("-D" + BootstrapConstants.SERIALIZED_TEST_APP_MODEL + "=" + serializedTestModel.toAbsolutePath());
Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package io.quarkus.gradle.tasks;
22

3-
import java.util.function.Consumer;
4-
53
import javax.inject.Inject;
64

75
import org.gradle.api.artifacts.Configuration;
6+
import org.gradle.api.tasks.Internal;
87

98
import io.quarkus.deployment.dev.DevModeCommandLineBuilder;
10-
import io.quarkus.deployment.dev.DevModeContext;
119
import io.quarkus.deployment.dev.IsolatedTestModeMain;
1210
import io.quarkus.gradle.extension.QuarkusPluginExtension;
11+
import io.quarkus.runtime.LaunchMode;
1312

1413
public abstract class QuarkusTest extends QuarkusDev {
1514

@@ -21,12 +20,15 @@ public QuarkusTest(Configuration quarkusDevConfiguration, QuarkusPluginExtension
2120
extension);
2221
}
2322

23+
@Override
2424
protected void modifyDevModeContext(DevModeCommandLineBuilder builder) {
25-
builder.entryPointCustomizer(new Consumer<DevModeContext>() {
26-
@Override
27-
public void accept(DevModeContext devModeContext) {
28-
devModeContext.setAlternateEntryPoint(IsolatedTestModeMain.class.getName());
29-
}
30-
});
25+
builder.entryPointCustomizer(
26+
devModeContext -> devModeContext.setAlternateEntryPoint(IsolatedTestModeMain.class.getName()));
27+
}
28+
29+
@Override
30+
@Internal
31+
protected LaunchMode getLaunchMode() {
32+
return LaunchMode.TEST;
3133
}
3234
}

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

Lines changed: 98 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ public static ResolvedDependencyBuilder getProjectArtifact(Project project, bool
193193

194194
initProjectModule(project, mainModule, sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME), ArtifactSources.MAIN);
195195
if (workspaceDiscovery) {
196+
appArtifact.setReloadable();
196197
final TaskCollection<Test> testTasks = project.getTasks().withType(Test.class);
197198
if (!testTasks.isEmpty()) {
198199
final Map<File, SourceSet> sourceSetsByClassesDir = new HashMap<>();
@@ -241,18 +242,36 @@ private static void collectDestinationDirs(Collection<SourceDir> sources, final
241242
private void collectExtensionDependencies(Project project, Configuration deploymentConfiguration,
242243
ApplicationModelBuilder modelBuilder) {
243244
final ResolvedConfiguration rc = deploymentConfiguration.getResolvedConfiguration();
245+
final Set<ArtifactKey> processedDeps = new HashSet<>();
244246
for (var dep : rc.getFirstLevelModuleDependencies()) {
245-
processDeploymentDependency(project, dep, modelBuilder, false);
247+
processDeploymentDependency(project, dep, modelBuilder, false, processedDeps);
246248
}
247249
}
248250

249251
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));
252+
ApplicationModelBuilder modelBuilder, boolean clearReloadableFlag, Set<ArtifactKey> processedDeps) {
253+
final Set<ResolvedArtifact> resolvedArtifacts = resolvedDep.getModuleArtifacts();
254+
boolean processChildren = resolvedArtifacts.isEmpty();
255+
for (var a : resolvedArtifacts) {
256+
final ArtifactKey artifactKey = getKey(a);
257+
if (!processedDeps.add(artifactKey)) {
258+
continue;
259+
}
260+
processChildren = true;
261+
ResolvedDependencyBuilder dep = modelBuilder.getDependency(artifactKey);
254262
if (dep == null) {
255-
if (a.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier projectComponentIdentifier) {
263+
if (isApplicationRoot(modelBuilder, artifactKey)) {
264+
// An application root artifact may be found among the dependencies in a could of cases:
265+
// test fixtures in an application project and as a deployment module in an extension project
266+
// running deployment module tests.
267+
// In case of test fixtures, the root artifact does not have to be added to the model as a dependency,
268+
// it can simply be skipped.
269+
// In case of a deployment test, it has to be added as a dependency, since otherwise, the deployment
270+
// module will appear to be missing.
271+
// This part here looks like a hack but appears to work for both cases so far.
272+
dep = modelBuilder.getApplicationArtifact();
273+
} else if (a.getId()
274+
.getComponentIdentifier() instanceof ProjectComponentIdentifier projectComponentIdentifier) {
256275
var includedBuild = ToolingUtils.includedBuild(project,
257276
projectComponentIdentifier.getBuild().getBuildPath());
258277
final Project projectDep;
@@ -297,22 +316,26 @@ private static void processDeploymentDependency(Project project, ResolvedDepende
297316
}
298317
}
299318
if (dep != null) {
300-
if (!dep.isDeploymentCp()) {
301-
dep.setDeploymentCp();
302-
processChildren = true;
319+
if (dep.isRuntimeExtensionArtifact()) {
320+
clearReloadableFlag = true;
303321
}
304-
if (clearReloadableFlag) {
322+
dep.setDeploymentCp();
323+
if (clearReloadableFlag && dep != modelBuilder.getApplicationArtifact()) {
305324
dep.clearFlag(DependencyFlags.RELOADABLE);
306325
}
307326
}
308327
}
309328
if (processChildren) {
310329
for (var child : resolvedDep.getChildren()) {
311-
processDeploymentDependency(project, child, modelBuilder, clearReloadableFlag);
330+
processDeploymentDependency(project, child, modelBuilder, clearReloadableFlag, processedDeps);
312331
}
313332
}
314333
}
315334

335+
private static boolean isApplicationRoot(ApplicationModelBuilder modelBuilder, ArtifactKey artifactKey) {
336+
return modelBuilder.getApplicationArtifact().getKey().equals(artifactKey);
337+
}
338+
316339
private static ResolvedDependencyBuilder addArtifactDependency(Project project, ApplicationModelBuilder modelBuilder,
317340
ResolvedArtifact a) {
318341
ResolvedDependencyBuilder dep = modelBuilder.getDependency(getKey(a));
@@ -350,9 +373,7 @@ private void collectDependencies(ResolvedConfiguration configuration, Resolvable
350373

351374
final Set<File> artifactFiles = getArtifactFilesOrNull(configuration, dependencies);
352375
for (ResolvedDependency d : configuration.getFirstLevelModuleDependencies()) {
353-
collectDependencies(d, workspaceDiscovery, project, artifactFiles, new HashSet<>(),
354-
modelBuilder,
355-
wsModule,
376+
collectDependencies(d, workspaceDiscovery, project, artifactFiles, modelBuilder, wsModule,
356377
(byte) (COLLECT_TOP_EXTENSION_RUNTIME_NODES | COLLECT_DIRECT_DEPS | COLLECT_RELOADABLE_MODULES));
357378
}
358379

@@ -403,86 +424,94 @@ private static Set<File> getArtifactFilesOrNull(ResolvedConfiguration configurat
403424
}
404425

405426
private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency resolvedDep, boolean workspaceDiscovery,
406-
Project project, Set<File> artifactFiles, Set<ArtifactKey> processedModules, ApplicationModelBuilder modelBuilder,
427+
Project project, Set<File> artifactFiles, ApplicationModelBuilder modelBuilder,
407428
WorkspaceModule.Mutable parentModule,
408429
byte flags) {
409430
WorkspaceModule.Mutable projectModule = null;
410-
for (ResolvedArtifact a : resolvedDep.getModuleArtifacts()) {
431+
final Set<ResolvedArtifact> resolvedArtifacts = resolvedDep.getModuleArtifacts();
432+
boolean processChildren = resolvedArtifacts.isEmpty();
433+
for (ResolvedArtifact a : resolvedArtifacts) {
411434
if (!isDependency(a)) {
412435
continue;
413436
}
414-
var depBuilder = modelBuilder.getDependency(getKey(a));
415-
if (depBuilder != null) {
416-
if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) {
417-
depBuilder.setDirect(true);
418-
}
437+
final ArtifactKey artifactKey = getKey(a);
438+
if (isApplicationRoot(modelBuilder, artifactKey)) {
419439
continue;
420440
}
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());
441+
var depBuilder = modelBuilder.getDependency(artifactKey);
442+
if (depBuilder == null) {
443+
processChildren = true;
444+
final ArtifactCoords depCoords = getArtifactCoords(a);
445+
depBuilder = ResolvedDependencyBuilder.newInstance()
446+
.setCoords(depCoords)
447+
.setRuntimeCp();
448+
if (parentModule != null) {
449+
parentModule.addDependency(new ArtifactDependency(depCoords));
450+
}
436451

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);
452+
PathCollection paths = null;
453+
if (workspaceDiscovery && a.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier compId) {
454+
Project projectDep = project.getRootProject().findProject(compId.getProjectPath());
455+
456+
final String classifier = a.getClassifier();
457+
if (classifier == null || classifier.isEmpty()) {
458+
final IncludedBuild includedBuild = ToolingUtils.includedBuild(project.getRootProject(),
459+
compId.getBuild().getBuildPath());
460+
if (includedBuild != null) {
461+
if (includedBuild instanceof IncludedBuildInternal ib) {
462+
projectDep = ToolingUtils.includedBuildProject(ib, compId.getProjectPath());
463+
}
464+
if (projectDep != null) {
465+
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
466+
} else {
467+
final PathList.Builder pathBuilder = PathList.builder();
468+
addSubstitutedProject(pathBuilder, includedBuild.getProjectDir());
469+
paths = pathBuilder.build();
470+
}
447471
} else {
448-
final PathList.Builder pathBuilder = PathList.builder();
449-
addSubstitutedProject(pathBuilder, includedBuild.getProjectDir());
450-
paths = pathBuilder.build();
472+
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
451473
}
452474
} else {
453475
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
454476
}
455-
} else {
456-
initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder);
457477
}
458-
}
459478

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)) {
479+
depBuilder.setResolvedPaths(paths == null ? PathList.of(a.getFile().toPath()) : paths);
480+
if (processQuarkusDependency(depBuilder, modelBuilder)) {
481+
flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
482+
}
483+
modelBuilder.addDependency(depBuilder);
484+
485+
if (artifactFiles != null) {
486+
artifactFiles.add(a.getFile());
487+
}
488+
}
489+
if (projectModule == null && depBuilder.getWorkspaceModule() != null) {
490+
projectModule = depBuilder.getWorkspaceModule().mutable();
491+
}
492+
if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) {
493+
depBuilder.setDirect(true);
494+
flags = clearFlag(flags, COLLECT_DIRECT_DEPS);
495+
}
496+
if (depBuilder.isRuntimeExtensionArtifact()) {
497+
if (isFlagOn(flags, COLLECT_RELOADABLE_MODULES)) {
498+
flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
499+
processChildren = true;
500+
}
501+
if (isFlagOn(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES)
502+
&& !depBuilder.isFlagSet(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT)) {
463503
depBuilder.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT);
464504
flags = clearFlag(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES);
465505
}
466-
flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
467506
}
468507
if (!isFlagOn(flags, COLLECT_RELOADABLE_MODULES)) {
469508
depBuilder.clearFlag(DependencyFlags.RELOADABLE);
470509
}
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-
}
479510
}
480511

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);
512+
if (processChildren) {
513+
for (org.gradle.api.artifacts.ResolvedDependency child : resolvedDep.getChildren()) {
514+
collectDependencies(child, workspaceDiscovery, project, artifactFiles, modelBuilder, projectModule, flags);
486515
}
487516
}
488517
}

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
}

0 commit comments

Comments
 (0)