Repository: hibernate/hibernate-reactive
Pull request #2339 (2025-07-09 08:24:53)

[3.0] Migrate to Gradle version catalogs
Backport #1989 (PR #2331) to 3.0


Patch:
diff --git a/build.gradle b/build.gradle
index c514dd74..532d932e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,33 +3,15 @@ plugins {
 
     id 'java-library'
     id 'maven-publish'
-    id 'com.diffplug.spotless' version '6.25.0'
-    id 'org.asciidoctor.jvm.convert' version '4.0.2' apply false
-    id 'io.github.gradle-nexus.publish-plugin' version '1.3.0'
+    alias(libs.plugins.com.diffplug.spotless)
+    alias(libs.plugins.org.asciidoctor.jvm.convert) apply false
+    alias(libs.plugins.io.github.gradle.nexus.publish.plugin)
 }
 
 group = "org.hibernate.reactive"
 // leverage the ProjectVersion which comes from the `local.versions` plugin
 version = project.projectVersion.fullName
 
-// Versions which need to be aligned across modules; this also
-// allows overriding the build using a parameter, which can be
-// useful to monitor compatibility for upcoming versions on CI:
-//
-// ./gradlew clean build -PhibernateOrmVersion=5.6.15-SNAPSHOT
-ext {
-    // Mainly, to allow CI to test the latest versions of Vert.X
-    // Example:
-    // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT
-    if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) {
-        vertxSqlClientVersion = '4.5.16'
-    }
-
-    testcontainersVersion = '1.21.0'
-
-    logger.lifecycle "Vert.x SQL Client Version: " + project.vertxSqlClientVersion
-}
-
 subprojects {
     apply plugin: 'java-library'
     apply plugin: 'com.diffplug.spotless'
@@ -135,3 +117,10 @@ subprojects {
     }
 }
 
+rootProject.afterEvaluate {
+    // Workaround since "libs.versions.NAME" notation cannot be used here
+    def libs = project.extensions.getByType(VersionCatalogsExtension).named('libs')
+    logger.lifecycle "ORM version: ${libs.findVersion('hibernateOrmVersion').get().requiredVersion}"
+    logger.lifecycle "ORM Gradle plugin version: ${libs.findVersion('hibernateOrmGradlePluginVersion').get().requiredVersion}"
+    logger.lifecycle "Vert.x SQL Client version: ${libs.findVersion('vertxSqlClientVersion').get().requiredVersion}"
+}
diff --git a/documentation/build.gradle b/documentation/build.gradle
index aa6a2762..95c3dcb2 100644
--- a/documentation/build.gradle
+++ b/documentation/build.gradle
@@ -52,7 +52,7 @@ def aggregateJavadocsTask = tasks.register( 'aggregateJavadocs', Javadoc ) {
 		use = true
 		options.encoding = 'UTF-8'
 
-		def matcher = hibernateOrmVersion =~ /\d+\.\d+/
+		def matcher = libs.versions.hibernateOrmVersion =~ /\d+\.\d+/
 		def ormMinorVersion = matcher.find() ? matcher.group() : "5.6";
 
 		links = [
diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle
index 8695f9df..50c5a411 100644
--- a/examples/native-sql-example/build.gradle
+++ b/examples/native-sql-example/build.gradle
@@ -18,7 +18,7 @@ buildscript {
 
 plugins {
     // Optional: Hibernate Gradle plugin to enable bytecode enhancements
-    id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}"
+    alias(libs.plugins.org.hibernate.orm)
 }
 
 description = 'Hibernate Reactive native SQL Example'
@@ -27,20 +27,20 @@ dependencies {
     implementation project( ':hibernate-reactive-core' )
 
     // Hibernate Validator (optional)
-    implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final'
-    runtimeOnly 'org.glassfish.expressly:expressly:5.0.0'
+    implementation(libs.org.hibernate.validator.hibernate.validator)
+    runtimeOnly(libs.org.glassfish.expressly.expressly)
 
     // JPA metamodel generation for criteria queries (optional)
-    annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}"
+    annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen)
 
     // database driver for PostgreSQL
-    runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
+    runtimeOnly(libs.io.vertx.vertx.pg.client)
 
     // logging (optional)
-    runtimeOnly "org.apache.logging.log4j:log4j-core:2.20.0"
+    runtimeOnly(libs.org.apache.logging.log4j.log4j.core)
 
     // Allow authentication to PostgreSQL using SCRAM:
-    runtimeOnly 'com.ongres.scram:client:2.1'
+    runtimeOnly(libs.com.ongres.scram.client)
 }
 
 // Optional: enable the bytecode enhancements
