Skip to content

ci: run all functional tests against both Hibernate 5.6 and 7.2#15561

Open
jamesfredley wants to merge 17 commits into8.0.x-hibernate7from
ci/hibernate-matrix-testing
Open

ci: run all functional tests against both Hibernate 5.6 and 7.2#15561
jamesfredley wants to merge 17 commits into8.0.x-hibernate7from
ci/hibernate-matrix-testing

Conversation

@jamesfredley
Copy link
Copy Markdown
Contributor

@jamesfredley jamesfredley commented Apr 7, 2026

Summary

Run all functional tests against both Hibernate 5.6 and 7.2 without duplicating test projects, and fix a bug where Hibernate 7's Spring Boot autoconfiguration was never registered.

Changes

1. Unified CI matrix job (.github/workflows/gradle.yml)

Merged the separate functional and hibernate5Functional CI jobs into a single functional job with a hibernate-version: ['5', '7'] matrix dimension (same pattern as MongoDB version matrix).

Before (2 jobs, no h7 coverage for general tests):

Job What it ran
functional 20 general tests only (skipped h5-labeled/mongo)
hibernate5Functional 12 h5-labeled tests only

After (1 job, full h5 + h7 coverage):

Job Matrix What it runs
functional hibernate-version: ['5', '7'] x java: [17, 21, 25] All 32 functional tests per Hibernate version

Each matrix slot:

  • Passes -PhibernateVersion=5 or 7 to trigger dependency substitution
  • Passes -PskipHibernate7Tests or -PskipHibernate5Tests to exclude the opposite version's labeled projects
  • Skips MongoDB tests (separate job)

Updated the publish job needs to remove the deleted hibernate5Functional.

2. Gradle dependency substitution (gradle/functional-test-config.gradle)

Added a -PhibernateVersion property that uses resolutionStrategy.dependencySubstitution to redirect Hibernate 5 dependencies to Hibernate 7 for general (non-labeled) functional test projects:

  • grails-data-hibernate5 -> grails-data-hibernate7
  • grails-data-hibernate5-spring-boot -> grails-data-hibernate7-spring-boot
  • Excludes h5-only runtime deps (hibernate-ehcache, jboss-transaction-api) that have no h7 equivalent

This means zero changes to individual test project build.gradle files - the substitution happens centrally.

Also added skipHibernate5Tests and skipHibernate7Tests property checks to the onlyIf block. These were previously only honored by the unit test configs (hibernate5-test-config.gradle / hibernate7-test-config.gradle), not by functional-test-config.gradle.

3. Bug fix: h7 boot-plugin AutoConfiguration.imports was empty

The file grails-data-hibernate7/boot-plugin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports was empty. This meant Spring Boot never discovered HibernateGormAutoConfiguration when grails-data-hibernate7 was on the classpath, causing IllegalStateException: GORM has not been initialized correctly in any application using h7 via autoconfiguration.

