Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 8 additions & 41 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,17 @@ jobs:
path: grails-forge/tmp1/cli/**/*
if-no-files-found: 'error'
functional:
name: "Functional Tests (Java ${{ matrix.java }}, indy=${{ matrix.indy }})"
name: "Functional Tests (Java ${{ matrix.java }}, Hibernate ${{ matrix.hibernate-version }}, indy=${{ matrix.indy }})"
if: ${{ !contains(github.event.head_commit.message, '[skip tests]') }}
strategy:
fail-fast: false
matrix:
java: [ 17, 21, 25 ]
hibernate-version: [ '5', '7' ]
indy: [ false ]
include:
- java: 17
hibernate-version: '5'
indy: true
runs-on: ubuntu-24.04
steps:
Expand All @@ -234,6 +236,8 @@ jobs:
- name: "🔍 Setup TestLens"
uses: testlens-app/setup-testlens@v1
- name: "🏃 Run Functional Tests"
env:
GITHUB_MAVEN_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
run: >
./gradlew bootJar check
--continue
Expand All @@ -243,8 +247,9 @@ jobs:
-PgrailsIndy=${{ matrix.indy }}
-PonlyFunctionalTests
-PskipCodeStyle
-PskipHibernate5Tests
-PskipMongodbTests
-PhibernateVersion=${{ matrix.hibernate-version }}
-PskipHibernate${{ matrix.hibernate-version == '5' && '7' || '5' }}Tests
mongodbFunctional:
if: ${{ !contains(github.event.head_commit.message, '[skip tests]') }}
name: "Mongodb Functional Tests (Java ${{ matrix.java }}, MongoDB ${{ matrix.mongodb-version }}, indy=${{ matrix.indy }})"
Expand Down Expand Up @@ -285,43 +290,6 @@ jobs:
-PonlyMongodbTests
-PmongodbContainerVersion=${{ matrix.mongodb-version }}
-PskipCodeStyle
hibernate5Functional:
if: ${{ !contains(github.event.head_commit.message, '[skip tests]') }}
name: "Hibernate5 Functional Tests (Java ${{ matrix.java }}, indy=${{ matrix.indy }})"
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
java: [ 17, 25 ]
indy: [ false ]
include:
- java: 17
indy: true
steps:
- name: "Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it
run: curl -s https://api.ipify.org
- name: "📥 Checkout the repository"
uses: actions/checkout@v6
- name: "☕️ Setup JDK"
uses: actions/setup-java@v4
with:
distribution: liberica
java-version: ${{ matrix.java }}
- name: "🐘 Setup Gradle"
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
develocity-access-key: ${{ secrets.GRAILS_DEVELOCITY_ACCESS_KEY }}
- name: "🏃 Run Functional Tests"
env:
GITHUB_MAVEN_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
run: >
./gradlew bootJar check
--continue
--rerun-tasks
--stacktrace
-PgrailsIndy=${{ matrix.indy }}
-PonlyHibernate5Tests
-PskipCodeStyle
publishGradle:
if: github.repository_owner == 'apache' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
needs: [ buildGradle ]
Expand Down Expand Up @@ -364,15 +332,14 @@ jobs:
name: grails-gradle-artifacts.txt
path: grails-gradle/build/grails-gradle-artifacts.txt
publish:
needs: [ publishGradle, build, functional, hibernate5Functional, mongodbFunctional ]
needs: [ publishGradle, build, functional, mongodbFunctional ]
if: >-
${{ always() &&
github.repository_owner == 'apache' &&
(github.event_name == 'push' || github.event_name == 'workflow_dispatch') &&
needs.publishGradle.result == 'success' &&
(needs.build.result == 'success' || needs.build.result == 'skipped') &&
(needs.functional.result == 'success' || needs.functional.result == 'skipped') &&
(needs.hibernate5Functional.result == 'success' || needs.hibernate5Functional.result == 'skipped') &&
(needs.mongodbFunctional.result == 'success' || needs.mongodbFunctional.result == 'skipped')
}}
runs-on: ubuntu-24.04
Expand Down
56 changes: 56 additions & 0 deletions gradle/functional-test-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@ rootProject.subprojects
.findAll { !(it.name in testProjects) && !(it.name in docProjects) && !(it.name in cliProjects) }
.each { project.evaluationDependsOn(it.path) }

// Determine which Hibernate version to use for general functional tests.
// Pass -PhibernateVersion=7 to run general functional tests against Hibernate 7 instead of 5.
def targetHibernateVersion = project.findProperty('hibernateVersion') ?: '5'
boolean isHibernateSpecificProject = project.name.startsWith('grails-test-examples-hibernate5') ||
project.name.startsWith('grails-test-examples-hibernate7')
boolean isMongoProject = project.name.startsWith('grails-test-examples-mongodb')
boolean isGeneralFunctionalTest = !isHibernateSpecificProject && !isMongoProject

