Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bf05dfc
docs: add Neo4j GormRegistry migration plan (PR1 baseline + PR2 wiring)
borinquenkid Jun 29, 2026
510840d
feat: migrate grails-data-neo4j to Groovy 4/Jakarta/GORM 8 baseline
borinquenkid Jul 3, 2026
98945fc
fix: address Copilot review findings on PR #15816
borinquenkid Jul 3, 2026
2877865
fix: resolve Neo4j regressions surfaced by rebasing onto Groovy 5
borinquenkid Jul 4, 2026
8ae69b9
feat(grails-data-neo4j): fold standalone build into root settings.gradle
borinquenkid Jul 5, 2026
1e440bf
fix: avoid Groovy MOP getProperty interception in Neo4jDataStoreSprin…
borinquenkid Jul 6, 2026
3f6266a
feat: wire Neo4j adapter to GormRegistry's GormApiFactory mechanism
borinquenkid Jul 3, 2026
4904e4c
feat(grails-data-neo4j): re-add example apps and docs into monorepo (…
borinquenkid Jul 5, 2026
f2bdfdd
fix(grails-data-neo4j): declare intentional Jetty/neo4j-driver BOM ov…
borinquenkid Jul 6, 2026
6a074bb
chore(grails-data-neo4j): clean up Checkstyle/CodeNarc violations in …
borinquenkid Jul 5, 2026
1910468
fix: address jdaugherty's review feedback on consolidated Neo4j PR
borinquenkid Jul 11, 2026
1591129
fix: BOM-manage neo4j-java-driver with a strictly constraint, not exc…
borinquenkid Jul 11, 2026
08698bd
fix: rename gorm-neo4j-spring-boot to grails-data-neo4j-spring-boot
borinquenkid Jul 11, 2026
332d13f
feat: add dedicated Neo4j functional-test CI job and publish gating
borinquenkid Jul 11, 2026
53f0bb8
feat(grails-data-neo4j): restore neo4j-standalone example app
borinquenkid Jul 11, 2026
ca1cd33
feat(grails-data-neo4j): restore test-data-service example app
borinquenkid Jul 11, 2026
5e436f2
feat(grails-forge): restore Neo4j GORM support
borinquenkid Jul 11, 2026
00bdb11
refactor(grails-data-neo4j): rename grails-datastore-gorm-neo4j to gr…
borinquenkid Jul 11, 2026
1989e69
refactor(grails-data-neo4j): rename example apps to base/hibernate5
borinquenkid Jul 11, 2026
73f1854
fix(grails-data-neo4j): resolve all 270 CodeNarc violations in grails…
borinquenkid Jul 11, 2026
65e72a5
fix(grails-test-examples): drop stale grailsSpringSecurityVersion pro…
borinquenkid Jul 11, 2026
02b12e2
refactor(grails-data-neo4j): dedupe test/Jetty/driver build config, d…
borinquenkid Jul 12, 2026
75a8c1e
fix(grails-data-neo4j): scope neo4j-java-driver pin to a dedicated gr…
borinquenkid Jul 12, 2026
b0a2ba4
fix(grails-data-neo4j): remove dead GormEnhancer overrides in Neo4jDa…
borinquenkid Jul 19, 2026
b0f3371
fix(grails-data-neo4j): implement embedded-component support and fix …
borinquenkid Jul 19, 2026
9f507a7
fix(grails-data-neo4j): add missing jakarta.servlet-api test dep; fix…
borinquenkid Jul 19, 2026
f46c47a
fix(grails-forge): update GormImplSpec's stale 'neo4j' expectation
borinquenkid Jul 19, 2026
eeebb06
fix(grails-data-neo4j): use grails-neo4j-bom platform in docs module
borinquenkid Jul 19, 2026
b834100
fix(grails-test-examples-neo4j): use ContainerGebSpec in the restored…
borinquenkid Aug 1, 2026
452449b
test(tck): skip TCK "Test optimistic locking" for Neo4j
borinquenkid Aug 1, 2026
37c67e5
test(tck): skip TCK criteria-pagination-without-sort feature for Neo4j
borinquenkid Aug 1, 2026
616339a
fix(grails-data-neo4j): BOM-manage neo4j-harness version, dedupe exam…
borinquenkid Aug 16, 2026
7981e42
fix(grails-console,grails-core): name empty-catch params 'ignored' fo…
borinquenkid Aug 16, 2026
5284c5c
Merge branch 'feat/gorm-registry-core-impl' into feat/neo4j-gorm-regi…
borinquenkid Aug 16, 2026
1f08891
Merge branch 'feat/gorm-registry-core-impl' into feat/neo4j-gorm-regi…
borinquenkid Aug 16, 2026
fbc58f3
fix(grails-neo4j-bom): align with 8.0.x derived-BOM pattern
borinquenkid Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
44 changes: 42 additions & 2 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ jobs:
-PskipHibernate5Tests
-PskipHibernate7Tests
-PskipMongodbTests
-PskipNeo4jTests
-PskipSpringSecurityTests
-PskipRedisTests
${{ matrix.shard_arguments }}
Expand Down Expand Up @@ -777,6 +778,44 @@ jobs:
-PonlyHibernate7Tests
-PskipCodeStyle
${{ matrix.shard_arguments }}
neo4jFunctional:
if: ${{ !contains(github.event.head_commit.message, '[skip tests]') }}
name: "Neo4j Functional Tests (Java ${{ matrix.java }}, indy=${{ matrix.indy }})"
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
java: [ 21, 25 ]
indy: [ false ]
include:
- java: 21
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: "☕️ Setup JDK"
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: liberica
java-version: ${{ matrix.java }}
- name: "🐘 Setup Gradle"
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
with:
cache-provider: basic # 'basic' uses the MIT-licensed, open-source cache provider; the default 'enhanced' provider (v6+) is proprietary (Gradle commercial Terms of Use)
develocity-access-key: ${{ secrets.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 }}
-PonlyNeo4jTests
-PskipCodeStyle
publishGradle:
if: github.repository_owner == 'apache' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
needs: [ buildGradle ]
Expand Down Expand Up @@ -831,7 +870,7 @@ jobs:
name: grails-gradle-artifacts.txt
path: grails-gradle/build/grails-gradle-artifacts.txt
publish:
needs: [ publishGradle, build, functional, security, securityConfig, redis, hibernate5Functional, hibernate7Functional, mongodbFunctional ]
needs: [ publishGradle, build, functional, security, securityConfig, redis, hibernate5Functional, hibernate7Functional, mongodbFunctional, neo4jFunctional ]
if: >-
${{ always() &&
github.repository_owner == 'apache' &&
Expand All @@ -844,7 +883,8 @@ jobs:
(needs.redis.result == 'success' || needs.redis.result == 'skipped') &&
(needs.hibernate5Functional.result == 'success' || needs.hibernate5Functional.result == 'skipped') &&
(needs.hibernate7Functional.result == 'success' || needs.hibernate7Functional.result == 'skipped') &&
(needs.mongodbFunctional.result == 'success' || needs.mongodbFunctional.result == 'skipped')
(needs.mongodbFunctional.result == 'success' || needs.mongodbFunctional.result == 'skipped') &&
(needs.neo4jFunctional.result == 'success' || needs.neo4jFunctional.result == 'skipped')
}}
runs-on: ubuntu-24.04
steps:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ _alternativeTable.gsp
**/src/en/ref/Versions/Grails BOM.adoc
**/src/en/ref/Versions/Grails BOM Hibernate5.adoc
**/src/en/ref/Versions/Grails BOM Hibernate7.adoc
**/src/en/ref/Versions/Grails BOM Neo4j.adoc
**/src/en/ref/Versions/Grails BOM Micronaut.adoc
**/src/en/ref/Versions/Grails BOM Hibernate5 Micronaut.adoc
**/src/en/ref/Versions/Grails BOM Hibernate7 Micronaut.adoc
Expand Down
2 changes: 2 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ These can be set on the command line like so:
* `onlyHibernate5Tests` - runs only a hibernate5 related test
* `onlyHibernate7Tests` - runs only a hibernate7 related test
* `onlyMongodbTests` - runs only a mongodb related test
* `onlyNeo4jTests` - runs only a neo4j related test
* `onlyRedisTests` - runs only redis related tests
* `onlySpringSecurityTests` - runs only spring security related tests
* `serializeMongoTests` - if true, only integration tests from one mongo project will run at a time
Expand All @@ -46,6 +47,7 @@ These can be set on the command line like so:
* `skipHibernate5Tests` - does not run hibernate5 related tests
* `skipHibernate7Tests` - does not run hibernate7 related tests
* `skipMongodbTests` - does not run mongo related tests
* `skipNeo4jTests` - does not run neo4j related tests
* `skipRedisTests` - does not run redis related tests
* `skipSpringSecurityTests` - does not run spring security related tests
* `skipTests` - no tests will run
Expand Down
3 changes: 3 additions & 0 deletions RENAME.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ Below is a reference of all migrated artifacts - both their old and new name.
| org.grails.plugins | views-json-templates | org.apache.grails | grails-data-mongodb-gson-templates | | | grails-data-mapping |
| org.grails | gorm-mongodb-spring-boot | org.apache.grails | grails-data-mongodb-spring-boot | | | grails-data-mapping |
| org.grails | grails-datastore-gorm-simple | org.apache.grails.data | grails-data-simple | | | grails-data-mapping |
| org.grails | grails-datastore-gorm-neo4j | org.apache.grails.data | grails-data-neo4j-core | | | grails-data-mapping |
| org.grails.plugins | neo4j | org.apache.grails | grails-data-neo4j | | | grails-data-mapping |
| org.grails | gorm-neo4j-spring-boot | org.apache.grails | grails-data-neo4j-spring-boot | | | grails-data-mapping |
| org.grails | grails-plugin-databinding | org.apache.grails | grails-databinding | | | grails-core |
| org.grails | grails-databinding | org.apache.grails.databinding | grails-databinding-core | | | grails-core |
| org.grails | grails-plugin-datasource | org.apache.grails | grails-datasource | | | grails-core |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class GrailsDependencyValidatorPlugin implements Plugin<Project> {
*/
static final String ALLOWED_OVERRIDES_EXT = 'allowedBomOverrides'

private static final Set<String> BOM_PROJECT_NAMES = ['grails-bom', 'grails-gradle-bom', 'grails-base-bom', 'grails-hibernate5-bom', 'grails-hibernate7-bom', 'grails-micronaut-bom', 'grails-hibernate5-micronaut-bom', 'grails-hibernate7-micronaut-bom'].toSet()
private static final Set<String> BOM_PROJECT_NAMES = ['grails-bom', 'grails-gradle-bom', 'grails-base-bom', 'grails-hibernate5-bom', 'grails-hibernate7-bom', 'grails-neo4j-bom', 'grails-micronaut-bom', 'grails-hibernate5-micronaut-bom', 'grails-hibernate7-micronaut-bom'].toSet()

/**
* Configuration names that pull in a Grails BOM purely as build tooling rather than as part
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class GrailsDependencyValidatorPluginSpec extends Specification {
ProjectBuilder.builder().withName('grails-bom').withParent(root).build()
ProjectBuilder.builder().withName('grails-micronaut-bom').withParent(root).build()
ProjectBuilder.builder().withName('grails-hibernate7-bom').withParent(root).build()
ProjectBuilder.builder().withName('grails-neo4j-bom').withParent(root).build()
root
}

Expand Down Expand Up @@ -95,4 +96,29 @@ class GrailsDependencyValidatorPluginSpec extends Specification {
GradleException e = thrown(GradleException)
e.message.contains('declares more than one Grails BOM')
}

void "detectBomPath recognizes grails-neo4j-bom as the project's single declared BOM"() {
given: "a grails-data-neo4j consumer that selects grails-neo4j-bom instead of the default grails-bom"
Project root = rootWithBoms()
Project project = ProjectBuilder.builder().withName('grails-data-neo4j-core').withParent(root).build()
addBomPlatform(project, 'implementation', ':grails-neo4j-bom')

expect:
GrailsDependencyValidatorPlugin.detectBomPath(project) == ':grails-neo4j-bom'
}

void "detectBomPath fails when grails-neo4j-bom is layered alongside the default grails-bom"() {
given: "a misconfiguration declaring both grails-bom and grails-neo4j-bom on real configurations"
Project root = rootWithBoms()
Project project = ProjectBuilder.builder().withName('misconfigured-neo4j').withParent(root).build()
addBomPlatform(project, 'api', ':grails-bom')
addBomPlatform(project, 'implementation', ':grails-neo4j-bom')

when:
GrailsDependencyValidatorPlugin.detectBomPath(project)

then:
GradleException e = thrown(GradleException)
e.message.contains('declares more than one Grails BOM')
}
}
24 changes: 24 additions & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,30 @@ ext {
'hibernate-envers' : "org.hibernate:hibernate-envers:${combinedVersions['hibernate.version']}",
]
combinedDependencies += customBomDependencies
} else if (project.name in ['grails-neo4j-bom'] || project.name.startsWith('grails-data-neo4j')) {
customBomVersions = [
// Spring Boot's BOM manages a newer, binary-incompatible major version of the
// driver; grails-data-neo4j-core needs this older one for its embedded
// Neo4j 3.5.x test harness. Declared here (with 'strictly' below, like liquibase/
// hibernate above) since a plain constraint can't out-rank a version Spring Boot's
// platform already offers. Scoped to grails-neo4j-bom only (not the default
// grails-bom) so consumers who don't use grails-data-neo4j keep Spring Boot's
// managed driver version.
'neo4j-driver.version': '4.4.13',
// The embedded test harness matching the driver/server version above. Consumed
// by grails-data-neo4j-core's published main sources (EmbeddedNeo4jServer,
// Neo4jEmbeddedConnectionSource, Neo4jConnectionSourceFactory), so it needs a
// BOM-managed version too, not just a build-internal gradle.properties entry -
// otherwise Forge-generated applications using grails.neo4j.type=embedded fail to
// resolve it.
'neo4j-harness.version': '3.5.35',
]
combinedVersions += customBomVersions
customBomDependencies = [
'neo4j-driver' : "org.neo4j.driver:neo4j-java-driver:${combinedVersions['neo4j-driver.version']}",
'neo4j-harness': "org.neo4j.test:neo4j-harness:${combinedVersions['neo4j-harness.version']}",
]
combinedDependencies += customBomDependencies
} else if (project.name in ['grails-hibernate7-bom'] || project.name.startsWith('grails-data-hibernate7')) {
customBomVersions = [
'cache-ri-impl.version' : '1.1.1',
Expand Down
6 changes: 6 additions & 0 deletions etc/bin/rename_gradle_artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ declare -a gorm_mappings=(
"org[.]grails:grails-datastore-async|org.apache.grails.data:grails-datastore-async"
"org[.]grails:gorm-mongodb-spring-boot|org.apache.grails:grails-data-mongodb-spring-boot"
"org[.]grails:gorm-hibernate5-spring-boot|org.apache.grails:grails-data-hibernate5-spring-boot"
"org[.]grails[.]plugins:neo4j|org.apache.grails:grails-data-neo4j"
"org[.]grails:grails-datastore-gorm-neo4j|org.apache.grails.data:grails-data-neo4j-core"
"org[.]grails:gorm-neo4j-spring-boot|org.apache.grails:grails-data-neo4j-spring-boot"
)
declare -a excluded_gorm_mappings=(
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]views-json-templates['\"]|exclude module:'grails-data-mongodb-gson-templates'"
Expand All @@ -230,6 +233,9 @@ declare -a excluded_gorm_mappings=(
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]gorm-mongodb-spring-boot['\"]|exclude module:'grails-data-mongodb-spring-boot'"
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]gorm-hibernate5-spring-boot['\"]|exclude module:'grails-data-hibernate5-spring-boot'"
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]database-migration['\"]|exclude module:'grails-data-hibernate5-dbmigration'"
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]neo4j['\"]|exclude module:'grails-data-neo4j'"
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]grails-datastore-gorm-neo4j['\"]|exclude module:'grails-data-neo4j-core'"
"exclude[[:space:]]+module[[:space:]]*:[[:space:]]*['\"]gorm-neo4j-spring-boot['\"]|exclude module:'grails-data-neo4j-spring-boot'"
)
mappings+=("${gorm_mappings[@]}")
excluded_mappings+=("${excluded_gorm_mappings[@]}")
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ defaultElImplementationVersion=5.0.0
# See https://projects.eclipse.org/releases/jakarta-10 and latest 5.0.x from https://mvnrepository.com/artifact/jakarta.el/jakarta.el-api
elApiVersion=5.0.1
expectitCoreVersion=0.9.0
geantyrefVersion=1.3.15
gparsVersion=1.2.1
# Keep gradle version synced with .sdkmanrc, all gradle-wrapper.properties files,
# and grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/templates/gradleWrapperProperties.rocker.raw
Expand Down
9 changes: 9 additions & 0 deletions gradle/functional-test-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ tasks.withType(Test).configureEach { Test task ->
boolean isMongo = project.name.startsWith('grails-test-examples-mongodb')
boolean isSpringSecurity = project.name.startsWith('grails-test-examples-spring-security')
boolean isRedis = project.name.startsWith('grails-test-examples-redis')
boolean isNeo4j = project.name.startsWith('grails-test-examples-neo4j')

// Honor DO_NOT_CACHE_TESTS=1 so developers can repeatedly invoke the same test command
// without --rerun-tasks (and without recompiling everything else).
Expand All @@ -108,6 +109,10 @@ tasks.withType(Test).configureEach { Test task ->
return false
}

if (!isNeo4j && project.hasProperty('onlyNeo4jTests')) {
return false
}

if (isHibernate5 && project.hasProperty('skipHibernate5Tests')) {
return false
}
Expand Down Expand Up @@ -140,6 +145,10 @@ tasks.withType(Test).configureEach { Test task ->
return false
}

if (isNeo4j && project.hasProperty('skipNeo4jTests')) {
return false
}

return true
}

Expand Down
8 changes: 8 additions & 0 deletions gradle/grails-data-tck-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ tasks.withType(Test).configureEach { Test it ->
return false
}

if (project.hasProperty('skipNeo4jTests') && project.name.startsWith('grails-data-neo4j')) {
return false
}

if (project.hasProperty('onlyNeo4jTests') && !project.name.startsWith('grails-data-neo4j')) {
return false
}

if (project.hasProperty('onlyCoreTests')) {
return false
}
Expand Down
5 changes: 5 additions & 0 deletions gradle/publish-root-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def publishedProjects = [
'grails-bom',
'grails-hibernate5-bom',
'grails-hibernate7-bom',
'grails-neo4j-bom',
'grails-beans-dsl',
'grails-bootstrap',
'grails-cache',
Expand Down Expand Up @@ -159,6 +160,10 @@ def publishedProjects = [
// graphql
'grails-data-graphql',
'grails-data-graphql-core',
// neo4j
'grails-data-neo4j',
'grails-data-neo4j-core',
'grails-data-neo4j-spring-boot',
// wrapper
'grails-wrapper',
// profiles
Expand Down
1 change: 1 addition & 0 deletions gradle/test-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ tasks.withType(Test).configureEach {
'onlyHibernate5Tests',
'onlyHibernate7Tests',
'onlyMongodbTests',
'onlyNeo4jTests',
'onlyRedisTests',
'onlySpringSecurityTests',
'skipCoreTests',
Expand Down
Loading
Loading