Fixed by adding the registration entry (matching h5's file):

org.grails.datastore.gorm.boot.autoconfigure.HibernateGormAutoConfiguration

This is a bug fix independent of the CI matrix work - it affects any Spring Boot application using grails-data-hibernate7.

4. Remove h5-specific EhCache config from general test projects

Removed org.hibernate.cache.ehcache.EhCacheRegionFactory references from application.yml in:

  • grails-test-examples/gorm/ - had provider_class and region.factory_class pointing to EhCache
  • grails-test-examples/hyphenated/ - had region.factory_class pointing to EhCache

EhCache is not available with Hibernate 7, and these tests don't need second-level caching.

Files changed (5 files, +49/-47)

File Change
.github/workflows/gradle.yml Merge 2 jobs into 1 matrix job, update publish needs
gradle/functional-test-config.gradle Add dep substitution, h5-only exclusions, skip properties
grails-data-hibernate7/.../AutoConfiguration.imports Register HibernateGormAutoConfiguration (was empty)
grails-test-examples/gorm/.../application.yml Remove EhCache region factory config
grails-test-examples/hyphenated/.../application.yml Remove EhCache region factory config

Local usage

# Run all functional tests with Hibernate 5 (default behavior)
./gradlew -PonlyFunctionalTests -PskipMongodbTests -PskipHibernate7Tests check

# Run all functional tests with Hibernate 7
./gradlew -PonlyFunctionalTests -PskipMongodbTests -PskipHibernate5Tests -PhibernateVersion=7 check

# Run only h5-labeled tests
./gradlew -PonlyHibernate5Tests check

# Run only h7-labeled tests
./gradlew -PonlyHibernate7Tests check

…5 and 7

Replace the separate functional and hibernate5Functional CI jobs with a
single functional job that uses a hibernate-version matrix (['5', '7']).
This ensures all 20+ general functional tests run against both Hibernate
versions without duplicating test projects.

Changes:
- functional-test-config.gradle: Add -PhibernateVersion property that
  uses Gradle dependency substitution to redirect grails-data-hibernate5
  to grails-data-hibernate7 for general (non-labeled) test projects.
  Excludes h5-only runtime deps (hibernate-ehcache, jboss-transaction-api)
  when testing with Hibernate 7. Add skipHibernate5Tests and
  skipHibernate7Tests properties to the onlyIf block.
- gradle.yml: Merge functional and hibernate5Functional into one job
  with hibernate-version matrix. Each matrix slot skips the opposite
  version's labeled projects. Update publish job dependencies.

Assisted-by: Claude Code <Claude@Claude.ai>
The h7 boot-plugin AutoConfiguration.imports was empty, preventing
Spring Boot from discovering HibernateGormAutoConfiguration when
grails-data-hibernate7 is on the classpath. This caused GORM has not
been initialized correctly errors in functional tests running with
Hibernate 7 via dependency substitution.

Also remove Hibernate 5-specific EhCache region factory configuration
from the gorm and hyphenated functional test application.yml files.
EhCache is not available with Hibernate 7, and the second-level cache
is not needed by these tests.

Assisted-by: Claude Code <Claude@Claude.ai>
…sion=7

Five general functional test projects use Hibernate 5-specific GORM
APIs that changed in Hibernate 7. Skip them when running with
-PhibernateVersion=7 rather than letting them fail. Their h7-compatible
equivalents already exist in grails-test-examples/hibernate7/.

Incompatible projects:
- app1: HibernateSpec unit test domain class detection differs in h7
- datasources: ChainedTransactionManager commit behavior changed in h7
- gorm: executeUpdate(String) requires Map parameter in h7
- views-functional-tests: depends on h5-specific caching config
- scaffolding-fields: integration test context fails under h7

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley
Copy link
Copy Markdown
Contributor Author

Hibernate 5 vs 7 - Detailed Differences and Test Coverage

GORM API differences between Hibernate 5.6 and 7.2

Investigation of the functional test suite revealed these concrete behavioral differences between the two Hibernate versions:

1. executeUpdate(String) no longer accepts plain Strings (H7)

H7's HibernateGormStaticApi rejects executeUpdate('delete from Foo') with a plain String. It requires either a GString with interpolated parameters or the parameterized overload:

// H5 - works
Book.executeUpdate('delete from Book')

// H7 - throws UnsupportedOperationException
Book.executeUpdate('delete from Book')

// H7 - correct
Book.executeUpdate('delete from Book', [:])

Error: UnsupportedOperationException: executeUpdate(CharSequence) only accepts a Groovy GString with interpolated parameters

This was already fixed in the h7-labeled copies (e.g., DataServiceMultiDataSourceSpec, MetricService), where executeUpdate('delete from Foo') was changed to executeUpdate('delete from Foo', [:]).

2. HibernateSpec domain class detection (H7)

H5's HibernateSpec auto-detects domain classes via classpath scanning. H7's HibernateSpec was rewritten to use HibernateDatastoreSpringInitializer with a different domain class discovery mechanism. Some tests need an explicit getDomainClasses() override:

// H5 - auto-detects Book from classpath
class BookHibernateSpec extends HibernateSpec { ... }

// H7 - needs explicit declaration in some cases
class BookHibernateSpec extends HibernateSpec {
    @Override
    List<Class> getDomainClasses() { [Book] }
}

3. ChainedTransactionManager commit behavior (H7)

H7 changed how ChainedTransactionManager.commit() handles multi-datasource transactions, throwing HeuristicCompletionException: outcome state is rolled back where H5 committed successfully. The h7-labeled datasources tests use session.doReturningWork { it.metaData.getURL() } instead of session.connection().metaData.getURL().

4. @RestoreSystemProperties vs explicit cleanup (H7)

H7 tests replaced Spock's @RestoreSystemProperties annotation with explicit cleanup() methods for system property management (seen in DatabasePerTenantSpec, MultiTenantMultiDataSourceSpec).

5. @Integration annotation (H7)

Some H7 integration tests require @Integration(applicationClass = Application) explicitly, where H5 inferred the application class automatically.

6. HttpClientSupport trait vs explicit HttpClient (H7)

H7 tests replaced implements HttpClientSupport with explicit @Shared HttpClient client + @OnceBefore setup (seen in MultiDataSourceWithSessionSpec, BookControllerSpec in issue450).

7. JSON response structure differences (H7)

Views/JSON rendering produces slightly different output with H7 - association rendering and HAL responses differ.

8. Scaffolding rendering (H7)

Scaffolding with grails-fields renders pages differently under H7, causing Geb page object assertions to fail.


Test matrix - what runs where

33 general functional test projects exist. With -PhibernateVersion=7, dependency substitution swaps grails-data-hibernate5 to grails-data-hibernate7 centrally - no individual build.gradle changes needed.

5 projects are excluded from the H7 dep-substitution run because they exercise H5-specific GORM APIs listed above:

Project Failure Category H7 Equivalent
app1 HibernateSpec domain class detection (#2) No direct equivalent (unit test only)
datasources ChainedTransactionManager behavior (#3) No direct equivalent (new test project)
gorm executeUpdate(String) (#1), @RestoreSystemProperties (#4), transaction propagation H7 labeled copies cover most scenarios
views-functional-tests JSON/HAL response structure (#7) No direct equivalent
scaffolding-fields Scaffolding rendering (#8) No direct equivalent

28 general projects run under both H5 and H7 via the matrix:

app2, app3, app4, app5, async-events-pubsub-demo, cache, database-cleanup, demo33, exploded, external-configuration, geb, geb-gebconfig, gsp-layout, gsp-sitemesh3, gsp-spring-boot, hyphenated, issue-11102, issue-11767, issue-15228, issue-698-domain-save-npe, issue-views-182, micronaut, micronaut-groovy-only, namespaces, plugins, scaffolding, test-phases, views-functional-tests-plugin

12 h5-labeled projects run only in the H5 slot (as before):

grails-data-service, grails-data-service-multi-datasource, grails-database-per-tenant, grails-hibernate, grails-hibernate-groovy-proxy, grails-multiple-datasources, grails-multitenant-multi-datasource, grails-partitioned-multi-tenancy, grails-schema-per-tenant, issue450, spring-boot-hibernate, standalone-hibernate

12 h7-labeled projects run only in the H7 slot (as before):

Same 12 projects mirrored in grails-test-examples/hibernate7/ with the API adaptations described above.


Also fixed: H7 boot-plugin AutoConfiguration.imports was empty

The file grails-data-hibernate7/boot-plugin/.../AutoConfiguration.imports was empty - Spring Boot never discovered HibernateGormAutoConfiguration when H7 was on the classpath. This is a bug independent of the CI matrix work; it affects any Spring Boot application using grails-data-hibernate7 via autoconfiguration. Fixed in commit e2336d9.

@jamesfredley
Copy link
Copy Markdown
Contributor Author

@borinquenkid @jdaugherty I ran short on time to wrap this up. It is close. The test differences above should be reviewed for accuracy.

@jamesfredley jamesfredley marked this pull request as ready for review April 7, 2026 18:13
Copilot AI review requested due to automatic review settings April 7, 2026 18:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the build and CI configuration so the full functional-test suite is exercised against both Hibernate 5.6 and 7.2, and fixes missing Spring Boot autoconfiguration registration for grails-data-hibernate7.

Changes:

  • Consolidates functional-test CI into a single job with a hibernate-version: [5, 7] matrix and updates publish job dependencies accordingly.
  • Adds centralized Gradle dependency substitution/exclusions to run general functional test projects against Hibernate 7 without duplicating projects, plus adds skip flags support in functional test gating.
  • Registers HibernateGormAutoConfiguration for Hibernate 7 Spring Boot autoconfiguration and removes EhCache-specific config from general test example apps.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
.github/workflows/gradle.yml Merges functional jobs into a Hibernate-version matrix and updates downstream needs/conditions.
gradle/functional-test-config.gradle Adds -PhibernateVersion switching via dependency substitution, exclusions, and new skip flag handling for functional tests.
grails-data-hibernate7/boot-plugin/.../AutoConfiguration.imports Registers Hibernate 7 GORM Boot autoconfiguration so Spring Boot can discover it.
grails-test-examples/gorm/grails-app/conf/application.yml Removes EhCache region/provider configuration and disables 2nd-level/query cache.
grails-test-examples/hyphenated/grails-app/conf/application.yml Removes EhCache region factory configuration and disables 2nd-level cache.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +24 to +31
// 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

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.
Comment on lines +125 to +137
// 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
}
}
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.
@jdaugherty
Copy link
Copy Markdown
Contributor

Why not duplicate the tests? This assumes the module substitution works in a consistent way. How do we know if there are dependency conflicts - the compile is only going to compile with 1 while the test will potentially run with both.

@jamesfredley
Copy link
Copy Markdown
Contributor Author

I wasn't really concerned with the duplication, given 5.6 will be removed in Grails 9 or 10, mostly likely. But in reviewing these, the duplication has allowed drift and we are not testing the same way, which could allow undocumented breaking changes for end apps. Ideally we make these DRY like the TCK.

- Fix 17 plain executeUpdate('...') calls across 7 specs in
  grails-test-examples/gorm to use executeUpdate('...', [:]).
  H7's HibernateGormStaticApi rejects plain CharSequence args
  (requires either a GString with interpolated params or the
  Map overload).

- Add getDomainClasses() override to BookHibernateSpec in app1.
  H7's HibernateSpec uses HibernateDatastoreSpringInitializer
  which requires explicit domain class declaration; H5 auto-detected
  via classpath scanning.

- Remove grails-test-examples-app1 and grails-test-examples-gorm
  from h7IncompatibleProjects list — both now run cleanly under
  Hibernate 7 via dependency substitution.

Remaining excluded: datasources (ChainedTransactionManager),
views-functional-tests (HAL/JSON diffs), scaffolding-fields
(grails-fields rendering diffs).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@testlens-app

This comment has been minimized.

@borinquenkid
Copy link
Copy Markdown
Member

borinquenkid commented Apr 8, 2026

H7 gorm Functional Test Failures — Bug Report

Running grails-test-examples-gorm with -PhibernateVersion=7 produces 13 failures across 4 specs.
Below are the 5 distinct root causes.


Bug 1 (Intentional) — executeQuery / executeUpdate plain String blocked

Tests test basic HQL query, test HQL aggregate functions, test HQL group by, test executeUpdate for bulk operations
Spec GormCriteriaQueriesSpec
Error UnsupportedOperationException: executeQuery(CharSequence) only accepts a Groovy GString with interpolated parameters

Description: H7 intentionally rejects executeQuery("from Book where inStock = true") when no parameters are passed. The same tightening was already applied to executeUpdate. Callers must use executeQuery('...', [:]) or a GString with interpolated params.

This is by design. The test bodies need to adopt the parameterized form — not a GORM bug.


Bug 2 — DetachedCriteria.get() throws NonUniqueResultException instead of returning first result

Test test detached criteria as reusable query
Spec GormCriteriaQueriesSpec:454
Error jakarta.persistence.NonUniqueResultException: Query did not return a unique result: 2 results were returned

Description: H5 DetachedCriteria.get() returned the first matching row when multiple rows existed. H7's AbstractSelectionQuery.getSingleResult() is now strict and throws if the result is not unique.

Expected fix: HibernateQueryExecutor.singleResult() should apply setMaxResults(1) before calling getSingleResult(), or switch to getResultList().stream().findFirst().


Bug 3 — Found two representations of same collection: gorm.Author.books

Tests test saving child with belongsTo saves parent reference, test dirty checking with associations, test belongsTo allows orphan removal, test updating multiple children, test addTo creates bidirectional link
Spec GormCascadeOperationsSpec
Error HibernateSystemException: Found two representations of same collection: gorm.Author.books

Description: H7 enforces stricter collection identity. After author.addToBooks(book); author.save(flush: true), the session contains two references to the same Author.books collection, causing a HibernateException on flush. H5 tolerated this.

Expected fix: GORM's addTo* / cascade-flush path in grails-data-hibernate7 must synchronize both sides of the bidirectional association and merge/evict stale collection snapshots before flushing.


Bug 4 — @Query aggregate functions fail with type mismatch

Tests test findAveragePrice, test findMaxPageCount
Spec GormDataServicesSpec
Errors Incorrect query result type: query produces 'java.lang.Double' but type 'java.lang.Long' was given / query produces 'java.lang.Integer' but type 'java.lang.Long' was given

Description: HibernateHqlQuery.buildQuery() always calls session.createQuery(hql, ctx.targetClass()). For aggregate HQL (select avg(b.price) ..., select max(b.pageCount) ...), the query does not return an entity, but ctx.targetClass() returns the entity class (e.g., Book). H7's SqmQueryImpl enforces strict result-type alignment — avg() produces Double, max(pageCount) produces Integer, neither is coercible to the bound entity type.

Expected fix: HibernateHqlQuery.buildQuery() must detect non-entity HQL (aggregates / projections) and call the untyped session.createQuery(hql) in those cases, letting GORM handle result casting downstream.


Bug 5 — where { pageCount > price * 10 } fails with CoercionException

Test test where query comparing two properties
Spec GormWhereQueryAdvancedSpec:175
Error org.hibernate.type.descriptor.java.CoercionException: Error coercing value

Description: A where-DSL closure comparing an Integer property (pageCount) to an arithmetic expression involving a BigDecimal property (price * 10) worked in H5. H7's SQM type system no longer allows implicit coercion between Integer and BigDecimal in a comparison predicate.

Expected fix: The GORM where-query-to-SQM translator should emit an explicit CAST in the SQM tree when the two operands of a comparison have different numeric types.

…urn types, cross-property arithmetic

Bug 2: HibernateQueryExecutor.singleResult() now catches both
org.hibernate.NonUniqueResultException and jakarta.persistence.NonUniqueResultException
(H7 throws the JPA variant; the original catch missed it) and returns the
first result instead of propagating.

Bug 4: HqlQueryContext.aggregateTargetClass() now returns precise types per
function: count() → Long, avg() → Double, sum/min/max() → Number.
Previously all aggregates were bound to Long, causing QueryTypeMismatchException
in H7's strict SQM type checking.

Bug 5: Cross-property arithmetic in where-DSL (e.g. pageCount > price * 10)
was silently dropped — the RHS property reference was coerced to a literal.
Fixed via:
- PropertyReference: Groovy wrapper returned by propertyMissing for numeric
  properties; *, +, -, / operators produce a PropertyArithmetic value object
- PropertyArithmetic: value type carrying (propertyName, Operator, operand)
- HibernateDetachedCriteria: H7-only DetachedCriteria subclass that overrides
  propertyMissing to return PropertyReference for numeric properties, and
  newInstance() to preserve the subtype through cloning
- HibernateGormStaticApi: overrides where/whereLazy/whereAny to use
  HibernateDetachedCriteria as the closure delegate
- PredicateGenerator: resolveNumericExpression() detects PropertyArithmetic
  and builds cb.prod/sum/diff/quot(path, operand) instead of a literal

H5 and MongoDB are unaffected — all new types are confined to grails-data-hibernate7.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@testlens-app

This comment has been minimized.

…ve on managed entities

H7 enforces strict collection identity during flush. GORM's addTo* and
save() flow had two failure modes:

1. When an entity is already managed in the current Hibernate session,
   calling session.merge() causes H7 to create a second PersistentCollection
   for the same role+key alongside the one already tracked in the session
   cache -> 'Found two representations of same collection'.

   Fix (HibernateGormInstanceApi.performMerge): check session.contains(target)
   before merging. If the entity is already managed, skip merge entirely;
   dirty-checking and cascade will handle children on flush.

2. When addTo* is called on a managed entity, GormEntity.addTo uses direct
   field access (reflector.getProperty) which bypasses H7's bytecode-enhanced
   interceptor, sees null, and creates a plain ArrayList on the field. H7's
   session cache already tracks a PersistentBag/Set for that role -> two
   representations on the next save.

   Fix (HibernateEntity.addTo): override addTo in the H7 trait; for managed
   entities (id != null), trigger the H7 interceptor via InvokerHelper.getProperty
   to obtain the live PersistentCollection before delegating to
   GormEntity.super.addTo.

   Fix (HibernateEntityTransformation): re-target the concrete addToXxx
   generated methods so their internal addTo call dispatches through
   HibernateEntity.addTo rather than being hard-wired to GormEntity.addTo.

   Fix (HibernateGormInstanceApi.reconcileCollections): detect stale
   PersistentCollections (session != current session) and replace them with
   plain collections before merge, covering any edge cases where the H7
   interceptor path is not taken.

Adds AddToManagedEntitySpec with 4 tests covering:
- addTo on an already-persisted entity
- multiple addTo on a fresh transient entity
- modify child + save twice
- removeFrom + save

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@testlens-app

This comment has been minimized.

@jdaugherty
Copy link
Copy Markdown
Contributor

@borinquenkid after you get the tests working, can we merge just your changes to the hibernate branch? The plan was to discuss the need for this PR later and not merge it immediately. I think ti's important to merge your fixes & to add tests for them in a separate PR

@borinquenkid
Copy link
Copy Markdown
Member

I am not exactly sure what to answer here but there were bug fixes and test fixes and the last one failing is bad setup

…and proper applicationClass

- Replace executeQuery(plainString) and executeUpdate(plainString) calls
  with the (String, Map) overloads (empty map for parameterless queries).
  HibernateGormStaticApi intentionally rejects plain String in the
  no-arg overload to prevent HQL injection; parameterless static queries
  must use the Map overload.

- Add applicationClass = Application to @Integration so the spec shares
  the same application context and transaction manager as the other specs
  in this module, preventing test-data bleed between specs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jdaugherty
Copy link
Copy Markdown
Contributor

I found an example of where this strategy is a major problem: ehcache - that library is 5.x only and should be used in 7.x (it was replaced by hibernate-jcache)

Comment thread gradle/functional-test-config.gradle Outdated
Comment on lines 95 to 96
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I guess...the naming of these booleans is a bit counter-intuitive because of the ! operator. For example, isHibernate5 will be true for general projects but false for projects that actually use Hibernate 5.

…checkstyle

- Validate -PhibernateVersion accepts only '5' or '7' and fail the build fast with a GradleException for any other value (addresses Copilot review on line 31).

- Rename the counter-intuitive isHibernate5/isHibernate7/isMongo booleans in functional-test-config.gradle. The previous names used a leading ! and matched projects that were NOT that version, making the onlyIf conditions confusing. Replace with positive isHibernate5Project / isHibernate7Project / isMongoTaskProject and collapse nested ifs (addresses Copilot and @sanjana2505006 feedback).

- Fix SingleSpaceSeparator checkstyle violations in PredicateGenerator.java switch arms (blocking CI Core Projects check).

Assisted-by: claude-code:claude-opus-4
@jamesfredley
Copy link
Copy Markdown
Contributor Author

Review feedback addressed in dc7c4a0

1. Validate -PhibernateVersion and fail fast (Copilot)

hibernateVersion is accepted as an arbitrary string and silently falls back to "Hibernate 5 behavior" for any value other than '7'.

Added validation in gradle/functional-test-config.gradle that throws a GradleException when the value is not '5' or '7':

./gradlew :grails-test-examples-gorm:help -PhibernateVersion=6
...
> Unsupported hibernateVersion '6'. Expected '5' or '7'.

2. Rename counter-intuitive booleans (Copilot, @sanjana2505006)

isHibernate5 == false actually means "this is an hibernate5-labeled project".

Renamed to positive-meaning names and collapsed the nested if statements in the onlyIf block so the reader no longer has to negate mentally:

// before
boolean isHibernate5 = !project.name.startsWith('grails-test-examples-hibernate5')
if (project.hasProperty('skipHibernate5Tests')) {
    if (!isHibernate5) { return false }
}

// after
boolean isHibernate5Project = project.name.startsWith('grails-test-examples-hibernate5')
if (project.hasProperty('skipHibernate5Tests') && isHibernate5Project) {
    return false
}

Same pattern for isHibernate7Project and isMongoTaskProject. Behavior is unchanged.

3. Fix blocking checkstyle failure in PredicateGenerator.java

The Core Projects CI check was failing with SingleSpaceSeparator on the aligned switch-arm arrows introduced in the "fix 3 H7 GORM bugs" commit. Removed the extra spaces.

// before
case ADD      -> cb.sum(propertyPath, pa.operand());
case DIVIDE   -> cb.quot(propertyPath, pa.operand());

// after
case ADD -> cb.sum(propertyPath, pa.operand());
case DIVIDE -> cb.quot(propertyPath, pa.operand());

Verified locally with ./gradlew :grails-data-hibernate7-core:checkstyleMain - now passes.


Open strategy questions (not addressed here)

@jdaugherty - your two strategic points are acknowledged and deserve their own discussion:

  1. Duplicate vs. substitute test projects. Module substitution does surface the ehcache-style conflict you flagged (addressed in this PR with explicit exclude rules for hibernate-ehcache and jboss-transaction-api_1.3_spec). If we want stronger guarantees against other silent conflicts, the alternative is duplicating the general test projects under grails-test-examples/hibernate7/ the same way the h5-labeled projects are mirrored. Happy to split that into a follow-up PR once we decide.
  2. Merge path for just the fixes. The H7 bug fixes in HibernateQueryExecutor, HqlQueryContext, PredicateGenerator, PropertyReference, PropertyArithmetic, HibernateDetachedCriteria, and HibernateGormStaticApi (commits 707c33d, a458c4a) are independent of the CI matrix. I can cherry-pick them into a separate PR against 8.0.x-hibernate7 if that unblocks the bug-fix merge while this matrix discussion continues.

Remaining CI item

The latest run had 1 remaining failure: UserControllerSpec > User list in grails-test-examples-scaffolding - the page loaded "Please sign in" instead of "User List", i.e. a Spring Security redirect, not a GORM/H7 issue. Looks like test setup rather than a product bug, but I'll re-verify on the next CI run after this push.

Assisted-by: claude-code:claude-opus-4

…ate-matrix-testing

# Conflicts:
#	.github/workflows/gradle.yml
#	gradle/functional-test-config.gradle
#	grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/HibernateDetachedCriteria.groovy
…tional tests

When -PhibernateVersion=7 is set, general (non-hibernate-labeled) functional test projects get the grails-data-hibernate5 module substituted with grails-data-hibernate7 via dependency substitution. However, those test projects also import platform(project(':grails-bom')) directly, which ships the Hibernate 5 version constraints.

Extend the dependency substitution to also swap the default grails-bom to grails-hibernate7-bom in the same projects, so the transitive graph gets a consistent set of Hibernate 7 version constraints. This matches the pattern used by the h7-labeled test projects in grails-test-examples/hibernate7/, which import grails-hibernate7-bom directly.

Without this, the H7 matrix slot fails with:

    Could not resolve org.hibernate.orm:hibernate-core.

    Cannot find a version of 'org.hibernate.orm:hibernate-core' that satisfies the version constraints

Assisted-by: claude-code:claude-opus-4
Two fixes to unblock CI after the recent BOM restructure on 8.0.x-hibernate7:

1) grails-forge-core/build.gradle was referencing the old grails-bom/build/publications/... path. The BOM was moved to grails-bom/default/ in the split, so grailsVersionInfo now fails with 'input file expected to be present but it does not exist'. Point the task at the new location.

2) grails-hibernate7-bom pinned hibernate.version = 7.2.5.Final via a strictly constraint, while spring-boot-dependencies:4.0.5 (transitively imported through grails-base-bom) pulls hibernate-core 7.2.7.Final. The conflicting constraints cause 'Cannot find a version of org.hibernate.orm:hibernate-core that satisfies the version constraints' whenever a general test project consumes the Hibernate 7 stack. Bump hibernate.version to 7.2.7.Final to match Spring Boot's managed version.

Assisted-by: claude-code:claude-opus-4
…ge analytics

Two follow-up fixes after the previous commit's CI run still showed missing-version resolution failures:

1) gradle/functional-test-config.gradle: the previous module-level substitution of org.apache.grails:grails-bom -> grails-hibernate7-bom didn't catch direct project references. Test build files (e.g. grails-test-examples-app1) declare 'platform(project(':grails-bom'))' literally, so dependency-substitution by module name does not match. Add a project-level substitution 'project(':grails-bom') -> project(':grails-hibernate7-bom')' that fires for the same general-functional-tests + hibernateVersion=7 condition, ensuring transitive Hibernate 7 constraints (hibernate-models, jandex, hibernate-tools-orm) get versioned.

2) grails-forge/grails-forge-analytics-postgres/build.gradle: was missing platform('io.micronaut:micronaut-bom') across all dependency configurations, so 'org.testcontainers:testcontainers-postgresql' resolved with no version and broke the Forge build. Add the platform import to annotationProcessor / implementation / testAnnotationProcessor / testImplementation to mirror the pattern used by grails-forge-cli.