diff --git a/examples/session-example/build.gradle b/examples/session-example/build.gradle
index f436ccd2..41f9135a 100644
--- a/examples/session-example/build.gradle
+++ b/examples/session-example/build.gradle
@@ -18,7 +18,7 @@ buildscript {
 
 plugins {
     // Optional: Hibernate Gradle plugin to enable bytecode enhancements
-    id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}"
+    alias(libs.plugins.org.hibernate.orm)
 }
 
 description = 'Hibernate Reactive Session Examples'
@@ -27,21 +27,21 @@ dependencies {
     implementation project( ':hibernate-reactive-core' )
 
     // Hibernate Validator (optional)
-    implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final'
-    runtimeOnly 'org.glassfish.expressly:expressly:5.0.0'
+    implementation(libs.org.hibernate.validator.hibernate.validator)
+    runtimeOnly(libs.org.glassfish.expressly.expressly)
 
     // JPA metamodel generation for criteria queries (optional)
-    annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}"
+    annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen)
 
     // database drivers for PostgreSQL and MySQL
-    runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
-    runtimeOnly "io.vertx:vertx-mysql-client:${vertxSqlClientVersion}"
+    runtimeOnly(libs.io.vertx.vertx.pg.client)
+    runtimeOnly(libs.io.vertx.vertx.mysql.client)
 
     // logging (optional)
-    runtimeOnly "org.apache.logging.log4j:log4j-core:2.20.0"
+    runtimeOnly(libs.org.apache.logging.log4j.log4j.core)
 
     // Allow authentication to PostgreSQL using SCRAM:
-    runtimeOnly 'com.ongres.scram:client:2.1'
+    runtimeOnly(libs.com.ongres.scram.client)
 }
 
 // Optional: enable the bytecode enhancements
diff --git a/gradle.properties b/gradle.properties
index 3ad8bf46..346e9fa4 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -18,7 +18,9 @@ org.gradle.java.installations.auto-download=false
 
 #########################################################################
 # Additional custom gradle build properties.
-# Please, leave these properties commented upstream
+# Please, leave these properties commented upstream.
+# They are meant to be used for local builds or WIP branches.
+# The same properties can be set from the command line.
 ##########################################################################
 
 # Enable Testcontainers + Docker when present (value ignored)
@@ -34,12 +36,12 @@ org.gradle.java.installations.auto-download=false
 # Enable the maven local repository (for local development when needed) when present (value ignored)
 #enableMavenLocalRepo = true
 
+### Settings the following properties will override the version defined in gradle/libs.versions.toml
+
 # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`)
-hibernateOrmVersion = 7.0.2.Final
+#hibernateOrmVersion = 7.0.2.Final
 
 # Override default Hibernate ORM Gradle plugin version
