From a3d5e86b0fe289d34a6c3c9642b2856c6f2f6978 Mon Sep 17 00:00:00 2001 From: Sergio del Amo Date: Tue, 7 Jan 2025 16:40:34 +0100 Subject: [PATCH] For Maven, if a dependency with runtime and test, a runtime dependency is added (#2683) --- .../build/dependencies/Dependency.java | 14 ++++ .../build/dependencies/DependencyContext.java | 12 ++-- .../FeatureWithDuplicatesSpec.groovy | 8 ++- .../build/maven/MavenDependencySpec.groovy | 65 ++++++++++++++++++ .../LogbackInTestAndRuntimeSpec.groovy | 66 +++++++++++++++++++ 5 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 starter-core/src/test/groovy/io/micronaut/starter/build/maven/MavenDependencySpec.groovy create mode 100644 starter-core/src/test/groovy/io/micronaut/starter/feature/logging/LogbackInTestAndRuntimeSpec.groovy diff --git a/starter-core/src/main/java/io/micronaut/starter/build/dependencies/Dependency.java b/starter-core/src/main/java/io/micronaut/starter/build/dependencies/Dependency.java index 9322aaac9c7..3d4d0119485 100644 --- a/starter-core/src/main/java/io/micronaut/starter/build/dependencies/Dependency.java +++ b/starter-core/src/main/java/io/micronaut/starter/build/dependencies/Dependency.java @@ -210,6 +210,20 @@ public boolean isAnnotationProcessorPriority() { return annotationProcessorPriority; } + public static Dependency of(Dependency dep, Scope scope) { + return new Dependency(scope, + dep.getGroupId(), + dep.getArtifactId(), + dep.getVersion(), + dep.getVersionProperty(), + dep.requiresLookup(), + dep.isAnnotationProcessorPriority(), + dep.getOrder(), + dep.isPom(), + dep.getExclusions(), + dep.getSubstitutions()); + } + public static class Builder { private Scope scope; diff --git a/starter-core/src/main/java/io/micronaut/starter/build/dependencies/DependencyContext.java b/starter-core/src/main/java/io/micronaut/starter/build/dependencies/DependencyContext.java index 1382b531c8e..2d52ee63799 100644 --- a/starter-core/src/main/java/io/micronaut/starter/build/dependencies/DependencyContext.java +++ b/starter-core/src/main/java/io/micronaut/starter/build/dependencies/DependencyContext.java @@ -19,11 +19,7 @@ import io.micronaut.starter.options.BuildTool; import io.micronaut.starter.options.Language; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Predicate; import static io.micronaut.starter.build.dependencies.Phase.COMPILATION; @@ -79,8 +75,10 @@ default List removeDuplicates(Collection dependencies, L dependenciesInTestClasspathWithoutDuplicates.removeIf(testDep -> { MavenCoordinate test = new MavenCoordinate(testDep.getGroupId(), testDep.getArtifactId(), testDep.getVersion()); return dependenciesInMainClasspathWithoutDuplicates.stream() - .filter(mainDep -> (mainDep.getScope().getPhases().contains(RUNTIME) && mainDep.getScope().getPhases().contains(COMPILATION))) - .anyMatch(mainDep -> { + .filter(mainDep -> + (buildTool == BuildTool.MAVEN && mainDep.getScope().getPhases().contains(RUNTIME)) || + (mainDep.getScope().getPhases().contains(RUNTIME) && mainDep.getScope().getPhases().contains(COMPILATION)) + ).anyMatch(mainDep -> { MavenCoordinate main = new MavenCoordinate(mainDep.getGroupId(), mainDep.getArtifactId(), mainDep.getVersion()); return main.equals(test); }); diff --git a/starter-core/src/test/groovy/io/micronaut/starter/build/dependencies/FeatureWithDuplicatesSpec.groovy b/starter-core/src/test/groovy/io/micronaut/starter/build/dependencies/FeatureWithDuplicatesSpec.groovy index a880c06695c..58ef99caeb4 100644 --- a/starter-core/src/test/groovy/io/micronaut/starter/build/dependencies/FeatureWithDuplicatesSpec.groovy +++ b/starter-core/src/test/groovy/io/micronaut/starter/build/dependencies/FeatureWithDuplicatesSpec.groovy @@ -28,8 +28,12 @@ class FeatureWithDuplicatesSpec extends BeanContextSpec implements CommandOutput verifier.hasDependency("org.gebish", "geb-core", Scope.COMPILE) and: 'for a dependency in runtime and test, both runtime and test should be added' - verifier.hasDependency("org.seleniumhq.selenium", "selenium-firefox-driver", Scope.RUNTIME) - verifier.hasDependency("org.seleniumhq.selenium", "selenium-firefox-driver", Scope.TEST) + if (buildTool.isGradle()) { + assert verifier.hasDependency("org.seleniumhq.selenium", "selenium-firefox-driver", Scope.RUNTIME) + assert verifier.hasDependency("org.seleniumhq.selenium", "selenium-firefox-driver", Scope.TEST) + } else if(buildTool == BuildTool.MAVEN) { + assert verifier.hasDependency("org.seleniumhq.selenium", "selenium-firefox-driver", Scope.RUNTIME) + } where: [language, buildTool] << [Language.values(), BuildTool.values()].combinations() diff --git a/starter-core/src/test/groovy/io/micronaut/starter/build/maven/MavenDependencySpec.groovy b/starter-core/src/test/groovy/io/micronaut/starter/build/maven/MavenDependencySpec.groovy new file mode 100644 index 00000000000..2aa3574afdf --- /dev/null +++ b/starter-core/src/test/groovy/io/micronaut/starter/build/maven/MavenDependencySpec.groovy @@ -0,0 +1,65 @@ +package io.micronaut.starter.build.maven + +import io.micronaut.starter.BeanContextSpec +import io.micronaut.starter.application.generator.DependencyContextImpl +import io.micronaut.starter.build.dependencies.CoordinateResolver +import io.micronaut.starter.build.dependencies.Dependency +import io.micronaut.starter.build.dependencies.DependencyContext +import io.micronaut.starter.build.dependencies.Scope +import io.micronaut.starter.fixture.CommandOutputFixture +import io.micronaut.starter.options.BuildTool +import io.micronaut.starter.options.Language + +class MavenDependencySpec extends BeanContextSpec implements CommandOutputFixture { + + public static final String ARTIFACT_ID_LOGBACK_CLASSIC = "logback-classic" + public static final String GROUP_ID_LOGBACK = "ch.qos.logback" + + void "maven dependency in test and runtime should be only in compile"() { + given: + CoordinateResolver coordinateResolver = beanContext.getBean(CoordinateResolver) + DependencyContext dependencyContext = new DependencyContextImpl(coordinateResolver) + + when: + List dependencies = dependencyContext.removeDuplicates(List.of( + Dependency.builder().scope(Scope.COMPILE).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + Dependency.builder().scope(Scope.RUNTIME).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + ), Language.JAVA, BuildTool.MAVEN) + + then: + dependencies == List.of( + Dependency.builder().scope(Scope.COMPILE).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build()) + + when: + dependencies = dependencyContext.removeDuplicates(List.of( + Dependency.builder().scope(Scope.TEST).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + Dependency.builder().scope(Scope.RUNTIME).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + ), Language.JAVA, BuildTool.GRADLE) + + then: + dependencies == List.of( + Dependency.builder().scope(Scope.RUNTIME).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + Dependency.builder().scope(Scope.TEST).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + ) + + when: + dependencies = dependencyContext.removeDuplicates(List.of( + Dependency.builder().scope(Scope.TEST).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + Dependency.builder().scope(Scope.RUNTIME).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + ), Language.JAVA, BuildTool.MAVEN) + + then: + dependencies == List.of( + Dependency.builder().scope(Scope.RUNTIME).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build()) + + when: + dependencies = dependencyContext.removeDuplicates(List.of( + Dependency.builder().scope(Scope.COMPILE).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + Dependency.builder().scope(Scope.RUNTIME).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build(), + ), Language.JAVA, BuildTool.MAVEN) + + then: + dependencies == List.of( + Dependency.builder().scope(Scope.COMPILE).groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).build()) + } +} diff --git a/starter-core/src/test/groovy/io/micronaut/starter/feature/logging/LogbackInTestAndRuntimeSpec.groovy b/starter-core/src/test/groovy/io/micronaut/starter/feature/logging/LogbackInTestAndRuntimeSpec.groovy new file mode 100644 index 00000000000..2ce4a048b1c --- /dev/null +++ b/starter-core/src/test/groovy/io/micronaut/starter/feature/logging/LogbackInTestAndRuntimeSpec.groovy @@ -0,0 +1,66 @@ +package io.micronaut.starter.feature.logging + +import io.micronaut.context.annotation.Requires +import io.micronaut.starter.ApplicationContextSpec +import io.micronaut.starter.BuildBuilder +import io.micronaut.starter.application.ApplicationType +import io.micronaut.starter.application.generator.GeneratorContext +import io.micronaut.starter.build.BuildTestUtil +import io.micronaut.starter.build.BuildTestVerifier +import io.micronaut.starter.build.dependencies.Dependency +import io.micronaut.starter.build.dependencies.Scope +import io.micronaut.starter.feature.Feature +import io.micronaut.starter.fixture.CommandOutputFixture +import io.micronaut.starter.options.BuildTool +import io.micronaut.starter.options.Language +import jakarta.inject.Singleton + +class LogbackInTestAndRuntimeSpec extends ApplicationContextSpec implements CommandOutputFixture { + private static final String ARTIFACT_ID_LOGBACK_CLASSIC = "logback-classic" + private static final String GROUP_ID_LOGBACK = "ch.qos.logback" + + Map getConfiguration() { + return super.getConfiguration() + ["spec.name": "LogbackInTestAndRuntimeSpec"] + } + + void "compile if runtime and test dependency"() { + given: + BuildTool buildTool = BuildTool.MAVEN + Language language = Language.JAVA + when: + String template = new BuildBuilder(beanContext, buildTool) + .language(language) + .features(["test-logback"]) + .render() + BuildTestVerifier verifier = BuildTestUtil.verifier(buildTool, language, template) + + then: + verifier.hasDependency(GROUP_ID_LOGBACK, ARTIFACT_ID_LOGBACK_CLASSIC, Scope.RUNTIME) + !verifier.hasDependency(GROUP_ID_LOGBACK, ARTIFACT_ID_LOGBACK_CLASSIC, Scope.TEST) + } + + @Requires(property = "spec.name", value = "LogbackInTestAndRuntimeSpec") + @Singleton + static class TestLogback implements Feature { + + @Override + String getName() { + return "test-logback" + } + + @Override + String getTitle() { + return "Test Logback" + } + + @Override + void apply(GeneratorContext generatorContext) { + generatorContext.addDependency(Dependency.builder().groupId(GROUP_ID_LOGBACK).artifactId(ARTIFACT_ID_LOGBACK_CLASSIC).scope(Scope.TEST).build()) + } + + @Override + boolean supports(ApplicationType applicationType) { + true + } + } +}