Assisted-by: claude-code:claude-opus-4
…ency buckets

The previous attempt to substitute project(':grails-bom') -> project(':grails-hibernate7-bom') did not propagate version constraints to consumers because grails-data-hibernate7-core declares 'implementation platform(project(':grails-hibernate7-bom'))', and 'implementation' is not visible to downstream consumers. As a result, general functional test projects still failed with 'Could not find org.hibernate.models:hibernate-models:.' and 'Could not find io.smallrye:jandex:.' when -PhibernateVersion=7.

Drop the project-level substitute (which had no effect) and instead attach the Hibernate 7 BOM directly to the test project's dependency buckets (implementation, compileOnly, runtimeOnly, testImplementation, etc). The H7 BOM brings the version constraints into the test project's runtimeClasspath / compileClasspath where the unversioned transitive dependencies need them.

Assisted-by: claude-code:claude-opus-4
Micronaut BOM 3.10.4 sets a testcontainers.version property but does not actually publish testcontainers entries in dependencyManagement, so 'org.testcontainers:testcontainers-postgresql' kept resolving with no version. Import the testcontainers BOM explicitly to give the test classpath a real version.

Assisted-by: claude-code:claude-opus-4
…ostgresql

The dependency 'org.testcontainers:testcontainers-postgresql' does not exist in Maven Central. The actual artifact published in the testcontainers BOM is 'org.testcontainers:postgresql'. The previous testcontainers BOM import was correct, but the consumer side still used the wrong artifact name.