-# Using the stable version because I don't know how to configure the build to download the snapshot version from
-# a remote repository
 #hibernateOrmGradlePluginVersion = 7.0.2.Final
 
 # If set to true, skip Hibernate ORM version parsing (default is true, if set to null)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 00000000..816a2efb
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,59 @@
+[versions]
+assertjVersion = "3.27.3"
+hibernateOrmVersion = "7.0.2.Final"
+hibernateOrmGradlePluginVersion = "7.0.2.Final"
+jacksonDatabindVersion = "2.15.2"
+jbossLoggingAnnotationVersion = "3.0.4.Final"
+jbossLoggingVersion = "3.6.1.Final"
+junitVersion = "5.11.3"
+log4jVersion = "2.20.0"
+testcontainersVersion = "1.21.0"
+vertxSqlClientVersion = "4.5.16"
+vertxWebVersion= "4.5.16"
+vertxWebClientVersion = "4.5.16"
+
+[libraries]
+com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" }
+com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.0.0" }
+com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "12.10.0.jre11" }
+com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.3.0" }
+com-ongres-scram-client = { group = "com.ongres.scram", name = "client", version = "2.1" }
+io-smallrye-reactive-mutiny = { group = "io.smallrye.reactive", name = "mutiny", version = "2.9.0" }
+io-vertx-vertx-db2-client = { group = "io.vertx", name = "vertx-db2-client", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-junit5 = { group = "io.vertx", name = "vertx-junit5", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-micrometer-metrics = { group = "io.vertx", name = "vertx-micrometer-metrics", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-mssql-client = { group = "io.vertx", name = "vertx-mssql-client", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-mysql-client = { group = "io.vertx", name = "vertx-mysql-client", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-oracle-client = { group = "io.vertx", name = "vertx-oracle-client", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-pg-client = { group = "io.vertx", name = "vertx-pg-client", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-sql-client = { group = "io.vertx", name = "vertx-sql-client", version.ref = "vertxSqlClientVersion" }
+io-vertx-vertx-web = { group = "io.vertx", name = "vertx-web", version.ref = "vertxWebVersion" }
+io-vertx-vertx-web-client = { group = "io.vertx", name = "vertx-web-client", version.ref = "vertxWebClientVersion" }
+org-apache-logging-log4j-log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4jVersion" }
+org-assertj-assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertjVersion" }
+org-ehcache-ehcache = { group = "org.ehcache", name = "ehcache", version = "3.10.8" }
+org-glassfish-expressly-expressly = { group = "org.glassfish.expressly", name = "expressly", version = "5.0.0" }
+org-hibernate-orm-hibernate-core = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernateOrmVersion" }
+org-hibernate-orm-hibernate-jcache = { group = "org.hibernate.orm", name = "hibernate-jcache", version.ref = "hibernateOrmVersion" }
+org-hibernate-orm-hibernate-jpamodelgen = { group = "org.hibernate.orm", name = "hibernate-jpamodelgen", version.ref = "hibernateOrmVersion" }
+org-hibernate-validator-hibernate-validator = { group = "org.hibernate.validator", name = "hibernate-validator", version = "8.0.2.Final" }
+org-jboss-logging-jboss-logging = { group = "org.jboss.logging", name = "jboss-logging", version.ref = "jbossLoggingVersion" }
+org-jboss-logging-jboss-logging-annotations = { group = "org.jboss.logging", name = "jboss-logging-annotations", version.ref = "jbossLoggingAnnotationVersion" }
+org-jboss-logging-jboss-logging-processor = { group = "org.jboss.logging", name = "jboss-logging-processor", version.ref = "jbossLoggingAnnotationVersion" }
+org-junit-jupiter-junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitVersion" }
+org-junit-jupiter-junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitVersion" }
+org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.3" }
+org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.5" }
+org-testcontainers-cockroachdb = { group = "org.testcontainers", name = "cockroachdb", version.ref = "testcontainersVersion" }
+org-testcontainers-db2 = { group = "org.testcontainers", name = "db2", version.ref = "testcontainersVersion" }
+org-testcontainers-mariadb = { group = "org.testcontainers", name = "mariadb", version.ref = "testcontainersVersion" }
+org-testcontainers-mssqlserver = { group = "org.testcontainers", name = "mssqlserver", version.ref = "testcontainersVersion" }
+org-testcontainers-mysql = { group = "org.testcontainers", name = "mysql", version.ref = "testcontainersVersion" }
+org-testcontainers-oracle-xe = { group = "org.testcontainers", name = "oracle-xe", version.ref = "testcontainersVersion" }
+org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgresql", version.ref = "testcontainersVersion" }
+
+[plugins]
+com-diffplug-spotless = { id = "com.diffplug.spotless", version = "6.25.0" }
+io-github-gradle-nexus-publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version = "1.3.0" }
+org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.2" }
+org-hibernate-orm = { id = "org.hibernate.orm", version.ref = "hibernateOrmGradlePluginVersion" }
diff --git a/hibernate-reactive-core/build.gradle b/hibernate-reactive-core/build.gradle
index 36717d03..04f35e98 100644
--- a/hibernate-reactive-core/build.gradle
+++ b/hibernate-reactive-core/build.gradle
@@ -8,77 +8,77 @@ apply from: publishScript
 
 dependencies {
 
-    api "org.hibernate.orm:hibernate-core:${hibernateOrmVersion}"
+    api(libs.org.hibernate.orm.hibernate.core)
 
-    api 'io.smallrye.reactive:mutiny:2.9.0'
+    api(libs.io.smallrye.reactive.mutiny)
 
     //Logging
-    implementation 'org.jboss.logging:jboss-logging:3.6.1.Final'
-    annotationProcessor 'org.jboss.logging:jboss-logging:3.6.1.Final'
+    implementation(libs.org.jboss.logging.jboss.logging)
+    annotationProcessor(libs.org.jboss.logging.jboss.logging)
 
-    compileOnly 'org.jboss.logging:jboss-logging-annotations:3.0.4.Final'
-    annotationProcessor 'org.jboss.logging:jboss-logging-annotations:3.0.4.Final'
-    annotationProcessor 'org.jboss.logging:jboss-logging-processor:3.0.4.Final'
+    compileOnly(libs.org.jboss.logging.jboss.logging.annotations)
+    annotationProcessor(libs.org.jboss.logging.jboss.logging.annotations)
+    annotationProcessor(libs.org.jboss.logging.jboss.logging.processor)
 
 
     //Specific implementation details of Hibernate Reactive:
-    implementation "io.vertx:vertx-sql-client:${vertxSqlClientVersion}"
+    implementation(libs.io.vertx.vertx.sql.client)
 
     // Testing
-    testImplementation 'org.assertj:assertj-core:3.27.3'
-    testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}"
+    testImplementation(libs.org.assertj.assertj.core)
+    testImplementation(libs.io.vertx.vertx.junit5)
 
     // Drivers
-    testImplementation "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
-    testImplementation "io.vertx:vertx-mysql-client:${vertxSqlClientVersion}"
-    testImplementation "io.vertx:vertx-db2-client:${vertxSqlClientVersion}"
-    testImplementation "io.vertx:vertx-mssql-client:${vertxSqlClientVersion}"
-    testImplementation "io.vertx:vertx-oracle-client:${vertxSqlClientVersion}"
+    testImplementation(libs.io.vertx.vertx.pg.client)
+    testImplementation(libs.io.vertx.vertx.mysql.client)
+    testImplementation(libs.io.vertx.vertx.db2.client)
+    testImplementation(libs.io.vertx.vertx.mssql.client)
+    testImplementation(libs.io.vertx.vertx.oracle.client)
 
     // Metrics
-    testImplementation "io.vertx:vertx-micrometer-metrics:${vertxSqlClientVersion}"
+    testImplementation(libs.io.vertx.vertx.micrometer.metrics)
 
     // Optional dependency of vertx-pg-client, essential when connecting via SASL SCRAM
-    testImplementation 'com.ongres.scram:client:2.1'
+    testImplementation(libs.com.ongres.scram.client)
 
     // JUnit Jupiter
-    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3'
-    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.3'
+    testImplementation(libs.org.junit.jupiter.junit.jupiter.api)
+    testRuntimeOnly(libs.org.junit.jupiter.junit.jupiter.engine)
 
     // JDBC driver to test with ORM and PostgreSQL
-    testRuntimeOnly "org.postgresql:postgresql:42.7.5"
+    testRuntimeOnly(libs.org.postgresql.postgresql)
 
     // JDBC driver for Testcontainers with MS SQL Server
-    testRuntimeOnly "com.microsoft.sqlserver:mssql-jdbc:12.10.0.jre11"
+    testRuntimeOnly(libs.com.microsoft.sqlserver.mssql.jdbc)
 
     // JDBC driver for Testcontainers with MariaDB Server
-    testRuntimeOnly "org.mariadb.jdbc:mariadb-java-client:3.5.3"
+    testRuntimeOnly(libs.org.mariadb.jdbc.mariadb.java.client)
 
     // JDBC driver for Testcontainers with MYSQL Server
-    testRuntimeOnly "com.mysql:mysql-connector-j:9.3.0"
+    testRuntimeOnly(libs.com.mysql.mysql.connector.j)
 
     // JDBC driver for Db2 server, for testing
-    testRuntimeOnly "com.ibm.db2:jcc:12.1.0.0"
+    testRuntimeOnly(libs.com.ibm.db2.jcc)
 
     // EHCache
-    testRuntimeOnly ("org.ehcache:ehcache:3.10.8") {
+    testRuntimeOnly(libs.org.ehcache.ehcache) {
             capabilities {
                 requireCapability 'org.ehcache.modules:ehcache-xml-jakarta'
             }
     }
-    testRuntimeOnly ("org.hibernate.orm:hibernate-jcache:${hibernateOrmVersion}")
+    testRuntimeOnly(libs.org.hibernate.orm.hibernate.jcache)
 
     // log4j
-    testRuntimeOnly 'org.apache.logging.log4j:log4j-core:2.20.0'
+    testRuntimeOnly(libs.org.apache.logging.log4j.log4j.core)
 
     // Testcontainers
-    testImplementation "org.testcontainers:postgresql:${testcontainersVersion}"
-    testImplementation "org.testcontainers:mysql:${testcontainersVersion}"
-    testImplementation "org.testcontainers:mariadb:${testcontainersVersion}"
-    testImplementation "org.testcontainers:db2:${testcontainersVersion}"
-    testImplementation "org.testcontainers:cockroachdb:${testcontainersVersion}"
-    testImplementation "org.testcontainers:mssqlserver:${testcontainersVersion}"
-    testImplementation "org.testcontainers:oracle-xe:${testcontainersVersion}"
+    testImplementation(libs.org.testcontainers.postgresql)
+    testImplementation(libs.org.testcontainers.mysql)
+    testImplementation(libs.org.testcontainers.mariadb)
+    testImplementation(libs.org.testcontainers.db2)
+    testImplementation(libs.org.testcontainers.cockroachdb)
+    testImplementation(libs.org.testcontainers.mssqlserver)
+    testImplementation(libs.org.testcontainers.oracle.xe)
 }
 
 // Reproducible Builds
diff --git a/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java
index 36b5ae10..c34a4b47 100644
--- a/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java
+++ b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java
@@ -28,6 +28,7 @@ public class VersionsPlugin implements Plugin<Project> {
 	public static final String SKIP_ORM_VERSION_PARSING = "skipOrmVersionParsing";
 
 	public static final String RELATIVE_FILE = "gradle/version.properties";
+	public static final String RELATIVE_CATALOG = "gradle/libs.versions.toml";
 
 	@Override
 	public void apply(Project project) {
@@ -57,12 +58,13 @@ public void apply(Project project) {
 			project.getLogger().lifecycle( "Development version: n/a" );
 		}
 
-		final String ormVersionString = determineOrmVersion( project );
+		final VersionsTomlParser tomlParser = new VersionsTomlParser( RELATIVE_CATALOG );
+		final String ormVersionString = determineOrmVersion( project, tomlParser );
 		final Object ormVersion = resolveOrmVersion( ormVersionString, project );
 		project.getLogger().lifecycle( "ORM version: {}", ormVersion );
 		project.getExtensions().add( ORM_VERSION, ormVersion );
 
-		final Object ormPluginVersion = determineOrmPluginVersion( ormVersion, project );
+		final Object ormPluginVersion = determineOrmPluginVersion( ormVersion, project, tomlParser );
 		project.getLogger().lifecycle( "ORM Gradle plugin version: {}", ormPluginVersion );
 		project.getExtensions().add( ORM_PLUGIN_VERSION, ormPluginVersion );
 	}
@@ -123,10 +125,17 @@ private static void withInputStream(File file, Consumer<InputStream> action) {
 		}
 	}
 
-	private String determineOrmVersion(Project project) {
+	private String determineOrmVersion(Project project, VersionsTomlParser parser) {
+		// Check if it has been set in the project
 		if ( project.hasProperty( ORM_VERSION ) ) {
 			return (String) project.property( ORM_VERSION );
 		}
+
+		// Check in the catalog
+		final String version = parser.read( ORM_VERSION );
+		if ( version != null ) {
+			return version;
+		}
 		throw new IllegalStateException( "Hibernate ORM version not specified on project" );
 	}
 
@@ -138,10 +147,18 @@ private Object resolveOrmVersion(String stringForm, Project project) {
 		return new ProjectVersion( stringForm );
 	}
 
-	private Object determineOrmPluginVersion(Object ormVersion, Project project) {
+	private Object determineOrmPluginVersion(Object ormVersion, Project project, VersionsTomlParser parser) {
+		// Check if it has been set in the project
 		if ( project.hasProperty( ORM_PLUGIN_VERSION ) ) {
 			return project.property( ORM_PLUGIN_VERSION );
 		}
-		return ormVersion;
+
+		// Check in the catalog
+		final String version = parser.read( ORM_PLUGIN_VERSION );
+		if ( version != null ) {
+			return version;
+		}
+
+		throw new IllegalStateException( "Hibernate ORM Gradle plugin version not specified on project" );
 	}
 }
diff --git a/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java
new file mode 100644
index 00000000..b0adafd6
--- /dev/null
+++ b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java
@@ -0,0 +1,68 @@
+package org.hibernate.reactive.env;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Read the versions section of the library catalog
+ */
+public class VersionsTomlParser {
+
+    private final Map<String, String> data = new HashMap<>();
+
+    public VersionsTomlParser(String filePath) {
+        parse( filePath );
+    }
+
+    private void parse(String filePath) {
+        try ( BufferedReader reader = new BufferedReader( new FileReader( filePath ) ) ) {
+            String line;
+            String currentSection = null;
+            while ( ( line = reader.readLine() ) != null ) {
+                line = line.trim();
+
+                // Skip comments and blank lines
+                if ( line.isEmpty() || line.startsWith( "#" ) ) {
+                    continue;
+                }
+
+                // Handle [section]
+                if ( line.startsWith( "[" ) && line.endsWith( "]" ) ) {
+                    currentSection = line.substring( 1, line.length() - 1 ).trim();
+                    continue;
+                }
+
+                if ( "versions".equalsIgnoreCase( currentSection ) ) {
+                    // Handle key = value
+                    int equalsIndex = line.indexOf( '=' );
+                    if ( equalsIndex == -1 ) {
+                        continue;
+                    }
+
+                    String key = line.substring( 0, equalsIndex ).trim();
+                    String value = line.substring( equalsIndex + 1 ).trim();
+
+                    // Remove optional quotes around string values
+                    if ( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
+                        value = value.substring( 1, value.length() - 1 );
+                    }
+
+                    data.put( key, value );
+                }
+            }
+        }
+        catch (IOException e) {
+            throw new RuntimeException( e );
+        }
+    }
+
+    /**
+     * Read the value of the property in the versions section of a toml file
+     */
+    public String read(String property) {
+        return data.get( property );
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index e997f3e7..159d91e2 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -19,6 +19,44 @@ gradle.ext.baselineJavaVersion = JavaLanguageVersion.of( 17 )
 // You can't use bytecode higher than what Gradle supports, even with toolchains.
 def GRADLE_MAX_SUPPORTED_BYTECODE_VERSION = 23
 
+// This overrides the default version catalog in gradle/libs.versions.toml, which can be
+// useful to monitor compatibility for upcoming versions on CI:
+dependencyResolutionManagement {
+    versionCatalogs {
+        create("libs") {
+            // ./gradlew build -PhibernateOrmVersion=7.0.2.Final
+            def hibernateOrmVersion = settings.ext.find("hibernateOrmVersion") ?: ""
+            if ( hibernateOrmVersion != "" ) {
+                version("hibernateOrmVersion", hibernateOrmVersion)
+            }
+
+            // ./gradlew build -PhibernateOrmGradlePluginVersion=7.0.2.Final
+            def hibernateOrmGradlePluginVersion = settings.ext.find("hibernateOrmGradlePluginVersion") ?: ""
+            if ( hibernateOrmGradlePluginVersion ) {
+                version("hibernateOrmGradlePluginVersion", hibernateOrmGradlePluginVersion)
+            }
+
+            // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT
+            def vertxSqlClientVersion = settings.ext.find("vertxSqlClientVersion") ?: ""
+            if ( vertxSqlClientVersion ) {
+                version("vertxSqlClientVersion", vertxSqlClientVersion)
+            }
+
+            // ./gradlew build -PvertxWebVersion=4.0.0-SNAPSHOT
+            def vertxWebVersion = settings.ext.find("vertxWebVersion") ?: vertxSqlClientVersion
+            if ( vertxWebVersion ) {
+                version("vertxWebVersion", vertxWebVersion)
+            }
+
+            // ./gradlew build -PvertxWebClientVersion=4.0.0-SNAPSHOT
+            def vertxWebClientVersion = settings.ext.find("vertxWebClientVersion") ?: vertxSqlClientVersion
+            if ( vertxWebClientVersion ) {
+                version("vertxWebClientVersion", vertxWebClientVersion)
+            }
+        }
+    }
+}
+
 // If either 'main.jdk.version' or 'test.jdk.version' is set, enable the toolchain and use the selected jdk.
 // If only one property is set, the other defaults to the baseline Java version (8).
 // Note that when toolchain is enabled, you also need to specify


Test patch:
diff --git a/integration-tests/bytecode-enhancements-it/build.gradle b/integration-tests/bytecode-enhancements-it/build.gradle
index 17ffdf10..cd9a23e5 100644
--- a/integration-tests/bytecode-enhancements-it/build.gradle
+++ b/integration-tests/bytecode-enhancements-it/build.gradle
@@ -10,37 +10,32 @@ buildscript {
 }
 
 plugins {
-    id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}"
+    alias(libs.plugins.org.hibernate.orm)
 }
 
 description = 'Bytecode enhancements integration tests'
 
-ext {
-    log4jVersion = '2.20.0'
-    assertjVersion = '3.27.3'
-}
-
 dependencies {
     implementation project(':hibernate-reactive-core')
 
     // JPA metamodel generation for criteria queries (optional)
-    annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}"
+    annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen)
 
     // Testing on one database should be enough
-    runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
+    runtimeOnly(libs.io.vertx.vertx.pg.client)
 
     // Allow authentication to PostgreSQL using SCRAM:
-    runtimeOnly 'com.ongres.scram:client:2.1'
+    runtimeOnly(libs.com.ongres.scram.client)
 
     // logging
-    runtimeOnly "org.apache.logging.log4j:log4j-core:${log4jVersion}"
+    runtimeOnly(libs.org.apache.logging.log4j.log4j.core)
 
     // Testcontainers
-    testImplementation "org.testcontainers:postgresql:${testcontainersVersion}"
+    testImplementation(libs.org.testcontainers.postgresql)
 
     // Testing
-    testImplementation "org.assertj:assertj-core:${assertjVersion}"
-    testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}"
+    testImplementation(libs.org.assertj.assertj.core)
+    testImplementation(libs.io.vertx.vertx.junit5)
 }
 
 // Optional: enable the bytecode enhancements
@@ -113,4 +108,4 @@ tasks.addRule( "Pattern testDb<id>" ) { String taskName ->
 
         }
     }
-}
\ No newline at end of file
+}
diff --git a/integration-tests/hibernate-validator-postgres-it/build.gradle b/integration-tests/hibernate-validator-postgres-it/build.gradle
index 27689b24..61500ef8 100644
--- a/integration-tests/hibernate-validator-postgres-it/build.gradle
+++ b/integration-tests/hibernate-validator-postgres-it/build.gradle
@@ -10,39 +10,34 @@ buildscript {
 }
 
 plugins {
-    id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}"
+    alias(libs.plugins.org.hibernate.orm)
 }
 
 description = 'Quarkus QE integration tests'
 
-ext {
-    log4jVersion = '2.20.0'
-    assertjVersion = '3.27.3'
-}
-
 dependencies {
     implementation project(':hibernate-reactive-core')
-    implementation "org.hibernate.validator:hibernate-validator:8.0.2.Final"
-    runtimeOnly 'org.glassfish.expressly:expressly:5.0.0'
+    implementation(libs.org.hibernate.validator.hibernate.validator)
+    runtimeOnly(libs.org.glassfish.expressly.expressly)
 
     // JPA metamodel generation for criteria queries (optional)
-    annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}"
+    annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen)
 
     // Testing on one database should be enough
