From f39fcd96cffdcbb75436e172f576ec9b0d3219e7 Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Fri, 10 Feb 2023 23:25:54 +0100 Subject: [PATCH] Make sure quarkus:go-offline properly supports test scoped dependencies --- .../java/io/quarkus/maven/GoOfflineMojo.java | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/devtools/maven/src/main/java/io/quarkus/maven/GoOfflineMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/GoOfflineMojo.java index 2c82939b41f4b..76b6bda9e6fa7 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/GoOfflineMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/GoOfflineMojo.java @@ -5,6 +5,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; @@ -28,6 +29,7 @@ import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace; import io.quarkus.bootstrap.util.IoUtils; +import io.quarkus.bootstrap.workspace.ArtifactSources; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.runtime.LaunchMode; @@ -39,19 +41,27 @@ public class GoOfflineMojo extends AbstractMojo { @Parameter(defaultValue = "${project}", readonly = true, required = true) - protected MavenProject project; + MavenProject project; @Component - private RepositorySystem repoSystem; + RepositorySystem repoSystem; @Component RemoteRepositoryManager remoteRepositoryManager; @Parameter(defaultValue = "${repositorySystemSession}", readonly = true) - private RepositorySystemSession repoSession; + RepositorySystemSession repoSession; @Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true, required = true) - private List repos; + List repos; + + /** + * Target launch mode corresponding to {@link io.quarkus.runtime.LaunchMode} for which the dependencies should be resolved. + * {@code io.quarkus.runtime.LaunchMode.TEST} is the default, since it includes both {@code provided} and {@code test} + * dependency scopes. + */ + @Parameter(property = "mode", required = false, defaultValue = "test") + String mode; @Override public void execute() throws MojoExecutionException, MojoFailureException { @@ -62,21 +72,40 @@ public void execute() throws MojoExecutionException, MojoFailureException { project.getVersion()); final MavenArtifactResolver resolver = getResolver(); + final BootstrapAppModelResolver appModelResolver = new BootstrapAppModelResolver(resolver); + + final Set excludedScopes; + if (mode.equalsIgnoreCase("test")) { + appModelResolver.setTest(true); + excludedScopes = Set.of(); + } else if (mode.equalsIgnoreCase("dev") || mode.equalsIgnoreCase("development")) { + appModelResolver.setDevMode(true); + excludedScopes = Set.of("test"); + } else if (mode.equalsIgnoreCase("prod") || mode.isEmpty()) { + excludedScopes = Set.of("test", "provided"); + } else { + throw new IllegalArgumentException( + "Unrecognized mode '" + mode + "', supported values are test, dev, development, prod"); + } + final DependencyNode root; try { - root = resolver.collectDependencies(pom, List.of()).getRoot(); + root = resolver.getSystem().collectDependencies( + resolver.getSession(), + resolver.newCollectManagedRequest(pom, List.of(), List.of(), List.of(), List.of(), excludedScopes)) + .getRoot(); } catch (Exception e) { throw new MojoExecutionException("Failed to collect dependencies of " + pom, e); } - final List createdDirs = new ArrayList<>(); + final LocalWorkspace workspace = resolver.getMavenContext().getWorkspace(); + final List createdDirs = new ArrayList<>(workspace.getProjects().size()); try { - ensureResolvableModule(root, resolver.getMavenContext().getWorkspace(), createdDirs); - final ArtifactCoords appArtifact = ArtifactCoords.of(pom.getGroupId(), pom.getArtifactId(), pom.getClassifier(), - pom.getExtension(), pom.getVersion()); - resolveAppModel(resolver, appArtifact, LaunchMode.NORMAL); - resolveAppModel(resolver, appArtifact, LaunchMode.DEVELOPMENT); - resolveAppModel(resolver, appArtifact, LaunchMode.TEST); + ensureResolvableModule(root, workspace, createdDirs); + appModelResolver.resolveModel(ArtifactCoords.of(pom.getGroupId(), pom.getArtifactId(), pom.getClassifier(), + pom.getExtension(), pom.getVersion())); + } catch (AppModelResolverException e) { + throw new MojoExecutionException("Failed to resolve Quarkus application model for " + project.getArtifact(), e); } finally { for (Path d : createdDirs) { IoUtils.recursiveDelete(d); @@ -84,21 +113,6 @@ public void execute() throws MojoExecutionException, MojoFailureException { } } - private void resolveAppModel(final MavenArtifactResolver resolver, final ArtifactCoords appArtifact, LaunchMode mode) - throws MojoExecutionException { - final BootstrapAppModelResolver appModelResolver = new BootstrapAppModelResolver(resolver); - if (mode == LaunchMode.DEVELOPMENT) { - appModelResolver.setDevMode(true); - } else if (mode == LaunchMode.TEST) { - appModelResolver.setTest(true); - } - try { - appModelResolver.resolveModel(appArtifact); - } catch (AppModelResolverException e) { - throw new MojoExecutionException("Failed to resolve Quarkus application model for " + project.getArtifact(), e); - } - } - private MavenArtifactResolver getResolver() throws MojoExecutionException { try { return MavenArtifactResolver.builder() @@ -118,7 +132,12 @@ private static void ensureResolvableModule(DependencyNode node, LocalWorkspace w if (artifact != null) { final LocalProject module = workspace.getProject(artifact.getGroupId(), artifact.getArtifactId()); if (module != null && !module.getRawModel().getPackaging().equals(ArtifactCoords.TYPE_POM)) { - final Path classesDir = module.getClassesDir(); + final Path classesDir; + if (artifact.getClassifier().equals(ArtifactSources.TEST)) { + classesDir = module.getTestClassesDir(); + } else { + classesDir = module.getClassesDir(); + } if (!Files.exists(classesDir)) { Path topDirToCreate = classesDir; while (!Files.exists(topDirToCreate.getParent())) {