Assisted-by: claude-code:claude-opus-4
Same root cause as the previous commit for grails-forge-analytics-postgres: 'org.testcontainers:testcontainers-spock' is not a published artifact; the correct id is 'org.testcontainers:spock'. Add the testcontainers BOM so the version is managed centrally.

Assisted-by: claude-code:claude-opus-4
Add testcontainersVersion=1.20.4 to grails-forge/gradle.properties and reference it via the property in both forge build.gradle files instead of the inline literal.

Assisted-by: claude-code:claude-opus-4
@testlens-app
Copy link
Copy Markdown

testlens-app bot commented Apr 16, 2026

🚨 TestLens detected 8 failed tests 🚨

Here is what you can do:

  1. Inspect the test failures carefully.
  2. If you are convinced that some of the tests are flaky, you can mute them below.
  3. Finally, trigger a rerun by checking the rerun checkbox.

Test Summary

Check Project/Task Test Runs
CI / Build Grails Forge (Java 21, indy=false) :grails-forge-core:test [grails-forge] MongoSyncSpec > test mongo sync dependencies are present for gradle
CI / Build Grails Forge (Java 21, indy=false) :grails-forge-core:test [grails-forge] TestContainersSpec > test mongo-gorm dependency is present for gradle
CI / Build Grails Forge (Java 21, indy=false) :grails-forge-core:test [grails-forge] TestContainersSpec > test mongo-sync dependency is present for gradle
CI / Build Grails Forge (Java 21, indy=false) :grails-forge-core:test [grails-forge] TestContainersSpec > test postgres dependency is present for gradle
CI / Build Grails Forge (Java 21, indy=true) :grails-forge-core:test [grails-forge] MongoSyncSpec > test mongo sync dependencies are present for gradle
CI / Build Grails Forge (Java 21, indy=true) :grails-forge-core:test [grails-forge] TestContainersSpec > test mongo-gorm dependency is present for gradle
CI / Build Grails Forge (Java 21, indy=true) :grails-forge-core:test [grails-forge] TestContainersSpec > test mongo-sync dependency is present for gradle
CI / Build Grails Forge (Java 21, indy=true) :grails-forge-core:test [grails-forge] TestContainersSpec > test postgres dependency is present for gradle