-    runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
+    runtimeOnly(libs.io.vertx.vertx.pg.client)
 
     // Allow authentication to PostgreSQL using SCRAM:
-    runtimeOnly 'com.ongres.scram:client:2.1'
+    runtimeOnly(libs.com.ongres.scram.client)
 
     // logging
-    runtimeOnly "org.apache.logging.log4j:log4j-core:${log4jVersion}"
+    runtimeOnly(libs.org.apache.logging.log4j.log4j.core)
 
     // Testcontainers
-    testImplementation "org.testcontainers:postgresql:${testcontainersVersion}"
+    testImplementation(libs.org.testcontainers.postgresql)
 
     // Testing
-    testImplementation "org.assertj:assertj-core:${assertjVersion}"
-    testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}"
+    testImplementation(libs.org.assertj.assertj.core)
+    testImplementation(libs.io.vertx.vertx.junit5)
 }
 
 // Optional: enable the bytecode enhancements
@@ -116,4 +111,4 @@ tasks.addRule( "Pattern testDb<id>" ) { String taskName ->
 
         }
     }
-}
\ No newline at end of file
+}
diff --git a/integration-tests/techempower-postgres-it/build.gradle b/integration-tests/techempower-postgres-it/build.gradle
index 5c4ecda4..edfc4ae4 100644
--- a/integration-tests/techempower-postgres-it/build.gradle
+++ b/integration-tests/techempower-postgres-it/build.gradle
@@ -11,37 +11,25 @@ buildscript {
 
 description = 'TechEmpower integration tests'
 
-ext {
-	jacksonDatabindVersion = '2.15.2'
-	jbossLoggingVersion = '3.5.0.Final'
-	assertjVersion = '3.27.3'
-	vertxWebVersion = project.hasProperty( 'vertxWebVersion' )
-			? project.property( 'vertxWebVersion' )
-			: vertxSqlClientVersion
-	vertxWebClientVersion = project.hasProperty( 'vertxWebClientVersion' )
-			? project.property( 'vertxWebClientVersion' )
-			: vertxSqlClientVersion
-}
-
 dependencies {
 	implementation project( ':hibernate-reactive-core' )
-	implementation "io.vertx:vertx-web:${vertxWebVersion}"
-	implementation "io.vertx:vertx-web-client:${vertxWebClientVersion}"
+	implementation(libs.io.vertx.vertx.web)
+	implementation(libs.io.vertx.vertx.web.client)
 
-	runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
+	runtimeOnly(libs.io.vertx.vertx.pg.client)
 	// The Pg client requires this dependency
-	runtimeOnly "com.ongres.scram:client:2.1"
-	runtimeOnly "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}"
+	runtimeOnly(libs.com.ongres.scram.client)
+	runtimeOnly(libs.com.fasterxml.jackson.core.jackson.databind)
 
 	// logging
-	implementation "org.jboss.logging:jboss-logging:${jbossLoggingVersion}"
+	implementation(libs.org.jboss.logging.jboss.logging)
 
 	// Testcontainers
-	implementation "org.testcontainers:postgresql:${testcontainersVersion}"
+	implementation(libs.org.testcontainers.postgresql)
 
 	// Testing
-	testImplementation "org.assertj:assertj-core:${assertjVersion}"
-	testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}"
+	testImplementation(libs.org.assertj.assertj.core)
+	testImplementation(libs.io.vertx.vertx.junit5)
 }
 
 // Configuration for the tests
