From 62483ed4e49ca601d0fb45b65f38cddb8635bcc6 Mon Sep 17 00:00:00 2001 From: Alex Katlein Date: Mon, 19 Feb 2024 18:29:11 +0100 Subject: [PATCH] Fixed a prior change which erroneously pulled in all transitive deployment modules - Now it's back to the previous behavior (pulling in deployment modules declared as dependencies of other deployment modules) - Gradle extension plugin now verifies that all required deployment modules are specified in dependencies - Added integration test to make sure such transitive dependencies are resolved correctly (especially regarding exclusions) - Clarified documentation about validation of extensions --- .../gradle/QuarkusExtensionPlugin.java | 6 +- devtools/gradle/gradle-model/build.gradle.kts | 1 + .../ConditionalDependenciesEnabler.java | 6 - devtools/gradle/gradle/libs.versions.toml | 4 +- .../src/main/asciidoc/writing-extensions.adoc | 10 +- integration-tests/gradle/pom.xml | 34 +++ .../build.gradle | 32 ++ .../gradle.properties | 2 + .../settings.gradle | 17 ++ .../main/java/org/acme/GreetingResource.java | 16 + .../src/main/java/org/acme/MyEntity.java | 14 + .../resources/META-INF/resources/index.html | 285 ++++++++++++++++++ .../src/main/resources/application.properties | 5 + .../java/org/acme/GreetingResourceIT.java | 8 + .../java/org/acme/GreetingResourceTest.java | 21 ++ .../deployment/build.gradle | 2 + ...usionInExtensionDependencyDevModeTest.java | 27 ++ 17 files changed, 475 insertions(+), 15 deletions(-) create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/build.gradle create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/gradle.properties create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/settings.gradle create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/GreetingResource.java create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/MyEntity.java create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/META-INF/resources/index.html create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/application.properties create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/native-test/java/org/acme/GreetingResourceIT.java create mode 100644 integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/test/java/org/acme/GreetingResourceTest.java create mode 100644 integration-tests/gradle/src/test/java/io/quarkus/gradle/devmode/MavenExclusionInExtensionDependencyDevModeTest.java diff --git a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionPlugin.java b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionPlugin.java index 10b44971e697c..6f8cdb1146038 100644 --- a/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionPlugin.java +++ b/devtools/gradle/gradle-extension-plugin/src/main/java/io/quarkus/extension/gradle/QuarkusExtensionPlugin.java @@ -56,11 +56,13 @@ private void registerTasks(Project project, QuarkusExtensionConfiguration quarku Configuration runtimeModuleClasspath = project.getConfigurations() .getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); + TaskProvider validateExtensionTask = tasks.register(VALIDATE_EXTENSION_TASK_NAME, + ValidateExtensionTask.class, quarkusExt, runtimeModuleClasspath); + TaskProvider extensionDescriptorTask = tasks.register(EXTENSION_DESCRIPTOR_TASK_NAME, ExtensionDescriptorTask.class, quarkusExt, mainSourceSet, runtimeModuleClasspath); - TaskProvider validateExtensionTask = tasks.register(VALIDATE_EXTENSION_TASK_NAME, - ValidateExtensionTask.class, quarkusExt, runtimeModuleClasspath); + extensionDescriptorTask.configure(task -> task.dependsOn(validateExtensionTask)); project.getPlugins().withType( JavaPlugin.class, diff --git a/devtools/gradle/gradle-model/build.gradle.kts b/devtools/gradle/gradle-model/build.gradle.kts index be5055edd3d8c..da71708ccb97c 100644 --- a/devtools/gradle/gradle-model/build.gradle.kts +++ b/devtools/gradle/gradle-model/build.gradle.kts @@ -4,6 +4,7 @@ plugins { dependencies { compileOnly(libs.kotlin.gradle.plugin.api) + gradleApi() } group = "io.quarkus" diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java index 4d00b1055fcdd..dd34c24d8d6b1 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java @@ -102,12 +102,6 @@ private void collectConditionalDependencies(Set runtimeArtifac queueConditionalDependency(extension, conditionalDep); } } - - // If the extension doesn't have any conditions we just enable it by default - if (extension.getDependencyConditions().isEmpty()) { - extension.setConditional(true); - enableConditionalDependency(extension.getExtensionId()); - } } } } diff --git a/devtools/gradle/gradle/libs.versions.toml b/devtools/gradle/gradle/libs.versions.toml index 87c07810793ae..ea90dbb35ddee 100644 --- a/devtools/gradle/gradle/libs.versions.toml +++ b/devtools/gradle/gradle/libs.versions.toml @@ -22,8 +22,8 @@ quarkus-project-core-extension-codestarts = { module = "io.quarkus:quarkus-proje kotlin-gradle-plugin-api = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin-api", version.ref = "kotlin" } smallrye-config-yaml = { module = "io.smallrye.config:smallrye-config-source-yaml", version.ref = "smallrye-config" } -jackson-databind = {module="com.fasterxml.jackson.core:jackson-databind"} -jackson-dataformat-yaml = {module="com.fasterxml.jackson.dataformat:jackson-dataformat-yaml"} +jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind" } +jackson-dataformat-yaml = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" } junit-bom = { module = "org.junit:junit-bom", version.ref = "junit5" } junit-api = { module = "org.junit.jupiter:junit-jupiter-api" } diff --git a/docs/src/main/asciidoc/writing-extensions.adoc b/docs/src/main/asciidoc/writing-extensions.adoc index 36f38ed605e3e..9ce12cb7c48e7 100644 --- a/docs/src/main/asciidoc/writing-extensions.adoc +++ b/docs/src/main/asciidoc/writing-extensions.adoc @@ -384,8 +384,12 @@ Your extension project should be setup as a multi-module project with two submod Your runtime artifact should depend on `io.quarkus:quarkus-core`, and possibly the runtime artifacts of other Quarkus modules if you want to use functionality provided by them. + Your deployment time module should depend on `io.quarkus:quarkus-core-deployment`, your runtime artifact, -and possibly the deployment artifacts of other Quarkus modules if you want to use functionality provided by them. +and the deployment artifacts of any other Quarkus extensions your own extension depends on. This is essential, otherwise any transitively +pulled in extensions will not provide their full functionality. + +NOTE: The Maven and Gradle plugins will validate this for you and alert you to any deployment artifacts you might have forgotten to add. [WARNING] ==== @@ -573,10 +577,6 @@ dependencies { } ---- -[WARNING] -==== -This plugin is still experimental, it does not validate the extension dependencies as the equivalent Maven plugin does. -==== [[build-step-processors]] === Build Step Processors diff --git a/integration-tests/gradle/pom.xml b/integration-tests/gradle/pom.xml index 7cd72302039e2..610218d8b61aa 100644 --- a/integration-tests/gradle/pom.xml +++ b/integration-tests/gradle/pom.xml @@ -104,6 +104,10 @@ io.quarkus quarkus-hibernate-orm-panache + + io.quarkus + quarkus-hibernate-reactive-panache + io.quarkus quarkus-hibernate-search-orm-elasticsearch @@ -136,6 +140,10 @@ io.quarkus quarkus-kubernetes-client + + io.quarkus + quarkus-reactive-pg-client + io.quarkus quarkus-resteasy @@ -242,6 +250,19 @@ + + io.quarkus + quarkus-hibernate-reactive-panache-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-hibernate-search-orm-elasticsearch-deployment @@ -307,6 +328,19 @@ + + io.quarkus + quarkus-reactive-pg-client-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-resteasy-deployment diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/build.gradle b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/build.gradle new file mode 100644 index 0000000000000..21deaf7f0d7ca --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'java' + id 'io.quarkus' +} + +repositories { + mavenLocal { + content { + includeGroupByRegex 'io.quarkus.*' + includeGroup 'org.hibernate.orm' + } + } + mavenCentral() +} + +dependencies { + implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}") + implementation 'io.quarkus:quarkus-resteasy-reactive-jackson' + implementation 'io.quarkus:quarkus-hibernate-reactive-panache' + implementation 'io.quarkus:quarkus-reactive-pg-client' + implementation 'io.quarkus:quarkus-arc' + implementation 'io.quarkus:quarkus-resteasy-reactive' + testImplementation 'io.quarkus:quarkus-junit5' + testImplementation 'io.rest-assured:rest-assured' +} + +group 'org.acme' +version '1.0.0-SNAPSHOT' + +test { + systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager" +} diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/gradle.properties b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/gradle.properties new file mode 100644 index 0000000000000..ec2b6ef199c2c --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/gradle.properties @@ -0,0 +1,2 @@ +quarkusPlatformArtifactId=quarkus-bom +quarkusPlatformGroupId=io.quarkus diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/settings.gradle b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/settings.gradle new file mode 100644 index 0000000000000..b2d511f9f6a1a --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/settings.gradle @@ -0,0 +1,17 @@ +pluginManagement { + repositories { + mavenLocal { + content { + includeGroupByRegex 'io.quarkus.*' + includeGroup 'org.hibernate.orm' + } + } + mavenCentral() + gradlePluginPortal() + } + plugins { + id 'io.quarkus' version "${quarkusPluginVersion}" + } +} + +rootProject.name='code-with-quarkus' diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/GreetingResource.java b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/GreetingResource.java new file mode 100644 index 0000000000000..6938062ec8ff7 --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/GreetingResource.java @@ -0,0 +1,16 @@ +package org.acme; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/hello") +public class GreetingResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "Hello from RESTEasy Reactive"; + } +} diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/MyEntity.java b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/MyEntity.java new file mode 100644 index 0000000000000..a18f8d226cf27 --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/java/org/acme/MyEntity.java @@ -0,0 +1,14 @@ + +package org.acme; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import java.util.UUID; + +@Entity +public class MyEntity { + @Id + @GeneratedValue + private UUID id; +} \ No newline at end of file diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/META-INF/resources/index.html b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/META-INF/resources/index.html new file mode 100644 index 0000000000000..bd66dc4bb5121 --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/META-INF/resources/index.html @@ -0,0 +1,285 @@ + + + + + code-with-quarkus - 1.0.0-SNAPSHOT + + + +
+
+
+ + + + + quarkus_logo_horizontal_rgb_1280px_reverse + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+