🏷️ Commit: cf6d9ce
▶️ Tests: 8009 executed
⚪️ Checks: 29/29 completed

Test Failures (first 5 of 8)

MongoSyncSpec > test mongo sync dependencies are present for gradle (:grails-forge-core:test [grails-forge] in CI / Build Grails Forge (Java 21, indy=false))
Condition not satisfied:

template.contains('testImplementation "org.testcontainers:testcontainers-mongodb"')
|        |
|        false
buildscript {
    repositories {
        maven {
           url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
        }
        mavenCentral()
        maven {
           url = 'https://repo.grails.org/grails/restricted'
        }
        maven {
           url = 'https://repository.apache.org/content/groups/snapshots'
           content {
              includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
           }
           mavenContent {
              snapshotsOnly()
           }
        }
        maven {
           url = 'https://repository.apache.org/content/groups/staging'
           content {
              includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
           }
           mavenContent {
              releasesOnly()
           }
        }
    }
    dependencies { // Not Published to Gradle Plugin Portal
        classpath "cloud.wondrify:asset-pipeline-gradle"
        classpath platform("org.apache.grails:grails-bom:$grailsVersion")
        classpath "org.apache.grails:grails-data-hibernate5"
        classpath "org.apache.grails:grails-gradle-plugins"
    }
}
 
plugins {
    id "war"
    id "idea"
    id "eclipse"
}
 
// Not Published to Gradle Plugin Portal
apply plugin: "org.apache.grails.gradle.grails-web"
apply plugin: "org.apache.grails.gradle.grails-gsp"
apply plugin: "cloud.wondrify.asset-pipeline"
 
group = "example.grails"
 
repositories {
    maven {
       url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
    }
    mavenCentral()
    maven {
       url = 'https://repo.grails.org/grails/restricted'
    }
    maven {
       url = 'https://repository.apache.org/content/groups/snapshots'
       content {
          includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
       }
       mavenContent {
          snapshotsOnly()
       }
    }
    maven {
       url = 'https://repository.apache.org/content/groups/staging'
       content {
          includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
       }
       mavenContent {
          releasesOnly()
       }
    }
}
 
dependencies {
    profile "org.apache.grails.profiles:web"
    developmentOnly "org.springframework.boot:spring-boot-devtools" // Spring Boot DevTools may cause performance slowdowns or compatibility issues on larger applications
    testAndDevelopmentOnly "org.webjars.npm:bootstrap"
    testAndDevelopmentOnly "org.webjars.npm:bootstrap-icons"
    testAndDevelopmentOnly "org.webjars.npm:jquery"
    implementation platform("org.apache.grails:grails-bom:$grailsVersion")
    implementation "org.apache.grails:grails-core"
    implementation "org.apache.grails:grails-data-hibernate5"
    implementation "org.apache.grails:grails-databinding"
    implementation "org.apache.grails:grails-events"
    implementation "org.apache.grails:grails-gsp"
    implementation "org.apache.grails:grails-interceptors"
    implementation "org.apache.grails:grails-layout"
    implementation "org.apache.grails:grails-logging"
    implementation "org.apache.grails:grails-rest-transforms"
    implementation "org.apache.grails:grails-scaffolding"
    implementation "org.apache.grails:grails-services"
    implementation "org.apache.grails:grails-url-mappings"
    implementation "org.apache.grails:grails-web-boot"
    implementation "org.mongodb:mongodb-driver-sync"
    implementation "org.springframework.boot:spring-boot-autoconfigure"
    implementation "org.springframework.boot:spring-boot-starter"
    implementation "org.springframework.boot:spring-boot-starter-actuator"
    implementation "org.springframework.boot:spring-boot-starter-logging"
    implementation "org.springframework.boot:spring-boot-starter-tomcat"
    implementation "org.springframework.boot:spring-boot-starter-validation"
    implementation "org.springframework.boot:spring-boot-tomcat"
    console "org.apache.grails:grails-console"
    runtimeOnly "cloud.wondrify:asset-pipeline-grails"
    runtimeOnly "com.h2database:h2"
    runtimeOnly "com.zaxxer:HikariCP"
    runtimeOnly "org.fusesource.jansi:jansi"
    integrationTestImplementation testFixtures("org.apache.grails:grails-geb")
    testImplementation "org.apache.grails:grails-testing-support-datamapping"
    testImplementation "org.apache.grails:grails-testing-support-web"
    testImplementation "org.mockito:mockito-core"
    testImplementation "org.spockframework:spock-core"
    testImplementation "org.testcontainers:mongodb"
    testImplementation "org.testcontainers:spock"
    testImplementation "org.testcontainers:testcontainers"
}
 