diff --git a/integration-tests/verticle-postgres-it/build.gradle b/integration-tests/verticle-postgres-it/build.gradle
index 0be23462..2cd6edfe 100644
--- a/integration-tests/verticle-postgres-it/build.gradle
+++ b/integration-tests/verticle-postgres-it/build.gradle
@@ -11,37 +11,25 @@ buildscript {
 
 description = 'Bytecode enhancements integration tests'
 
-ext {
-    jacksonDatabindVersion = '2.15.2'
-    jbossLoggingVersion = '3.5.0.Final'
-    assertjVersion = '3.27.3'
-    vertxWebVersion = project.hasProperty( 'vertxWebVersion' )
-            ? project.property( 'vertxWebVersion' )
-            : vertxSqlClientVersion
-    vertxWebClientVersion = project.hasProperty( 'vertxWebClientVersion' )
-            ? project.property( 'vertxWebClientVersion' )
-            : vertxSqlClientVersion
-}
-
 dependencies {
     implementation project(':hibernate-reactive-core')
-    implementation "io.vertx:vertx-web:${vertxWebVersion}"
-    implementation "io.vertx:vertx-web-client:${vertxWebClientVersion}"
+    implementation(libs.io.vertx.vertx.web)
+    implementation(libs.io.vertx.vertx.web.client)
 
-    runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}"
+    runtimeOnly(libs.io.vertx.vertx.pg.client)
     // The Pg client requires this dependency
-    runtimeOnly "com.ongres.scram:client:2.1"
-    runtimeOnly "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}"
+    runtimeOnly(libs.com.ongres.scram.client)
+    runtimeOnly(libs.com.fasterxml.jackson.core.jackson.databind)
 
     // logging
-    implementation "org.jboss.logging:jboss-logging:${jbossLoggingVersion}"
+    implementation(libs.org.jboss.logging.jboss.logging)
 
     // Testcontainers
-    implementation "org.testcontainers:postgresql:${testcontainersVersion}"
+    implementation(libs.org.testcontainers.postgresql)
 
     // Testing
-    testImplementation "org.assertj:assertj-core:${assertjVersion}"
-    testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}"
+    testImplementation(libs.org.assertj.assertj.core)
+    testImplementation(libs.io.vertx.vertx.junit5)
 }
 
 // Configuration for the tests