You just made a Quarkus application.

+

This page is served by Quarkus.

+ Visit the Dev UI +

This page: src/main/resources/META-INF/resources/index.html

+

App configuration: src/main/resources/application.properties

+

Static assets: src/main/resources/META-INF/resources/

+

Code: src/main/java

+

Generated starter code:

+
    +
  • + RESTEasy Reactive Easily start your Reactive RESTful Web Services +
    @Path: /hello +
    Related guide +
  • + +
+
+
+

Selected extensions

+
    +
  • RESTEasy Reactive Jackson
  • +
  • Hibernate Reactive with Panache
  • +
  • Reactive PostgreSQL client (guide)
  • +
+
Documentation
+

Practical step-by-step guides to help you achieve a specific goal. Use them to help get your work + done.

+
Set up your IDE
+

Everyone has a favorite IDE they like to use to code. Learn how to configure yours to maximize your + Quarkus productivity.

+
+
+
+ + diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/application.properties b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/application.properties new file mode 100644 index 0000000000000..abaaf7722ef5e --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/main/resources/application.properties @@ -0,0 +1,5 @@ +quarkus.datasource.db-kind = postgresql +quarkus.datasource.username = quarkus_test +quarkus.datasource.password = quarkus_test +quarkus.datasource.reactive.url = vertx-reactive:postgresql://localhost:5432/quarkus_test +#quarkus.datasource.jdbc=false \ No newline at end of file diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/native-test/java/org/acme/GreetingResourceIT.java b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/native-test/java/org/acme/GreetingResourceIT.java new file mode 100644 index 0000000000000..cfa9d1b1aff2b --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/native-test/java/org/acme/GreetingResourceIT.java @@ -0,0 +1,8 @@ +package org.acme; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +class GreetingResourceIT extends GreetingResourceTest { + // Execute the same tests but in packaged mode. +} diff --git a/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/test/java/org/acme/GreetingResourceTest.java b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/test/java/org/acme/GreetingResourceTest.java new file mode 100644 index 0000000000000..1e0da3846c90e --- /dev/null +++ b/integration-tests/gradle/src/main/resources/maven-exclusion-in-extension-dependency/src/test/java/org/acme/GreetingResourceTest.java @@ -0,0 +1,21 @@ +package org.acme; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +class GreetingResourceTest { + @Test + void testHelloEndpoint() { + given() + .when().get("/hello") + .then() + .statusCode(200) + .body(is("Hello from RESTEasy Reactive")); + } + +} diff --git a/integration-tests/gradle/src/main/resources/multi-composite-build-extensions-project/extensions/another-example-extension/deployment/build.gradle b/integration-tests/gradle/src/main/resources/multi-composite-build-extensions-project/extensions/another-example-extension/deployment/build.gradle index 2114fbe38a983..4e2d4fa1829d5 100644 --- a/integration-tests/gradle/src/main/resources/multi-composite-build-extensions-project/extensions/another-example-extension/deployment/build.gradle +++ b/integration-tests/gradle/src/main/resources/multi-composite-build-extensions-project/extensions/another-example-extension/deployment/build.gradle @@ -13,6 +13,8 @@ dependencies { api project(':another-example-extension') // why: https://quarkus.io/guides/building-my-first-extension + implementation ('org.acme.extensions:example-extension-deployment') + implementation 'io.quarkus:quarkus-core-deployment' implementation 'io.quarkus:quarkus-arc-deployment' implementation ('org.acme.libs:libraryB') diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/devmode/MavenExclusionInExtensionDependencyDevModeTest.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/devmode/MavenExclusionInExtensionDependencyDevModeTest.java new file mode 100644 index 0000000000000..ef27b3d10c9b2 --- /dev/null +++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/devmode/MavenExclusionInExtensionDependencyDevModeTest.java @@ -0,0 +1,27 @@ +package io.quarkus.gradle.devmode; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This makes sure that exclusions in POM files of deployment modules are respected. + *

+ * One case where this is critical is when using quarkus-hibernate-reactive. Its deployment + * module takes care of pulling in quarkus-hibernate-orm-deployment where it excludes + * Agroal and Narayana. + *

+ * If that exclusion isn't taken into account by the Gradle plugin, it pulls in + * quarkus-hibernate-orm-deployment on its own, where those other modules aren't excluded, + * which leads to a failure at runtime because Agroal tries to initialize and looks + * for a JDBC driver which isn't typically available in reactive DB scenarios. + */ +public class MavenExclusionInExtensionDependencyDevModeTest extends QuarkusDevGradleTestBase { + @Override + protected String projectDirectoryName() { + return "maven-exclusion-in-extension-dependency"; + } + + @Override + protected void testDevMode() throws Exception { + assertThat(getHttpResponse("/hello")).contains("Hello"); + } +}