compileJava.options.release = 17
 
tasks.withType(Test).configureEach {
    useJUnitPlatform()
}
 
assets {
    excludes = [
            'webjars/jquery/**',
            'webjars/bootstrap/**',
            'webjars/bootstrap-icons/**'
    ]
    includes = [
            'webjars/jquery/*/dist/jquery.js',
            'webjars/bootstrap/*/dist/js/bootstrap.bundle.js',
            'webjars/bootstrap/*/dist/css/bootstrap.css',
            'webjars/bootstrap-icons/*/font/bootstrap-icons.css',
            'webjars/bootstrap-icons/*/font/fonts/*',
    ]
}

	at org.grails.forge.feature.database.MongoSyncSpec.test mongo sync dependencies are present for gradle(MongoSyncSpec.groovy:56)
TestContainersSpec > test mongo-gorm dependency is present for gradle (:grails-forge-core:test [grails-forge] in CI / Build Grails Forge (Java 21, indy=false))
Condition not satisfied:

template.contains('testImplementation "org.testcontainers:testcontainers-mongodb"')
|        |
|        false
buildscript {
    repositories {
        maven {
           url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
        }
        mavenCentral()
        maven {
           url = 'https://repo.grails.org/grails/restricted'
        }
        maven {
           url = 'https://repository.apache.org/content/groups/snapshots'
           content {
              includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
           }
           mavenContent {
              snapshotsOnly()
           }
        }
        maven {
           url = 'https://repository.apache.org/content/groups/staging'
           content {
              includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
           }
           mavenContent {
              releasesOnly()
           }
        }
    }
    dependencies { // Not Published to Gradle Plugin Portal
        classpath "cloud.wondrify:asset-pipeline-gradle"
        classpath platform("org.apache.grails:grails-bom:$grailsVersion")
        classpath "org.apache.grails:grails-data-hibernate5"
        classpath "org.apache.grails:grails-gradle-plugins"
    }
}
 
plugins {
    id "war"
    id "idea"
    id "eclipse"
}
 
// Not Published to Gradle Plugin Portal
apply plugin: "org.apache.grails.gradle.grails-web"
apply plugin: "org.apache.grails.gradle.grails-gsp"
apply plugin: "cloud.wondrify.asset-pipeline"
 
group = "example.grails"
 
repositories {
    maven {
       url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
    }
    mavenCentral()
    maven {
       url = 'https://repo.grails.org/grails/restricted'
    }
    maven {
       url = 'https://repository.apache.org/content/groups/snapshots'
       content {
          includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
       }
       mavenContent {
          snapshotsOnly()
       }
    }
    maven {
       url = 'https://repository.apache.org/content/groups/staging'
       content {
          includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
       }
       mavenContent {
          releasesOnly()
       }
    }
}
 
dependencies {
    profile "org.apache.grails.profiles:web"
    developmentOnly "org.springframework.boot:spring-boot-devtools" // Spring Boot DevTools may cause performance slowdowns or compatibility issues on larger applications
    testAndDevelopmentOnly "org.webjars.npm:bootstrap"
    testAndDevelopmentOnly "org.webjars.npm:bootstrap-icons"
    testAndDevelopmentOnly "org.webjars.npm:jquery"
    implementation platform("org.apache.grails:grails-bom:$grailsVersion")
    implementation "org.apache.grails:grails-core"
    implementation "org.apache.grails:grails-data-hibernate5"
    implementation "org.apache.grails:grails-data-mongodb"
    implementation "org.apache.grails:grails-databinding"
    implementation "org.apache.grails:grails-events"
    implementation "org.apache.grails:grails-gsp"
    implementation "org.apache.grails:grails-interceptors"
    implementation "org.apache.grails:grails-layout"
    implementation "org.apache.grails:grails-logging"
    implementation "org.apache.grails:grails-rest-transforms"
    implementation "org.apache.grails:grails-scaffolding"
    implementation "org.apache.grails:grails-services"
    implementation "org.apache.grails:grails-url-mappings"
    implementation "org.apache.grails:grails-web-boot"
    implementation "org.springframework.boot:spring-boot-autoconfigure"
    implementation "org.springframework.boot:spring-boot-starter"
    implementation "org.springframework.boot:spring-boot-starter-actuator"
    implementation "org.springframework.boot:spring-boot-starter-logging"
    implementation "org.springframework.boot:spring-boot-starter-tomcat"
    implementation "org.springframework.boot:spring-boot-starter-validation"
    implementation "org.springframework.boot:spring-boot-tomcat"
    console "org.apache.grails:grails-console"
    runtimeOnly "cloud.wondrify:asset-pipeline-grails"
    runtimeOnly "com.h2database:h2"
    runtimeOnly "com.zaxxer:HikariCP"
    runtimeOnly "org.fusesource.jansi:jansi"
    integrationTestImplementation testFixtures("org.apache.grails:grails-geb")
    testImplementation "org.apache.grails:grails-testing-support-datamapping"
    testImplementation "org.apache.grails:grails-testing-support-web"
    testImplementation "org.spockframework:spock-core"
    testImplementation "org.testcontainers:mongodb"
    testImplementation "org.testcontainers:spock"
    testImplementation "org.testcontainers:testcontainers"
}
 
compileJava.options.release = 17
 
tasks.withType(Test).configureEach {
    useJUnitPlatform()
}
 
assets {
    excludes = [
            'webjars/jquery/**',
            'webjars/bootstrap/**',
            'webjars/bootstrap-icons/**'
    ]
    includes = [
            'webjars/jquery/*/dist/jquery.js',
            'webjars/bootstrap/*/dist/js/bootstrap.bundle.js',
            'webjars/bootstrap/*/dist/css/bootstrap.css',
            'webjars/bootstrap-icons/*/font/bootstrap-icons.css',
            'webjars/bootstrap-icons/*/font/fonts/*',
    ]
}

	at org.grails.forge.feature.database.TestContainersSpec.test mongo-gorm dependency is present for gradle(TestContainersSpec.groovy:83)
TestContainersSpec > test mongo-sync dependency is present for gradle (:grails-forge-core:test [grails-forge] in CI / Build Grails Forge (Java 21, indy=false))
Condition not satisfied:

template.contains('testImplementation "org.testcontainers:testcontainers-mongodb"')
|        |
|        false
buildscript {
    repositories {
        maven {
           url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
        }
        mavenCentral()
        maven {
           url = 'https://repo.grails.org/grails/restricted'
        }
        maven {
           url = 'https://repository.apache.org/content/groups/snapshots'
           content {
              includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
           }
           mavenContent {
              snapshotsOnly()
           }
        }
        maven {
           url = 'https://repository.apache.org/content/groups/staging'
           content {
              includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
           }
           mavenContent {
              releasesOnly()
           }
        }
    }
    dependencies { // Not Published to Gradle Plugin Portal
        classpath "cloud.wondrify:asset-pipeline-gradle"
        classpath platform("org.apache.grails:grails-bom:$grailsVersion")
        classpath "org.apache.grails:grails-data-hibernate5"
        classpath "org.apache.grails:grails-gradle-plugins"
    }
}
 
plugins {
    id "war"
    id "idea"
    id "eclipse"
}
 