Comment on lines +24 to +31
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hibernateVersion is accepted as an arbitrary string and silently falls back to “Hibernate 5 behavior” for any value other than '7'. That can hide typos/misconfiguration (especially for local runs). Consider normalizing + validating the value (e.g., allow only '5'/'7' and throw a GradleException otherwise) so the build fails fast when an unsupported value is provided.

Copilot uses AI. Check for mistakes.
// General functional test projects that use Hibernate 5-specific GORM APIs and cannot run
// under Hibernate 7 via dependency substitution. These use executeUpdate(String) without
// parameters (H7 requires a Map parameter), HibernateSpec unit tests (different domain class
// detection in H7), or ChainedTransactionManager behavior that changed in H7.
// Their H7-compatible equivalents live in grails-test-examples/hibernate7/.
List<String> h7IncompatibleProjects = [
'grails-test-examples-app1',
'grails-test-examples-datasources',
'grails-test-examples-gorm',
'grails-test-examples-views-functional-tests',
'grails-test-examples-scaffolding-fields',
]

configurations.configureEach {
resolutionStrategy.dependencySubstitution {
// Test projects will often include dependencies from local projects. This will ensure any dependencies
Expand Down Expand Up @@ -51,6 +72,22 @@ configurations.configureEach {
}
}
}

// For general (non-hibernate-labeled) functional test projects, redirect Hibernate 5 dependencies
// to Hibernate 7 projects when -PhibernateVersion=7 is set. These rules are added after the loop
// so they override the default substitutions for the h5 modules.
// Projects in h7IncompatibleProjects are excluded since they use H5-specific GORM APIs.
if (isGeneralFunctionalTest && targetHibernateVersion == '7' && !(project.name in h7IncompatibleProjects)) {
substitute module('org.apache.grails:grails-data-hibernate5') using project(':grails-data-hibernate7')
substitute module('org.apache.grails:grails-data-hibernate5-spring-boot') using project(':grails-data-hibernate7-spring-boot')
}
}

// Exclude Hibernate 5-specific runtime dependencies when testing general projects with Hibernate 7.
// These libraries have no Hibernate 7 equivalent and would cause classpath conflicts.
if (isGeneralFunctionalTest && targetHibernateVersion == '7' && !(project.name in h7IncompatibleProjects)) {
exclude group: 'org.hibernate', module: 'hibernate-ehcache'
exclude group: 'org.jboss.spec.javax.transaction', module: 'jboss-transaction-api_1.3_spec'
}
}

Expand All @@ -68,6 +105,11 @@ tasks.withType(Test).configureEach { Test task ->
return false
}

// Skip projects with known H7 API incompatibilities when running with hibernateVersion=7
if (targetHibernateVersion == '7' && project.name in h7IncompatibleProjects) {
return false
}

if (project.hasProperty('onlyHibernate5Tests')) {
if (isHibernate5) {
return false
Expand All @@ -80,6 +122,20 @@ tasks.withType(Test).configureEach { Test task ->
}
}

// Skip hibernate5-labeled projects when -PskipHibernate5Tests is set
if (project.hasProperty('skipHibernate5Tests')) {
if (!isHibernate5) {
return false
}
}

// Skip hibernate7-labeled projects when -PskipHibernate7Tests is set
if (project.hasProperty('skipHibernate7Tests')) {
if (!isHibernate7) {
return false
}
}
Comment on lines +121 to +133
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The skipHibernate5Tests / skipHibernate7Tests logic relies on isHibernate5 / isHibernate7 being defined as negated startsWith(...) checks (so isHibernate5 == false actually means “this is an hibernate5-labeled project”). This inverted naming makes the skip conditions hard to reason about and easy to break with future edits. Consider redefining these booleans to match their names (or renaming them to isNotHibernate5Project/etc.) and then update the onlyIf conditions accordingly.

Copilot uses AI. Check for mistakes.

if (project.hasProperty('onlyMongodbTests')) {
if (isMongo) {
return false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.grails.datastore.gorm.boot.autoconfigure.HibernateGormAutoConfiguration
6 changes: 2 additions & 4 deletions grails-test-examples/gorm/grails-app/conf/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,8 @@ grails:
---
hibernate:
cache:
use_second_level_cache: true
provider_class: net.sf.ehcache.hibernate.EhCacheProvider
region:
factory_class: org.hibernate.cache.ehcache.EhCacheRegionFactory
use_second_level_cache: false
use_query_cache: false
dataSource:
pooled: true
jmxExport: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,8 @@ grails:
hibernate:
cache:
queries: false
use_second_level_cache: true
use_second_level_cache: false
use_query_cache: false
region.factory_class: 'org.hibernate.cache.ehcache.EhCacheRegionFactory'

endpoints:
jmx:
Expand Down
Loading