diff --git a/.agents/skills/codebase-memory/SKILL.md b/.agents/skills/codebase-memory/SKILL.md new file mode 100644 index 00000000000..cbfcec3b14c --- /dev/null +++ b/.agents/skills/codebase-memory/SKILL.md @@ -0,0 +1,104 @@ +--- +name: codebase-memory-setup +description: Helps the developer set up codebase-memory-mcp locally +license: Apache-2.0 +--- + + +--- +name: codebase-memory-setup +description: > +Verify and set up the codebase-memory MCP server for Grails-Core architectural navigation. +Use this skill at the start of any Grails-Core session to detect whether the MCP server is +active, prompt the user to install it if missing, and provide step-by-step configuration +instructions. Trigger whenever working with grails-core and MCP tool availability is unknown, +or when the user asks about faster codebase navigation, architectural mode, or MCP setup. +--- + +# Codebase Memory MCP: Environment Verification & Setup + +This skill governs how to verify, onboard, and configure the `codebase-memory` MCP server when +working in the Grails-Core repository. It enables "Architectural Mode" — a significantly faster +mode of codebase navigation using graph-based memory tools. + +--- + +## Step 1: Detect Operating Mode (Mandatory on Load) + +Before doing anything else, check your available tool definitions for the presence of any of +these tools: + +- `index_repository` +- `search_graph` +- `trace_call_path` +- `query_graph` + +| Condition | Mode | +|---|---| +| Tools **present** | **Architectural Mode** — proceed normally | +| Tools **absent** | **Standard Mode** — proceed to Step 2 | + +--- + +## Step 2: Proactive Onboarding (Standard Mode Only) + +If the MCP server is **not** detected, interrupt the current flow (unless addressing a critical +fix) and present the following message to the user: + +> "I've detected that this repository is optimized for **Codebase Memory MCP**, which allows me +> to navigate the Grails-Core architecture 90% faster. However, the server is not currently +> running in your environment. Would you like me to help you install it now?" + +Wait for the user's response before continuing. + +--- + +## Step 3: Installation (If User Approves) + +The package ships as a **static binary** (not npm). Use the appropriate one-liner for the user's +platform, or run it yourself if you have shell access. + +**macOS / Linux (bash):** + +```bash +curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash +``` + +**Windows (PowerShell):** + +```powershell +irm https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/scripts/setup-windows.ps1 | iex +``` + +Both scripts download the correct binary for the platform, place it on the PATH, and run +`codebase-memory-mcp install` to auto-configure all detected agents (Claude Code, Zed, Cursor, +etc.) in one step. + +> **Note:** `npm install -g codebase-memory-mcp` will not work — ignore any documentation +> suggesting this. + +After the script completes, restart the agent environment. + +### Index the Repository + +Once the server is active, index grails-core by telling the agent: + +``` +"Index this project" +``` + +The agent will call `index_repository` and build the knowledge graph automatically. + +--- + +## Step 4: Verify Activation + +Confirm that `index_repository`, `search_graph`, `trace_call_path`, and `query_graph` are now +available. If they are, **Architectural Mode** is active — proceed with the original task. + +If tools are still missing, ask the user to confirm the install script completed without errors +and that the agent environment was fully restarted. \ No newline at end of file diff --git a/.agents/skills/grails-developer/SKILL.md b/.agents/skills/grails-developer/SKILL.md index 00a6728513f..e004968c26c 100644 --- a/.agents/skills/grails-developer/SKILL.md +++ b/.agents/skills/grails-developer/SKILL.md @@ -1,28 +1,13 @@ - --- name: grails-developer description: Comprehensive guide for Grails 7 development, covering web applications, REST APIs, GORM, controllers, services, views, plugins, and testing with Spock and Geb license: Apache-2.0 -compatibility: opencode, claude, grok, gemini, copilot, cursor, windsurf -metadata: - audience: developers - frameworks: grails - versions: 7 --- + ## What I Do diff --git a/.agents/skills/groovy-developer/SKILL.md b/.agents/skills/groovy-developer/SKILL.md index 5931bf5add8..0b7feab35f9 100644 --- a/.agents/skills/groovy-developer/SKILL.md +++ b/.agents/skills/groovy-developer/SKILL.md @@ -1,29 +1,13 @@ - --- name: groovy-developer description: Expert guide for Groovy 4 development, covering concise syntax, closures, DSLs, metaprogramming, static compilation, and integration with Java 17 and Grails license: Apache-2.0 -compatibility: opencode, claude, grok, gemini, copilot, cursor, windsurf -metadata: - audience: developers - languages: groovy, java - versions: 4.0 - paradigms: dynamic, static, functional, object-oriented, DSL-oriented --- + ## What I Do diff --git a/.agents/skills/hibernate-developer/SKILL.md b/.agents/skills/hibernate-developer/SKILL.md new file mode 100644 index 00000000000..92927252758 --- /dev/null +++ b/.agents/skills/hibernate-developer/SKILL.md @@ -0,0 +1,119 @@ +--- +name: hibernate-developer +description: Guide for working in the grails-data-hibernate7 module, especially Hibernate 7 domain binding, mapping migration, generators, and integration tests. Use this when changing code or tests under grails-data-hibernate7. +license: Apache-2.0 +--- + + +## What I Do + +- Provide repository-specific guidance for the `grails-data-hibernate7` project. +- Help with Hibernate 7 migration work in domain binding, mapping metadata, identifiers, generators, collections, and second-pass binding. +- Guide changes around `GrailsDomainBinder`, `GrailsPropertyBinder`, `IdentityBinder`, `VersionBinder`, collection binders, and related utilities. +- Keep changes aligned with the testing constraints and migration status documented in `grails-data-hibernate7/AGENTS.md`. + +## When to Use Me + +Activate this skill when working on the Hibernate 7 module, especially for: + +- Changes under `grails-data-hibernate7/**`. +- Hibernate 7 mapping and metadata binding work. +- Identifier, version, collection, association, or generator binding changes. +- Hibernate 7 regression fixes and migration follow-up tasks. +- Specs that exercise Hibernate-backed mapping behavior rather than lightweight unit behavior. + +## Module Context + +This skill is for the Grails framework's Hibernate 7 integration module, not for a Grails application. Prefer guidance from this skill over generic Grails app patterns when working in `grails-data-hibernate7`. + +`GrailsDomainBinder` is the main entry point for binding Grails domain classes to Hibernate metadata. Changes often ripple through: + +- `org.grails.orm.hibernate.cfg` +- `org.grails.orm.hibernate.cfg.domainbinding` +- `org.grails.orm.hibernate.cfg.domainbinding.collectionType` +- `org.grails.orm.hibernate.cfg.domainbinding.secondpass` +- `org.grails.orm.hibernate.cfg.domainbinding.generator` + +## Key Classes and Responsibilities + +### Main Binding Flow + +- `GrailsDomainBinder`: central coordinator for Hibernate 7 mapping contribution. +- `GrailsPropertyBinder`: main coordinator for converting persistent properties into Hibernate `Value` instances. +- `PropertyFromValueCreator`: shared utility for creating Hibernate `Property` instances from a bound `Value`. + +### Identifier and Version Binding + +- `IdentityBinder`: coordinates identifier binding. +- `SimpleIdBinder`: handles simple identifiers. +- `CompositeIdBinder`: handles composite identifiers. +- `VersionBinder`: binds optimistic locking version properties. +- `NaturalIdentifierBinder`: binds `naturalId` properties. + +### Associations and Collections + +- `OneToOneBinder`, `ManyToOneBinder`, `ManyToOneValuesBinder`: association binding. +- `CollectionBinder`: collection mapping. +- `CollectionSecondPassBinder`, `ListSecondPassBinder`, `MapSecondPassBinder`: second-pass association and collection binding. +- `CollectionHolder` plus the collection type classes: carry collection metadata through binding. + +### Value and Column Binding + +- `SimpleValueBinder`: binds simple properties. +- `SimpleValueColumnBinder`: binds columns to simple values. +- `ComponentBinder`, `ComponentPropertyBinder`: embedded/component binding. +- `EnumTypeBinder`: enum mapping. + +### Generators + +- `BasicValueCreator`: creates identifier values and generators. +- `GrailsSequenceWrapper`, `GrailsSequenceGeneratorEnum`: generator integration helpers. +- `GrailsIdentityGenerator`, `GrailsIncrementGenerator`, `GrailsNativeGenerator`, `GrailsSequenceStyleGenerator`, `GrailsTableGenerator`: Grails-specific Hibernate 7 generator implementations. + +## Current Module Guidance + +Keep these module-specific expectations in mind: + +- `GrailsPropertyBinder` has already been simplified to a unified binder-dispatch structure. Preserve that consolidation instead of reintroducing scattered property creation or ad hoc branching. +- Property creation and addition should stay centralized through callers using `PropertyFromValueCreator` where applicable. +- Utility classes in `domainbinding.util` should prefer Hibernate-aware GORM types internally, but public signatures may still need base interfaces when Spock mocks require them. +- `GrailsIncrementGenerator` still contains reflection-based Hibernate 7 compatibility workarounds; avoid broad refactors unless the change explicitly addresses that area. + +## Testing Rules + +When touching `grails-data-hibernate7`, test through real Hibernate wiring rather than assuming mocks are enough. + +- Use `HibernateGormDatastoreSpec` for Hibernate 7 integration and domain-binding specifications. +- Prefer `manager.addAllDomainClasses([...])` in `setupSpec()` to register entities for specs. +- Define test entities as top-level classes in the same Groovy spec file. +- Ensure test domain class names are globally unique within the package to avoid collisions during parallel execution. +- Prefer real entities over heavy mocking for binder logic. + +## Change Workflow + +1. Identify which binder, creator, generator, fetcher, or second-pass class owns the behavior. +2. Trace whether the change affects only `Value` creation, `Property` creation, or both. +3. Preserve the existing separation between logical mapping decisions and Hibernate object construction. +4. Update or add specs in `grails-data-hibernate7` that exercise the affected behavior through the public Hibernate-backed path. +5. Run the relevant Hibernate 7 module tests, and expand test coverage when binder flow or entity registration behavior changes. + +## Pitfalls to Avoid + +- Do not treat this module like a simple Grails application layer; it is framework and mapping infrastructure code. +- Do not reintroduce duplicated property-creation logic if a shared binder or creator already owns it. +- Do not rely on unit-only mocking for Hibernate internals when the behavior depends on real metadata binding. +- Do not use nested or inner entity classes in Hibernate 7 specs when top-level classes are required for AST transforms and reliable registration. + +## Known Status and Constraints + +- The Hibernate 7 binder migration is largely in migrated state across the main binders, collection types, second-pass binders, generators, and utilities. +- Unidirectional many-to-many support in `CollectionSecondPassBinder` is implemented. +- `GrailsIncrementGenerator` reflection hacks remain a known temporary compromise until a later Hibernate upgrade removes the need. + +## Source of Truth + +This skill is derived from `grails-data-hibernate7/AGENTS.md`. When the module guidance changes, update this skill so agents can load the same rules directly from `.agents/skills/hibernate-developer/SKILL.md`. diff --git a/.agents/skills/java-developer/SKILL.md b/.agents/skills/java-developer/SKILL.md index 0f8a9d163ac..94d7dc5b932 100644 --- a/.agents/skills/java-developer/SKILL.md +++ b/.agents/skills/java-developer/SKILL.md @@ -1,28 +1,13 @@ - --- name: java-developer description: Guide for developing in Java 17 LTS, including modern features, best practices, and integration with Groovy/Grails projects license: Apache-2.0 -compatibility: opencode, claude, grok, gemini, copilot, cursor, windsurf -metadata: - audience: developers - languages: java - versions: 17 --- + ## What I Do diff --git a/.agents/skills/style-fixer/SKILL.md b/.agents/skills/style-fixer/SKILL.md new file mode 100644 index 00000000000..e115fe6b8fb --- /dev/null +++ b/.agents/skills/style-fixer/SKILL.md @@ -0,0 +1,200 @@ +--- +name: style-fixer +description: Guide for running, interpreting, and fixing code style violations in grails-core using GrailsCodeStylePlugin — covering CodeNarc, Checkstyle, PMD, SpotBugs, and Spotless +license: Apache-2.0 +--- + + +## What I Do + +- Explain how `GrailsCodeStylePlugin` enforces code quality across all 60+ modules via a single aggregation task. +- Guide you through running style checks, interpreting the per-tool Markdown violation reports, and fixing each class of violation. +- Describe which tools are always-on vs. opt-in, how to configure them via Gradle properties, and which violations can be auto-fixed. + +## When to Use Me + +Activate this skill when: + +- Running `./gradlew aggregateStyleViolations` and interpreting the resulting `*_VIOLATIONS.md` files. +- Fixing CodeNarc, Checkstyle, PMD, SpotBugs, or Spotless violations reported in those files. +- Configuring code style tools across the repo (enabling/disabling tools or adjusting rule files). +- Preparing a commit — the plugin output must be clean before merging. + +--- + +## Plugin Overview + +`GrailsCodeStylePlugin` is applied to **every** subproject via the `org.apache.grails.gradle.grails-code-style` plugin ID. It: + +1. Applies CodeNarc, Checkstyle, and (optionally) PMD, SpotBugs, Spotless, and JaCoCo. +2. Redirects all XML reports to a **shared** directory (`build/codestyle//`) so they are visible from the root. +3. Registers a per-project `codeStyle` task and a root `aggregateStyleViolations` task. +4. Writes aggregated Markdown violation files to the repo root. + +--- + +## Key Tasks + +| Task | Scope | Description | +|------|-------|-------------| +| `./gradlew codeStyle` | per-project | Runs all enabled style checks for that project | +| `./gradlew aggregateStyleViolations` | root | Runs all checks across every module, then writes `*_VIOLATIONS.md` | +| `./gradlew codenarcFix` | per-project | Auto-fixes a subset of CodeNarc violations | + +### Quick commands + +```bash +# Check a single module +./gradlew :grails-core:codeStyle + +# Full multi-module check + report +./gradlew aggregateStyleViolations + +# Skip style in tests (default); include test sources +./gradlew aggregateStyleViolations -Pgrails.codestyle.enabled.tests=true + +# Ignore failures (collect reports without failing the build) +./gradlew aggregateStyleViolations -Pgrails.codestyle.ignoreFailures=true + +# Auto-fix some CodeNarc violations before running checks +./gradlew codenarcFix codeStyle +``` + +--- + +## Output Files + +After running `aggregateStyleViolations`, these files appear in the repo root: + +| File | Tool | Always generated | +|------|------|-----------------| +| `CODENARC_VIOLATIONS.md` | CodeNarc | Yes | +| `CHECKSTYLE_VIOLATIONS.md` | Checkstyle | Yes | +| `PMD_VIOLATIONS.md` | PMD | Yes — may contain `No violations found!` when `grails.codestyle.enabled.pmd=false` | +| `SPOTBUGS_VIOLATIONS.md` | SpotBugs | Yes — may contain `No violations found!` when `grails.codestyle.enabled.spotbugs=false` | +| `JACOCO_COVERAGE_VIOLATIONS.md` | JaCoCo | Only if `grails.codestyle.enabled.jacoco=true` | + +Each file is a Markdown table grouped by module, with columns: **Class**, **Tool**, **Violation**, **Line**, **Message**. + +A clean run produces `No violations found! 🎉` in each file. **A commit must not include any violations.** + +--- + +## Tool Details + +### CodeNarc (Groovy — always enabled) + +Rule file: `build/codestyle/codenarc/codenarc.groovy` (generated by the plugin under `build/codestyle/...` during setup; it may be overwritten and is not intended to be edited directly). + +Most common violations and how to fix them: + +| Rule | Fix | +|------|-----| +| `UnnecessaryGString` | Replace `"plain string"` with `'plain string'` | +| `UnnecessarySemicolon` | Remove trailing `;` | +| `SpaceBeforeOpeningBrace` | Add space before `{` → `method() {` | +| `SpaceAroundMapEntryColon` | `[key: value]` not `[key:value]` | +| `ConsecutiveBlankLines` | Collapse 3+ blank lines to 2 | +| `ClassStartsWithBlankLine` | Remove blank line right after `class Foo {` | +| `NoWildcardImports` | Expand `import org.foo.*` to explicit imports | +| `UnusedImport` | Remove imports not referenced in the file | +| `MethodName` | Method names must be camelCase (not `snake_case`) | +| `VariableName` | Variable names must be camelCase | +| `LineLength` | Keep lines ≤ 200 chars (default) | + +Auto-fixable via `codenarcFix`: `ClassStartsWithBlankLine`, `SpaceAroundMapEntryColon`, `UnnecessaryGString`, `UnnecessarySemicolon`, `SpaceBeforeOpeningBrace`, `ConsecutiveBlankLines`. + +### Checkstyle (Java — always enabled) + +Rule file: `build/codestyle/checkstyle/checkstyle.xml`. + +Common violations: + +| Rule | Fix | +|------|-----| +| `ImportOrder` | Re-order imports: `java|javax`, then `groovy`, then `jakarta`, then blank, then `io.spring|org.springframework`, then `grails|org.apache.grails|org.grails`, then static imports | +| `AvoidStarImport` | Use explicit class imports | +| `UnusedImports` | Remove unused imports | +| `WhitespaceAround` | Add spaces around operators and keywords | +| `NeedBraces` | Add `{}` to single-statement `if`/`for`/`while` | +| `FileTabCharacter` | Replace tabs with 4 spaces | +| `NewlineAtEndOfFile` | Ensure file ends with `\n` | + +### PMD (Java/Groovy — opt-in) + +Enable: `-Pgrails.codestyle.enabled.pmd=true` + +Rule file: `build/codestyle/pmd/pmd.xml`. + +### SpotBugs (Java bytecode — opt-in) + +Enable: `-Pgrails.codestyle.enabled.spotbugs=true` + +Runs at `Effort.MAX` / `Confidence.HIGH`. Only high-confidence bugs are reported. + +### Spotless (Java auto-formatting — opt-in) + +Enable: `-Pgrails.codestyle.enabled.spotless=true` + +Uses Palantir Java Format. Can auto-fix by running: +```bash +./gradlew spotlessApply +``` + +--- + +## Configuration Properties + +All properties can be set in `gradle.properties` or passed as `-P` flags: + +| Property | Default | Description | +|----------|---------|-------------| +| `grails.codestyle.enabled.checkstyle` | `true` | Enable Checkstyle | +| `grails.codestyle.enabled.codenarc` | `true` | Enable CodeNarc | +| `grails.codestyle.enabled.pmd` | `false` | Enable PMD | +| `grails.codestyle.enabled.spotbugs` | `false` | Enable SpotBugs | +| `grails.codestyle.enabled.spotless` | `false` | Enable Spotless | +| `grails.codestyle.enabled.jacoco` | `false` | Enable JaCoCo coverage | +| `grails.codestyle.enabled.tests` | `false` | Also check test source sets | +| `grails.codestyle.ignoreFailures` | `false` | Collect reports without failing build | +| `grails.codestyle.codenarc.fix` | `false` | Run `codenarcFix` before CodeNarc tasks | +| `grails.codestyle.dir.checkstyle` | (auto) | Custom path to Checkstyle config dir | +| `grails.codestyle.dir.codenarc` | (auto) | Custom path to CodeNarc config dir | +| `grails.codestyle.dir.pmd` | (auto) | Custom path to PMD config dir | +| `grails.codestyle.dir.spotless` | (auto) | Custom path to Spotless config dir | +| `skipCodeStyle` | unset | If present, all style tasks are skipped | + +--- + +## Fixing Violations Workflow + +1. Run `./gradlew aggregateStyleViolations -Pgrails.codestyle.ignoreFailures=true` +2. Open `CODENARC_VIOLATIONS.md` and `CHECKSTYLE_VIOLATIONS.md` to see all issues by module +3. For CodeNarc, run `./gradlew codenarcFix` to auto-fix what it can +4. Fix remaining violations manually using the table above +5. Re-run `./gradlew aggregateStyleViolations` and confirm files contain `No violations found! 🎉` +6. Delete the generated `*_VIOLATIONS.md` files before committing, even if they report no violations + +--- + +## Reports Directory Structure + +All XML reports are consolidated at: +``` +build/codestyle/ +├── checkstyle/ +│ ├── grails-core-checkstyleMain.xml +│ ├── grails-web-mvc-checkstyleMain.xml +│ └── ... +├── codenarc/ +│ ├── grails-core-codenarcMain.xml +│ └── ... +├── pmd/ (if enabled) +└── spotbugs/ (if enabled) +``` + +The module name is derived from the filename: everything before the last `-` (e.g. `grails-core-checkstyleMain.xml` → module `grails-core`). diff --git a/.agents/skills/test-fixer/SKILL.md b/.agents/skills/test-fixer/SKILL.md new file mode 100644 index 00000000000..8d6079d0c02 --- /dev/null +++ b/.agents/skills/test-fixer/SKILL.md @@ -0,0 +1,188 @@ +--- +name: test-fixer +description: Guide for running, aggregating, and fixing test failures across all grails-core modules using GrailsTestPlugin — producing TEST_FAILURES.md from multi-module XML test results +license: Apache-2.0 +--- + + +## What I Do + +- Explain how `GrailsTestPlugin` aggregates test failures from all 60+ modules into a single `TEST_FAILURES.md` report. +- Guide you through running tests across the entire repo with `--continue` so one failure doesn't stop the rest. +- Help interpret `TEST_FAILURES.md`, navigate to failing specs, and fix the underlying issues. + +## When to Use Me + +Activate this skill when: + +- Running the full test suite and needing to see all failures in one place instead of tailing 60 separate reports. +- Preparing a commit — `TEST_FAILURES.md` must report `All tests passed! 🎉` before merging. +- Triaging which modules have regressions after a dependency upgrade or refactor. + +--- + +## Plugin Overview + +`GrailsTestPlugin` is applied to the **root project only** via the `org.apache.grails.gradle.test-aggregation` plugin ID (registered in `build-logic`). + +It registers a single `aggregateTestFailures` task that: + +1. Waits for (`mustRunAfter`) every `Test` task in every subproject. +2. Scans all `build/test-results/**/*.xml` directories across subprojects and all top-level repo directories. +3. Parses every `TEST-*.xml` JUnit report for `` and `` elements. +4. Writes `TEST_FAILURES.md` to the repo root — a Markdown table of failures grouped by module. + +Note: This plugin does **not** run tests itself. It only aggregates results already written to disk. Gradle's own test engine (JUnit Platform) handles test execution and XML report generation. + +--- + +## Key Tasks + +### Targeted Testing (Recommended) +To save time, clean old results and run only related tests: + +```bash +# 1. Clear stale XML reports +./gradlew clean + +# 2. Run related tests and aggregate +./gradlew :grails-data-hibernate7-core:test --tests "grails.gorm.tests.BasicCollection*" aggregateTestFailures --continue +``` + +### Full Run +```bash +# Run all tests across all modules, continue even on failure, then aggregate +./gradlew test aggregateTestFailures --continue +``` + +`--continue` is essential: without it, Gradle stops at the first failing module and `aggregateTestFailures` never runs. +**ALWAYS run `clean` before a targeted run if you want `TEST_FAILURES.md` to reflect only the current run.** + +--- + +## Output File + +`TEST_FAILURES.md` is written to the repo root. Format: + +```markdown +# Test Failures Summary +Generated on: 2026-04-10 12:00:00 + +Found 3 failures. + +## Module: grails-data-hibernate7-core +| Class | Test | Type | Message | +| :--- | :--- | :--- | :--- | +| org.grails.orm.hibernate.FooSpec | some feature | org.spockframework.runtime.SpockAssertionError | expected: ... | +``` + +A clean run produces: +```markdown +All tests passed! 🎉 +``` + +**A clean run should report no issues. Note that `TEST_FAILURES.md` is a generated artifact and is ignored by git, so it will not be committed.** + +--- + +## Interpreting Failures + +Each row in the table gives you: + +| Column | Meaning | +|--------|---------| +| `Class` | Fully-qualified Spock spec or JUnit class | +| `Test` | Feature method name (Spock) or test method name (JUnit) | +| `Type` | Exception class (e.g. `SpockAssertionError`, `IllegalStateException`) | +| `Message` | First 200 characters of the failure message or stack | + +### Common Failure Patterns + +| Type | Likely Cause | +|------|-------------| +| `ConditionNotSatisfiedException` | Spock `then:` assertion failed — check expected vs actual values | +| `SpockAssertionError` | Explicit `assert` failed inside a spec | +| `BeanCreationException` | Spring context failed to start — check `@SpringBootTest` config or missing beans | +| `HibernateException` | Schema/session issue — check entity mapping or test datasource | +| `IllegalStateException` | Missing setup, invalid test state, or static pollution from parallel tests | +| `NullPointerException` | Uninitialized mock or service — check `given:` block | +| `MissingMethodException` | Groovy dynamic dispatch failure — usually a missing method or wrong type | + +--- + +## Running Tests for a Specific Module + +```bash +# All tests in a module +./gradlew :grails-data-hibernate7-dbmigration:test + +# A specific spec +./gradlew :grails-data-hibernate7-dbmigration:test \ + --tests "org.grails.plugins.databasemigration.command.DbmGenerateGormChangelogCommandSpec" + +# A specific feature method (use the exact feature name) +./gradlew :grails-data-hibernate7-core:test \ + --tests "org.grails.orm.hibernate.FooSpec.my feature name" + +# Force rerun even if Gradle thinks it's up-to-date +./gradlew :grails-data-hibernate7-core:test --rerun-tasks +``` + +--- + +## Test Source Layout + +| Source set | Directory | Task | +|------------|-----------|------| +| Unit tests | `src/test/groovy/` | `test` | +| Integration tests | `src/integration-test/groovy/` | `integrationTest` | + +Most specs in grails-core are **unit tests** (`src/test/groovy/`) run by the `test` task. +A small number of modules use `integrationTest` for full Spring context tests. + +--- + +## Parallel Test Execution + +Tests run in parallel (`maxParallelForks` defaults to `4` on CI and to `availableProcessors * 3/4` otherwise; override with `-PmaxTestParallel`). This can cause: + +- **Static state pollution** — one test mutating a static field that another test reads. +- **Port conflicts** — multiple test JVMs binding the same port. +- **`@Shared` field contamination** — shared state not properly cleaned up between feature methods. + +To diagnose flaky failures, re-run with forced serial execution: +```bash +./gradlew :module:test -PmaxTestParallel=1 --rerun-tasks +``` + +--- + +## Test Configuration Flags + +| Property | Effect | +|----------|--------| +| `skipTests` | Skips all `Test` tasks (build only) | +| `maxTestParallel=N` | Override parallel fork count | +| `onlyFunctionalTests` | Run only functional test suites | +| `skipHibernate7Tests` | Skip H7-specific test suites | +| `onlyMongodbTests` | Run only MongoDB test suites | +| `onlyCoreTests` | Run only core module tests | + +--- + +## XML Report Location + +Gradle writes JUnit XML test results to: +``` +/build/test-results/ +├── test/ +│ └── TEST-org.grails.SomSpec.xml +└── integrationTest/ + └── TEST-org.grails.SomeIntegrationSpec.xml +``` + +`aggregateTestFailures` scans all these directories automatically. diff --git a/.editorconfig b/.editorconfig index 4c509b592c4..fc99647e201 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,4 +23,5 @@ indent_size = 4 indent_style = space insert_final_newline = true spaces_around_operators = true -wildcard_import_limit = 999 \ No newline at end of file +wildcard_import_limit = 999 +imports_layout = java.**, |, javax.**, |, groovy.**, org.apache.groovy.**, org.codehaus.groovy.**, |, jakarta.**, |, *, |, io.spring.**, org.springframework.**, |, grails.**, org.apache.grails.**, org.grails.**, |, $* \ No newline at end of file diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8352fa57be0..51556fc4a69 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,5 @@ # .git-blame-ignore-revs # Reformat code: https://github.com/apache/grails-core/pull/14925 20c3278683f2993e23c947c409eafa978c0aefb7 +# Reformat code for hibernate 7 +811bacd377678e22bac6308065da28b1caa17700 \ No newline at end of file diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ef4cb95ae2b..afebcffa9d4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,10 +30,12 @@ on: push: branches: - '[4-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' pull_request: # The branches below must be a subset of the branches above branches: - '[4-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' # queue jobs and only allow 1 run per branch due to the likelihood of hitting GitHub resource limits concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 4a3663fea1e..bdb2bede507 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -18,6 +18,7 @@ on: push: branches: - '[0-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' pull_request: workflow_dispatch: # queue jobs and only allow 1 run per branch due to the likelihood of hitting GitHub resource limits @@ -43,13 +44,22 @@ jobs: with: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Core Projects" - run: ./gradlew codeStyle + run: | + mkdir -p build/reports/codestyle + ./gradlew codeStyle --continue 2>&1 | tee build/codestyle-output.log || true + # Extract Spotless violations into a separate report + sed -n '/The following files had format violations:/,/Run.*spotlessApply.*to fix all violations\./p' build/codestyle-output.log > build/reports/codestyle/spotless-violations.txt || true + # Fail the step if the Gradle build actually failed + grep -q "BUILD SUCCESSFUL" build/codestyle-output.log - name: "📤 Upload Failure Reports" if: always() uses: actions/upload-artifact@v7.0.1 with: name: core-reports - path: build/reports/codestyle/ + path: | + build/reports/codestyle/ + **/build/reports/pmd/ + **/build/reports/spotbugs/ - name: "📋 Publish Code Style Report in Job Summary" if: always() run: | diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 8132d637e28..5f1e09017cf 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -18,6 +18,7 @@ on: push: branches: - '[0-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' pull_request: workflow_dispatch: # Queue jobs - cancel in-progress PR runs when new commits pushed, but allow branch builds to complete diff --git a/.github/workflows/groovy-joint-workflow.yml b/.github/workflows/groovy-joint-workflow.yml index 6949e938c4d..c6a0fc8bae7 100644 --- a/.github/workflows/groovy-joint-workflow.yml +++ b/.github/workflows/groovy-joint-workflow.yml @@ -17,10 +17,12 @@ name: "CI - Groovy Joint Validation Build" on: push: branches: - - '[4-9]+.[0-9]+.x' + - '[0-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' pull_request: branches: - - '[4-9]+.[0-9]+.x' + - '[0-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' workflow_dispatch: # queue jobs and only allow 1 run per branch due to the likelihood of hitting GitHub resource limits concurrency: @@ -123,7 +125,6 @@ jobs: run: | cd groovy ./gradlew pTML -x groovydoc -x javadoc -x javadocAll -x groovydocAll -x asciidoc -x docGDK - build_grails: needs: [build_groovy] runs-on: ubuntu-latest diff --git a/.github/workflows/rat.yml b/.github/workflows/rat.yml index c7e3a6072b9..b593e140861 100644 --- a/.github/workflows/rat.yml +++ b/.github/workflows/rat.yml @@ -17,14 +17,12 @@ name: "Licensing - RAT Report" on: push: branches: - - '[4-9]+.[0-9]+.x' - - '[3-9]+.[3-9]+.x' - - license-audit + - '[0-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' pull_request: branches: - - '[4-9]+.[0-9]+.x' - - '[3-9]+.[3-9]+.x' - - license-audit + - '[0-9]+.[0-9]+.x' + - '8.0.x-hibernate7.*' workflow_dispatch: # queue jobs and only allow 1 run per branch due to the likelihood of hitting GitHub resource limits concurrency: diff --git a/.gitignore b/.gitignore index ca770d0c557..0f5465f9d1c 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ testWatchedFile.properties _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 Micronaut.adoc **/src/en/ref/Configuration/Application Properties.adoc stacktrace.log @@ -63,3 +64,9 @@ tmp/ !etc/bin etc/bin/results .vscode/ +STATE_SNAPSHOT.xml +0_build_grails.txt +*VIOLATIONS.md +/TEST_FAILURES.md +local-tasks.gradle +local-init.gradle diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index ab13aa909ae..ce4b40f7953 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -54,6 +54,7 @@ +