// Not Published to Gradle Plugin Portal
apply plugin: "org.apache.grails.gradle.grails-web"
apply plugin: "org.apache.grails.gradle.grails-gsp"
apply plugin: "cloud.wondrify.asset-pipeline"
 
group = "example.grails"
 
repositories {
    maven {
       url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
    }
    mavenCentral()
    maven {
       url = 'https://repo.grails.org/grails/restricted'
    }
    maven {
       url = 'https://repository.apache.org/content/groups/snapshots'
       content {
          includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
       }
       mavenContent {
          snapshotsOnly()
       }
    }
    maven {
       url = 'https://repository.apache.org/content/groups/staging'
       content {
          includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
       }
       mavenContent {
          releasesOnly()
       }
    }
}
 
dependencies {
    profile "org.apache.grails.profiles:web"
    developmentOnly "org.springframework.boot:spring-boot-devtools" // Spring Boot DevTools may cause performance slowdowns or compatibility issues on larger applications
    testAndDevelopmentOnly "org.webjars.npm:bootstrap"
    testAndDevelopmentOnly "org.webjars.npm:bootstrap-icons"
    testAndDevelopmentOnly "org.webjars.npm:jquery"
    implementation platform("org.apache.grails:grails-bom:$grailsVersion")
    implementation "org.apache.grails:grails-core"
    implementation "org.apache.grails:grails-data-hibernate5"
    implementation "org.apache.grails:grails-databinding"
    implementation "org.apache.grails:grails-events"
    implementation "org.apache.grails:grails-gsp"
    implementation "org.apache.grails:grails-interceptors"
    implementation "org.apache.grails:grails-layout"
    implementation "org.apache.grails:grails-logging"
    implementation "org.apache.grails:grails-rest-transforms"
    implementation "org.apache.grails:grails-scaffolding"
    implementation "org.apache.grails:grails-services"
    implementation "org.apache.grails:grails-url-mappings"
    implementation "org.apache.grails:grails-web-boot"
    implementation "org.mongodb:mongodb-driver-sync"
    implementation "org.springframework.boot:spring-boot-autoconfigure"
    implementation "org.springframework.boot:spring-boot-starter"
    implementation "org.springframework.boot:spring-boot-starter-actuator"
    implementation "org.springframework.boot:spring-boot-starter-logging"
    implementation "org.springframework.boot:spring-boot-starter-tomcat"
    implementation "org.springframework.boot:spring-boot-starter-validation"
    implementation "org.springframework.boot:spring-boot-tomcat"
    console "org.apache.grails:grails-console"
    runtimeOnly "cloud.wondrify:asset-pipeline-grails"
    runtimeOnly "com.h2database:h2"
    runtimeOnly "com.zaxxer:HikariCP"
    runtimeOnly "org.fusesource.jansi:jansi"
    integrationTestImplementation testFixtures("org.apache.grails:grails-geb")
    testImplementation "org.apache.grails:grails-testing-support-datamapping"
    testImplementation "org.apache.grails:grails-testing-support-web"
    testImplementation "org.spockframework:spock-core"
    testImplementation "org.testcontainers:mongodb"
    testImplementation "org.testcontainers:spock"
    testImplementation "org.testcontainers:testcontainers"
}
 
compileJava.options.release = 17
 
tasks.withType(Test).configureEach {
    useJUnitPlatform()
}
 
assets {
    excludes = [
            'webjars/jquery/**',
            'webjars/bootstrap/**',
            'webjars/bootstrap-icons/**'
    ]
    includes = [
            'webjars/jquery/*/dist/jquery.js',
            'webjars/bootstrap/*/dist/js/bootstrap.bundle.js',
            'webjars/bootstrap/*/dist/css/bootstrap.css',
            'webjars/bootstrap-icons/*/font/bootstrap-icons.css',
            'webjars/bootstrap-icons/*/font/fonts/*',
    ]
}

	at org.grails.forge.feature.database.TestContainersSpec.test mongo-sync dependency is present for gradle(TestContainersSpec.groovy:72)
TestContainersSpec > test postgres dependency is present for gradle (:grails-forge-core:test [grails-forge] in CI / Build Grails Forge (Java 21, indy=false))
Condition not satisfied:

template.contains('testImplementation "org.testcontainers:testcontainers-postgresql"')
|        |
|        false
buildscript {
    repositories {
        maven {
           url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
        }
        mavenCentral()
        maven {
           url = 'https://repo.grails.org/grails/restricted'
        }
        maven {
           url = 'https://repository.apache.org/content/groups/snapshots'
           content {
              includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
           }
           mavenContent {
              snapshotsOnly()
           }
        }
        maven {
           url = 'https://repository.apache.org/content/groups/staging'
           content {
              includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
           }
           mavenContent {
              releasesOnly()
           }
        }
    }
    dependencies { // Not Published to Gradle Plugin Portal
        classpath "cloud.wondrify:asset-pipeline-gradle"
        classpath platform("org.apache.grails:grails-bom:$grailsVersion")
        classpath "org.apache.grails:grails-data-hibernate5"
        classpath "org.apache.grails:grails-gradle-plugins"
    }
}
 
plugins {
    id "war"
    id "idea"
    id "eclipse"
}
 
// Not Published to Gradle Plugin Portal
apply plugin: "org.apache.grails.gradle.grails-web"
apply plugin: "org.apache.grails.gradle.grails-gsp"
apply plugin: "cloud.wondrify.asset-pipeline"
 
group = "example.grails"
 
repositories {
    maven {
       url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
    }
    mavenCentral()
    maven {
       url = 'https://repo.grails.org/grails/restricted'
    }
    maven {
       url = 'https://repository.apache.org/content/groups/snapshots'
       content {
          includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
       }
       mavenContent {
          snapshotsOnly()
       }
    }
    maven {
       url = 'https://repository.apache.org/content/groups/staging'
       content {
          includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
       }
       mavenContent {
          releasesOnly()
       }
    }
}
 
dependencies {
    profile "org.apache.grails.profiles:web"
    developmentOnly "org.springframework.boot:spring-boot-devtools" // Spring Boot DevTools may cause performance slowdowns or compatibility issues on larger applications
    testAndDevelopmentOnly "org.webjars.npm:bootstrap"
    testAndDevelopmentOnly "org.webjars.npm:bootstrap-icons"
    testAndDevelopmentOnly "org.webjars.npm:jquery"
    implementation platform("org.apache.grails:grails-bom:$grailsVersion")
    implementation "org.apache.grails:grails-core"
    implementation "org.apache.grails:grails-data-hibernate5"
    implementation "org.apache.grails:grails-databinding"
    implementation "org.apache.grails:grails-events"
    implementation "org.apache.grails:grails-gsp"
    implementation "org.apache.grails:grails-interceptors"
    implementation "org.apache.grails:grails-layout"
    implementation "org.apache.grails:grails-logging"
    implementation "org.apache.grails:grails-rest-transforms"
    implementation "org.apache.grails:grails-scaffolding"
    implementation "org.apache.grails:grails-services"
    implementation "org.apache.grails:grails-url-mappings"
    implementation "org.apache.grails:grails-web-boot"
    implementation "org.springframework.boot:spring-boot-autoconfigure"
    implementation "org.springframework.boot:spring-boot-starter"
    implementation "org.springframework.boot:spring-boot-starter-actuator"
    implementation "org.springframework.boot:spring-boot-starter-logging"
    implementation "org.springframework.boot:spring-boot-starter-tomcat"
    implementation "org.springframework.boot:spring-boot-starter-validation"
    implementation "org.springframework.boot:spring-boot-tomcat"
    console "org.apache.grails:grails-console"
    runtimeOnly "cloud.wondrify:asset-pipeline-grails"
    runtimeOnly "com.zaxxer:HikariCP"
    runtimeOnly "org.fusesource.jansi:jansi"
    runtimeOnly "org.postgresql:postgresql"
    integrationTestImplementation testFixtures("org.apache.grails:grails-geb")
    testImplementation "org.apache.grails:grails-testing-support-datamapping"
    testImplementation "org.apache.grails:grails-testing-support-web"
    testImplementation "org.spockframework:spock-core"
    testImplementation "org.testcontainers:postgresql"
    testImplementation "org.testcontainers:spock"
    testImplementation "org.testcontainers:testcontainers"
}
 
compileJava.options.release = 17
 
tasks.withType(Test).configureEach {
    useJUnitPlatform()
}
 
assets {
    excludes = [
            'webjars/jquery/**',
            'webjars/bootstrap/**',
            'webjars/bootstrap-icons/**'
    ]
    includes = [
            'webjars/jquery/*/dist/jquery.js',
            'webjars/bootstrap/*/dist/js/bootstrap.bundle.js',
            'webjars/bootstrap/*/dist/css/bootstrap.css',
            'webjars/bootstrap-icons/*/font/bootstrap-icons.css',
            'webjars/bootstrap-icons/*/font/fonts/*',
    ]
}

	at org.grails.forge.feature.database.TestContainersSpec.test postgres dependency is present for gradle(TestContainersSpec.groovy:50)
MongoSyncSpec > test mongo sync dependencies are present for gradle (:grails-forge-core:test [grails-forge] in CI / Build Grails Forge (Java 21, indy=true))
Condition not satisfied:

template.contains('testImplementation "org.testcontainers:testcontainers-mongodb"')
|        |
|        false
buildscript {
    repositories {
        maven {
           url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
        }
        mavenCentral()
        maven {
           url = 'https://repo.grails.org/grails/restricted'
        }
        maven {
           url = 'https://repository.apache.org/content/groups/snapshots'
           content {
              includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
           }
           mavenContent {
              snapshotsOnly()
           }
        }
        maven {
           url = 'https://repository.apache.org/content/groups/staging'
           content {
              includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
           }
           content {
              includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
           }
           mavenContent {
              releasesOnly()
           }
        }
    }
    dependencies { // Not Published to Gradle Plugin Portal
        classpath "cloud.wondrify:asset-pipeline-gradle"
        classpath platform("org.apache.grails:grails-bom:$grailsVersion")
        classpath "org.apache.grails:grails-data-hibernate5"
        classpath "org.apache.grails:grails-gradle-plugins"
    }
}
 
plugins {
    id "war"
    id "idea"
    id "eclipse"
}
 
// Not Published to Gradle Plugin Portal
apply plugin: "org.apache.grails.gradle.grails-web"
apply plugin: "org.apache.grails.gradle.grails-gsp"
apply plugin: "cloud.wondrify.asset-pipeline"
 
group = "example.grails"
 
repositories {
    maven {
       url = 'file:/home/runner/work/grails-core/grails-core/build/local-maven'
    }
    mavenCentral()
    maven {
       url = 'https://repo.grails.org/grails/restricted'
    }
    maven {
       url = 'https://repository.apache.org/content/groups/snapshots'
       content {
          includeVersionByRegex('org[.]apache[.]grails.*', '.*', '.*-SNAPSHOT')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*-SNAPSHOT')
       }
       mavenContent {
          snapshotsOnly()
       }
    }
    maven {
       url = 'https://repository.apache.org/content/groups/staging'
       content {
          includeVersionByRegex('org[.]apache[.]grails[.]gradle', 'grails-publish', '.*')
       }
       content {
          includeVersionByRegex('org[.]apache[.]groovy.*', 'groovy.*', '.*')
       }
       mavenContent {
          releasesOnly()
       }
    }
}
 
dependencies {
    profile "org.apache.grails.profiles:web"
    developmentOnly "org.springframework.boot:spring-boot-devtools" // Spring Boot DevTools may cause performance slowdowns or compatibility issues on larger applications
    testAndDevelopmentOnly "org.webjars.npm:bootstrap"
    testAndDevelopmentOnly "org.webjars.npm:bootstrap-icons"
    testAndDevelopmentOnly "org.webjars.npm:jquery"
    implementation platform("org.apache.grails:grails-bom:$grailsVersion")
    implementation "org.apache.grails:grails-core"
    implementation "org.apache.grails:grails-data-hibernate5"
    implementation "org.apache.grails:grails-databinding"
    implementation "org.apache.grails:grails-events"
    implementation "org.apache.grails:grails-gsp"
    implementation "org.apache.grails:grails-interceptors"
    implementation "org.apache.grails:grails-layout"
    implementation "org.apache.grails:grails-logging"
    implementation "org.apache.grails:grails-rest-transforms"
    implementation "org.apache.grails:grails-scaffolding"
    implementation "org.apache.grails:grails-services"
    implementation "org.apache.grails:grails-url-mappings"
    implementation "org.apache.grails:grails-web-boot"
    implementation "org.mongodb:mongodb-driver-sync"
    implementation "org.springframework.boot:spring-boot-autoconfigure"
    implementation "org.springframework.boot:spring-boot-starter"
    implementation "org.springframework.boot:spring-boot-starter-actuator"
    implementation "org.springframework.boot:spring-boot-starter-logging"
    implementation "org.springframework.boot:spring-boot-starter-tomcat"
    implementation "org.springframework.boot:spring-boot-starter-validation"
    implementation "org.springframework.boot:spring-boot-tomcat"
    console "org.apache.grails:grails-console"
    runtimeOnly "cloud.wondrify:asset-pipeline-grails"
    runtimeOnly "com.h2database:h2"
    runtimeOnly "com.zaxxer:HikariCP"
    runtimeOnly "org.fusesource.jansi:jansi"
    integrationTestImplementation testFixtures("org.apache.grails:grails-geb")
    testImplementation "org.apache.grails:grails-testing-support-datamapping"
    testImplementation "org.apache.grails:grails-testing-support-web"
    testImplementation "org.spockframework:spock-core"
    testImplementation "org.testcontainers:mongodb"
    testImplementation "org.testcontainers:spock"
    testImplementation "org.testcontainers:testcontainers"
}
 
compileJava.options.release = 17
 
tasks.withType(Test).configureEach {
    useJUnitPlatform()
}
 
assets {
    excludes = [
            'webjars/jquery/**',
            'webjars/bootstrap/**',
            'webjars/bootstrap-icons/**'
    ]
    includes = [
            'webjars/jquery/*/dist/jquery.js',
            'webjars/bootstrap/*/dist/js/bootstrap.bundle.js',
            'webjars/bootstrap/*/dist/css/bootstrap.css',
            'webjars/bootstrap-icons/*/font/bootstrap-icons.css',
            'webjars/bootstrap-icons/*/font/fonts/*',
    ]
}

	at org.grails.forge.feature.database.MongoSyncSpec.test mongo sync dependencies are present for gradle(MongoSyncSpec.groovy:56)

Muted Tests

Select tests to mute in this pull request:

  • MongoSyncSpec > test mongo sync dependencies are present for gradle
  • TestContainersSpec > test mongo-gorm dependency is present for gradle
  • TestContainersSpec > test mongo-sync dependency is present for gradle
  • TestContainersSpec > test postgres dependency is present for gradle

Reuse successful test results:

  • ♻️ Only rerun the tests that failed or were muted before

Click the checkbox to trigger a rerun:

  • Rerun jobs

Learn more about TestLens at testlens.app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants