From 29a24649f14f5f662b0fb5627c84dd24ddd130f2 Mon Sep 17 00:00:00 2001 From: James Daugherty Date: Thu, 28 May 2026 12:23:09 -0400 Subject: [PATCH 01/16] Add grails-code-analysis convention plugin and violation aggregation Splits static code analysis out of the code-style plugin into a dedicated grails-code-analysis convention plugin (PMD + SpotBugs), and adds a root-only grails-violation-aggregation plugin that consolidates the per-module Checkstyle/CodeNarc/PMD XML reports into Markdown summaries under build/reports/violations/ via an aggregateStyleViolations task. Extracted from the Hibernate 7 staging branch (PR #15654) so it can be reviewed as a focused, single-topic change against 8.0.x, per review feedback that the analysis tooling should land in its own PR. Includes: - GrailsCodeAnalysisPlugin + GrailsCodeAnalysisExtension - GrailsViolationAggregationPlugin (aggregateStyleViolations) - GrailsCodeStylePlugin improvements: enable/disable properties, codenarcFix task, test-styling toggle; resource path renamed to grails-code-style, PMD config under grails-code-analysis - codeanalysis.yml workflow; codestyle.yml switched to aggregated reports - pmd/spotbugs versions; violation-fixer skill - Applies grails-code-analysis to 96 subprojects and wires forge Assisted-by: claude-code:claude-4.7-opus --- .agents/skills/violation-fixer/SKILL.md | 231 +++++++++ .github/workflows/codeanalysis.yml | 95 ++++ .github/workflows/codestyle.yml | 75 ++- build-logic/plugins/build.gradle | 19 +- .../apache/grails/buildsrc/GradleUtils.groovy | 7 + .../GrailsCodeAnalysisExtension.groovy | 53 ++ .../buildsrc/GrailsCodeAnalysisPlugin.groovy | 183 +++++++ .../buildsrc/GrailsCodeStyleExtension.groovy | 9 +- .../buildsrc/GrailsCodeStylePlugin.groovy | 141 ++++-- .../GrailsViolationAggregationPlugin.groovy | 467 ++++++++++++++++++ .../pmd/pmd.xml | 31 ++ .../checkstyle/checkstyle-suppressions.xml | 0 .../checkstyle/checkstyle.xml | 0 .../codenarc/codenarc.groovy | 0 .../buildsrc/GrailsCodeStylePluginSpec.groovy | 135 +++++ ...railsViolationAggregationPluginSpec.groovy | 177 +++++++ build.gradle | 4 + gradle.properties | 2 + grails-async/core/build.gradle | 1 + grails-async/gpars/build.gradle | 1 + grails-async/plugin/build.gradle | 1 + grails-async/rxjava/build.gradle | 1 + grails-async/rxjava2/build.gradle | 1 + grails-async/rxjava3/build.gradle | 1 + grails-bootstrap/build.gradle | 1 + grails-cache/build.gradle | 1 + grails-codecs-core/build.gradle | 1 + grails-codecs/build.gradle | 1 + grails-common/build.gradle | 1 + grails-console/build.gradle | 1 + grails-controllers/build.gradle | 1 + grails-converters/build.gradle | 1 + grails-core/build.gradle | 1 + .../boot-plugin/build.gradle | 1 + grails-data-hibernate5/core/build.gradle | 1 + .../dbmigration/build.gradle | 1 + .../grails-plugin/build.gradle | 1 + .../spring-orm/build.gradle | 1 + grails-data-mongodb/boot-plugin/build.gradle | 1 + grails-data-mongodb/bson/build.gradle | 1 + grails-data-mongodb/core/build.gradle | 1 + grails-data-mongodb/ext/build.gradle | 1 + .../grails-plugin/build.gradle | 1 + .../gson-templates/build.gradle | 1 + grails-data-simple/build.gradle | 1 + grails-databinding-core/build.gradle | 1 + grails-databinding/build.gradle | 1 + grails-datamapping-async/build.gradle | 1 + grails-datamapping-core/build.gradle | 1 + grails-datamapping-rx/build.gradle | 1 + grails-datamapping-support/build.gradle | 1 + grails-datamapping-tck/build.gradle | 1 + grails-datamapping-validation/build.gradle | 1 + grails-datasource/build.gradle | 1 + grails-datastore-async/build.gradle | 1 + grails-datastore-core/build.gradle | 1 + grails-datastore-web/build.gradle | 1 + grails-domain-class/build.gradle | 1 + grails-encoder/build.gradle | 1 + grails-events/core/build.gradle | 1 + grails-events/gpars/build.gradle | 1 + grails-events/plugin/build.gradle | 1 + grails-events/rxjava/build.gradle | 1 + grails-events/rxjava2/build.gradle | 1 + grails-events/rxjava3/build.gradle | 1 + grails-events/spring/build.gradle | 1 + grails-events/transforms/build.gradle | 1 + grails-fields/build.gradle | 1 + grails-forge/build.gradle | 1 + grails-forge/gradle/code-style-config.gradle | 1 + grails-geb/build.gradle | 1 + grails-gradle/common/build.gradle | 1 + grails-gradle/model/build.gradle | 1 + grails-gradle/plugins/build.gradle | 1 + grails-gradle/tasks/build.gradle | 1 + grails-gsp/core/build.gradle | 1 + grails-gsp/grails-layout/build.gradle | 1 + grails-gsp/grails-sitemesh3/build.gradle | 1 + grails-gsp/grails-taglib/build.gradle | 1 + grails-gsp/grails-web-gsp-taglib/build.gradle | 1 + grails-gsp/grails-web-gsp/build.gradle | 1 + grails-gsp/grails-web-jsp/build.gradle | 1 + grails-gsp/grails-web-taglib/build.gradle | 1 + grails-gsp/plugin/build.gradle | 1 + grails-i18n/build.gradle | 1 + grails-interceptors/build.gradle | 1 + grails-logging/build.gradle | 1 + grails-mimetypes/build.gradle | 1 + grails-rest-transforms/build.gradle | 1 + grails-scaffolding/build.gradle | 1 + grails-services/build.gradle | 1 + grails-shell-cli/build.gradle | 1 + grails-spring/build.gradle | 1 + grails-test-core/build.gradle | 1 + grails-test-suite-base/build.gradle | 1 + grails-testing-support-core/build.gradle | 1 + .../build.gradle | 1 + .../build.gradle | 1 + .../build.gradle | 1 + .../build.gradle | 1 + .../build.gradle | 1 + grails-testing-support-mongodb/build.gradle | 1 + .../build.gradle | 1 + grails-testing-support-web/build.gradle | 1 + grails-url-mappings/build.gradle | 1 + grails-validation/build.gradle | 1 + grails-views-core/build.gradle | 1 + grails-views-gson/build.gradle | 1 + grails-views-markup/build.gradle | 1 + grails-web-boot/build.gradle | 1 + grails-web-common/build.gradle | 1 + grails-web-core/build.gradle | 1 + grails-web-databinding/build.gradle | 1 + grails-web-mvc/build.gradle | 1 + grails-web-url-mappings/build.gradle | 1 + grails-wrapper/build.gradle | 1 + 116 files changed, 1641 insertions(+), 86 deletions(-) create mode 100644 .agents/skills/violation-fixer/SKILL.md create mode 100644 .github/workflows/codeanalysis.yml create mode 100644 build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy create mode 100644 build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy create mode 100644 build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy create mode 100644 build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-analysis/pmd/pmd.xml rename build-logic/plugins/src/main/resources/META-INF/{org.apache.grails.buildsrc.codestyle => org.apache.grails.buildsrc.grails-code-style}/checkstyle/checkstyle-suppressions.xml (100%) rename build-logic/plugins/src/main/resources/META-INF/{org.apache.grails.buildsrc.codestyle => org.apache.grails.buildsrc.grails-code-style}/checkstyle/checkstyle.xml (100%) rename build-logic/plugins/src/main/resources/META-INF/{org.apache.grails.buildsrc.codestyle => org.apache.grails.buildsrc.grails-code-style}/codenarc/codenarc.groovy (100%) create mode 100644 build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy create mode 100644 build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy diff --git a/.agents/skills/violation-fixer/SKILL.md b/.agents/skills/violation-fixer/SKILL.md new file mode 100644 index 00000000000..07ed784d355 --- /dev/null +++ b/.agents/skills/violation-fixer/SKILL.md @@ -0,0 +1,231 @@ +--- +name: violation-fixer +description: Guide for running, interpreting, and fixing code style and analysis violations in grails-core using GrailsCodeStylePlugin, GrailsCodeAnalysisPlugin, and GrailsViolationAggregationPlugin — covering CodeNarc, Checkstyle, PMD, SpotBugs, and JaCoCo +license: Apache-2.0 +--- + + +## What I Do + +- Explain how `GrailsCodeStylePlugin`, `GrailsCodeAnalysisPlugin`, and `GrailsViolationAggregationPlugin` enforce code quality across all 60+ modules. +- Guide you through running style and analysis 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 aggregateViolations` and interpreting the resulting `*_VIOLATIONS.md` files. +- Fixing CodeNarc, Checkstyle, PMD, SpotBugs, or Spotless violations reported in those files. +- Configuring code style or analysis tools across the repo (enabling/disabling tools or adjusting rule files). +- Preparing a commit — the plugin output must be clean before merging. + +--- + +## Plugin Overview + +| Plugin | Applied to | Responsibility | +|--------|-----------|----------------| +| `org.apache.grails.gradle.grails-code-style` | Every subproject | Applies Checkstyle and CodeNarc; registers per-project `codeStyle` task; redirects XML reports to root `build/reports/codestyle/` | +| `org.apache.grails.gradle.grails-code-analysis` | Every subproject | Applies PMD and SpotBugs (both opt-in); registers per-project `codeAnalysis` task; redirects XML reports to root `build/reports/codestyle/` | +| `org.apache.grails.gradle.grails-jacoco` | Every subproject | Applies JaCoCo; wires `jacocoTestReport` to run after each `test` task | +| `org.apache.grails.gradle.grails-violation-aggregation` | **Root project only** | Registers `aggregateViolations` and `aggregateJacocoCoverage` tasks; writes Markdown summaries to `build/reports/violations/` | + +--- + +## Key Tasks + +| Task | Scope | Description | +|------|-------|-------------| +| `./gradlew codeStyle` | per-project | Runs Checkstyle and CodeNarc for that project | +| `./gradlew codeAnalysis` | per-project | Runs PMD and/or SpotBugs for that project (when enabled) | +| `./gradlew aggregateViolations` | root | Runs all checks across every module, then writes `*_VIOLATIONS.md` to `build/reports/violations/` | +| `./gradlew aggregateJacocoCoverage` | root | Runs JaCoCo reports across every module, then writes `JACOCO_COVERAGE.md` to `build/reports/violations/` | +| `./gradlew codenarcFix` | per-project | Auto-fixes a subset of CodeNarc violations | + +### Quick commands + +```bash +# Check a single module (style only) +./gradlew :grails-core:codeStyle + +# Check a single module (analysis — must be enabled via properties) +./gradlew :grails-core:codeAnalysis -Pgrails.codeanalysis.enabled.pmd=true + +# Full multi-module check + report +./gradlew aggregateViolations + +# Include test sources in style checks +./gradlew aggregateViolations -Pgrails.codestyle.enabled.tests=true + +# Include test sources in analysis +./gradlew aggregateViolations -Pgrails.codeanalysis.enabled.tests=true + +# Ignore failures (collect reports without failing the build) +./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.codeanalysis.ignoreFailures=true + +# Auto-fix some CodeNarc violations before running checks +./gradlew codenarcFix codeStyle + +# JaCoCo coverage report +./gradlew aggregateJacocoCoverage +``` + +--- + +## Output Files + +After running `aggregateViolations`, these files appear under `build/reports/violations/` in the **root project build directory**: + +| File | Tool | Always generated | +|------|------|-----------------| +| `build/reports/violations/CODENARC_VIOLATIONS.md` | CodeNarc | Yes | +| `build/reports/violations/CHECKSTYLE_VIOLATIONS.md` | Checkstyle | Yes | +| `build/reports/violations/PMD_VIOLATIONS.md` | PMD | Yes — contains `No violations found!` when PMD is disabled | +| `build/reports/violations/SPOTBUGS_VIOLATIONS.md` | SpotBugs | Yes — contains `No violations found!` when SpotBugs is disabled | + +After running `aggregateJacocoCoverage`: + +| File | Tool | Generated | +|------|------|-----------| +| `build/reports/violations/JACOCO_COVERAGE.md` | JaCoCo | Only when at least one subproject has a JaCoCo CSV report | + +All reports are inside `build/` and are excluded from version control via `.gitignore`. A clean run produces `No violations found! 🎉` in each style file. **The build must be clean before committing.** + +Each file is a Markdown table grouped by module, with columns: **Class**, **Tool**, **Violation**, **Line**, **Message**. + +--- + +## Tool Details + +### CodeNarc (Groovy — always enabled) + +Rule file: `build/codestyle/codenarc/codenarc.groovy` (generated by the plugin during setup; 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.codeanalysis.enabled.pmd=true` + +Rule file: `build/codeanalysis/pmd/pmd.xml`. + +### SpotBugs (Java bytecode — opt-in) + +Enable: `-Pgrails.codeanalysis.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: + +### `grails-code-style` plugin (Checkstyle + CodeNarc) + +| Property | Default | Description | +|----------|---------|-------------| +| `grails.codestyle.enabled.checkstyle` | `true` | Enable Checkstyle | +| `grails.codestyle.enabled.codenarc` | `true` | Enable CodeNarc | +| `grails.codestyle.enabled.spotless` | `false` | Enable Spotless | +| `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 | +| `skipCodeStyle` | unset | If present, all style tasks are skipped | + +### `grails-code-analysis` plugin (PMD + SpotBugs) + +| Property | Default | Description | +|----------|---------|-------------| +| `grails.codeanalysis.enabled.pmd` | `false` | Enable PMD | +| `grails.codeanalysis.enabled.spotbugs` | `false` | Enable SpotBugs | +| `grails.codeanalysis.enabled.tests` | `false` | Also analyse test source sets | +| `grails.codeanalysis.ignoreFailures` | `false` | Collect reports without failing build | +| `grails.codeanalysis.dir.pmd` | (auto) | Custom path to PMD config dir | +| `skipCodeStyle` | unset | If present, all analysis tasks are also skipped | + +--- + +## Fixing Violations Workflow + +1. Run `./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.codeanalysis.ignoreFailures=true` +2. Open `build/reports/violations/CODENARC_VIOLATIONS.md` and `build/reports/violations/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 aggregateViolations` and confirm files contain `No violations found! 🎉` +6. The reports are inside `build/` and do not need to be deleted before committing + +--- + +## Reports Directory Structure + +All XML reports are consolidated at: +``` +build/reports/codestyle/ ← XML inputs for style aggregation +├── checkstyle/ +│ ├── grails-core-checkstyleMain.xml +│ ├── grails-web-mvc-checkstyleMain.xml +│ └── ... +├── codenarc/ +│ ├── grails-core-codenarcMain.xml +│ └── ... +├── pmd/ (if enabled) +└── spotbugs/ (if enabled) + +build/reports/violations/ ← Markdown summaries written by aggregateViolations +├── CODENARC_VIOLATIONS.md +├── CHECKSTYLE_VIOLATIONS.md +├── PMD_VIOLATIONS.md +├── SPOTBUGS_VIOLATIONS.md +└── JACOCO_COVERAGE.md ← written by aggregateJacocoCoverage +``` + +The module name is derived from the filename: everything before the last `-` (e.g. `grails-core-checkstyleMain.xml` → module `grails-core`). diff --git a/.github/workflows/codeanalysis.yml b/.github/workflows/codeanalysis.yml new file mode 100644 index 00000000000..f9d08fe5f2f --- /dev/null +++ b/.github/workflows/codeanalysis.yml @@ -0,0 +1,95 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: "Code Analysis" +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 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} +jobs: + check_core_projects: + name: "Core Projects" + runs-on: ubuntu-24.04 + steps: + - name: "🌐 Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it + run: curl -s https://api.ipify.org + - name: "📥 Checkout repository" + uses: actions/checkout@v6 + - name: "☕️ Setup JDK" + uses: actions/setup-java@v4 + with: + distribution: liberica + java-version: 21 + - name: "🐘 Setup Gradle" + uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + - name: "🔎 Check Core Projects" + run: ./gradlew aggregateAnalysisViolations --continue + - name: "📤 Upload Reports" + if: always() + uses: actions/upload-artifact@v7.0.1 + with: + name: core-reports + path: build/reports/violations/ + - name: "📋 Publish Code Analysis Report in Job Summary" + if: always() + run: | + echo "## 🔎 Code Analysis Report - Core Projects" >> $GITHUB_STEP_SUMMARY + for report in PMD_VIOLATIONS.md SPOTBUGS_VIOLATIONS.md; do + file="build/reports/violations/$report" + [ -f "$file" ] && cat "$file" >> $GITHUB_STEP_SUMMARY || true + done + check_gradle_plugin_projects: + name: "Gradle Plugin Projects" + runs-on: ubuntu-24.04 + steps: + - name: "🌐 Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it + run: curl -s https://api.ipify.org + - name: "📥 Checkout repository" + uses: actions/checkout@v6 + - name: "☕️ Setup JDK" + uses: actions/setup-java@v4 + with: + distribution: liberica + java-version: 21 + - name: "🐘 Setup Gradle" + uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} + - name: "🔎 Check Gradle Plugin Projects" + working-directory: grails-gradle + run: ./gradlew aggregateAnalysisViolations --continue + - name: "📤 Upload Reports" + if: always() + uses: actions/upload-artifact@v7.0.1 + with: + name: gradle-plugin-reports + path: grails-gradle/build/reports/violations/ + - name: "📋 Publish Code Analysis Report in Job Summary" + if: always() + run: | + echo "## 🔎 Code Analysis Report - Gradle Plugin Projects" >> $GITHUB_STEP_SUMMARY + for report in PMD_VIOLATIONS.md SPOTBUGS_VIOLATIONS.md; do + file="grails-gradle/build/reports/violations/$report" + [ -f "$file" ] && cat "$file" >> $GITHUB_STEP_SUMMARY || true + done diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index 4a3663fea1e..cb4abe4ec8d 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,27 +44,23 @@ jobs: with: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Core Projects" - run: ./gradlew codeStyle - - name: "📤 Upload Failure Reports" + run: ./gradlew aggregateStyleViolations --continue + - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@v7.0.1 with: name: core-reports - path: build/reports/codestyle/ + path: build/reports/violations/ - name: "📋 Publish Code Style Report in Job Summary" if: always() run: | echo "## 🔎 Code Style Report - Core Projects" >> $GITHUB_STEP_SUMMARY - for file in build/reports/codestyle/checkstyle/*.xml build/reports/codestyle/codenarc/*.xml; do - [ -f "$file" ] || continue - if grep -q "> $GITHUB_STEP_SUMMARY - grep "> $GITHUB_STEP_SUMMARY - grep "> $GITHUB_STEP_SUMMARY - fi + for report in CODENARC_VIOLATIONS.md CHECKSTYLE_VIOLATIONS.md; do + file="build/reports/violations/$report" + [ -f "$file" ] && cat "$file" >> $GITHUB_STEP_SUMMARY || true done - check_gradle_plugin_projects: - name: "Gradle Plugin Projects" + check_forge_projects: + name: "Forge Projects" runs-on: ubuntu-24.04 steps: - name: "🌐 Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it @@ -79,29 +76,25 @@ jobs: uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 with: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - - name: "🔎 Check Gradle Plugin Projects" - working-directory: grails-gradle - run: ./gradlew codeStyle - - name: "📤 Upload Failure Reports" + - name: "🔎 Check Forge Projects" + working-directory: grails-forge + run: ./gradlew aggregateStyleViolations --continue + - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@v7.0.1 with: - name: gradle-plugin-reports - path: grails-gradle/build/reports/codestyle/ + name: forge-reports + path: grails-forge/build/reports/violations/ - name: "📋 Publish Code Style Report in Job Summary" if: always() run: | - echo "## 🔎 Code Style Report - Gradle Plugin Projects" >> $GITHUB_STEP_SUMMARY - for file in grails-gradle/build/reports/codestyle/checkstyle/*.xml grails-gradle/build/reports/codestyle/codenarc/*.xml; do - [ -f "$file" ] || continue - if grep -q "> $GITHUB_STEP_SUMMARY - grep "> $GITHUB_STEP_SUMMARY - grep "> $GITHUB_STEP_SUMMARY - fi + echo "## 🔎 Code Style Report - Forge Projects" >> $GITHUB_STEP_SUMMARY + for report in CODENARC_VIOLATIONS.md CHECKSTYLE_VIOLATIONS.md; do + file="grails-forge/build/reports/violations/$report" + [ -f "$file" ] && cat "$file" >> $GITHUB_STEP_SUMMARY || true done - check_grails_forge_projects: - name: "Forge Projects" + check_gradle_plugin_projects: + name: "Gradle Plugin Projects" runs-on: ubuntu-24.04 steps: - name: "🌐 Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it @@ -117,24 +110,20 @@ jobs: uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 with: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - - name: "🔎 Check Forge Projects" - working-directory: grails-forge - run: ./gradlew codeStyle - - name: "📤 Upload Failure Reports" + - name: "🔎 Check Gradle Plugin Projects" + working-directory: grails-gradle + run: ./gradlew aggregateStyleViolations --continue + - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@v7.0.1 with: - name: forge-reports - path: grails-forge/build/reports/codestyle/ + name: gradle-plugin-reports + path: grails-gradle/build/reports/violations/ - name: "📋 Publish Code Style Report in Job Summary" if: always() run: | - echo "## 🔎 Code Style Report - Forge Projects" >> $GITHUB_STEP_SUMMARY - for file in grails-forge/build/reports/codestyle/checkstyle/*.xml grails-forge/build/reports/codestyle/codenarc/*.xml; do - [ -f "$file" ] || continue - if grep -q "> $GITHUB_STEP_SUMMARY - grep "> $GITHUB_STEP_SUMMARY - grep "> $GITHUB_STEP_SUMMARY - fi - done \ No newline at end of file + echo "## 🔎 Code Style Report - Gradle Plugin Projects" >> $GITHUB_STEP_SUMMARY + for report in CODENARC_VIOLATIONS.md CHECKSTYLE_VIOLATIONS.md; do + file="grails-gradle/build/reports/violations/$report" + [ -f "$file" ] && cat "$file" >> $GITHUB_STEP_SUMMARY || true + done diff --git a/build-logic/plugins/build.gradle b/build-logic/plugins/build.gradle index ef5b010fbd7..b196ee24316 100644 --- a/build-logic/plugins/build.gradle +++ b/build-logic/plugins/build.gradle @@ -38,6 +38,15 @@ dependencies { implementation "${gradleBomDependencies['grails-publish-plugin']}" implementation "org.gradle.crypto.checksum:org.gradle.crypto.checksum.gradle.plugin:${gradleProperties.gradleChecksumPluginVersion}" implementation "org.cyclonedx.bom:org.cyclonedx.bom.gradle.plugin:${gradleProperties.gradleCycloneDxPluginVersion}" + implementation "com.github.spotbugs.snom:spotbugs-gradle-plugin:${gradleProperties.spotbugsPluginVersion}" + + testImplementation "org.spockframework:spock-core:${gradleBomDependencyVersions['gradle-spock.version']}" + testImplementation gradleTestKit() + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() } gradlePlugin { @@ -62,6 +71,14 @@ gradlePlugin { id = 'org.apache.grails.gradle.grails-code-style' implementationClass = 'org.apache.grails.buildsrc.GrailsCodeStylePlugin' } + register('grailsCodeAnalysis') { + id = 'org.apache.grails.gradle.grails-code-analysis' + implementationClass = 'org.apache.grails.buildsrc.GrailsCodeAnalysisPlugin' + } + register('grailsViolationAggregation') { + id = 'org.apache.grails.gradle.grails-violation-aggregation' + implementationClass = 'org.apache.grails.buildsrc.GrailsViolationAggregationPlugin' + } register('groovydocEnhancer') { id = 'org.apache.grails.buildsrc.groovydoc-enhancer' implementationClass = 'org.apache.grails.buildsrc.GroovydocEnhancerPlugin' @@ -79,4 +96,4 @@ gradlePlugin { implementationClass = 'org.apache.grails.buildsrc.GrailsDependencyValidatorPlugin' } } -} \ No newline at end of file +} diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy index 55ac4e38ab6..f556d634e23 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy @@ -22,6 +22,7 @@ package org.apache.grails.buildsrc import groovy.transform.CompileStatic import org.gradle.api.Project import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider @CompileStatic class GradleUtils { @@ -37,6 +38,12 @@ class GradleUtils { asfFile.exists() ? currentDirectory : findAsfRootDir(currentDirectory.dir('../')) } + static Provider booleanProvider(Project project, String name, boolean defaultValue = false) { + project.providers.gradleProperty(name) + .map { Boolean.parseBoolean(it as String) } + .orElse(defaultValue) + } + static T lookupProperty(Project project, String name, T defaultValue = null) { T v = lookupPropertyByType(project, name, defaultValue?.class) as T return v == null ? defaultValue : v diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy new file mode 100644 index 00000000000..f7ba0448fed --- /dev/null +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.grails.buildsrc + +import javax.inject.Inject + +import groovy.transform.CompileStatic + +import org.gradle.api.Project +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory + +@CompileStatic +class GrailsCodeAnalysisExtension { + + /** + * Defaults to project.rootProject.buildDir/codestyle/pmd. + * Directory for PMD configuration files (e.g. pmd.xml). + */ + final DirectoryProperty pmdDirectory + + /** + * Defaults to rootProject.buildDir/reports/codeanalysis. + * PMD and SpotBugs XML reports will be written here. + */ + final DirectoryProperty reportsDirectory + + @Inject + GrailsCodeAnalysisExtension(ObjectFactory objects, Project project) { + pmdDirectory = objects.directoryProperty().convention( + project.rootProject.layout.buildDirectory.dir('codeanalysis/pmd') + ) + reportsDirectory = objects.directoryProperty().convention( + project.rootProject.layout.buildDirectory.dir('reports/codeanalysis') + ) + } +} diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy new file mode 100644 index 00000000000..a4d1ee17d12 --- /dev/null +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.grails.buildsrc + +import java.nio.file.Files +import java.nio.file.Path + +import groovy.transform.CompileStatic + +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.plugins.quality.Pmd +import org.gradle.api.plugins.quality.PmdExtension +import org.gradle.api.plugins.quality.PmdPlugin +import org.gradle.api.provider.Provider + +import com.github.spotbugs.snom.Confidence +import com.github.spotbugs.snom.Effort +import com.github.spotbugs.snom.SpotBugsExtension +import com.github.spotbugs.snom.SpotBugsPlugin +import com.github.spotbugs.snom.SpotBugsReport +import com.github.spotbugs.snom.SpotBugsTask + +/** + * Convention plugin for Grails byte code analysis (PMD and SpotBugs). + * Both tools are opt-in; enable via Gradle properties. + */ +@CompileStatic +class GrailsCodeAnalysisPlugin implements Plugin { + + static String PMD_DIR_PROPERTY = 'grails.codeanalysis.dir.pmd' + static String PMD_ENABLED_PROPERTY = 'grails.codeanalysis.enabled.pmd' + static String PMD_CONFIG_FILE_NAME = 'pmd.xml' + + static String SPOTBUGS_ENABLED_PROPERTY = 'grails.codeanalysis.enabled.spotbugs' + + static String IGNORE_FAILURES_PROPERTY = 'grails.codeanalysis.ignoreFailures' + static String TEST_ANALYSIS_PROPERTY = 'grails.codeanalysis.enabled.tests' + + static String BASE_RESOURCE_PATH = '/META-INF/org.apache.grails.buildsrc.grails-code-analysis' + + @Override + void apply(Project project) { + initExtension(project) + configurePmd(project) + configureSpotbugs(project) + + // withType returns a live empty collection when the tool is not enabled, + // so these dependsOn calls are safe regardless of whether PMD/SpotBugs are active + project.tasks.register('codeAnalysis') { task -> + task.group = 'verification' + task.description = 'Runs code analysis checks (PMD, SpotBugs)' + task.dependsOn(project.tasks.withType(Pmd)) + task.dependsOn(project.tasks.withType(SpotBugsTask)) + } + } + + private static void initExtension(Project project) { + def gca = project.extensions.create('grailsCodeAnalysis', GrailsCodeAnalysisExtension) + + gca.pmdDirectory.set(project.provider { + def directory = project.hasProperty(PMD_DIR_PROPERTY) ? + project.rootProject.layout.projectDirectory.dir(project.property(PMD_DIR_PROPERTY) as String) : + project.rootProject.layout.buildDirectory.get().dir('codeanalysis').dir('pmd') + + def toCreate = directory.asFile.toPath() + Files.createDirectories(toCreate) + + createOrLoad( + toCreate.resolve(PMD_CONFIG_FILE_NAME), + "${BASE_RESOURCE_PATH}/pmd/${PMD_CONFIG_FILE_NAME}", + project + ) + + directory + }) + } + + private static void createOrLoad(Path expectedPath, String defaultResource, Project project) { + boolean defaultPath = expectedPath.startsWith(project.rootProject.buildDir.toPath()) + if (!Files.exists(expectedPath) || expectedPath.size() == 0 || defaultPath) { + def defaultValue = GrailsCodeAnalysisPlugin.getResourceAsStream(defaultResource) + if (!defaultValue) { + throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}") + } + project.logger.info('Replacing code analysis configuration') + expectedPath.text = defaultValue.text + } + } + + static void configurePmd(Project project) { + Provider pmdEnabled = GradleUtils.booleanProvider(project, PMD_ENABLED_PROPERTY) + if (!pmdEnabled.get()) { + return + } + + project.pluginManager.apply(PmdPlugin) + + Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY) + Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_ANALYSIS_PROPERTY) + + project.extensions.configure(PmdExtension) { + it.ruleSetFiles = project.files(project.extensions.getByType(GrailsCodeAnalysisExtension).pmdDirectory.file(PMD_CONFIG_FILE_NAME)) + it.ruleSets = [] + it.ignoreFailures = ignoreFailures.get() + it.consoleOutput = true + it.toolVersion = project.findProperty('pmdVersion') + } + + project.tasks.withType(Pmd).configureEach { Pmd task -> + task.group = 'verification' + task.onlyIf { !project.hasProperty('skipCodeStyle') } + task.ignoreFailures = ignoreFailures.get() + + if (task.name.contains('Test') || task.name.contains('test')) { + task.enabled = testStylingEnabled.get() + } + + task.reports.xml.required.set(true) + task.reports.xml.outputLocation.set( + project.extensions.getByType(GrailsCodeAnalysisExtension) + .reportsDirectory.get() + .dir('pmd') + .file("${project.name}-${task.name}.xml") + ) + } + } + + static void configureSpotbugs(Project project) { + Provider spotbugsEnabled = GradleUtils.booleanProvider(project, SPOTBUGS_ENABLED_PROPERTY) + if (!spotbugsEnabled.get()) { + return + } + + project.pluginManager.apply(SpotBugsPlugin) + + Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY) + Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_ANALYSIS_PROPERTY) + + project.extensions.configure(SpotBugsExtension) { + it.effort.set(Effort.valueOf('MAX')) + it.reportLevel.set(Confidence.valueOf('HIGH')) + it.ignoreFailures.set(ignoreFailures) + } + + project.tasks.withType(SpotBugsTask).configureEach { SpotBugsTask task -> + task.group = 'verification' + NamedDomainObjectContainer spotBugsReports = task.reports + SpotBugsReport htmlReport = spotBugsReports.maybeCreate('html') + htmlReport.required.set(true) + SpotBugsReport xmlReport = spotBugsReports.maybeCreate('xml') + xmlReport.required.set(true) + xmlReport.outputLocation.set( + project.extensions.getByType(GrailsCodeAnalysisExtension) + .reportsDirectory.get() + .dir('spotbugs') + .file("${project.name}-${task.name}.xml") + ) + task.onlyIf { !project.hasProperty('skipCodeStyle') } + + if (task.name.contains('Test') || task.name.contains('test')) { + task.enabled = testStylingEnabled.get() + } + } + } +} diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy index 8d338d34825..6fb04b0ae4d 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy @@ -25,18 +25,19 @@ import groovy.transform.CompileStatic import org.gradle.api.Project import org.gradle.api.file.DirectoryProperty import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property @CompileStatic class GrailsCodeStyleExtension { /** - * Defaults to project.buildDir/checkstyle. + * Defaults to project.rootProject.buildDir/codestyle/checkstyle. * Default checkstyle files will be written here and used from this location. */ final DirectoryProperty checkstyleDirectory /** - * Defaults to project.buildDir/codenarc. + * Defaults to project.rootProject.buildDir/codestyle/codenarc. * Default codenarc files will be written here and used from this location. */ final DirectoryProperty codenarcDirectory @@ -50,10 +51,10 @@ class GrailsCodeStyleExtension { @Inject GrailsCodeStyleExtension(ObjectFactory objects, Project project) { checkstyleDirectory = objects.directoryProperty().convention( - project.rootProject.layout.buildDirectory.dir('checkstyle') + project.rootProject.layout.buildDirectory.dir('codestyle/checkstyle') ) codenarcDirectory = objects.directoryProperty().convention( - project.rootProject.layout.buildDirectory.dir('codenarc') + project.rootProject.layout.buildDirectory.dir('codestyle/codenarc') ) reportsDirectory = objects.directoryProperty().convention( project.rootProject.layout.buildDirectory.dir('reports/codestyle') diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy index 67974e3b884..d8ba2c881e8 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy @@ -21,44 +21,52 @@ package org.apache.grails.buildsrc import java.nio.file.Files import java.nio.file.Path +import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.file.Directory import org.gradle.api.plugins.quality.Checkstyle import org.gradle.api.plugins.quality.CheckstyleExtension import org.gradle.api.plugins.quality.CheckstylePlugin import org.gradle.api.plugins.quality.CodeNarc import org.gradle.api.plugins.quality.CodeNarcExtension import org.gradle.api.plugins.quality.CodeNarcPlugin +import org.gradle.api.provider.Provider +/** + * Convention plugin for Grails code style enforcement (Checkstyle and CodeNarc). + */ @CompileStatic class GrailsCodeStylePlugin implements Plugin { static String CHECKSTYLE_DIR_PROPERTY = 'grails.codestyle.dir.checkstyle' + static String CHECKSTYLE_ENABLED_PROPERTY = 'grails.codestyle.enabled.checkstyle' static String CHECKSTYLE_CONFIG_FILE_NAME = 'checkstyle.xml' static String CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME = 'checkstyle-suppressions.xml' static String CODENARC_DIR_PROPERTY = 'grails.codestyle.dir.codenarc' + static String CODENARC_ENABLED_PROPERTY = 'grails.codestyle.enabled.codenarc' static String CODENARC_CONFIG_FILE_NAME = 'codenarc.groovy' - static String BASE_RESOURCE_PATH = '/META-INF/org.apache.grails.buildsrc.codestyle' + static String CODENARC_FIX_PROPERTY = 'grails.codestyle.codenarc.fix' + + static String IGNORE_FAILURES_PROPERTY = 'grails.codestyle.ignoreFailures' + + static String TEST_STYLING_PROPERTY = 'grails.codestyle.enabled.tests' + + static String BASE_RESOURCE_PATH = '/META-INF/org.apache.grails.buildsrc.grails-code-style' @Override void apply(Project project) { initExtension(project) configureCodeStyle(project) - doNotApplyStylingToTests(project) } private static void initExtension(Project project) { def gce = project.extensions.create('grailsCodeStyle', GrailsCodeStyleExtension) - // Unfortunately, the codenarc plugin is still using a non-lazy property. - // Rather than rewrite the plugin to use afterEvaluate, - // this plugin uses properties to override the configuration location by default - + // We are trying to avoid afterEvaluate usage here, so use properties for enabling / disabling gce.checkstyleDirectory.set(project.provider { def directory = project.hasProperty(CHECKSTYLE_DIR_PROPERTY) ? @@ -70,11 +78,13 @@ class GrailsCodeStylePlugin implements Plugin { createOrLoad( toCreate.resolve(CHECKSTYLE_CONFIG_FILE_NAME), - "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_CONFIG_FILE_NAME}" + "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_CONFIG_FILE_NAME}", + project ) createOrLoad( toCreate.resolve(CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME), - "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME}" + "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME}", + project ) directory @@ -90,40 +100,27 @@ class GrailsCodeStylePlugin implements Plugin { createOrLoad( toCreate.resolve(CODENARC_CONFIG_FILE_NAME), - "${BASE_RESOURCE_PATH}/codenarc/${CODENARC_CONFIG_FILE_NAME}" + "${BASE_RESOURCE_PATH}/codenarc/${CODENARC_CONFIG_FILE_NAME}", + project ) directory }) } - private static void createOrLoad(Path expectedPath, String defaultResource) { - if (!Files.exists(expectedPath) || expectedPath.size() == 0) { + private static void createOrLoad(Path expectedPath, String defaultResource, Project project) { + boolean defaultPath = expectedPath.startsWith(project.rootProject.buildDir.toPath()) + if (!Files.exists(expectedPath) || expectedPath.size() == 0 || defaultPath) { def defaultValue = GrailsCodeStylePlugin.getResourceAsStream(defaultResource) if (!defaultValue) { throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}") } + // TODO: This really need to use gradle caching instead + project.logger.info("Replacing code style configuration") expectedPath.text = defaultValue.text } } - private static void doNotApplyStylingToTests(Project project) { - project.tasks.named('checkstyleTest') { - it.enabled = false // Do not check test sources at this time - } - - project.afterEvaluate { - // Do not check test sources at this time - ['codenarcIntegrationTest', 'codenarcTest'].each { testTaskName -> - if (project.tasks.names.contains(testTaskName)) { - project.tasks.named(testTaskName) { - it.enabled = false - } - } - } - } - } - private static void configureCodeStyle(Project project) { configureCheckstyle(project) configureCodenarc(project) @@ -131,31 +128,37 @@ class GrailsCodeStylePlugin implements Plugin { project.tasks.register('codeStyle') { it.group = 'verification' it.description = 'Runs code style checks' - it.dependsOn(project.tasks.withType(Checkstyle)) it.dependsOn(project.tasks.withType(CodeNarc)) + it.dependsOn(project.tasks.withType(Checkstyle)) } } static void configureCheckstyle(Project project) { project.pluginManager.apply(CheckstylePlugin) + Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY) + Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_STYLING_PROPERTY) + project.extensions.configure(CheckstyleExtension) { // Explicit `it` is required in extension configuration it.getConfigDirectory().set(project.extensions.getByType(GrailsCodeStyleExtension).checkstyleDirectory) it.maxWarnings = 0 it.showViolations = true - it.ignoreFailures = false + it.ignoreFailures = ignoreFailures.get() it.toolVersion = project.findProperty('checkstyleVersion') } project.tasks.withType(Checkstyle).configureEach { Checkstyle task -> task.group = 'verification' task.onlyIf { !project.hasProperty('skipCodeStyle') } + task.ignoreFailures = ignoreFailures.get() + + if (task.name.contains('Test') || task.name.contains('test')) { + task.enabled = testStylingEnabled.get() + } // Redirect XML report output to a single directory to consolidate - // reports across all subprojects into one known location. - // Include the task name to avoid overlapping outputs when a project has - // multiple source sets (e.g. grails-cache has ast + main). + // reports across all subprojects into one known location task.reports.xml.outputLocation.set( project.extensions.getByType(GrailsCodeStyleExtension) .reportsDirectory.get() @@ -168,20 +171,34 @@ class GrailsCodeStylePlugin implements Plugin { static void configureCodenarc(Project project) { project.pluginManager.apply(CodeNarcPlugin) + registerCodenarcFixTask(project) + + Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY) + Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_STYLING_PROPERTY) + Provider codenarcFix = GradleUtils.booleanProvider(project, CODENARC_FIX_PROPERTY) + project.extensions.configure(CodeNarcExtension) { it.configFile = project.extensions.getByType(GrailsCodeStyleExtension) - .codenarcDirectory.get().file(CODENARC_CONFIG_FILE_NAME).asFile + .codenarcDirectory.file(CODENARC_CONFIG_FILE_NAME).get().asFile + it.ignoreFailures = ignoreFailures.get() it.toolVersion = project.findProperty('codenarcVersion') } project.tasks.withType(CodeNarc).configureEach { CodeNarc task -> task.group = 'verification' task.onlyIf { !project.hasProperty('skipCodeStyle') } + task.ignoreFailures = ignoreFailures.get() + + if (codenarcFix.get()) { + task.dependsOn('codenarcFix') + } + + if (task.name.contains('Test') || task.name.contains('test')) { + task.enabled = testStylingEnabled.get() + } // Redirect XML report output to a single directory to consolidate - // reports across all subprojects into one known location. - // Include the task name to avoid overlapping outputs when a project has - // multiple source sets. + // reports across all subprojects into one known location task.reports.xml.required.set(true) task.reports.xml.outputLocation.set( project.extensions.getByType(GrailsCodeStyleExtension) @@ -191,4 +208,52 @@ class GrailsCodeStylePlugin implements Plugin { ) } } + + @CompileDynamic + private static void registerCodenarcFixTask(Project project) { + project.tasks.register('codenarcFix') { + it.group = 'verification' + it.description = 'Automatically fixes some CodeNarc violations' + it.doLast { + project.fileTree(project.projectDir) { + it.include 'src/**/*.groovy' + it.include 'grails-app/**/*.groovy' + it.include 'scripts/**/*.groovy' + it.exclude '**/build/**' + }.each { file -> + String content = file.text + String original = content + + // 1. ClassStartsWithBlankLine + content = content.replaceAll(/(class\s+[^{]+\{\n)([ \t]*[^ \s\n\/])/, '$1\n$2') + + // 2. SpaceAroundMapEntryColon + content = content.replaceAll(/([\[,]\s*(?:[\w\-.]+|'[^']+'|"[^"]+")):([^\s\/])/, '$1: $2') + content = content.replaceAll(/(\(\s*(?:[\w\-.]+|'[^']+'|"[^"]+")):([^\s\/])/, '$1: $2') + + // 3. UnnecessaryGString + content = content.replaceAll(/(? + if (!inner.contains("'")) { + return "'$inner'" + } + return all + } + + // 4. UnnecessarySemicolon + content = content.replaceAll(/(?m);[ \t]*$/, '') + + // 5. SpaceBeforeOpeningBrace + content = content.replaceAll(/(? { + + private static final Logger LOGGER = Logging.getLogger(GrailsViolationAggregationPlugin) + + @Override + void apply(Project project) { + if (project != project.rootProject) { + throw new GradleException( + 'GrailsViolationAggregationPlugin must be applied to the root project only. ' + + 'Apply grails-code-style and grails-jacoco to subprojects instead.' + ) + } + + Provider violationsDir = project.layout.buildDirectory.dir('reports/violations') + Provider styleXmlDir = project.layout.buildDirectory.dir('reports/codestyle') + Provider analysisXmlDir = project.layout.buildDirectory.dir('reports/codeanalysis') + + TaskProvider styleTask = registerStyleAggregation(project, styleXmlDir, violationsDir) + TaskProvider analysisTask = registerAnalysisAggregation(project, analysisXmlDir, violationsDir) + registerJacocoAggregation(project, violationsDir) + + project.tasks.register('aggregateViolations') { Task task -> + task.group = 'verification' + task.description = 'Aggregates all violation reports (style + analysis) into build/reports/violations/' + task.dependsOn(styleTask, analysisTask) + } + } + + private static TaskProvider registerStyleAggregation(Project root, Provider styleXmlDir, Provider violationsDir) { + // Wire property flags as Providers — values are resolved at task execution time, not at apply() time, + // and Providers are configuration-cache safe to capture in task actions + Provider checkStyleTests = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.TEST_STYLING_PROPERTY) + Provider codenarcEnabled = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.CODENARC_ENABLED_PROPERTY, true) + Provider checkstyleEnabled = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.CHECKSTYLE_ENABLED_PROPERTY, true) + + TaskProvider aggregateTask = root.tasks.register('aggregateStyleViolations') { Task task -> + task.group = 'verification' + task.description = 'Aggregates CodeNarc and Checkstyle violation reports into build/reports/violations/' + task.outputs.file(root.file('build/reports/violations/CODENARC_VIOLATIONS.md')) + task.outputs.file(root.file('build/reports/violations/CHECKSTYLE_VIOLATIONS.md')) + task.doLast { + parseStyleViolations(styleXmlDir.get(), violationsDir.get(), + checkStyleTests.get(), codenarcEnabled.get(), checkstyleEnabled.get()) + } + } + root.subprojects { Project sub -> + sub.pluginManager.withPlugin('codenarc') { AppliedPlugin p -> + aggregateTask.configure { Task task -> + task.dependsOn(sub.tasks.withType(CodeNarc)) + } + } + sub.pluginManager.withPlugin('checkstyle') { AppliedPlugin p -> + aggregateTask.configure { Task task -> + task.dependsOn(sub.tasks.withType(Checkstyle)) + } + } + } + aggregateTask + } + + private static TaskProvider registerAnalysisAggregation(Project root, Provider analysisXmlDir, Provider violationsDir) { + Provider checkAnalysisTests = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.TEST_ANALYSIS_PROPERTY) + Provider pmdEnabled = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.PMD_ENABLED_PROPERTY) + Provider spotbugsEnabled = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.SPOTBUGS_ENABLED_PROPERTY) + + TaskProvider aggregateTask = root.tasks.register('aggregateAnalysisViolations') { Task task -> + task.group = 'verification' + task.description = 'Aggregates PMD and SpotBugs violation reports into build/reports/violations/' + task.outputs.file(root.file('build/reports/violations/PMD_VIOLATIONS.md')) + task.outputs.file(root.file('build/reports/violations/SPOTBUGS_VIOLATIONS.md')) + task.doLast { + parseAnalysisViolations(analysisXmlDir.get(), violationsDir.get(), + checkAnalysisTests.get(), pmdEnabled.get(), spotbugsEnabled.get()) + } + } + root.subprojects { Project sub -> + sub.pluginManager.withPlugin('pmd') { AppliedPlugin p -> + aggregateTask.configure { Task task -> + task.dependsOn(sub.tasks.withType(Pmd)) + } + } + sub.pluginManager.withPlugin('com.github.spotbugs') { AppliedPlugin p -> + aggregateTask.configure { Task task -> + task.dependsOn(sub.tasks.withType(SpotBugsTask)) + } + } + } + aggregateTask + } + + private static void registerJacocoAggregation(Project root, Provider violationsDir) { + // Collect all potential CSV paths at configuration time — Project must not be referenced from task actions + FileCollection jacocoCsvFiles = root.files( + root.allprojects.collect { Project p -> p.file('build/reports/jacoco/test/jacocoTestReport.csv') } + ) + + TaskProvider aggregateTask = root.tasks.register('aggregateJacocoCoverage') { Task task -> + task.group = 'verification' + task.description = 'Aggregates JaCoCo coverage reports from all subprojects into build/reports/violations/' + task.inputs.files(jacocoCsvFiles).optional(true) + task.outputs.file(root.file('build/reports/violations/JACOCO_COVERAGE.md')) + task.doLast { + parseJacocoCoverage(jacocoCsvFiles, violationsDir.get()) + } + } + root.subprojects { Project sub -> + sub.pluginManager.withPlugin('jacoco') { AppliedPlugin p -> + aggregateTask.configure { Task task -> + task.dependsOn(sub.tasks.withType(JacocoReport)) + } + } + } + } + + @CompileDynamic + private static void parseStyleViolations(Directory styleXmlDir, Directory violationsDir, + boolean checkStyleTests, boolean codenarcEnabled, boolean checkstyleEnabled) { + def slurper = new XmlSlurper() + slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) + slurper.setFeature('http://xml.org/sax/features/namespaces', false) + + def getModule = { String fileName -> + def lastDash = fileName.lastIndexOf('-') + lastDash != -1 ? fileName.substring(0, lastDash) : fileName + } + + def isTestFile = { String fileName -> + fileName.toLowerCase().contains('test') || fileName.toLowerCase().contains('integrationtest') + } + + def shouldSkipClass = { boolean includeTests, String className, String filePath = null -> + if (includeTests) { + return false + } + if (filePath && (filePath.contains('src/test/') || filePath.contains('src/integrationTest/'))) { + return true + } + !filePath && (className.contains('Spec') || className.contains('Test') || className.contains('Tests')) + } + + def writeReport = { String fileName, List violations, String title -> + def outDir = violationsDir.asFile + outDir.mkdirs() + def reportFile = new File(outDir, fileName) + def out = new StringBuilder() + out.append("# ${title}\n") + out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n") + + if (violations.isEmpty()) { + out.append('No violations found! 🎉\n') + } else { + def uniqueViolations = violations.unique().sort { v -> "${v.module}:${v.className}:${v.line}" } + def groupedByModule = uniqueViolations.groupBy { it.module }.sort() + groupedByModule.each { module, modViolations -> + out.append("## Module: ${module}\n") + out.append('| Class | Tool | Violation | Line | Message |\n') + out.append('| :--- | :--- | :--- | :--- | :--- |\n') + modViolations.each { v -> + out.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n") + } + out.append('\n') + } + } + reportFile.text = out.toString() + LOGGER.lifecycle("Aggregated report generated: ${reportFile.absolutePath}") + } + + // CodeNarc + def codenarcViolations = [] + def codenarcDir = styleXmlDir.dir('codenarc').asFile + if (codenarcDir.exists() && codenarcEnabled) { + codenarcDir.eachFileMatch(~/.*\.xml/) { file -> + if (file.size() == 0 || (!checkStyleTests && isTestFile(file.name))) { + return + } + def module = getModule(file.name) + def xml = slurper.parse(file) + xml.Package.each { pkg -> + pkg.File.each { f -> + def pkgName = pkg.@name.text() + def fileName = f.@name.text() + def className = pkgName ? "${pkgName}.${fileName}" : fileName + className = className.replace('.groovy', '').replace('.java', '') + if (shouldSkipClass(checkStyleTests, className, f.@name.text())) { + return + } + f.Violation.each { v -> + codenarcViolations << [ + module : module, + className: className, + tool : 'CodeNarc', + type : v.@ruleName.text(), + line : v.@lineNumber.text(), + message : v.Message.text().trim() + ] + } + } + } + } + } + writeReport('CODENARC_VIOLATIONS.md', codenarcViolations, 'CodeNarc Violations Summary') + + // Checkstyle + def checkstyleViolations = [] + def checkstyleDir = styleXmlDir.dir('checkstyle').asFile + if (checkstyleDir.exists() && checkstyleEnabled) { + checkstyleDir.eachFileMatch(~/.*\.xml/) { file -> + if (file.size() == 0 || (!checkStyleTests && isTestFile(file.name))) { + return + } + def module = getModule(file.name) + def xml = slurper.parse(file) + xml.file.each { f -> + def filePath = f.@name.text() + def className = filePath.contains('src/main/groovy/') ? filePath.split('src/main/groovy/')[1] : + filePath.contains('src/main/java/') ? filePath.split('src/main/java/')[1] : + filePath.contains('src/test/groovy/') ? filePath.split('src/test/groovy/')[1] : + filePath.contains('src/test/java/') ? filePath.split('src/test/java/')[1] : + filePath.split('/').last() + className = className.replace('.groovy', '').replace('.java', '').replace('/', '.') + if (shouldSkipClass(checkStyleTests, className)) { + return + } + f.error.each { e -> + checkstyleViolations << [ + module : module, + className: className, + tool : 'Checkstyle', + type : e.@source.text().split(/\./).last(), + line : e.@line.text(), + message : e.@message.text().trim() + ] + } + } + } + } + writeReport('CHECKSTYLE_VIOLATIONS.md', checkstyleViolations, 'Checkstyle Violations Summary') + } + + @CompileDynamic + private static void parseAnalysisViolations(Directory analysisXmlDir, Directory violationsDir, + boolean checkAnalysisTests, boolean pmdEnabled, boolean spotbugsEnabled) { + def slurper = new XmlSlurper() + slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) + slurper.setFeature('http://xml.org/sax/features/namespaces', false) + + def getModule = { String fileName -> + def lastDash = fileName.lastIndexOf('-') + lastDash != -1 ? fileName.substring(0, lastDash) : fileName + } + + def isTestFile = { String fileName -> + fileName.toLowerCase().contains('test') || fileName.toLowerCase().contains('integrationtest') + } + + def shouldSkipClass = { boolean includeTests, String className -> + if (includeTests) { + return false + } + className.contains('Spec') || className.contains('Test') || className.contains('Tests') + } + + def writeReport = { String fileName, List violations, String title -> + def outDir = violationsDir.asFile + outDir.mkdirs() + def reportFile = new File(outDir, fileName) + def out = new StringBuilder() + out.append("# ${title}\n") + out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n") + + if (violations.isEmpty()) { + out.append('No violations found! 🎉\n') + } else { + def uniqueViolations = violations.unique().sort { v -> "${v.module}:${v.className}:${v.line}" } + def groupedByModule = uniqueViolations.groupBy { it.module }.sort() + groupedByModule.each { module, modViolations -> + out.append("## Module: ${module}\n") + out.append('| Class | Tool | Violation | Line | Message |\n') + out.append('| :--- | :--- | :--- | :--- | :--- |\n') + modViolations.each { v -> + out.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n") + } + out.append('\n') + } + } + reportFile.text = out.toString() + LOGGER.lifecycle("Aggregated report generated: ${reportFile.absolutePath}") + } + + // PMD + def pmdViolations = [] + def pmdDir = analysisXmlDir.dir('pmd').asFile + if (pmdDir.exists() && pmdEnabled) { + pmdDir.eachFileMatch(~/.*\.xml/) { file -> + if (file.size() == 0 || (!checkAnalysisTests && isTestFile(file.name))) { + return + } + def module = getModule(file.name) + def xml = slurper.parse(file) + xml.file.each { f -> + f.violation.each { v -> + def className = "${v.@package}.${v.@class}" + if (shouldSkipClass(checkAnalysisTests, className)) { + return + } + pmdViolations << [ + module : module, + className: className, + tool : 'PMD', + type : v.@rule.text(), + line : v.@beginline.text(), + message : v.text().trim() + ] + } + } + } + } + writeReport('PMD_VIOLATIONS.md', pmdViolations, 'PMD Violations Summary') + + // SpotBugs + def spotbugsViolations = [] + def spotbugsDir = analysisXmlDir.dir('spotbugs').asFile + if (spotbugsDir.exists() && spotbugsEnabled) { + spotbugsDir.eachFileMatch(~/.*\.xml/) { file -> + if (file.size() == 0 || (!checkAnalysisTests && isTestFile(file.name))) { + return + } + def module = getModule(file.name) + def xml = slurper.parse(file) + xml.BugInstance.each { b -> + def className = b.Class.@classname.text() + if (shouldSkipClass(checkAnalysisTests, className)) { + return + } + spotbugsViolations << [ + module : module, + className: className, + tool : 'SpotBugs', + type : b.@type.text(), + line : b.SourceLine.@start.text(), + message : b.LongMessage.text().trim() + ] + } + } + } + writeReport('SPOTBUGS_VIOLATIONS.md', spotbugsViolations, 'SpotBugs Violations Summary') + } + + @CompileDynamic + private static void parseJacocoCoverage(FileCollection csvFiles, Directory violationsDir) { + def jacocoCoverage = [] + csvFiles.each { File csvReport -> + if (csvReport.exists()) { + LOGGER.debug("Processing JaCoCo report: ${csvReport.absolutePath}") + csvReport.splitEachLine(',') { fields -> + if (fields.size() < 5 || fields[0] == 'GROUP') { + return + } + def module = fields[0] + def pkg = fields[1] + def clazz = fields[2] + def missedStr = fields[3] + def coveredStr = fields[4] + + if (missedStr.isNumber() && coveredStr.isNumber()) { + def m = missedStr.toInteger() + def c = coveredStr.toInteger() + def total = m + c + def percent = total > 0 ? (c * 100 / total).round(2) : 100.0 + + jacocoCoverage << [ + module : module, + className: "${pkg}.${clazz}", + percent : percent + ] + } + } + } + } + + if (jacocoCoverage.isEmpty()) { + LOGGER.info('No JaCoCo coverage reports found to aggregate') + return + } + + jacocoCoverage.removeIf { it.className.startsWith('org.grails.orm.hibernate.support.hibernate7.') } + + def outDir = violationsDir.asFile + outDir.mkdirs() + def reportFile = new File(outDir, 'JACOCO_COVERAGE.md') + def out = new StringBuilder() + out.append('# JaCoCo Coverage Report\n') + out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n") + + def groupedByModule = jacocoCoverage.groupBy { it.module }.sort() + groupedByModule.each { module, coverageList -> + out.append("## Module: ${module}\n") + out.append('| Class | % Instructions Covered |\n') + out.append('| :--- | :--- |\n') + coverageList.sort { it.percent }.each { c -> + out.append("| ${c.className} | ${c.percent}% |\n") + } + out.append('\n') + } + reportFile.text = out.toString() + LOGGER.lifecycle("Aggregated JaCoCo report generated: ${reportFile.absolutePath}") + } +} diff --git a/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-analysis/pmd/pmd.xml b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-analysis/pmd/pmd.xml new file mode 100644 index 00000000000..cf494a71258 --- /dev/null +++ b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-analysis/pmd/pmd.xml @@ -0,0 +1,31 @@ + + + + + PMD ruleset for the Grails codebase + + + + + + diff --git a/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/checkstyle/checkstyle-suppressions.xml b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle-suppressions.xml similarity index 100% rename from build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/checkstyle/checkstyle-suppressions.xml rename to build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle-suppressions.xml diff --git a/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/checkstyle/checkstyle.xml b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle.xml similarity index 100% rename from build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/checkstyle/checkstyle.xml rename to build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle.xml diff --git a/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/codenarc/codenarc.groovy b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/codenarc/codenarc.groovy similarity index 100% rename from build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/codenarc/codenarc.groovy rename to build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/codenarc/codenarc.groovy diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy new file mode 100644 index 00000000000..1d26a0ecedd --- /dev/null +++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.grails.buildsrc + +import org.gradle.testkit.runner.GradleRunner +import spock.lang.Specification +import spock.lang.TempDir +import java.nio.file.Path + +class GrailsCodeStylePluginSpec extends Specification { + @TempDir + Path testProjectDir + + File buildFile + File groovyFile + + def setup() { + buildFile = testProjectDir.resolve('build.gradle').toFile() + buildFile << """ + plugins { + id 'groovy' + id 'org.apache.grails.gradle.grails-code-style' + } + + // Minimal configuration for the plugin + repositories { + mavenCentral() + } + """ + + testProjectDir.resolve('src/main/groovy').toFile().mkdirs() + groovyFile = testProjectDir.resolve('src/main/groovy/Test.groovy').toFile() + } + + def "test codenarcFix task fixes violations"() { + given: "a file with violations" + groovyFile.text = """package org.test + +class Test{ + def map = [key:"value"] + def str = "unnecessary gstring" + def semi = "semicolon"; + def lines = 1 + + + def other = 2 +} +""" + when: "running codenarcFix" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('codenarcFix', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task finished successfully" + result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS + + and: "violations are fixed" + def fixedContent = groovyFile.text + fixedContent.contains('class Test {') // SpaceBeforeOpeningBrace + fixedContent.contains('class Test {\n\n def map') + fixedContent.contains("[key: 'value']") // SpaceAroundMapEntryColon and UnnecessaryGString + fixedContent.contains("'unnecessary gstring'") // UnnecessaryGString + fixedContent.contains("def semi = 'semicolon'") // UnnecessarySemicolon + !fixedContent.contains(";") + fixedContent.count('\n\n') == 3 // ConsecutiveBlankLines + } + + def "test codenarcFix task does not break strings with single quotes"() { + given: "a file with double quoted strings containing single quotes" + groovyFile.text = """package org.test + +class Test { + def s1 = "it's a test" + def s2 = "format 'yyyy-MM-dd'" + def s3 = "contains \\"double\\" and 'single' quotes" +} +""" + when: "running codenarcFix" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('codenarcFix', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task finished successfully" + result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS + + and: "strings with single quotes are NOT changed to single quotes (which would break them)" + def content = groovyFile.text + content.contains('def s1 = "it\'s a test"') + content.contains('def s2 = "format \'yyyy-MM-dd\'"') + // s3 has escaped double quotes, so it should also remain double quoted + content.contains('def s3 = "contains \\"double\\" and \'single\' quotes"') + } + + def "test codenarcFix task does not break escaped double quotes in double quotes"() { + given: "a file with escaped double quotes" + groovyFile.text = """package org.test + +class Test { + def s = "\\"\\\$it\\"" +} +""" + when: "running codenarcFix" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('codenarcFix', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task finished successfully" + result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS + + and: "escaped quotes are NOT broken" + groovyFile.text.contains('"\\"\\$it\\""') + } +} diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy new file mode 100644 index 00000000000..be51ff7508d --- /dev/null +++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.grails.buildsrc + +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import spock.lang.Specification +import spock.lang.TempDir + +import java.nio.file.Path + +class GrailsViolationAggregationPluginSpec extends Specification { + + @TempDir + Path testProjectDir + + def "plugin must be applied to root project only"() { + given: "a subproject-only build with the aggregation plugin" + testProjectDir.resolve('settings.gradle').toFile().text = "include 'sub'" + testProjectDir.resolve('build.gradle').toFile().text = '' + def sub = testProjectDir.resolve('sub') + sub.toFile().mkdirs() + sub.resolve('build.gradle').toFile().text = """ + plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' + } + """ + + when: "configuring the project" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('tasks') + .withPluginClasspath() + .buildAndFail() + + then: "an error is thrown" + result.output.contains('must be applied to the root project only') + } + + def "all aggregation tasks are registered on root"() { + given: "root project with aggregation plugin" + testProjectDir.resolve('settings.gradle').toFile().text = '' + testProjectDir.resolve('build.gradle').toFile().text = """ + plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' + } + """ + + when: "listing verification tasks" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('tasks', '--group=verification') + .withPluginClasspath() + .build() + + then: + result.output.contains('aggregateStyleViolations') + result.output.contains('aggregateAnalysisViolations') + result.output.contains('aggregateViolations') + result.output.contains('aggregateJacocoCoverage') + } + + def "aggregateStyleViolations writes CodeNarc and Checkstyle reports to build/reports/violations/"() { + given: "a root project with a subproject that has codestyle XML reports" + testProjectDir.resolve('settings.gradle').toFile().text = "include 'app-module'" + testProjectDir.resolve('build.gradle').toFile().text = """ + plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' + } + """ + def moduleDir = testProjectDir.resolve('app-module') + moduleDir.toFile().mkdirs() + moduleDir.resolve('build.gradle').toFile().text = """ + plugins { + id 'groovy' + id 'org.apache.grails.gradle.grails-code-style' + } + repositories { mavenCentral() } + dependencies { + implementation localGroovy() + } + """ + def srcFile = moduleDir.resolve('src/main/groovy/com/example/AppClass.groovy').toFile() + srcFile.parentFile.mkdirs() + srcFile.text = 'package com.example\nclass AppClass {}' + + // Pre-populate XML reports in the standard consolidated location (build/reports/codestyle/) + def checkstyleDir = testProjectDir.resolve('build/reports/codestyle/checkstyle').toFile() + checkstyleDir.mkdirs() + new File(checkstyleDir, 'app-module-checkstyleMain.xml').text = """ + + + + + +""" + def codenarcDir = testProjectDir.resolve('build/reports/codestyle/codenarc').toFile() + codenarcDir.mkdirs() + new File(codenarcDir, 'app-module-codenarcMain.xml').text = """ + + + + +The class is empty + + + + +""" + + when: "running aggregateStyleViolations skipping the actual style tasks" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('aggregateStyleViolations', '-x', 'checkstyleMain', '-x', 'codenarcMain', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task succeeds" + result.task(':aggregateStyleViolations').outcome == TaskOutcome.SUCCESS + + and: "reports land in build/reports/violations/ — NOT in the repo root" + def violationsDir = testProjectDir.resolve('build/reports/violations').toFile() + new File(violationsDir, 'CHECKSTYLE_VIOLATIONS.md').exists() + new File(violationsDir, 'CODENARC_VIOLATIONS.md').exists() + !testProjectDir.resolve('CHECKSTYLE_VIOLATIONS.md').toFile().exists() + !testProjectDir.resolve('CODENARC_VIOLATIONS.md').toFile().exists() + + and: "checkstyle report contains the violation" + def checkstyleMd = new File(violationsDir, 'CHECKSTYLE_VIOLATIONS.md').text + checkstyleMd.contains('## Module: app-module') + checkstyleMd.contains('JavadocPackageCheck') + + and: "codenarc report contains the violation" + def codenarcMd = new File(violationsDir, 'CODENARC_VIOLATIONS.md').text + codenarcMd.contains('## Module: app-module') + codenarcMd.contains('EmptyClass') + } + + def "aggregateJacocoCoverage handles no csv reports gracefully"() { + given: "root project with no subproject csv reports" + testProjectDir.resolve('settings.gradle').toFile().text = '' + testProjectDir.resolve('build.gradle').toFile().text = """ + plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' + } + """ + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('aggregateJacocoCoverage', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task succeeds without error" + result.task(':aggregateJacocoCoverage').outcome == TaskOutcome.SUCCESS + + and: "no report file is created" + !testProjectDir.resolve('build/reports/violations/JACOCO_COVERAGE.md').toFile().exists() + } +} diff --git a/build.gradle b/build.gradle index bb330e24872..87b54c25f29 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,10 @@ * limitations under the License. */ +plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' +} + import java.time.Instant import java.time.LocalDate import java.time.ZoneOffset diff --git a/gradle.properties b/gradle.properties index 547692b3272..75cd9d7d1ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -70,6 +70,8 @@ jbossTransactionApiVersion=2.0.0.Final # build dependencies for code quality checks checkstyleVersion=11.0.0 codenarcVersion=3.6.0-groovy-4.0 +pmdVersion=6.55.0 +spotbugsPluginVersion=6.4.8 # This prevents the Grails Gradle Plugin from unnecessarily excluding slf4j-simple in the generated POMs # https://github.com/apache/grails-gradle-plugin/issues/222 diff --git a/grails-async/core/build.gradle b/grails-async/core/build.gradle index cee4816f2ea..b2f5f45bc13 100644 --- a/grails-async/core/build.gradle +++ b/grails-async/core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-async/gpars/build.gradle b/grails-async/gpars/build.gradle index 8c8d001b266..e30f7d2e281 100644 --- a/grails-async/gpars/build.gradle +++ b/grails-async/gpars/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-async/plugin/build.gradle b/grails-async/plugin/build.gradle index c6d1f34085a..73984e20e09 100644 --- a/grails-async/plugin/build.gradle +++ b/grails-async/plugin/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-async/rxjava/build.gradle b/grails-async/rxjava/build.gradle index 0bc5e0a8c71..9494becc598 100644 --- a/grails-async/rxjava/build.gradle +++ b/grails-async/rxjava/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-async/rxjava2/build.gradle b/grails-async/rxjava2/build.gradle index 1e3d564320a..aa269ef1b8d 100644 --- a/grails-async/rxjava2/build.gradle +++ b/grails-async/rxjava2/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-async/rxjava3/build.gradle b/grails-async/rxjava3/build.gradle index d5c36cb6f4b..25e643124b4 100644 --- a/grails-async/rxjava3/build.gradle +++ b/grails-async/rxjava3/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-bootstrap/build.gradle b/grails-bootstrap/build.gradle index 8326c9da519..22b423f1494 100644 --- a/grails-bootstrap/build.gradle +++ b/grails-bootstrap/build.gradle @@ -29,6 +29,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-cache/build.gradle b/grails-cache/build.gradle index 9d607d16ca0..45c83921c40 100644 --- a/grails-cache/build.gradle +++ b/grails-cache/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-codecs-core/build.gradle b/grails-codecs-core/build.gradle index a6e2562f863..8b952e765f4 100644 --- a/grails-codecs-core/build.gradle +++ b/grails-codecs-core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-codecs/build.gradle b/grails-codecs/build.gradle index 0e612cbb19b..47fbaab85cd 100644 --- a/grails-codecs/build.gradle +++ b/grails-codecs/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-common/build.gradle b/grails-common/build.gradle index 8957177a9ab..f6ca3c40f17 100644 --- a/grails-common/build.gradle +++ b/grails-common/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-console/build.gradle b/grails-console/build.gradle index d3ec60a3f1d..21b341638da 100644 --- a/grails-console/build.gradle +++ b/grails-console/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-controllers/build.gradle b/grails-controllers/build.gradle index dc68dacf8fe..962430281be 100644 --- a/grails-controllers/build.gradle +++ b/grails-controllers/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-converters/build.gradle b/grails-converters/build.gradle index 0bb79ca3763..22e3e605e1a 100644 --- a/grails-converters/build.gradle +++ b/grails-converters/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-core/build.gradle b/grails-core/build.gradle index 7e486bfaaef..bbea195d0db 100644 --- a/grails-core/build.gradle +++ b/grails-core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-hibernate5/boot-plugin/build.gradle b/grails-data-hibernate5/boot-plugin/build.gradle index 2c6c0aa6273..6dfcb4389df 100644 --- a/grails-data-hibernate5/boot-plugin/build.gradle +++ b/grails-data-hibernate5/boot-plugin/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-hibernate5/core/build.gradle b/grails-data-hibernate5/core/build.gradle index 1f77e3657d3..4838afb4afd 100644 --- a/grails-data-hibernate5/core/build.gradle +++ b/grails-data-hibernate5/core/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-hibernate5/dbmigration/build.gradle b/grails-data-hibernate5/dbmigration/build.gradle index 3a74dd04290..342dbcfb17a 100644 --- a/grails-data-hibernate5/dbmigration/build.gradle +++ b/grails-data-hibernate5/dbmigration/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-hibernate5/grails-plugin/build.gradle b/grails-data-hibernate5/grails-plugin/build.gradle index 22fd52fe58e..dd0a1a13dea 100644 --- a/grails-data-hibernate5/grails-plugin/build.gradle +++ b/grails-data-hibernate5/grails-plugin/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-hibernate5/spring-orm/build.gradle b/grails-data-hibernate5/spring-orm/build.gradle index 3713dfb9ccf..6e65fbdc636 100644 --- a/grails-data-hibernate5/spring-orm/build.gradle +++ b/grails-data-hibernate5/spring-orm/build.gradle @@ -28,6 +28,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-mongodb/boot-plugin/build.gradle b/grails-data-mongodb/boot-plugin/build.gradle index 572e90fa09e..31a76648f24 100644 --- a/grails-data-mongodb/boot-plugin/build.gradle +++ b/grails-data-mongodb/boot-plugin/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-mongodb/bson/build.gradle b/grails-data-mongodb/bson/build.gradle index 1ac2663ee71..6c1e0243bb8 100644 --- a/grails-data-mongodb/bson/build.gradle +++ b/grails-data-mongodb/bson/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-mongodb/core/build.gradle b/grails-data-mongodb/core/build.gradle index f080478090f..94c1e6d97e1 100644 --- a/grails-data-mongodb/core/build.gradle +++ b/grails-data-mongodb/core/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-mongodb/ext/build.gradle b/grails-data-mongodb/ext/build.gradle index f8271315be4..982b44960db 100644 --- a/grails-data-mongodb/ext/build.gradle +++ b/grails-data-mongodb/ext/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-mongodb/grails-plugin/build.gradle b/grails-data-mongodb/grails-plugin/build.gradle index 1ace1bc70db..c22e6dca21e 100644 --- a/grails-data-mongodb/grails-plugin/build.gradle +++ b/grails-data-mongodb/grails-plugin/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-mongodb/gson-templates/build.gradle b/grails-data-mongodb/gson-templates/build.gradle index 445f6f36760..da0d0758faa 100644 --- a/grails-data-mongodb/gson-templates/build.gradle +++ b/grails-data-mongodb/gson-templates/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-data-simple/build.gradle b/grails-data-simple/build.gradle index 22567f865ca..1290a63ad55 100644 --- a/grails-data-simple/build.gradle +++ b/grails-data-simple/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-databinding-core/build.gradle b/grails-databinding-core/build.gradle index cf2bf90b51d..cee4c8051b6 100644 --- a/grails-databinding-core/build.gradle +++ b/grails-databinding-core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-databinding/build.gradle b/grails-databinding/build.gradle index 86b4fe0f048..363c0012853 100644 --- a/grails-databinding/build.gradle +++ b/grails-databinding/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datamapping-async/build.gradle b/grails-datamapping-async/build.gradle index a2731948935..00c2afdff4a 100644 --- a/grails-datamapping-async/build.gradle +++ b/grails-datamapping-async/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datamapping-core/build.gradle b/grails-datamapping-core/build.gradle index 9eb9a7412ce..700db6df885 100644 --- a/grails-datamapping-core/build.gradle +++ b/grails-datamapping-core/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datamapping-rx/build.gradle b/grails-datamapping-rx/build.gradle index 66157ce4594..e0d5c9d6ea9 100644 --- a/grails-datamapping-rx/build.gradle +++ b/grails-datamapping-rx/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datamapping-support/build.gradle b/grails-datamapping-support/build.gradle index 95656e2b87d..78a342a5c8d 100644 --- a/grails-datamapping-support/build.gradle +++ b/grails-datamapping-support/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datamapping-tck/build.gradle b/grails-datamapping-tck/build.gradle index 15e7de95097..bc42a8baa44 100644 --- a/grails-datamapping-tck/build.gradle +++ b/grails-datamapping-tck/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datamapping-validation/build.gradle b/grails-datamapping-validation/build.gradle index 0748bcffd95..accbf04ac20 100644 --- a/grails-datamapping-validation/build.gradle +++ b/grails-datamapping-validation/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datasource/build.gradle b/grails-datasource/build.gradle index a6ed818743b..c6cf03293e3 100644 --- a/grails-datasource/build.gradle +++ b/grails-datasource/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datastore-async/build.gradle b/grails-datastore-async/build.gradle index 68f9ed6685b..edb0d968a26 100644 --- a/grails-datastore-async/build.gradle +++ b/grails-datastore-async/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datastore-core/build.gradle b/grails-datastore-core/build.gradle index 8750516d37a..85da8ab7a1c 100644 --- a/grails-datastore-core/build.gradle +++ b/grails-datastore-core/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-datastore-web/build.gradle b/grails-datastore-web/build.gradle index 138497f193b..7589e7531e9 100644 --- a/grails-datastore-web/build.gradle +++ b/grails-datastore-web/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-domain-class/build.gradle b/grails-domain-class/build.gradle index a34f2607f95..95103142436 100644 --- a/grails-domain-class/build.gradle +++ b/grails-domain-class/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-encoder/build.gradle b/grails-encoder/build.gradle index a1cac6930e8..692cf98566a 100644 --- a/grails-encoder/build.gradle +++ b/grails-encoder/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/core/build.gradle b/grails-events/core/build.gradle index 0c68efd5606..fed99b5dd2d 100644 --- a/grails-events/core/build.gradle +++ b/grails-events/core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/gpars/build.gradle b/grails-events/gpars/build.gradle index ad365eceee4..3e80b36094f 100644 --- a/grails-events/gpars/build.gradle +++ b/grails-events/gpars/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/plugin/build.gradle b/grails-events/plugin/build.gradle index d2cc1e24455..5069cad90fe 100644 --- a/grails-events/plugin/build.gradle +++ b/grails-events/plugin/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/rxjava/build.gradle b/grails-events/rxjava/build.gradle index 312477fefae..d53e072abcd 100644 --- a/grails-events/rxjava/build.gradle +++ b/grails-events/rxjava/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/rxjava2/build.gradle b/grails-events/rxjava2/build.gradle index 5a107dd9241..43791ba91fb 100644 --- a/grails-events/rxjava2/build.gradle +++ b/grails-events/rxjava2/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/rxjava3/build.gradle b/grails-events/rxjava3/build.gradle index efca93c18dd..2daa711d671 100644 --- a/grails-events/rxjava3/build.gradle +++ b/grails-events/rxjava3/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/spring/build.gradle b/grails-events/spring/build.gradle index c568f926238..caefaf3ef6c 100644 --- a/grails-events/spring/build.gradle +++ b/grails-events/spring/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-events/transforms/build.gradle b/grails-events/transforms/build.gradle index 778980c0951..b8797a4699e 100644 --- a/grails-events/transforms/build.gradle +++ b/grails-events/transforms/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-fields/build.gradle b/grails-fields/build.gradle index 1ed72931b9b..1b30c8c623f 100644 --- a/grails-fields/build.gradle +++ b/grails-fields/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-forge/build.gradle b/grails-forge/build.gradle index d262f97fab9..a7ac18ca668 100644 --- a/grails-forge/build.gradle +++ b/grails-forge/build.gradle @@ -25,6 +25,7 @@ import java.time.format.DateTimeFormatter plugins { id 'org.apache.grails.buildsrc.properties' id 'org.apache.grails.buildsrc.dependency-validator' + id 'org.apache.grails.gradle.grails-violation-aggregation' } ext { diff --git a/grails-forge/gradle/code-style-config.gradle b/grails-forge/gradle/code-style-config.gradle index c8d7bbaf83d..b3a1e36a602 100644 --- a/grails-forge/gradle/code-style-config.gradle +++ b/grails-forge/gradle/code-style-config.gradle @@ -25,6 +25,7 @@ apply plugin: 'codenarc' apply plugin: 'com.diffplug.spotless' apply plugin: 'io.spring.nohttp' // enforce https everywhere apply plugin: 'org.apache.grails.gradle.grails-code-style' +apply plugin: 'org.apache.grails.gradle.grails-code-analysis' extensions.configure(SpotlessExtension) { // Explicit `it` is required in extension configuration block diff --git a/grails-geb/build.gradle b/grails-geb/build.gradle index 160bdf8e955..db3b5b47ea5 100644 --- a/grails-geb/build.gradle +++ b/grails-geb/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gradle/common/build.gradle b/grails-gradle/common/build.gradle index 7d05cb8211f..9ec66022fff 100644 --- a/grails-gradle/common/build.gradle +++ b/grails-gradle/common/build.gradle @@ -24,6 +24,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gradle/model/build.gradle b/grails-gradle/model/build.gradle index 23f4e81e021..2cd0762d4de 100644 --- a/grails-gradle/model/build.gradle +++ b/grails-gradle/model/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gradle/plugins/build.gradle b/grails-gradle/plugins/build.gradle index 405b5d4462e..78bca0abee3 100644 --- a/grails-gradle/plugins/build.gradle +++ b/grails-gradle/plugins/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gradle/tasks/build.gradle b/grails-gradle/tasks/build.gradle index a994c5f868c..5970381fa23 100644 --- a/grails-gradle/tasks/build.gradle +++ b/grails-gradle/tasks/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/core/build.gradle b/grails-gsp/core/build.gradle index e55a044be70..a032e6f9742 100644 --- a/grails-gsp/core/build.gradle +++ b/grails-gsp/core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-layout/build.gradle b/grails-gsp/grails-layout/build.gradle index 32eb8c13c35..59e02446ec0 100644 --- a/grails-gsp/grails-layout/build.gradle +++ b/grails-gsp/grails-layout/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-sitemesh3/build.gradle b/grails-gsp/grails-sitemesh3/build.gradle index 676039b0355..494e1dd0c92 100644 --- a/grails-gsp/grails-sitemesh3/build.gradle +++ b/grails-gsp/grails-sitemesh3/build.gradle @@ -26,6 +26,7 @@ plugins { // TODO: id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-taglib/build.gradle b/grails-gsp/grails-taglib/build.gradle index 55c91cfe45a..6ddf4cdd5c5 100644 --- a/grails-gsp/grails-taglib/build.gradle +++ b/grails-gsp/grails-taglib/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-web-gsp-taglib/build.gradle b/grails-gsp/grails-web-gsp-taglib/build.gradle index 869592160cd..e29c66a4ae4 100644 --- a/grails-gsp/grails-web-gsp-taglib/build.gradle +++ b/grails-gsp/grails-web-gsp-taglib/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-web-gsp/build.gradle b/grails-gsp/grails-web-gsp/build.gradle index f9df4c2edd1..b5c19fef864 100644 --- a/grails-gsp/grails-web-gsp/build.gradle +++ b/grails-gsp/grails-web-gsp/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-web-jsp/build.gradle b/grails-gsp/grails-web-jsp/build.gradle index 77760958190..92a20f8bcd2 100644 --- a/grails-gsp/grails-web-jsp/build.gradle +++ b/grails-gsp/grails-web-jsp/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/grails-web-taglib/build.gradle b/grails-gsp/grails-web-taglib/build.gradle index a69196b1140..f6c5fed7d1e 100644 --- a/grails-gsp/grails-web-taglib/build.gradle +++ b/grails-gsp/grails-web-taglib/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-gsp/plugin/build.gradle b/grails-gsp/plugin/build.gradle index 767a130825b..82e924f5a12 100644 --- a/grails-gsp/plugin/build.gradle +++ b/grails-gsp/plugin/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-i18n/build.gradle b/grails-i18n/build.gradle index ad7785dbfc6..c08aa68d99e 100644 --- a/grails-i18n/build.gradle +++ b/grails-i18n/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-interceptors/build.gradle b/grails-interceptors/build.gradle index 7d18d14b91e..a54d1af3542 100644 --- a/grails-interceptors/build.gradle +++ b/grails-interceptors/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-logging/build.gradle b/grails-logging/build.gradle index 9ba07de8269..40ca7b5ae21 100644 --- a/grails-logging/build.gradle +++ b/grails-logging/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-mimetypes/build.gradle b/grails-mimetypes/build.gradle index 0391a333643..20cd89b716d 100644 --- a/grails-mimetypes/build.gradle +++ b/grails-mimetypes/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-rest-transforms/build.gradle b/grails-rest-transforms/build.gradle index 3cbfdba682f..ad80cb4057f 100644 --- a/grails-rest-transforms/build.gradle +++ b/grails-rest-transforms/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-scaffolding/build.gradle b/grails-scaffolding/build.gradle index 49020837a18..93dfa5f2a48 100644 --- a/grails-scaffolding/build.gradle +++ b/grails-scaffolding/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-services/build.gradle b/grails-services/build.gradle index eda69a8eafd..c13a91ef248 100644 --- a/grails-services/build.gradle +++ b/grails-services/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-shell-cli/build.gradle b/grails-shell-cli/build.gradle index 1843aa8825c..b63e2a865ce 100644 --- a/grails-shell-cli/build.gradle +++ b/grails-shell-cli/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-spring/build.gradle b/grails-spring/build.gradle index 574091c26e5..45048ac9c32 100644 --- a/grails-spring/build.gradle +++ b/grails-spring/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-test-core/build.gradle b/grails-test-core/build.gradle index 82af7708ce1..f23de34dc12 100644 --- a/grails-test-core/build.gradle +++ b/grails-test-core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-test-suite-base/build.gradle b/grails-test-suite-base/build.gradle index 453cb33570f..6e5b9a320d0 100644 --- a/grails-test-suite-base/build.gradle +++ b/grails-test-suite-base/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.dependency-validator' id 'org.apache.grails.buildsrc.compile' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-core/build.gradle b/grails-testing-support-core/build.gradle index 11d60439dd5..223b2a9ba9d 100644 --- a/grails-testing-support-core/build.gradle +++ b/grails-testing-support-core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-datamapping/build.gradle b/grails-testing-support-datamapping/build.gradle index 09f4203521e..715fbe3f983 100755 --- a/grails-testing-support-datamapping/build.gradle +++ b/grails-testing-support-datamapping/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-dbcleanup-core/build.gradle b/grails-testing-support-dbcleanup-core/build.gradle index 7368f6dee10..70f9682077e 100644 --- a/grails-testing-support-dbcleanup-core/build.gradle +++ b/grails-testing-support-dbcleanup-core/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } diff --git a/grails-testing-support-dbcleanup-h2/build.gradle b/grails-testing-support-dbcleanup-h2/build.gradle index c12e761a303..2bc1cc0adff 100644 --- a/grails-testing-support-dbcleanup-h2/build.gradle +++ b/grails-testing-support-dbcleanup-h2/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } diff --git a/grails-testing-support-dbcleanup-postgresql/build.gradle b/grails-testing-support-dbcleanup-postgresql/build.gradle index 3644ad14619..6ff298cbc1e 100644 --- a/grails-testing-support-dbcleanup-postgresql/build.gradle +++ b/grails-testing-support-dbcleanup-postgresql/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-http-client/build.gradle b/grails-testing-support-http-client/build.gradle index ddb22c96564..7d8119d07d2 100644 --- a/grails-testing-support-http-client/build.gradle +++ b/grails-testing-support-http-client/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-mongodb/build.gradle b/grails-testing-support-mongodb/build.gradle index be2333a4500..cad012a5cb0 100644 --- a/grails-testing-support-mongodb/build.gradle +++ b/grails-testing-support-mongodb/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-views-gson/build.gradle b/grails-testing-support-views-gson/build.gradle index 7bfcc80cfec..c847e79679a 100644 --- a/grails-testing-support-views-gson/build.gradle +++ b/grails-testing-support-views-gson/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-testing-support-web/build.gradle b/grails-testing-support-web/build.gradle index 385b7bca5da..6b362c056de 100755 --- a/grails-testing-support-web/build.gradle +++ b/grails-testing-support-web/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-url-mappings/build.gradle b/grails-url-mappings/build.gradle index 720b4ba50dd..9e548d1212b 100644 --- a/grails-url-mappings/build.gradle +++ b/grails-url-mappings/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-validation/build.gradle b/grails-validation/build.gradle index 22cf4c820a1..38b907bf6d2 100644 --- a/grails-validation/build.gradle +++ b/grails-validation/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-views-core/build.gradle b/grails-views-core/build.gradle index 3da0370d06d..d30a0d560da 100644 --- a/grails-views-core/build.gradle +++ b/grails-views-core/build.gradle @@ -26,6 +26,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-views-gson/build.gradle b/grails-views-gson/build.gradle index 3848ebd373a..de8b38ed5f6 100644 --- a/grails-views-gson/build.gradle +++ b/grails-views-gson/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-views-markup/build.gradle b/grails-views-markup/build.gradle index 6d6bc3da1bd..48de6f7f0cb 100644 --- a/grails-views-markup/build.gradle +++ b/grails-views-markup/build.gradle @@ -25,6 +25,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-web-boot/build.gradle b/grails-web-boot/build.gradle index 755fe01739f..3dbbd9fde67 100644 --- a/grails-web-boot/build.gradle +++ b/grails-web-boot/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-web-common/build.gradle b/grails-web-common/build.gradle index 1053fba613f..ff03053790d 100644 --- a/grails-web-common/build.gradle +++ b/grails-web-common/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-web-core/build.gradle b/grails-web-core/build.gradle index 2b60e56ea90..cd9b52c6580 100644 --- a/grails-web-core/build.gradle +++ b/grails-web-core/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-web-databinding/build.gradle b/grails-web-databinding/build.gradle index 3fc3cd3578f..92b7aecc41e 100644 --- a/grails-web-databinding/build.gradle +++ b/grails-web-databinding/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-web-mvc/build.gradle b/grails-web-mvc/build.gradle index ac72a8621b2..d16e9f41f32 100644 --- a/grails-web-mvc/build.gradle +++ b/grails-web-mvc/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-web-url-mappings/build.gradle b/grails-web-url-mappings/build.gradle index adcd1f6579c..06c6b87870d 100644 --- a/grails-web-url-mappings/build.gradle +++ b/grails-web-url-mappings/build.gradle @@ -27,6 +27,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion diff --git a/grails-wrapper/build.gradle b/grails-wrapper/build.gradle index d51388ab06d..71a80b3ee42 100644 --- a/grails-wrapper/build.gradle +++ b/grails-wrapper/build.gradle @@ -24,6 +24,7 @@ plugins { id 'org.apache.grails.buildsrc.publish' id 'org.apache.grails.buildsrc.sbom' id 'org.apache.grails.gradle.grails-code-style' + id 'org.apache.grails.gradle.grails-code-analysis' } version = projectVersion From 0ca655d3f15729bb70dcadbe9ac87a20abcae67a Mon Sep 17 00:00:00 2001 From: James Daugherty Date: Thu, 28 May 2026 12:46:25 -0400 Subject: [PATCH 02/16] Address Copilot review feedback and fix codenarcFix corruption - Fix codenarcFix regex bugs (:: method refs, adjacent GStrings, and double quotes inside single-quoted strings) and add covering tests - Wire grails-violation-aggregation into the grails-gradle build so aggregateStyleViolations / aggregateAnalysisViolations exist there - Pass -Pgrails.codeanalysis.enabled.pmd/spotbugs in codeanalysis.yml so the workflow actually runs analysis instead of reporting nothing - Harden the violation-aggregation XmlSlurper against XXE (disallow DOCTYPE, disable external general/parameter entities) - Make createOrLoad idempotent: only rewrite config when missing or the on-disk content differs, and log at debug to avoid per-subproject churn - Remove unused Property import; correct codeanalysis report path in the GrailsCodeAnalysisExtension javadoc and the violation-fixer skill doc Co-authored-by: Walter Duque de Estrada Assisted-by: claude-code:claude-4.7-opus --- .agents/skills/violation-fixer/SKILL.md | 14 +-- .github/workflows/codeanalysis.yml | 4 +- .../GrailsCodeAnalysisExtension.groovy | 2 +- .../buildsrc/GrailsCodeStyleExtension.groovy | 1 - .../buildsrc/GrailsCodeStylePlugin.groovy | 36 +++++--- .../GrailsViolationAggregationPlugin.groovy | 6 ++ .../buildsrc/GrailsCodeStylePluginSpec.groovy | 88 +++++++++++++++++++ grails-gradle/build.gradle | 1 + 8 files changed, 129 insertions(+), 23 deletions(-) diff --git a/.agents/skills/violation-fixer/SKILL.md b/.agents/skills/violation-fixer/SKILL.md index 07ed784d355..5176120eebd 100644 --- a/.agents/skills/violation-fixer/SKILL.md +++ b/.agents/skills/violation-fixer/SKILL.md @@ -31,7 +31,7 @@ Activate this skill when: | Plugin | Applied to | Responsibility | |--------|-----------|----------------| | `org.apache.grails.gradle.grails-code-style` | Every subproject | Applies Checkstyle and CodeNarc; registers per-project `codeStyle` task; redirects XML reports to root `build/reports/codestyle/` | -| `org.apache.grails.gradle.grails-code-analysis` | Every subproject | Applies PMD and SpotBugs (both opt-in); registers per-project `codeAnalysis` task; redirects XML reports to root `build/reports/codestyle/` | +| `org.apache.grails.gradle.grails-code-analysis` | Every subproject | Applies PMD and SpotBugs (both opt-in); registers per-project `codeAnalysis` task; redirects XML reports to root `build/reports/codeanalysis/` | | `org.apache.grails.gradle.grails-jacoco` | Every subproject | Applies JaCoCo; wires `jacocoTestReport` to run after each `test` task | | `org.apache.grails.gradle.grails-violation-aggregation` | **Root project only** | Registers `aggregateViolations` and `aggregateJacocoCoverage` tasks; writes Markdown summaries to `build/reports/violations/` | @@ -214,11 +214,13 @@ build/reports/codestyle/ ← XML inputs for style aggregation │ ├── grails-core-checkstyleMain.xml │ ├── grails-web-mvc-checkstyleMain.xml │ └── ... -├── codenarc/ -│ ├── grails-core-codenarcMain.xml -│ └── ... -├── pmd/ (if enabled) -└── spotbugs/ (if enabled) +└── codenarc/ + ├── grails-core-codenarcMain.xml + └── ... + +build/reports/codeanalysis/ ← XML inputs for analysis aggregation (if enabled) +├── pmd/ +└── spotbugs/ build/reports/violations/ ← Markdown summaries written by aggregateViolations ├── CODENARC_VIOLATIONS.md diff --git a/.github/workflows/codeanalysis.yml b/.github/workflows/codeanalysis.yml index f9d08fe5f2f..38acd2d50e7 100644 --- a/.github/workflows/codeanalysis.yml +++ b/.github/workflows/codeanalysis.yml @@ -44,7 +44,7 @@ jobs: with: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Core Projects" - run: ./gradlew aggregateAnalysisViolations --continue + run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@v7.0.1 @@ -78,7 +78,7 @@ jobs: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Gradle Plugin Projects" working-directory: grails-gradle - run: ./gradlew aggregateAnalysisViolations --continue + run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@v7.0.1 diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy index f7ba0448fed..cf21bc87432 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy @@ -30,7 +30,7 @@ import org.gradle.api.model.ObjectFactory class GrailsCodeAnalysisExtension { /** - * Defaults to project.rootProject.buildDir/codestyle/pmd. + * Defaults to project.rootProject.buildDir/codeanalysis/pmd. * Directory for PMD configuration files (e.g. pmd.xml). */ final DirectoryProperty pmdDirectory diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy index 6fb04b0ae4d..599e9c5ca3c 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy @@ -25,7 +25,6 @@ import groovy.transform.CompileStatic import org.gradle.api.Project import org.gradle.api.file.DirectoryProperty import org.gradle.api.model.ObjectFactory -import org.gradle.api.provider.Property @CompileStatic class GrailsCodeStyleExtension { diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy index d8ba2c881e8..e8934f44447 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy @@ -109,15 +109,17 @@ class GrailsCodeStylePlugin implements Plugin { } private static void createOrLoad(Path expectedPath, String defaultResource, Project project) { - boolean defaultPath = expectedPath.startsWith(project.rootProject.buildDir.toPath()) - if (!Files.exists(expectedPath) || expectedPath.size() == 0 || defaultPath) { - def defaultValue = GrailsCodeStylePlugin.getResourceAsStream(defaultResource) - if (!defaultValue) { - throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}") - } - // TODO: This really need to use gradle caching instead - project.logger.info("Replacing code style configuration") - expectedPath.text = defaultValue.text + def defaultValue = GrailsCodeStylePlugin.getResourceAsStream(defaultResource) + if (!defaultValue) { + throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}") + } + String defaultText = defaultValue.text + boolean missing = !Files.exists(expectedPath) || expectedPath.size() == 0 + // Only rewrite when missing or the on-disk content differs from the bundled + // resource, so repeated builds across many subprojects don't churn the file. + if (missing || expectedPath.text != defaultText) { + project.logger.debug("Writing code style configuration to ${expectedPath}") + expectedPath.text = defaultText } } @@ -228,15 +230,23 @@ class GrailsCodeStylePlugin implements Plugin { content = content.replaceAll(/(class\s+[^{]+\{\n)([ \t]*[^ \s\n\/])/, '$1\n$2') // 2. SpaceAroundMapEntryColon - content = content.replaceAll(/([\[,]\s*(?:[\w\-.]+|'[^']+'|"[^"]+")):([^\s\/])/, '$1: $2') - content = content.replaceAll(/(\(\s*(?:[\w\-.]+|'[^']+'|"[^"]+")):([^\s\/])/, '$1: $2') + // (?!:) prevents matching the first : in a :: method reference (e.g. String::trim) + content = content.replaceAll(/([\[,]\s*(?:[\w\-.]+|'[^']+'|"[^"]+")):(?!:)([^\s\/])/, '$1: $2') + content = content.replaceAll(/(\(\s*(?:[\w\-.]+|'[^']+'|"[^"]+")):(?!:)([^\s\/])/, '$1: $2') // 3. UnnecessaryGString - content = content.replaceAll(/(? + // The alternation skips over single-quoted strings so their embedded double-quote + // content is never touched. The (? args -> + if (args[1] == null) { + return args[0] // single-quoted string matched — leave it untouched + } + String inner = args[1] if (!inner.contains("'")) { return "'$inner'" } - return all + return args[0] } // 4. UnnecessarySemicolon diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy index d8e69897a8c..8d747a191af 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy @@ -175,7 +175,10 @@ class GrailsViolationAggregationPlugin implements Plugin { private static void parseStyleViolations(Directory styleXmlDir, Directory violationsDir, boolean checkStyleTests, boolean codenarcEnabled, boolean checkstyleEnabled) { def slurper = new XmlSlurper() + slurper.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true) slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) + slurper.setFeature('http://xml.org/sax/features/external-general-entities', false) + slurper.setFeature('http://xml.org/sax/features/external-parameter-entities', false) slurper.setFeature('http://xml.org/sax/features/namespaces', false) def getModule = { String fileName -> @@ -300,7 +303,10 @@ class GrailsViolationAggregationPlugin implements Plugin { private static void parseAnalysisViolations(Directory analysisXmlDir, Directory violationsDir, boolean checkAnalysisTests, boolean pmdEnabled, boolean spotbugsEnabled) { def slurper = new XmlSlurper() + slurper.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true) slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false) + slurper.setFeature('http://xml.org/sax/features/external-general-entities', false) + slurper.setFeature('http://xml.org/sax/features/external-parameter-entities', false) slurper.setFeature('http://xml.org/sax/features/namespaces', false) def getModule = { String fileName -> diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy index 1d26a0ecedd..3620c119c16 100644 --- a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy +++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy @@ -132,4 +132,92 @@ class Test { and: "escaped quotes are NOT broken" groovyFile.text.contains('"\\"\\$it\\""') } + + def "test codenarcFix task does not corrupt method references (::)"() { + given: "a file with :: method references" + groovyFile.text = """package org.test + +import java.util.Arrays + +class Test { + def result = Arrays.stream(items).map(String::trim).toList() + def other = items.collect(String::valueOf) + def cors = parseConfigList(config, 'allowedOrigins', corsConfig::setAllowedOrigins) +} +""" + when: "running codenarcFix" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('codenarcFix', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task finished successfully" + result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS + + and: "method references are NOT broken" + def content = groovyFile.text + content.contains('String::trim') + content.contains('String::valueOf') + content.contains('corsConfig::setAllowedOrigins') + !content.contains('String: :trim') + !content.contains('String: :valueOf') + !content.contains('corsConfig: :setAllowedOrigins') + } + + def "test codenarcFix task does not corrupt adjacent GString and plain string"() { + given: "a file with a GString method name followed by a plain string argument" + groovyFile.text = '''package org.test + +class Test { + def invoke(invoker, name) { + invoker."${name}"("plain arg") + invoker."${name}"("-Pargs=${someVar}") + } +} +''' + when: "running codenarcFix" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('codenarcFix', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task finished successfully" + result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS + + and: "adjacent GString boundaries are NOT fused" + def content = groovyFile.text + content.contains('invoker."${name}"(\'plain arg\')') + content.contains('invoker."${name}"("-Pargs=${someVar}")') + !content.contains('invoker."${name}\'(\'plain arg")') + !content.contains('invoker."${name}\'(\'plain arg\')') + } + + def "test codenarcFix task does not corrupt double quotes inside single-quoted strings"() { + given: "a file with single-quoted strings containing double quotes" + groovyFile.text = """package org.test + +class Test { + def d1 = description('Accepts format "hh:mm:ss"') + def d2 = writeLine('[cols="2,5,2", options="header"]') + def d3 = 'value with "double quotes" inside' +} +""" + when: "running codenarcFix" + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('codenarcFix', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task finished successfully" + result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS + + and: "double quotes inside single-quoted strings are NOT changed" + def content = groovyFile.text + content.contains('\'Accepts format "hh:mm:ss"\'') + content.contains('\'[cols="2,5,2", options="header"]\'') + content.contains('\'value with "double quotes" inside\'') + } } diff --git a/grails-gradle/build.gradle b/grails-gradle/build.gradle index a8959b364db..382c9771024 100644 --- a/grails-gradle/build.gradle +++ b/grails-gradle/build.gradle @@ -23,6 +23,7 @@ import java.time.format.DateTimeFormatter plugins { id 'org.apache.grails.buildsrc.properties' id 'org.apache.grails.buildsrc.dependency-validator' + id 'org.apache.grails.gradle.grails-violation-aggregation' } allprojects { From b18a5238487333b7b3c0e51a78f48a2cd06872e2 Mon Sep 17 00:00:00 2001 From: James Daugherty Date: Thu, 28 May 2026 16:22:33 -0400 Subject: [PATCH 03/16] Make JaCoCo aggregation class-exclusion filter configurable Addresses Copilot review feedback: the JaCoCo aggregation previously hard-coded a filter dropping classes under org.grails.orm.hibernate.support.hibernate7. This tied a generic aggregation plugin to a specific package name. - Introduce grails.jacoco.aggregation.excludedClassPrefixes (comma separated), defaulting to the hibernate7 support package. The default is required because the Hibernate 5 and Hibernate 7 variants compile classes with identical fully-qualified names, and JaCoCo cannot aggregate two different classes that share a name. - Resolve the value as a configuration-cache-safe Provider, register it as a task input, and pass it into the parse method. - Document the property and its rationale on the plugin. - Add specs covering the default exclusion and the configurable override. Assisted-by: claude-code:claude-4.7-opus --- .../GrailsViolationAggregationPlugin.groovy | 34 +++++++++- ...railsViolationAggregationPluginSpec.groovy | 64 +++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy index 8d747a191af..e689d8d8148 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy @@ -61,6 +61,20 @@ class GrailsViolationAggregationPlugin implements Plugin { private static final Logger LOGGER = Logging.getLogger(GrailsViolationAggregationPlugin) + /** + * Comma-separated list of fully-qualified class-name prefixes to exclude from the aggregated + * JaCoCo coverage report. Configure via {@code -Pgrails.jacoco.aggregation.excludedClassPrefixes=...} + * or in {@code gradle.properties}. + * + *

Defaults to {@link #DEFAULT_JACOCO_EXCLUDED_CLASS_PREFIXES}: the Hibernate 7 support classes + * share fully-qualified names with their Hibernate 5 counterparts, and JaCoCo cannot aggregate + * coverage for two different classes with the same name (it fails with + * "Can't add different class with same name"). Excluding one variant keeps the aggregate valid. + */ + static final String JACOCO_EXCLUDED_CLASS_PREFIXES_PROPERTY = 'grails.jacoco.aggregation.excludedClassPrefixes' + + static final String DEFAULT_JACOCO_EXCLUDED_CLASS_PREFIXES = 'org.grails.orm.hibernate.support.hibernate7.' + @Override void apply(Project project) { if (project != project.rootProject) { @@ -153,13 +167,23 @@ class GrailsViolationAggregationPlugin implements Plugin { root.allprojects.collect { Project p -> p.file('build/reports/jacoco/test/jacocoTestReport.csv') } ) + // Resolve the excluded class-name prefixes as a Provider so the value is captured + // configuration-cache-safely and read at task execution time. + Provider> excludedClassPrefixes = root.providers + .gradleProperty(JACOCO_EXCLUDED_CLASS_PREFIXES_PROPERTY) + .orElse(DEFAULT_JACOCO_EXCLUDED_CLASS_PREFIXES) + .map { String value -> + value.split(',').collect { it.trim() }.findAll { !it.isEmpty() } + } + TaskProvider aggregateTask = root.tasks.register('aggregateJacocoCoverage') { Task task -> task.group = 'verification' task.description = 'Aggregates JaCoCo coverage reports from all subprojects into build/reports/violations/' task.inputs.files(jacocoCsvFiles).optional(true) + task.inputs.property('excludedClassPrefixes', excludedClassPrefixes) task.outputs.file(root.file('build/reports/violations/JACOCO_COVERAGE.md')) task.doLast { - parseJacocoCoverage(jacocoCsvFiles, violationsDir.get()) + parseJacocoCoverage(jacocoCsvFiles, violationsDir.get(), excludedClassPrefixes.get()) } } root.subprojects { Project sub -> @@ -412,7 +436,7 @@ class GrailsViolationAggregationPlugin implements Plugin { } @CompileDynamic - private static void parseJacocoCoverage(FileCollection csvFiles, Directory violationsDir) { + private static void parseJacocoCoverage(FileCollection csvFiles, Directory violationsDir, List excludedClassPrefixes) { def jacocoCoverage = [] csvFiles.each { File csvReport -> if (csvReport.exists()) { @@ -448,7 +472,11 @@ class GrailsViolationAggregationPlugin implements Plugin { return } - jacocoCoverage.removeIf { it.className.startsWith('org.grails.orm.hibernate.support.hibernate7.') } + // Drop classes whose fully-qualified names collide across Hibernate variants (see + // JACOCO_EXCLUDED_CLASS_PREFIXES_PROPERTY) so the aggregate report stays valid. + if (excludedClassPrefixes) { + jacocoCoverage.removeIf { entry -> excludedClassPrefixes.any { prefix -> entry.className.startsWith(prefix) } } + } def outDir = violationsDir.asFile outDir.mkdirs() diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy index be51ff7508d..3c6f50cbb61 100644 --- a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy +++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy @@ -174,4 +174,68 @@ class GrailsViolationAggregationPluginSpec extends Specification { and: "no report file is created" !testProjectDir.resolve('build/reports/violations/JACOCO_COVERAGE.md').toFile().exists() } + + def "aggregateJacocoCoverage excludes the default hibernate7 support classes"() { + given: "a root project with a jacoco csv containing an h7 support class and a normal class" + testProjectDir.resolve('settings.gradle').toFile().text = '' + testProjectDir.resolve('build.gradle').toFile().text = """ + plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' + } + """ + writeJacocoCsv([ + 'app,org.grails.orm.hibernate.support.hibernate7,HibernateSupport,10,0', + 'app,org.example.kept,KeptClass,0,20', + ]) + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('aggregateJacocoCoverage', '--stacktrace') + .withPluginClasspath() + .build() + + then: "task succeeds and the report drops the colliding h7 class but keeps the normal one" + result.task(':aggregateJacocoCoverage').outcome == TaskOutcome.SUCCESS + def report = testProjectDir.resolve('build/reports/violations/JACOCO_COVERAGE.md').toFile() + report.exists() + def text = report.text + text.contains('org.example.kept.KeptClass') + !text.contains('org.grails.orm.hibernate.support.hibernate7.HibernateSupport') + } + + def "aggregateJacocoCoverage exclusion prefixes are configurable via property"() { + given: "a root project and a custom exclusion prefix that keeps the h7 class and drops a custom one" + testProjectDir.resolve('settings.gradle').toFile().text = '' + testProjectDir.resolve('build.gradle').toFile().text = """ + plugins { + id 'org.apache.grails.gradle.grails-violation-aggregation' + } + """ + writeJacocoCsv([ + 'app,org.grails.orm.hibernate.support.hibernate7,HibernateSupport,10,0', + 'app,com.example.skip,SkipMe,5,5', + 'app,org.example.kept,KeptClass,0,20', + ]) + + when: + def result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withArguments('aggregateJacocoCoverage', '-Pgrails.jacoco.aggregation.excludedClassPrefixes=com.example.skip', '--stacktrace') + .withPluginClasspath() + .build() + + then: "the custom prefix is dropped while the default h7 class is now retained" + result.task(':aggregateJacocoCoverage').outcome == TaskOutcome.SUCCESS + def text = testProjectDir.resolve('build/reports/violations/JACOCO_COVERAGE.md').toFile().text + text.contains('org.example.kept.KeptClass') + text.contains('org.grails.orm.hibernate.support.hibernate7.HibernateSupport') + !text.contains('com.example.skip.SkipMe') + } + + private void writeJacocoCsv(List dataRows) { + def csv = testProjectDir.resolve('build/reports/jacoco/test/jacocoTestReport.csv').toFile() + csv.parentFile.mkdirs() + csv.text = (['GROUP,PACKAGE,CLASS,INSTRUCTION_MISSED,INSTRUCTION_COVERED'] + dataRows).join('\n') + '\n' + } } From 20d73d8e8a699893c8cdb6be70274feaee08bf3d Mon Sep 17 00:00:00 2001 From: James Fredley Date: Fri, 29 May 2026 01:59:47 -0400 Subject: [PATCH 04/16] fix(ci): pin Code Analysis workflow actions to ASF-approved SHAs The codeanalysis.yml workflow used floating action tags (actions/checkout@v6, actions/setup-java@v4, actions/upload-artifact@v7.0.1) and an outdated setup-gradle pin, which the ASF org policy rejects, causing the "Code Analysis" workflow to fail at startup. Pin every action to the same ASF-approved commit SHAs already used by the other workflows (checkout v6.0.2, setup-java v5.2.0, setup-gradle v6.1.0 with cache-provider: basic, upload-artifact v7.0.1). Assisted-by: claude-code:claude-4.8-opus --- .github/workflows/codeanalysis.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/codeanalysis.yml b/.github/workflows/codeanalysis.yml index 38acd2d50e7..7f1f4fc4cf7 100644 --- a/.github/workflows/codeanalysis.yml +++ b/.github/workflows/codeanalysis.yml @@ -33,21 +33,22 @@ jobs: - name: "🌐 Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it run: curl -s https://api.ipify.org - name: "📥 Checkout repository" - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "☕️ Setup JDK" - uses: actions/setup-java@v4 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: liberica java-version: 21 - name: "🐘 Setup Gradle" - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 with: + cache-provider: basic # 'basic' uses the MIT-licensed, open-source cache provider; the default 'enhanced' provider (v6+) is proprietary (Gradle commercial Terms of Use) develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Core Projects" run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true - name: "📤 Upload Reports" if: always() - uses: actions/upload-artifact@v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: core-reports path: build/reports/violations/ @@ -66,22 +67,23 @@ jobs: - name: "🌐 Output Agent IP" # in the event RAO blocks this agent, this can be used to debug it run: curl -s https://api.ipify.org - name: "📥 Checkout repository" - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: "☕️ Setup JDK" - uses: actions/setup-java@v4 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: liberica java-version: 21 - name: "🐘 Setup Gradle" - uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0 + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 with: + cache-provider: basic # 'basic' uses the MIT-licensed, open-source cache provider; the default 'enhanced' provider (v6+) is proprietary (Gradle commercial Terms of Use) develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Gradle Plugin Projects" working-directory: grails-gradle run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true - name: "📤 Upload Reports" if: always() - uses: actions/upload-artifact@v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: gradle-plugin-reports path: grails-gradle/build/reports/violations/ From 57ae6d6d110472091a35fce3517281169c5dd04e Mon Sep 17 00:00:00 2001 From: James Fredley Date: Fri, 29 May 2026 11:15:31 -0400 Subject: [PATCH 05/16] Make code-analysis surface violations: PMD 7.25.0 + report-only CI PMD 6.55.0 cannot parse Java 21+ sources, so pmdMain threw "PMDException: Error while processing" on every file and never produced real findings. Bump to PMD 7.25.0, which supports Java 21 through 26 (the Micronaut/Forge modules compile on Java 25). Run the code-analysis CI jobs with -Pgrails.codeanalysis.ignoreFailures=true so PMD and SpotBugs complete, the aggregateAnalysisViolations task can run, and the full violation report is generated and published to the job summary instead of the build aborting with no report. This is intentionally non-gating for now: with PMD parsing correctly the Core build alone reports ~5,016 PMD + 187 SpotBugs violations, so the ruleset/remediation needs to be scoped before the checks can gate. Assisted-by: claude-code:claude-opus-4-8 --- .github/workflows/codeanalysis.yml | 4 ++-- gradle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeanalysis.yml b/.github/workflows/codeanalysis.yml index 7f1f4fc4cf7..6800eff8c0c 100644 --- a/.github/workflows/codeanalysis.yml +++ b/.github/workflows/codeanalysis.yml @@ -45,7 +45,7 @@ jobs: cache-provider: basic # 'basic' uses the MIT-licensed, open-source cache provider; the default 'enhanced' provider (v6+) is proprietary (Gradle commercial Terms of Use) develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Core Projects" - run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true + run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true -Pgrails.codeanalysis.ignoreFailures=true - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -80,7 +80,7 @@ jobs: develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: "🔎 Check Gradle Plugin Projects" working-directory: grails-gradle - run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true + run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true -Pgrails.codeanalysis.ignoreFailures=true - name: "📤 Upload Reports" if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/gradle.properties b/gradle.properties index 89307d46693..77c27d353b7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -70,7 +70,7 @@ jbossTransactionApiVersion=2.0.0.Final # build dependencies for code quality checks checkstyleVersion=11.0.0 codenarcVersion=3.6.0-groovy-4.0 -pmdVersion=6.55.0 +pmdVersion=7.25.0 spotbugsPluginVersion=6.4.8 # This prevents the Grails Gradle Plugin from unnecessarily excluding slf4j-simple in the generated POMs From e88abad437089fc9d3254cbf82ae17a96ab1667d Mon Sep 17 00:00:00 2001 From: Walter B Duque de Estrada Date: Sat, 30 May 2026 11:45:19 -0500 Subject: [PATCH 06/16] Refactor createOrLoad method to remove project parameter Fixed signature --- .../grails/buildsrc/GrailsCodeStylePlugin.groovy | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy index e8934f44447..8f7397e7412 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy @@ -78,13 +78,11 @@ class GrailsCodeStylePlugin implements Plugin { createOrLoad( toCreate.resolve(CHECKSTYLE_CONFIG_FILE_NAME), - "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_CONFIG_FILE_NAME}", - project + "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_CONFIG_FILE_NAME}" ) createOrLoad( toCreate.resolve(CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME), - "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME}", - project + "${BASE_RESOURCE_PATH}/checkstyle/${CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME}" ) directory @@ -100,25 +98,23 @@ class GrailsCodeStylePlugin implements Plugin { createOrLoad( toCreate.resolve(CODENARC_CONFIG_FILE_NAME), - "${BASE_RESOURCE_PATH}/codenarc/${CODENARC_CONFIG_FILE_NAME}", - project + "${BASE_RESOURCE_PATH}/codenarc/${CODENARC_CONFIG_FILE_NAME}" ) directory }) } - private static void createOrLoad(Path expectedPath, String defaultResource, Project project) { + private static void createOrLoad(Path expectedPath, String defaultResource) { def defaultValue = GrailsCodeStylePlugin.getResourceAsStream(defaultResource) if (!defaultValue) { throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}") } + String defaultText = defaultValue.text boolean missing = !Files.exists(expectedPath) || expectedPath.size() == 0 - // Only rewrite when missing or the on-disk content differs from the bundled - // resource, so repeated builds across many subprojects don't churn the file. + if (missing || expectedPath.text != defaultText) { - project.logger.debug("Writing code style configuration to ${expectedPath}") expectedPath.text = defaultText } } From 876a26ca69da77767c52facf1204d19097d05c35 Mon Sep 17 00:00:00 2001 From: Walter Duque de Estrada Date: Sat, 30 May 2026 15:48:10 -0500 Subject: [PATCH 07/16] Exclude build directory from Checkstyle task sources to ignore generated sources Co-Authored-By: Gemini --- .../org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy index 8f7397e7412..92366202bfc 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy @@ -155,6 +155,10 @@ class GrailsCodeStylePlugin implements Plugin { task.enabled = testStylingEnabled.get() } + task.exclude { org.gradle.api.file.FileTreeElement element -> + element.getFile().getAbsolutePath().contains("/build/") + } + // Redirect XML report output to a single directory to consolidate // reports across all subprojects into one known location task.reports.xml.outputLocation.set( From 837292bba6394138951377a10e744c71248ffced Mon Sep 17 00:00:00 2001 From: Walter Duque de Estrada Date: Sat, 30 May 2026 19:54:56 -0500 Subject: [PATCH 08/16] Align Spotless config with Checkstyle rules in grails-forge - Restrict Spotless to target only production Java files - Configure Spotless importOrder and removeUnusedImports to match Checkstyle layout conventions - Remove google-java-format from Spotless configurations to avoid JDK 25 compiler crashes - Clean up obsolete task references in build configurations - Fix Java styling and imports across grails-forge production files to satisfy Checkstyle validation Co-authored-by: Gemini --- .idea/codeStyles/Project.xml | 198 +++++++------ .idea/codeStyles/codeStyleConfig.xml | 22 +- build-logic/gradlew.bat | 164 +++++------ .../buildsrc/GrailsCodeStylePlugin.groovy | 10 +- .../checkstyle/checkstyle.xml | 2 + gradlew.bat | 164 +++++------ .../checkstyle/checkstyle-suppressions.xml | 39 +-- grails-forge/config/checkstyle/checkstyle.xml | 260 ++++-------------- grails-forge/gradle/code-style-config.gradle | 24 +- .../postgres/AnalyticsController.java | 10 +- .../forge/analytics/postgres/Application.java | 20 +- .../postgres/ApplicationRepository.java | 4 +- .../forge/analytics/postgres/Feature.java | 4 +- .../analytics/postgres/FeatureRepository.java | 10 +- .../postgres/gcp/GoogleCloudSqlSetup.java | 4 +- .../forge/api/ApplicationController.java | 35 ++- .../grails/forge/api/ApplicationTypeDTO.java | 5 +- .../grails/forge/api/ApplicationTypeList.java | 4 +- .../forge/api/ApplicationTypeOperations.java | 1 + .../forge/api/DevelopmentReloading.java | 4 +- .../forge/api/DevelopmentReloadingDTO.java | 1 + .../java/org/grails/forge/api/FeatureDTO.java | 3 +- .../org/grails/forge/api/FeatureList.java | 4 +- .../grails/forge/api/FeatureOperations.java | 6 +- .../org/grails/forge/api/FeatureService.java | 16 +- .../org/grails/forge/api/GormImplDTO.java | 1 + .../forge/api/GrailsForgeConfiguration.java | 8 +- .../org/grails/forge/api/JdkVersionDTO.java | 3 +- .../org/grails/forge/api/LanguageDTO.java | 3 +- .../java/org/grails/forge/api/Linkable.java | 6 +- .../org/grails/forge/api/Relationship.java | 4 +- .../org/grails/forge/api/RequestInfo.java | 7 +- .../org/grails/forge/api/SelectOptionDTO.java | 4 +- .../grails/forge/api/SelectOptionsDTO.java | 21 +- .../org/grails/forge/api/ServletImplDTO.java | 1 + .../org/grails/forge/api/UserAgentParser.java | 7 +- .../java/org/grails/forge/api/VersionDTO.java | 5 +- .../api/analytics/AnalyticsOperations.java | 5 +- .../api/analytics/GenerationListener.java | 14 +- .../api/bind/RequestInfoArgumentBinder.java | 12 +- .../api/create/AbstractCreateController.java | 20 +- .../create/github/GitHubCreateController.java | 16 +- .../create/github/GitHubCreateOperation.java | 10 +- .../create/github/GitHubCreateService.java | 30 +- .../create/github/GitHubRedirectService.java | 18 +- .../api/create/zip/ZipCreateController.java | 26 +- .../api/create/zip/ZipCreateOperation.java | 10 +- .../grails/forge/api/diff/DiffController.java | 33 ++- .../grails/forge/api/diff/DiffOperations.java | 20 +- .../api/event/ApplicationGeneratingEvent.java | 1 + .../options/ApplicationTypeSelectOptions.java | 7 +- .../DevelopmentReloadingSelectOptions.java | 7 +- .../api/options/GormImplSelectOptions.java | 5 +- .../api/options/JdkVersionSelectOptions.java | 7 +- .../api/options/LanguageSelectOptions.java | 7 +- .../api/options/SelectOptionsController.java | 6 +- .../api/options/SelectOptionsOperations.java | 3 +- .../api/options/ServletImplSelectOptions.java | 5 +- .../forge/api/preview/PreviewController.java | 25 +- .../grails/forge/api/preview/PreviewDTO.java | 5 +- .../forge/api/preview/PreviewOperations.java | 9 +- .../org/grails/forge/cli/Application.java | 22 +- .../org/grails/forge/cli/CodeGenConfig.java | 23 +- .../grails/forge/cli/CommonOptionsMixin.java | 3 +- .../forge/cli/GrailsPicocliFactory.java | 4 +- .../grails/forge/cli/InteractiveShell.java | 10 +- .../forge/cli/command/AddPropertyCommand.java | 23 +- .../grails/forge/cli/command/BaseCommand.java | 7 +- .../forge/cli/command/CodeGenCommand.java | 12 +- .../forge/cli/command/CreateAppCommand.java | 9 +- .../forge/cli/command/CreateCommand.java | 19 +- .../cli/command/CreateControllerCommand.java | 10 +- .../cli/command/CreateDomainClassCommand.java | 10 +- .../cli/command/CreateInterceptorCommand.java | 10 +- .../forge/cli/command/CreateJobCommand.java | 9 +- .../cli/command/CreatePluginCommand.java | 9 +- .../cli/command/CreateRestApiCommand.java | 9 +- .../cli/command/CreateServiceCommand.java | 10 +- .../cli/command/CreateTagLibCommand.java | 10 +- .../cli/command/CreateWebPluginCommand.java | 9 +- .../cli/command/CreateWebappCommand.java | 9 +- .../DevelopmentReloadingCandidates.java | 4 +- .../DevelopmentReloadingConverter.java | 3 +- .../forge/cli/command/GormImplCandidates.java | 4 +- .../forge/cli/command/GormImplConverter.java | 3 +- .../forge/cli/command/LanguageCandidates.java | 4 +- .../forge/cli/command/LanguageConverter.java | 3 +- .../forge/cli/command/ListFeatures.java | 17 +- .../cli/command/ServletImplCandidates.java | 4 +- .../cli/command/ServletImplConverter.java | 3 +- .../forge/cli/util/GrailsVersionProvider.java | 6 +- grails-forge/grails-forge-core/build.gradle | 2 +- .../org/grails/forge/analytics/Generated.java | 14 +- .../forge/application/ApplicationType.java | 4 +- .../forge/application/ContextFactory.java | 21 +- .../application/PluginAvailableFeatures.java | 5 +- .../org/grails/forge/application/Project.java | 4 +- .../application/RestApiAvailableFeatures.java | 5 +- .../application/WebAvailableFeatures.java | 5 +- .../WebPluginAvailableFeatures.java | 5 +- .../generator/DefaultProjectGenerator.java | 14 +- .../generator/GeneratorContext.java | 31 ++- .../generator/ProjectGenerator.java | 5 +- .../org/grails/forge/build/BuildPlugin.java | 1 + .../forge/build/dependencies/Coordinate.java | 4 +- .../DefaultCoordinateResolver.java | 9 +- .../forge/build/dependencies/Dependency.java | 5 +- .../build/dependencies/DependencyContext.java | 5 +- .../dependencies/DependencyCoordinate.java | 4 +- .../PomDependencyVersionResolver.java | 26 +- .../forge/build/dependencies/Scope.java | 4 +- .../build/gradle/DefaultGradleRepository.java | 4 +- .../forge/build/gradle/GradleBuild.java | 11 +- .../build/gradle/GradleBuildCreator.java | 10 +- .../build/gradle/GradleConfiguration.java | 5 +- .../forge/build/gradle/GradleDependency.java | 11 +- .../forge/build/gradle/GradlePlugin.java | 16 +- .../forge/build/gradle/GradleRepository.java | 6 +- .../client/github/oauth/AccessToken.java | 4 +- .../github/v3/GitHubSecretsPublicKey.java | 1 - .../forge/client/github/v3/GitHubUser.java | 2 +- .../client/github/v3/GitHubWorkflowRuns.java | 4 +- .../forge/defaults/LanguageDefaults.java | 1 + .../org/grails/forge/diff/FeatureDiffer.java | 14 +- .../forge/feature/ApplicationFeature.java | 1 + .../forge/feature/AvailableFeatures.java | 4 +- .../forge/feature/BaseAvailableFeatures.java | 7 +- .../org/grails/forge/feature/Category.java | 62 ++--- .../grails/forge/feature/DefaultFeature.java | 4 +- .../org/grails/forge/feature/Feature.java | 1 + .../grails/forge/feature/FeatureContext.java | 16 +- .../org/grails/forge/feature/Features.java | 12 +- .../feature/asciidoctor/Asciidoctor.java | 1 + .../feature/assetPipeline/AssetPipeline.java | 10 +- .../feature/build/gradle/Dockerfile.java | 6 +- .../forge/feature/build/gradle/Gradle.java | 7 +- .../feature/build/gradle/GradleBuildSrc.java | 1 + .../build/gradle/GradleSettingsFile.java | 5 +- .../grails/forge/feature/cache/EHCache.java | 5 +- .../forge/feature/cache/GrailsCache.java | 5 +- .../forge/feature/config/Configuration.java | 8 +- .../feature/config/ConfigurationFeature.java | 4 +- .../forge/feature/config/Properties.java | 5 +- .../org/grails/forge/feature/config/Yaml.java | 7 +- .../DatabaseDriverConfigurationFeature.java | 14 +- .../database/DatabaseDriverFeature.java | 6 +- .../forge/feature/database/GormFeature.java | 4 +- .../forge/feature/database/GraphqlGorm.java | 4 +- .../org/grails/forge/feature/database/H2.java | 8 +- .../forge/feature/database/HibernateGorm.java | 10 +- .../forge/feature/database/MongoGorm.java | 10 +- .../forge/feature/database/MongoSync.java | 5 +- .../grails/forge/feature/database/MySQL.java | 4 +- .../forge/feature/database/PostgreSQL.java | 4 +- .../forge/feature/database/SQLServer.java | 4 +- .../feature/database/TestContainers.java | 8 +- .../workflows/GitHubWorkflowFeature.java | 6 +- .../plain/PlainGithubWorkflowFeature.java | 1 + .../forge/feature/grails/GrailsBase.java | 5 +- .../forge/feature/grails/GrailsConsole.java | 5 +- .../feature/grails/GrailsDefaultPlugins.java | 7 +- .../feature/grails/GrailsGradlePlugin.java | 5 +- .../feature/grails/GrailsUrlMappings.java | 7 +- .../feature/grails/GrailsWebConsole.java | 5 +- .../grailsProfiles/GrailsProfiles.java | 9 +- .../feature/grailsWrapper/GrailsWrapper.java | 5 +- .../lang/groovy/GrailsApplication.java | 8 +- .../grails/forge/feature/logging/Logback.java | 5 +- .../feature/micronaut/GrailsMicronaut.java | 8 +- .../micronaut/MicronautHttpClient.java | 8 +- .../migration/DatabaseMigrationPlugin.java | 1 + .../grails/forge/feature/other/AppName.java | 7 +- .../forge/feature/other/GrailsQuartz.java | 1 + .../feature/other/HibernateValidator.java | 1 + .../grails/forge/feature/other/Readme.java | 16 +- .../forge/feature/other/ShadePlugin.java | 4 +- .../forge/feature/reloading/Jrebel.java | 5 +- .../feature/reloading/SpringBootDevTools.java | 4 +- .../forge/feature/sitemesh3/Sitemesh3.java | 1 + .../spring/SpringBootAutoconfigure.java | 5 +- .../spring/SpringBootJettyFeature.java | 8 +- .../spring/SpringBootStarterFeature.java | 5 +- .../spring/SpringBootTomcatFeature.java | 8 +- .../spring/SpringBootUndertowFeature.java | 8 +- .../spring/SpringBootVirtualThreads.java | 5 +- .../forge/feature/spring/SpringResources.java | 5 +- .../feature/test/GebWithTestcontainers.java | 13 +- .../test/GebWithWebDriverBinaries.java | 19 +- .../feature/test/GormTestingSupport.java | 5 +- .../feature/test/GrailsWebTestingSupport.java | 5 +- .../grails/forge/feature/test/Mockito.java | 5 +- .../forge/feature/test/MockitoValidator.java | 5 +- .../org/grails/forge/feature/test/Spock.java | 8 +- .../feature/test/ViewsJsonTestingSupport.java | 5 +- .../validation/CompositeFeatureValidator.java | 10 +- .../feature/validation/FeatureValidator.java | 4 +- .../validation/OneOfFeatureValidator.java | 9 +- .../grails/forge/feature/view/GrailsGsp.java | 12 +- .../forge/feature/view/Scaffolding.java | 5 +- .../forge/feature/view/json/ViewJson.java | 18 +- .../forge/feature/view/markup/ViewMarkup.java | 16 +- .../grails/forge/feature/web/GrailsWeb.java | 5 +- .../org/grails/forge/io/MapOutputHandler.java | 4 +- .../org/grails/forge/io/OutputHandler.java | 4 +- .../org/grails/forge/io/ZipOutputHandler.java | 15 +- .../org/grails/forge/options/BuildTool.java | 9 +- .../forge/options/DevelopmentReloading.java | 4 +- .../org/grails/forge/options/Language.java | 9 +- .../org/grails/forge/options/Options.java | 9 +- .../grails/forge/options/TestFramework.java | 4 +- .../forge/template/Config4kTemplate.java | 8 +- .../template/DefaultTemplateRenderer.java | 4 +- .../grails/forge/template/RockerTemplate.java | 4 +- .../grails/forge/template/RockerWritable.java | 4 +- .../forge/template/TemplateRenderer.java | 6 +- .../grails/forge/template/YamlTemplate.java | 6 +- .../org/grails/forge/util/GitHubUtil.java | 16 +- .../org/grails/forge/util/IOFeatureUtil.java | 13 +- .../java/org/grails/forge/util/NameUtils.java | 9 +- .../org/grails/forge/util/VersionInfo.java | 7 +- .../netty/analytics/AnalyticsClient.java | 5 +- grails-gradle/gradlew.bat | 164 +++++------ grails-profiles/profile/skeleton/gradlew.bat | 164 +++++------ .../test/resources/gradle-sample/gradlew.bat | 164 +++++------ 224 files changed, 1632 insertions(+), 1489 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index ab13aa909ae..898ed70de84 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,105 +1,97 @@ - - - + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index 52768fe1ae3..f23d524925f 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,25 +1,5 @@ - - \ No newline at end of file diff --git a/build-logic/gradlew.bat b/build-logic/gradlew.bat index aa5f10b069f..24c62d56f2d 100755 --- a/build-logic/gradlew.bat +++ b/build-logic/gradlew.bat @@ -1,82 +1,82 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables, and ensure extensions are enabled -setlocal EnableExtensions - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:execute -@rem Setup the command line - - - -@rem Execute Gradle -@rem endlocal doesn't take effect until after the line is parsed and variables are expanded -@rem which allows us to clear the local environment before executing the java command -endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel - -:exitWithErrorLevel -@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts -"%COMSPEC%" /c exit %ERRORLEVEL% +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy index 92366202bfc..0941c0b0ed7 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy @@ -135,7 +135,6 @@ class GrailsCodeStylePlugin implements Plugin { project.pluginManager.apply(CheckstylePlugin) Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY) - Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_STYLING_PROPERTY) project.extensions.configure(CheckstyleExtension) { // Explicit `it` is required in extension configuration @@ -151,8 +150,8 @@ class GrailsCodeStylePlugin implements Plugin { task.onlyIf { !project.hasProperty('skipCodeStyle') } task.ignoreFailures = ignoreFailures.get() - if (task.name.contains('Test') || task.name.contains('test')) { - task.enabled = testStylingEnabled.get() + if (task.name.toLowerCase().contains('test')) { + task.enabled = false } task.exclude { org.gradle.api.file.FileTreeElement element -> @@ -176,7 +175,6 @@ class GrailsCodeStylePlugin implements Plugin { registerCodenarcFixTask(project) Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY) - Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_STYLING_PROPERTY) Provider codenarcFix = GradleUtils.booleanProvider(project, CODENARC_FIX_PROPERTY) project.extensions.configure(CodeNarcExtension) { @@ -195,8 +193,8 @@ class GrailsCodeStylePlugin implements Plugin { task.dependsOn('codenarcFix') } - if (task.name.contains('Test') || task.name.contains('test')) { - task.enabled = testStylingEnabled.get() + if (task.name.toLowerCase().contains('test')) { + task.enabled = false } // Redirect XML report output to a single directory to consolidate diff --git a/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle.xml b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle.xml index e6034dc6c77..d88270afa10 100644 --- a/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle.xml +++ b/build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.grails-code-style/checkstyle/checkstyle.xml @@ -20,6 +20,8 @@ + + diff --git a/gradlew.bat b/gradlew.bat index aa5f10b069f..24c62d56f2d 100755 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,82 +1,82 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables, and ensure extensions are enabled -setlocal EnableExtensions - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:execute -@rem Setup the command line - - - -@rem Execute Gradle -@rem endlocal doesn't take effect until after the line is parsed and variables are expanded -@rem which allows us to clear the local environment before executing the java command -endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel - -:exitWithErrorLevel -@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts -"%COMSPEC%" /c exit %ERRORLEVEL% +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/grails-forge/config/checkstyle/checkstyle-suppressions.xml b/grails-forge/config/checkstyle/checkstyle-suppressions.xml index c36038ae6ba..58ee65cc408 100644 --- a/grails-forge/config/checkstyle/checkstyle-suppressions.xml +++ b/grails-forge/config/checkstyle/checkstyle-suppressions.xml @@ -1,31 +1,22 @@ - - + - - - diff --git a/grails-forge/config/checkstyle/checkstyle.xml b/grails-forge/config/checkstyle/checkstyle.xml index 54300e23d0b..d88270afa10 100644 --- a/grails-forge/config/checkstyle/checkstyle.xml +++ b/grails-forge/config/checkstyle/checkstyle.xml @@ -1,231 +1,91 @@ - - - - + - - - - - - + - - - - + + + - - - - - - - - - - + + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - + + + + + + + - - - - - - - - - - - - + + - - + + + + + - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - + + + + - - - - - - - - - - - - - - + + + + + + + + - + \ No newline at end of file diff --git a/grails-forge/gradle/code-style-config.gradle b/grails-forge/gradle/code-style-config.gradle index b3a1e36a602..dfa51bbca1c 100644 --- a/grails-forge/gradle/code-style-config.gradle +++ b/grails-forge/gradle/code-style-config.gradle @@ -31,21 +31,17 @@ extensions.configure(SpotlessExtension) { // Explicit `it` is required in extension configuration block it.java { target('src/main/java/**/*.java') - // Formatters: - licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java')) - } - it.groovy { - target('src/main/groovy/**') - // Formatters: - licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java')) - } - it.format('javaMisc') { - target( - 'src/main/**/module-info.java', - 'src/main/**/package-info.java', + importOrder( + 'java', + 'javax', + 'groovy', 'org.apache.groovy', 'org.codehaus.groovy', + 'jakarta', + '', + 'io.spring', 'org.springframework', + 'grails', 'org.apache.grails', 'org.grails' ) - // Formatters: - licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java'), '\\/\\*\\*') + removeUnusedImports() + licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java')) } } diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java index 2ac0279773d..cccb1c518db 100644 --- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java +++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java @@ -18,6 +18,11 @@ */ package org.grails.forge.analytics.postgres; +import java.util.List; +import java.util.stream.Collectors; + +import jakarta.transaction.Transactional; + import io.micronaut.core.annotation.NonNull; import io.micronaut.http.HttpStatus; import io.micronaut.http.annotation.Body; @@ -26,11 +31,8 @@ import io.micronaut.http.annotation.Post; import io.micronaut.scheduling.TaskExecutors; import io.micronaut.scheduling.annotation.ExecuteOn; -import org.grails.forge.analytics.Generated; -import jakarta.transaction.Transactional; -import java.util.List; -import java.util.stream.Collectors; +import org.grails.forge.analytics.Generated; @Controller("/analytics") @ExecuteOn(TaskExecutors.IO) diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java index 2e3fb86be75..8ff3b61909b 100644 --- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java +++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java @@ -18,21 +18,27 @@ */ package org.grails.forge.analytics.postgres; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +import jakarta.validation.constraints.NotBlank; + import io.micronaut.core.annotation.Creator; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; -import io.micronaut.data.annotation.*; +import io.micronaut.data.annotation.DateCreated; +import io.micronaut.data.annotation.GeneratedValue; +import io.micronaut.data.annotation.Id; +import io.micronaut.data.annotation.MappedEntity; +import io.micronaut.data.annotation.Relation; + import org.grails.forge.application.ApplicationType; import org.grails.forge.options.DevelopmentReloading; import org.grails.forge.options.GormImpl; import org.grails.forge.options.JdkVersion; -import jakarta.validation.constraints.NotBlank; -import java.time.LocalDateTime; -import java.util.Collections; -import java.util.Objects; -import java.util.Set; - /** * Models a generated application. * diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java index 38193cdfbec..392e1f219be 100644 --- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java +++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java @@ -18,6 +18,8 @@ */ package org.grails.forge.analytics.postgres; +import java.util.List; + import io.micronaut.core.annotation.NonNull; import io.micronaut.data.annotation.Id; import io.micronaut.data.annotation.Join; @@ -26,8 +28,6 @@ import io.micronaut.data.model.query.builder.sql.Dialect; import io.micronaut.data.repository.PageableRepository; -import java.util.List; - /** * Repository for storing generated applications. * diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java index f92ad7df488..58bbdc97517 100644 --- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java +++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java @@ -18,6 +18,8 @@ */ package org.grails.forge.analytics.postgres; +import java.util.Objects; + import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.data.annotation.GeneratedValue; @@ -25,8 +27,6 @@ import io.micronaut.data.annotation.MappedEntity; import io.micronaut.data.annotation.Relation; -import java.util.Objects; - /** * Models a selected application feature. * diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java index c9b0f3a5951..d86d094bfcc 100644 --- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java +++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java @@ -18,6 +18,11 @@ */ package org.grails.forge.analytics.postgres; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + import io.micronaut.core.annotation.NonNull; import io.micronaut.data.annotation.Id; import io.micronaut.data.jdbc.annotation.JdbcRepository; @@ -26,11 +31,6 @@ import io.micronaut.data.repository.CrudRepository; import io.micronaut.transaction.annotation.ReadOnly; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - @JdbcRepository(dialect = Dialect.POSTGRES) public abstract class FeatureRepository implements CrudRepository { diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java index 9a952343b7b..15f2e7be2c6 100644 --- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java +++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java @@ -18,6 +18,8 @@ */ package org.grails.forge.analytics.postgres.gcp; +import jakarta.inject.Singleton; + import io.micronaut.configuration.jdbc.hikari.DatasourceConfiguration; import io.micronaut.context.annotation.Property; import io.micronaut.context.annotation.Requires; @@ -25,8 +27,6 @@ import io.micronaut.context.event.BeanCreatedEvent; import io.micronaut.context.event.BeanCreatedEventListener; -import jakarta.inject.Singleton; - /** * Configuration for the Cloud SQL environment. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java index c3182db1e4e..7ffd24c31aa 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java @@ -18,6 +18,16 @@ */ package org.grails.forge.api; +import java.io.OutputStream; +import java.io.Writer; +import java.net.URI; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + import io.micronaut.context.MessageSource; import io.micronaut.core.annotation.Nullable; import io.micronaut.core.io.Writable; @@ -27,12 +37,6 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Produces; -import org.grails.forge.application.ApplicationType; -import org.grails.forge.application.OperatingSystem; -import org.grails.forge.options.*; -import org.grails.forge.template.RockerWritable; -import org.grails.forge.template.api.grailsForgeApi; -import org.grails.forge.util.VersionInfo; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.info.Info; @@ -40,15 +44,16 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import java.io.OutputStream; -import java.io.Writer; -import java.net.URI; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; +import org.grails.forge.application.ApplicationType; +import org.grails.forge.application.OperatingSystem; +import org.grails.forge.options.FeatureFilter; +import org.grails.forge.options.GormImpl; +import org.grails.forge.options.JdkVersion; +import org.grails.forge.options.Options; +import org.grails.forge.options.ServletImpl; +import org.grails.forge.template.RockerWritable; +import org.grails.forge.template.api.grailsForgeApi; +import org.grails.forge.util.VersionInfo; /** * Main interface on the Grails Application Forge API. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java index 91a4042e4a6..a7482ee284e 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java @@ -18,6 +18,8 @@ */ package org.grails.forge.api; +import java.util.List; + import io.micronaut.context.MessageSource; import io.micronaut.core.annotation.Creator; import io.micronaut.core.annotation.Internal; @@ -25,10 +27,9 @@ import io.micronaut.core.annotation.NonNull; import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; -import org.grails.forge.application.ApplicationType; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; +import org.grails.forge.application.ApplicationType; /** * DTO objects for {@link ApplicationType}. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java index 7b597fe360d..93aad4e6400 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java @@ -18,11 +18,11 @@ */ package org.grails.forge.api; +import java.util.List; + import io.micronaut.core.annotation.Introspected; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; - /** * Models a list of application types. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java index e05f853c13e..25b8b19cabd 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java @@ -21,6 +21,7 @@ import io.micronaut.core.annotation.Nullable; import io.micronaut.http.annotation.Get; import io.swagger.v3.oas.annotations.Parameter; + import org.grails.forge.application.ApplicationType; import org.grails.forge.options.FeatureFilter; diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java index 120d98631c5..3ee45eaed9e 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java @@ -18,10 +18,10 @@ */ package org.grails.forge.api; -import io.micronaut.core.annotation.NonNull; - import java.util.Locale; +import io.micronaut.core.annotation.NonNull; + public enum DevelopmentReloading { DEVTOOLS, JREBEL, diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java index 412bab03f1c..aec2f5a9c1b 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java @@ -26,6 +26,7 @@ import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; import io.swagger.v3.oas.annotations.media.Schema; + import org.grails.forge.options.DevelopmentReloading; import org.grails.forge.util.NameUtils; diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java index 6a6fd1ffcb9..62f2e38888c 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java @@ -23,9 +23,10 @@ import io.micronaut.core.annotation.Introspected; import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; -import org.grails.forge.feature.Feature; import io.swagger.v3.oas.annotations.media.Schema; +import org.grails.forge.feature.Feature; + /** * Represents an application feature. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java index 25a1e9132e9..f71dcc6cae5 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java @@ -18,11 +18,11 @@ */ package org.grails.forge.api; +import java.util.List; + import io.micronaut.core.annotation.Introspected; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; - /** * Models a list of features. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java index 4029f4906c1..168b2616933 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java @@ -18,12 +18,12 @@ */ package org.grails.forge.api; -import org.grails.forge.application.ApplicationType; -import org.grails.forge.options.Options; - import java.util.List; import java.util.Locale; +import org.grails.forge.application.ApplicationType; +import org.grails.forge.options.Options; + /** * API to expose information about features. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java index 69beabf3a5b..8868f66c290 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java @@ -18,22 +18,24 @@ */ package org.grails.forge.api; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +import jakarta.inject.Singleton; + import io.micronaut.context.BeanLocator; import io.micronaut.context.MessageSource; import io.micronaut.inject.qualifiers.Qualifiers; -import jakarta.inject.Singleton; + import org.grails.forge.application.ApplicationType; import org.grails.forge.feature.AvailableFeatures; import org.grails.forge.feature.DefaultFeature; import org.grails.forge.feature.Feature; import org.grails.forge.options.Options; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; - /** * Implements the {@link FeatureOperations} interface. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java index af0e8a9a343..36a1be9ab03 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java @@ -26,6 +26,7 @@ import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; import io.swagger.v3.oas.annotations.media.Schema; + import org.grails.forge.options.GormImpl; /** diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java index e2dd74b468e..3cfb282463a 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java @@ -18,15 +18,15 @@ */ package org.grails.forge.api; -import io.micronaut.context.annotation.ConfigurationProperties; -import io.micronaut.context.env.Environment; -import io.micronaut.core.annotation.Nullable; - import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.Optional; +import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.context.env.Environment; +import io.micronaut.core.annotation.Nullable; + /** * Allows configuration of the the links exposed in URLs. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java index 002edde6352..aefa6a27ebb 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java @@ -25,9 +25,10 @@ import io.micronaut.core.annotation.NonNull; import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; -import org.grails.forge.options.JdkVersion; import io.swagger.v3.oas.annotations.media.Schema; +import org.grails.forge.options.JdkVersion; + /** * DTO objects for {@link JdkVersion}. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java index ae9a9064377..dfcb9db10a1 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java @@ -25,11 +25,12 @@ import io.micronaut.core.annotation.NonNull; import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; +import io.swagger.v3.oas.annotations.media.Schema; + import org.grails.forge.defaults.IncludesDefaults; import org.grails.forge.defaults.LanguageDefaults; import org.grails.forge.options.Language; import org.grails.forge.util.NameUtils; -import io.swagger.v3.oas.annotations.media.Schema; /** * DTO objects for {@link Language}. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java index 9b17685cd7c..7b4cb186546 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java @@ -18,14 +18,14 @@ */ package org.grails.forge.api; +import java.util.LinkedHashMap; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonProperty; import io.micronaut.core.annotation.Introspected; import io.micronaut.core.annotation.ReflectiveAccess; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.LinkedHashMap; -import java.util.Map; - /** * A linkable type. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java index 6955dd79012..80c429a8519 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java @@ -18,11 +18,11 @@ */ package org.grails.forge.api; +import java.util.Locale; + import io.micronaut.core.annotation.NonNull; import io.micronaut.core.naming.Named; -import java.util.Locale; - /** * Relationship types. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java index a16c5338505..3139a583d81 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java @@ -18,12 +18,13 @@ */ package org.grails.forge.api; +import java.util.Locale; +import java.util.Objects; + import io.micronaut.http.HttpParameters; -import org.grails.forge.application.ApplicationType; import io.swagger.v3.oas.annotations.Hidden; -import java.util.Locale; -import java.util.Objects; +import org.grails.forge.application.ApplicationType; /** * The server URL. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java index ae4136f7604..c7e2ef189f6 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java @@ -18,13 +18,13 @@ */ package org.grails.forge.api; +import java.util.List; + import io.micronaut.core.annotation.Creator; import io.micronaut.core.annotation.Introspected; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; - /** * Supported Option * @param The underlying option type diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java index f25ee04940f..0e0c99d1be6 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java @@ -18,18 +18,27 @@ */ package org.grails.forge.api; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + import io.micronaut.context.MessageSource; import io.micronaut.core.annotation.Creator; import io.micronaut.core.annotation.Introspected; import io.swagger.v3.oas.annotations.media.Schema; -import org.grails.forge.api.options.*; + +import org.grails.forge.api.options.ApplicationTypeSelectOptions; +import org.grails.forge.api.options.DevelopmentReloadingSelectOptions; +import org.grails.forge.api.options.GormImplSelectOptions; +import org.grails.forge.api.options.JdkVersionSelectOptions; +import org.grails.forge.api.options.LanguageSelectOptions; +import org.grails.forge.api.options.ServletImplSelectOptions; import org.grails.forge.application.ApplicationType; import org.grails.forge.options.DevelopmentReloading; -import org.grails.forge.options.*; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; +import org.grails.forge.options.GormImpl; +import org.grails.forge.options.JdkVersion; +import org.grails.forge.options.Language; +import org.grails.forge.options.ServletImpl; /** * Aggregator for {@link SelectOptionDTO}. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java index f1c72e6c598..0f75a98fead 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java @@ -26,6 +26,7 @@ import io.micronaut.core.naming.Described; import io.micronaut.core.naming.Named; import io.swagger.v3.oas.annotations.media.Schema; + import org.grails.forge.options.ServletImpl; /** diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java index dd89db12834..0421dae7f08 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java @@ -18,13 +18,14 @@ */ package org.grails.forge.api; -import io.micronaut.core.util.StringUtils; -import org.grails.forge.application.OperatingSystem; - import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; +import io.micronaut.core.util.StringUtils; + +import org.grails.forge.application.OperatingSystem; + public class UserAgentParser { private static final Pattern[] WINDOWS_PATTERNS = new Pattern[] { Pattern.compile("Windows"), Pattern.compile("Win ?(95|98|3.1|NT|ME|2000)") }; diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java index f85067524e5..ef2e82feef1 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java @@ -18,11 +18,12 @@ */ package org.grails.forge.api; +import java.util.Map; + import io.micronaut.core.annotation.Introspected; -import org.grails.forge.util.VersionInfo; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.Map; +import org.grails.forge.util.VersionInfo; /** * Information about the application. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java index 367d0ef5b12..b6ea713f262 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java @@ -18,11 +18,12 @@ */ package org.grails.forge.api.analytics; +import java.util.concurrent.CompletableFuture; + import io.micronaut.core.annotation.NonNull; import io.micronaut.http.HttpStatus; -import org.grails.forge.analytics.Generated; -import java.util.concurrent.CompletableFuture; +import org.grails.forge.analytics.Generated; /** * Interface to implement to provide analytics. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java index 5a31e7f966a..b4156fb106d 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java @@ -18,18 +18,20 @@ */ package org.grails.forge.api.analytics; +import java.util.List; +import java.util.stream.Collectors; + +import jakarta.inject.Singleton; + import io.micronaut.context.annotation.Requires; import io.micronaut.runtime.event.annotation.EventListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.grails.forge.analytics.Generated; import org.grails.forge.analytics.SelectedFeature; import org.grails.forge.api.event.ApplicationGeneratingEvent; import org.grails.forge.application.generator.GeneratorContext; -import jakarta.inject.Singleton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.stream.Collectors; @Singleton @Requires(beans = AnalyticsOperations.class) diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java index 8c1125119f1..4bf52db9484 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java @@ -18,18 +18,20 @@ */ package org.grails.forge.api.bind; +import java.util.Locale; +import java.util.Optional; + +import jakarta.inject.Singleton; + import io.micronaut.core.convert.ArgumentConversionContext; import io.micronaut.core.io.socket.SocketUtils; import io.micronaut.core.type.Argument; import io.micronaut.http.HttpHeaders; import io.micronaut.http.HttpRequest; import io.micronaut.http.bind.binders.TypedRequestArgumentBinder; -import org.grails.forge.api.RequestInfo; -import org.grails.forge.api.GrailsForgeConfiguration; -import jakarta.inject.Singleton; -import java.util.Locale; -import java.util.Optional; +import org.grails.forge.api.GrailsForgeConfiguration; +import org.grails.forge.api.RequestInfo; /** * Binds the Server URL. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java index bf9286a94a7..4cdb2d6db90 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java @@ -18,12 +18,20 @@ */ package org.grails.forge.api.create; +import java.util.Collections; +import java.util.List; + +import jakarta.validation.constraints.Pattern; + import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.HttpHeaders; import io.micronaut.http.HttpStatus; import io.micronaut.http.annotation.Header; import io.micronaut.http.exceptions.HttpStatusException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.grails.forge.api.DevelopmentReloading; import org.grails.forge.api.UserAgentParser; import org.grails.forge.api.event.ApplicationGeneratingEvent; @@ -33,14 +41,12 @@ import org.grails.forge.application.generator.GeneratorContext; import org.grails.forge.application.generator.ProjectGenerator; import org.grails.forge.io.ConsoleOutput; -import org.grails.forge.options.*; +import org.grails.forge.options.BuildTool; +import org.grails.forge.options.GormImpl; +import org.grails.forge.options.JdkVersion; +import org.grails.forge.options.Options; +import org.grails.forge.options.ServletImpl; import org.grails.forge.util.NameUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import jakarta.validation.constraints.Pattern; -import java.util.Collections; -import java.util.List; /** * Abstract implementation of a create controller. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java index b217f4ccb0d..0026deb3d8b 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java @@ -18,6 +18,11 @@ */ package org.grails.forge.api.create.github; +import java.net.URI; +import java.util.List; + +import jakarta.validation.constraints.Pattern; + import io.micronaut.context.annotation.Requires; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; @@ -35,20 +40,17 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; -import org.grails.forge.api.RequestInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.grails.forge.api.DevelopmentReloading; +import org.grails.forge.api.RequestInfo; import org.grails.forge.application.ApplicationType; import org.grails.forge.client.github.v3.GitHubRepository; import org.grails.forge.options.BuildTool; import org.grails.forge.options.GormImpl; import org.grails.forge.options.JdkVersion; import org.grails.forge.options.ServletImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import jakarta.validation.constraints.Pattern; -import java.net.URI; -import java.util.List; /** * GitHub create controller. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java index 6800efa71f6..dc1dfd22851 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java @@ -18,22 +18,24 @@ */ package org.grails.forge.api.create.github; +import java.util.List; + +import jakarta.validation.constraints.Pattern; + import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.HttpHeaders; import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Header; -import org.grails.forge.api.RequestInfo; + import org.grails.forge.api.DevelopmentReloading; +import org.grails.forge.api.RequestInfo; import org.grails.forge.application.ApplicationType; import org.grails.forge.options.BuildTool; import org.grails.forge.options.GormImpl; import org.grails.forge.options.JdkVersion; import org.grails.forge.options.ServletImpl; -import jakarta.validation.constraints.Pattern; -import java.util.List; - /** * Defines the signature for creating an application in Github repository. * diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java index ba40f554a7a..cd65b3e9b1b 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java @@ -18,14 +18,28 @@ */ package org.grails.forge.api.create.github; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Stream; + +import jakarta.inject.Singleton; +import jakarta.validation.constraints.NotNull; + import io.micronaut.context.annotation.Requires; import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.client.exceptions.HttpClientResponseException; -import jakarta.inject.Singleton; -import org.grails.forge.api.GrailsForgeConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.grails.forge.api.DevelopmentReloading; +import org.grails.forge.api.GrailsForgeConfiguration; import org.grails.forge.api.create.AbstractCreateController; import org.grails.forge.application.ApplicationType; import org.grails.forge.application.generator.GeneratorContext; @@ -43,18 +57,6 @@ import org.grails.forge.options.JdkVersion; import org.grails.forge.options.ServletImpl; import org.grails.forge.util.GitHubUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import jakarta.validation.constraints.NotNull; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Stream; /** * GitHub create service. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java index 388f220e3c4..dd36f198fd2 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java @@ -18,20 +18,22 @@ */ package org.grails.forge.api.create.github; +import java.net.URI; +import java.util.UUID; + +import jakarta.inject.Singleton; +import jakarta.validation.constraints.NotNull; + import io.micronaut.context.annotation.Property; import io.micronaut.context.annotation.Requires; import io.micronaut.http.uri.UriBuilder; -import org.grails.forge.api.RequestInfo; -import org.grails.forge.api.GrailsForgeConfiguration; -import org.grails.forge.client.github.oauth.GitHubOAuthClient; -import org.grails.forge.client.github.v3.GitHubRepository; -import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jakarta.validation.constraints.NotNull; -import java.net.URI; -import java.util.UUID; +import org.grails.forge.api.GrailsForgeConfiguration; +import org.grails.forge.api.RequestInfo; +import org.grails.forge.client.github.oauth.GitHubOAuthClient; +import org.grails.forge.client.github.v3.GitHubRepository; /** * Redirect service. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java index f2682c1a199..3f4a38071f0 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java @@ -18,6 +18,16 @@ */ package org.grails.forge.api.create.zip; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.charset.Charset; +import java.util.List; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; @@ -31,8 +41,12 @@ import io.micronaut.http.annotation.Header; import io.micronaut.scheduling.TaskExecutors; import io.micronaut.scheduling.annotation.ExecuteOn; +import io.micronaut.validation.Validated; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.grails.forge.api.DevelopmentReloading; import org.grails.forge.api.create.AbstractCreateController; import org.grails.forge.application.ApplicationType; @@ -44,18 +58,6 @@ import org.grails.forge.options.GormImpl; import org.grails.forge.options.JdkVersion; import org.grails.forge.options.ServletImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.micronaut.validation.Validated; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.charset.Charset; -import java.util.List; /** * Implements the {@link ZipCreateOperation} interface for applications. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java index 3d74bd1470d..21ea2417a8c 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java @@ -18,20 +18,22 @@ */ package org.grails.forge.api.create.zip; +import java.util.List; + +import jakarta.validation.constraints.Pattern; + import io.micronaut.core.annotation.Nullable; import io.micronaut.core.io.Writable; import io.micronaut.http.HttpHeaders; import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Header; + import org.grails.forge.api.DevelopmentReloading; import org.grails.forge.application.ApplicationType; import org.grails.forge.options.BuildTool; import org.grails.forge.options.GormImpl; -import org.grails.forge.options.ServletImpl; import org.grails.forge.options.JdkVersion; - -import jakarta.validation.constraints.Pattern; -import java.util.List; +import org.grails.forge.options.ServletImpl; /** * Defines the signature for creating an application. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java index 4f71dc63d54..c854c67ca2a 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java @@ -18,6 +18,14 @@ */ package org.grails.forge.api.diff; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.HttpStatus; @@ -25,6 +33,12 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.exceptions.HttpStatusException; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; + import org.grails.forge.api.RequestInfo; import org.grails.forge.api.UserAgentParser; import org.grails.forge.application.ApplicationType; @@ -33,20 +47,13 @@ import org.grails.forge.application.generator.ProjectGenerator; import org.grails.forge.diff.FeatureDiffer; import org.grails.forge.io.ConsoleOutput; -import org.grails.forge.options.*; +import org.grails.forge.options.BuildTool; +import org.grails.forge.options.DevelopmentReloading; +import org.grails.forge.options.GormImpl; +import org.grails.forge.options.JdkVersion; +import org.grails.forge.options.Options; +import org.grails.forge.options.ServletImpl; import org.grails.forge.util.NameUtils; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import java.io.IOException; -import java.util.Collections; -import java.util.List; /** * A controller for performing Diffs. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java index 17cafc7fd26..28861f357d3 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java @@ -18,18 +18,24 @@ */ package org.grails.forge.api.diff; +import java.io.IOException; +import java.util.List; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; -import org.grails.forge.api.RequestInfo; -import org.grails.forge.application.ApplicationType; -import org.grails.forge.options.*; import io.swagger.v3.oas.annotations.Parameter; import org.reactivestreams.Publisher; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import java.io.IOException; -import java.util.List; +import org.grails.forge.api.RequestInfo; +import org.grails.forge.application.ApplicationType; +import org.grails.forge.options.BuildTool; +import org.grails.forge.options.DevelopmentReloading; +import org.grails.forge.options.GormImpl; +import org.grails.forge.options.JdkVersion; +import org.grails.forge.options.ServletImpl; /** * Operations for performing diffs. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java index 3f3c77fed65..0e3fa74ec4d 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java @@ -19,6 +19,7 @@ package org.grails.forge.api.event; import io.micronaut.context.event.ApplicationEvent; + import org.grails.forge.application.generator.GeneratorContext; /** diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java index 1fcc1b99679..a909e74214e 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java @@ -18,11 +18,12 @@ */ package org.grails.forge.api.options; -import org.grails.forge.api.ApplicationTypeDTO; -import org.grails.forge.api.SelectOptionDTO; +import java.util.List; + import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; +import org.grails.forge.api.ApplicationTypeDTO; +import org.grails.forge.api.SelectOptionDTO; @Schema(name = "ApplicationTypeSelectOptions") public class ApplicationTypeSelectOptions extends SelectOptionDTO { diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java index cdaf421ad6d..e2a6ef54517 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java @@ -18,11 +18,12 @@ */ package org.grails.forge.api.options; +import java.util.List; + import io.swagger.v3.oas.annotations.media.Schema; -import org.grails.forge.api.SelectOptionDTO; -import org.grails.forge.api.DevelopmentReloadingDTO; -import java.util.List; +import org.grails.forge.api.DevelopmentReloadingDTO; +import org.grails.forge.api.SelectOptionDTO; @Schema(name = "DevelopmentReloadingSelectOptions") public class DevelopmentReloadingSelectOptions extends SelectOptionDTO { diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java index dfae59161b1..c4d2f227029 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java @@ -18,12 +18,13 @@ */ package org.grails.forge.api.options; +import java.util.List; + import io.swagger.v3.oas.annotations.media.Schema; + import org.grails.forge.api.GormImplDTO; import org.grails.forge.api.SelectOptionDTO; -import java.util.List; - @Schema(name = "GormImplSelectOptions") public class GormImplSelectOptions extends SelectOptionDTO { public GormImplSelectOptions(List options, GormImplDTO defaultOption) { diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java index 48cb400ed64..1ef6123ec38 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java @@ -18,11 +18,12 @@ */ package org.grails.forge.api.options; -import org.grails.forge.api.JdkVersionDTO; -import org.grails.forge.api.SelectOptionDTO; +import java.util.List; + import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; +import org.grails.forge.api.JdkVersionDTO; +import org.grails.forge.api.SelectOptionDTO; @Schema(name = "JdkVersionSelectOptions") public class JdkVersionSelectOptions extends SelectOptionDTO { diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java index 9b83f2ce787..1ba3c635309 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java @@ -18,11 +18,12 @@ */ package org.grails.forge.api.options; -import org.grails.forge.api.LanguageDTO; -import org.grails.forge.api.SelectOptionDTO; +import java.util.List; + import io.swagger.v3.oas.annotations.media.Schema; -import java.util.List; +import org.grails.forge.api.LanguageDTO; +import org.grails.forge.api.SelectOptionDTO; @Schema(name = "LanguageSelectOptions") public class LanguageSelectOptions extends SelectOptionDTO { diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java index d4f4fe84e90..dda22db9d0b 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java @@ -18,15 +18,17 @@ */ package org.grails.forge.api.options; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + import io.micronaut.context.MessageSource; import io.micronaut.context.i18n.ResourceBundleMessageSource; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; + import org.grails.forge.api.RequestInfo; import org.grails.forge.api.SelectOptionsDTO; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; /** * Gets Information about select options for the Grails Forge. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java index 60a5e5e6f76..bf2c116f59c 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java @@ -18,9 +18,10 @@ */ package org.grails.forge.api.options; +import io.swagger.v3.oas.annotations.Parameter; + import org.grails.forge.api.RequestInfo; import org.grails.forge.api.SelectOptionsDTO; -import io.swagger.v3.oas.annotations.Parameter; public interface SelectOptionsOperations { SelectOptionsDTO selectOptions(@Parameter(hidden = true) RequestInfo serverURL); diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java index 159a2d3031b..1662718967b 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java @@ -18,12 +18,13 @@ */ package org.grails.forge.api.options; +import java.util.List; + import io.swagger.v3.oas.annotations.media.Schema; + import org.grails.forge.api.SelectOptionDTO; import org.grails.forge.api.ServletImplDTO; -import java.util.List; - @Schema(name = "ServletImplSelectOptions") public class ServletImplSelectOptions extends SelectOptionDTO { public ServletImplSelectOptions(List options, ServletImplDTO defaultOption) { diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java index 5f92955ddd0..ad85fb4571b 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java @@ -18,6 +18,11 @@ */ package org.grails.forge.api.preview; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import io.micronaut.context.event.ApplicationEventPublisher; import io.micronaut.core.annotation.Nullable; import io.micronaut.http.HttpStatus; @@ -25,25 +30,25 @@ import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.exceptions.HttpStatusException; +import io.swagger.v3.oas.annotations.Parameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.grails.forge.api.DevelopmentReloading; import org.grails.forge.api.Relationship; import org.grails.forge.api.RequestInfo; -import org.grails.forge.api.DevelopmentReloading; import org.grails.forge.api.create.AbstractCreateController; import org.grails.forge.application.ApplicationType; import org.grails.forge.application.Project; import org.grails.forge.application.generator.ProjectGenerator; import org.grails.forge.io.ConsoleOutput; import org.grails.forge.io.MapOutputHandler; -import org.grails.forge.options.*; +import org.grails.forge.options.BuildTool; +import org.grails.forge.options.GormImpl; +import org.grails.forge.options.JdkVersion; +import org.grails.forge.options.Options; +import org.grails.forge.options.ServletImpl; import org.grails.forge.util.NameUtils; -import io.swagger.v3.oas.annotations.Parameter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; /** * Previews an application contents. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java index b1548db17bd..cd312c6584d 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java @@ -18,12 +18,13 @@ */ package org.grails.forge.api.preview; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonInclude; import io.micronaut.core.annotation.Introspected; -import org.grails.forge.api.Linkable; import io.swagger.v3.oas.annotations.media.Schema; -import java.util.Map; +import org.grails.forge.api.Linkable; /** * A preview of the contents. diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java index e16700b32da..14b86e094c7 100644 --- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java +++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java @@ -18,20 +18,21 @@ */ package org.grails.forge.api.preview; +import java.io.IOException; +import java.util.List; + import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.swagger.v3.oas.annotations.Parameter; -import org.grails.forge.api.RequestInfo; + import org.grails.forge.api.DevelopmentReloading; +import org.grails.forge.api.RequestInfo; import org.grails.forge.application.ApplicationType; import org.grails.forge.options.BuildTool; import org.grails.forge.options.GormImpl; import org.grails.forge.options.JdkVersion; import org.grails.forge.options.ServletImpl; -import java.io.IOException; -import java.util.List; - public interface PreviewOperations { /** * Previews an application. diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java index 43732af4e38..5ce5ac7dea8 100644 --- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java +++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java @@ -18,18 +18,30 @@ */ package org.grails.forge.cli; +import java.util.concurrent.Callable; +import java.util.function.BiFunction; + import io.micronaut.context.ApplicationContext; import io.micronaut.context.BeanContext; import io.micronaut.context.annotation.Prototype; import io.micronaut.core.annotation.TypeHint; import io.micronaut.inject.BeanDefinition; -import org.grails.forge.cli.command.*; -import org.grails.forge.io.ConsoleOutput; import picocli.CommandLine; -import java.util.concurrent.Callable; -import java.util.function.BiFunction; - +import org.grails.forge.cli.command.BaseCommand; +import org.grails.forge.cli.command.CodeGenCommand; +import org.grails.forge.cli.command.CreateAppCommand; +import org.grails.forge.cli.command.CreatePluginCommand; +import org.grails.forge.cli.command.CreateRestApiCommand; +import org.grails.forge.cli.command.CreateWebPluginCommand; +import org.grails.forge.cli.command.CreateWebappCommand; +import org.grails.forge.cli.command.DevelopmentReloadingCandidates; +import org.grails.forge.cli.command.DevelopmentReloadingConverter; +import org.grails.forge.cli.command.GormImplCandidates; +import org.grails.forge.cli.command.GormImplConverter; +import org.grails.forge.cli.command.ServletImplCandidates; +import org.grails.forge.cli.command.ServletImplConverter; +import org.grails.forge.io.ConsoleOutput; @CommandLine.Command(name = "grails-forge-cli", description = { diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java index 6420468b2c3..3bc8ef964d2 100644 --- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java +++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java @@ -18,28 +18,33 @@ */ package org.grails.forge.cli; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import io.micronaut.context.BeanContext; import io.micronaut.core.annotation.Introspected; import io.micronaut.core.beans.BeanIntrospection; import io.micronaut.inject.qualifiers.Qualifiers; +import org.yaml.snakeyaml.Yaml; + import org.grails.forge.application.ApplicationType; import org.grails.forge.feature.AvailableFeatures; import org.grails.forge.feature.DefaultFeature; import org.grails.forge.feature.Feature; import org.grails.forge.io.ConsoleOutput; import org.grails.forge.io.FileSystemOutputHandler; +import org.grails.forge.options.DevelopmentReloading; import org.grails.forge.options.JdkVersion; import org.grails.forge.options.Language; import org.grails.forge.options.Options; -import org.grails.forge.options.DevelopmentReloading; -import org.yaml.snakeyaml.Yaml; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.util.*; -import java.util.stream.Collectors; @Introspected public class CodeGenConfig { diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java index 9d2d4f1f4c6..046156a033d 100644 --- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java +++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java @@ -19,10 +19,11 @@ package org.grails.forge.cli; import io.micronaut.core.annotation.ReflectiveAccess; -import org.grails.forge.cli.util.GrailsVersionProvider; import picocli.CommandLine; import picocli.CommandLine.Option; +import org.grails.forge.cli.util.GrailsVersionProvider; + /** * Mixin that adds help, version and other common options to a command. Example usage: *

diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java
index c91fcdfafd5..92f54565186 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.cli;
 
+import java.util.Optional;
+
 import io.micronaut.context.ApplicationContext;
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.TypeHint;
 import picocli.CommandLine;
 
-import java.util.Optional;
-
 /**
  * Picocli factory implementation that uses a Micronaut BeanContext to obtain bean instances.
  */
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
index 618b1cecd8b..38ef3ea2382 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
@@ -18,6 +18,11 @@
  */
 package org.grails.forge.cli;
 
+import static picocli.CommandLine.Help.Ansi.AUTO;
+
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
 import org.fusesource.jansi.AnsiConsole;
 import org.jline.reader.EndOfFileException;
 import org.jline.reader.LineReader;
@@ -31,11 +36,6 @@
 import picocli.CommandLine;
 import picocli.shell.jline3.PicocliJLineCompleter;
 
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-
-import static picocli.CommandLine.Help.Ansi.AUTO;
-
 public class InteractiveShell {
 
     private static final String DEFAULT_PROMPT = "@|blue grails>|@ ";
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
index 14e060e44cd..9e7f2bc585f 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
@@ -18,23 +18,26 @@
  */
 package org.grails.forge.cli.command;
 
-import grails.codegen.model.AbstractMemberDefinition;
-import grails.codegen.model.DomainFieldModifier;
-import grails.codegen.model.PropertyDefinition;
+import java.io.File;
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
-import org.grails.forge.cli.CodeGenConfig;
-import org.grails.forge.io.ConsoleOutput;
-import org.grails.forge.io.FileSystemOutputHandler;
-import org.grails.forge.io.OutputHandler;
 import picocli.CommandLine.Command;
 import picocli.CommandLine.Option;
 import picocli.CommandLine.Parameters;
 
-import java.io.File;
-import java.io.IOException;
+import grails.codegen.model.AbstractMemberDefinition;
+import grails.codegen.model.DomainFieldModifier;
+import grails.codegen.model.PropertyDefinition;
+
+import org.grails.forge.cli.CodeGenConfig;
+import org.grails.forge.io.ConsoleOutput;
+import org.grails.forge.io.FileSystemOutputHandler;
+import org.grails.forge.io.OutputHandler;
 
 /**
  * CLI command to add a property to an existing domain class.
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java
index 7abdfa429fb..9c938ed68e6 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java
@@ -18,15 +18,16 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.Locale;
+
 import io.micronaut.context.env.CachedEnvironment;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.annotation.ReflectiveAccess;
+import picocli.CommandLine;
+
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.cli.CommonOptionsMixin;
 import org.grails.forge.io.ConsoleOutput;
-import picocli.CommandLine;
-
-import java.util.Locale;
 
 public class BaseCommand implements ConsoleOutput {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java
index 7c501201cdd..db12d6194bf 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java
@@ -18,9 +18,16 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+import java.util.concurrent.Callable;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.io.ConsoleOutput;
@@ -28,11 +35,6 @@
 import org.grails.forge.io.OutputHandler;
 import org.grails.forge.template.TemplateRenderer;
 import org.grails.forge.util.NameUtils;
-import jakarta.inject.Inject;
-import picocli.CommandLine;
-
-import java.io.IOException;
-import java.util.concurrent.Callable;
 
 public abstract class CodeGenCommand extends BaseCommand implements Callable {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java
index 34c2ce476d1..c3a599d26bd 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java
@@ -18,17 +18,18 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
+import picocli.CommandLine;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.WebAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
-import picocli.CommandLine;
-
-import java.util.ArrayList;
-import java.util.List;
 
 @CommandLine.Command(name = CreateAppCommand.NAME, description = "Creates an application")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java
index aa478ae6749..12aa1e236e7 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java
@@ -18,9 +18,16 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.StringUtils;
+import picocli.CommandLine;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.Project;
@@ -28,14 +35,12 @@
 import org.grails.forge.feature.AvailableFeatures;
 import org.grails.forge.io.FileSystemOutputHandler;
 import org.grails.forge.io.OutputHandler;
-import org.grails.forge.options.*;
+import org.grails.forge.options.DevelopmentReloading;
+import org.grails.forge.options.GormImpl;
+import org.grails.forge.options.JdkVersion;
+import org.grails.forge.options.Options;
+import org.grails.forge.options.ServletImpl;
 import org.grails.forge.util.NameUtils;
-import picocli.CommandLine;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
 
 public abstract class CreateCommand extends BaseCommand implements Callable {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java
index ebf0682f6be..151106354eb 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java
@@ -18,10 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.controller;
@@ -31,9 +36,6 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
-import picocli.CommandLine;
-
-import java.io.IOException;
 
 @CommandLine.Command(name = CreateControllerCommand.NAME, description = "Creates a Grails Controller")
 public class CreateControllerCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java
index 5c37809c6b1..7ba6e6b6c1c 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java
@@ -18,10 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.domain;
@@ -31,9 +36,6 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
-import picocli.CommandLine;
-
-import java.io.IOException;
 
 @CommandLine.Command(name = CreateDomainClassCommand.NAME, description = "Creates a Domain Class")
 public class CreateDomainClassCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java
index 6e42d947e5f..0d708b20566 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java
@@ -18,10 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.interceptor;
@@ -31,9 +36,6 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
-import picocli.CommandLine;
-
-import java.io.IOException;
 
 @CommandLine.Command(name = CreateInterceptorCommand.NAME, description = "Creates a Interceptor Class")
 public class CreateInterceptorCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java
index 81e3efc8bcb..d33aedb39e6 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java
@@ -18,11 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
-import java.io.IOException;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.job;
@@ -31,7 +35,6 @@
 import org.grails.forge.io.OutputHandler;
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
-import picocli.CommandLine;
 
 @CommandLine.Command(name = CreateJobCommand.NAME, description = "Creates a new Quartz scheduled job")
 public class CreateJobCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java
index f88b4c90677..713d870d318 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java
@@ -18,17 +18,18 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
+import picocli.CommandLine;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.PluginAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
-import picocli.CommandLine;
-
-import java.util.ArrayList;
-import java.util.List;
 
 @CommandLine.Command(name = CreatePluginCommand.NAME, description = "Creates an Grails Plugin")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java
index 9f7f9b26023..218e2357a37 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java
@@ -18,17 +18,18 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
+import picocli.CommandLine;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.RestApiAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
-import picocli.CommandLine;
-
-import java.util.ArrayList;
-import java.util.List;
 
 @CommandLine.Command(name = CreateRestApiCommand.NAME, description = "Creates an REST API")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java
index 4c6640e19d8..9fa939d75d4 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java
@@ -18,10 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.service;
@@ -31,9 +36,6 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
-import picocli.CommandLine;
-
-import java.io.IOException;
 
 @CommandLine.Command(name = CreateServiceCommand.NAME, description = "Creates a Service Class")
 public class CreateServiceCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java
index 70eea1dadec..003631be3eb 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java
@@ -18,10 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
+import java.io.IOException;
+
+import jakarta.inject.Inject;
+
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import jakarta.inject.Inject;
+import picocli.CommandLine;
+
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.taglib;
@@ -31,9 +36,6 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
-import picocli.CommandLine;
-
-import java.io.IOException;
 
 @CommandLine.Command(name = CreateTagLibCommand.NAME, description = "Creates a Grails TagLib")
 public class CreateTagLibCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java
index 693e7e10eb2..b6df720233d 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java
@@ -18,17 +18,18 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
+import picocli.CommandLine;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.WebPluginAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
-import picocli.CommandLine;
-
-import java.util.ArrayList;
-import java.util.List;
 
 @CommandLine.Command(name = CreateWebPluginCommand.NAME, description = "Creates an Grails Web Plugin")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java
index 465544bd908..8d7c66acccd 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java
@@ -18,17 +18,18 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
+import picocli.CommandLine;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.WebAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
-import picocli.CommandLine;
-
-import java.util.ArrayList;
-import java.util.List;
 
 @CommandLine.Command(name = CreateWebappCommand.NAME, description = "Creates an application")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java
index 49e80e4c65d..f8ef80293c0 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
-import org.grails.forge.options.DevelopmentReloading;
-
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.grails.forge.options.DevelopmentReloading;
+
 public class DevelopmentReloadingCandidates extends ArrayList {
 
     public DevelopmentReloadingCandidates() {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java
index fb2a5211bb9..1542a973bdb 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java
@@ -18,9 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import org.grails.forge.options.DevelopmentReloading;
 import picocli.CommandLine;
 
+import org.grails.forge.options.DevelopmentReloading;
+
 public class DevelopmentReloadingConverter implements CommandLine.ITypeConverter {
 
     public static final DevelopmentReloading DEFAULT_RELOADING = DevelopmentReloading.DEVTOOLS;
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java
index 55246650308..38d7c836d37 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
-import org.grails.forge.options.GormImpl;
-
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.grails.forge.options.GormImpl;
+
 public class GormImplCandidates extends ArrayList {
     public GormImplCandidates() {
         super(Stream.of(GormImpl.values()).map(gi -> gi.toString().toLowerCase()).collect(Collectors.toList()));
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java
index 5b802d3b38e..c0c47e9e9b0 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java
@@ -19,9 +19,10 @@
 package org.grails.forge.cli.command;
 
 import io.micronaut.core.annotation.Introspected;
-import org.grails.forge.options.GormImpl;
 import picocli.CommandLine;
 
+import org.grails.forge.options.GormImpl;
+
 @Introspected
 public class GormImplConverter implements CommandLine.ITypeConverter {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java
index 8f202915fa7..4596278d60c 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
-import org.grails.forge.options.Language;
-
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.grails.forge.options.Language;
+
 public class LanguageCandidates extends ArrayList {
     public LanguageCandidates() {
         super(Stream.of(Language.values()).map(l -> l.toString().toLowerCase()).collect(Collectors.toList()));
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java
index 373f53b9d8d..4bda0860c24 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java
@@ -18,9 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import org.grails.forge.options.Language;
 import picocli.CommandLine;
 
+import org.grails.forge.options.Language;
+
 public class LanguageConverter implements CommandLine.ITypeConverter {
 
     @Override
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java
index a7ba128b482..38a9443c093 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java
@@ -18,7 +18,16 @@
  */
 package org.grails.forge.cli.command;
 
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
 import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.OperatingSystem;
@@ -29,14 +38,6 @@
 import org.grails.forge.io.ConsoleOutput;
 import org.grails.forge.options.Options;
 
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-
 public class ListFeatures {
 
     private final AvailableFeatures availableFeatures;
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java
index 0b6032453a9..1d7460d7baf 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
-import org.grails.forge.options.ServletImpl;
-
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.grails.forge.options.ServletImpl;
+
 public class ServletImplCandidates extends ArrayList {
     public ServletImplCandidates() {
         super(Stream.of(ServletImpl.values()).map(servlet -> servlet.toString().toLowerCase()).collect(Collectors.toList()));
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java
index 87e18708306..f404c75e374 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java
@@ -19,9 +19,10 @@
 package org.grails.forge.cli.command;
 
 import io.micronaut.core.annotation.Introspected;
-import org.grails.forge.options.ServletImpl;
 import picocli.CommandLine;
 
+import org.grails.forge.options.ServletImpl;
+
 @Introspected
 public class ServletImplConverter implements CommandLine.ITypeConverter {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
index 7e13a15c721..55ad440900b 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
@@ -18,11 +18,13 @@
  */
 package org.grails.forge.cli.util;
 
+import java.util.Objects;
+
 import jakarta.inject.Singleton;
-import org.grails.forge.util.VersionInfo;
+
 import picocli.CommandLine.IVersionProvider;
 
-import java.util.Objects;
+import org.grails.forge.util.VersionInfo;
 
 /**
  * Generates version information. Example usage:
diff --git a/grails-forge/grails-forge-core/build.gradle b/grails-forge/grails-forge-core/build.gradle
index 11445540639..1378c370ddd 100644
--- a/grails-forge/grails-forge-core/build.gradle
+++ b/grails-forge/grails-forge-core/build.gradle
@@ -128,7 +128,7 @@ nohttp {
     source.exclude('**/pom.rocker.raw')
 }
 
-['processResources', 'sourcesJar', 'spotlessJavaMisc', 'checkstyleNohttp'].each { name ->
+['processResources', 'sourcesJar', 'checkstyleNohttp'].each { name ->
     tasks.named(name).configure {
         it.dependsOn(copyGrailsWrapper, grailsVersionInfoTask)
     }
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java
index 408933655ae..013224b9b1f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java
@@ -18,17 +18,21 @@
  */
 package org.grails.forge.analytics;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
-import org.grails.forge.options.*;
+import org.grails.forge.options.DevelopmentReloading;
+import org.grails.forge.options.GormImpl;
+import org.grails.forge.options.JdkVersion;
+import org.grails.forge.options.ServletImpl;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Objects;
-
 @Introspected
 public class Generated {
     private final ApplicationType type;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java
index 2d53ab634a9..60ef046c5d1 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.application;
 
+import java.util.Locale;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.naming.Named;
 
-import java.util.Locale;
-
 public enum ApplicationType implements Named {
 
     WEB("Web Application", "A Grails® framework Web Application"),
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java
index f499008902b..32bdb002a41 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java
@@ -18,8 +18,15 @@
  */
 package org.grails.forge.application;
 
-import io.micronaut.core.annotation.Nullable;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.DefaultCoordinateResolver;
 import org.grails.forge.feature.AvailableFeatures;
@@ -28,12 +35,12 @@
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.feature.validation.FeatureValidator;
 import org.grails.forge.io.ConsoleOutput;
-import org.grails.forge.options.*;
-
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Set;
+import org.grails.forge.options.BuildTool;
+import org.grails.forge.options.DevelopmentReloading;
+import org.grails.forge.options.GormImpl;
+import org.grails.forge.options.Language;
+import org.grails.forge.options.Options;
+import org.grails.forge.options.ServletImpl;
 
 @Singleton
 public class ContextFactory {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java
index 61855d3ed77..49c76e26cb3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java
@@ -18,13 +18,14 @@
  */
 package org.grails.forge.application;
 
+import java.util.List;
+
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
+
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
-import java.util.List;
-
 @Named("plugin")
 @Singleton
 public class PluginAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java
index 8847b9d52d5..db9e2478a8b 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.application;
 
-import org.grails.forge.util.NameUtils;
-
 import java.util.HashMap;
 import java.util.Map;
 
+import org.grails.forge.util.NameUtils;
+
 public class Project extends ProjectIdentifier {
 
     private static final String PACKAGE_NAME = "packageName";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java
index 206d959267e..856287a2766 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java
@@ -18,13 +18,14 @@
  */
 package org.grails.forge.application;
 
+import java.util.List;
+
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
+
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
-import java.util.List;
-
 @Named("rest_api")
 @Singleton
 public class RestApiAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java
index ea6a84209b8..2d3896c4b74 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java
@@ -18,13 +18,14 @@
  */
 package org.grails.forge.application;
 
+import java.util.List;
+
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
+
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
-import java.util.List;
-
 @Named("web")
 @Singleton
 public class WebAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java
index 25b7c36b462..abe8f78303e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java
@@ -18,13 +18,14 @@
  */
 package org.grails.forge.application;
 
+import java.util.List;
+
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
+
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
-import java.util.List;
-
 @Named("web_plugin")
 @Singleton
 public class WebPluginAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java
index 71502385d3a..9c81866bf66 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java
@@ -18,10 +18,17 @@
  */
 package org.grails.forge.application.generator;
 
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Function;
+
+import jakarta.inject.Singleton;
+
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.inject.qualifiers.Qualifiers;
-import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.OperatingSystem;
@@ -39,11 +46,6 @@
 import org.grails.forge.template.Template;
 import org.grails.forge.template.TemplateRenderer;
 
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.function.Function;
-
 @Singleton
 public class DefaultProjectGenerator implements ProjectGenerator {
     private final ContextFactory contextFactory;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java
index d0713701b85..a27a41d8216 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java
@@ -18,15 +18,31 @@
  */
 package org.grails.forge.application.generator;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
 import com.fizzed.rocker.RockerModel;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.Project;
 import org.grails.forge.build.BuildPlugin;
 import org.grails.forge.build.BuildProperties;
-import org.grails.forge.build.dependencies.*;
+import org.grails.forge.build.dependencies.Coordinate;
+import org.grails.forge.build.dependencies.CoordinateResolver;
+import org.grails.forge.build.dependencies.Dependency;
+import org.grails.forge.build.dependencies.DependencyContext;
+import org.grails.forge.build.dependencies.LookupFailedException;
+import org.grails.forge.build.dependencies.Scope;
 import org.grails.forge.build.gradle.GradleRepository;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.Features;
@@ -35,15 +51,20 @@
 import org.grails.forge.feature.config.BootstrapConfiguration;
 import org.grails.forge.feature.config.Configuration;
 import org.grails.forge.feature.other.template.markdownLink;
-import org.grails.forge.options.*;
+import org.grails.forge.options.DevelopmentReloading;
+import org.grails.forge.options.GormImpl;
+import org.grails.forge.options.JdkVersion;
+import org.grails.forge.options.Language;
+import org.grails.forge.options.Options;
+import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.TestFramework;
+import org.grails.forge.options.TestRockerModelProvider;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.RockerWritable;
 import org.grails.forge.template.Template;
 import org.grails.forge.template.Writable;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.*;
-
 /**
  * A context object used when generating projects.
  *
@@ -294,7 +315,7 @@ public String getIntegrationTestSourcePath(String path) {
     }
 
     RockerModel parseModel(RockerModel javaTemplate, RockerModel groovyTemplate) {
-       return groovyTemplate;
+        return groovyTemplate;
     }
 
     public void addTemplate(String name, String path, TestRockerModelProvider testRockerModelProvider) {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java
index 685eab9b22e..c1b4120edeb 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java
@@ -18,8 +18,11 @@
  */
 package org.grails.forge.application.generator;
 
+import java.util.List;
+
 import io.micronaut.context.annotation.DefaultImplementation;
 import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.Project;
@@ -27,8 +30,6 @@
 import org.grails.forge.io.OutputHandler;
 import org.grails.forge.options.Options;
 
-import java.util.List;
-
 @DefaultImplementation(DefaultProjectGenerator.class)
 public interface ProjectGenerator {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java
index 6af46a707a0..a4ade3e5e90 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java
@@ -21,6 +21,7 @@
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.Ordered;
+
 import org.grails.forge.build.dependencies.CoordinateResolver;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.template.Writable;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java
index 5fb61cdf75e..c97e7e5a0b8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.dependencies;
 
+import java.util.Comparator;
+
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.OrderUtil;
 
-import java.util.Comparator;
-
 @Introspected
 public interface Coordinate {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java
index 2ff403db8ee..836b064fec9 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java
@@ -18,13 +18,14 @@
  */
 package org.grails.forge.build.dependencies;
 
-import io.micronaut.context.annotation.Primary;
-import io.micronaut.core.annotation.NonNull;
-import jakarta.inject.Singleton;
-
 import java.util.Arrays;
 import java.util.Optional;
 
+import jakarta.inject.Singleton;
+
+import io.micronaut.context.annotation.Primary;
+import io.micronaut.core.annotation.NonNull;
+
 @Singleton
 @Primary
 public class DefaultCoordinateResolver implements CoordinateResolver {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java
index 1604a9cec2a..94603d6e558 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java
@@ -18,11 +18,12 @@
  */
 package org.grails.forge.build.dependencies;
 
+import java.util.Objects;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-import org.grails.forge.template.Writable;
 
-import java.util.Objects;
+import org.grails.forge.template.Writable;
 
 public final class Dependency {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java
index 8c18b25f5da..eb4236990ca 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java
@@ -19,10 +19,11 @@
 package org.grails.forge.build.dependencies;
 
 
+import java.util.Collection;
+
 import io.micronaut.core.annotation.NonNull;
-import org.grails.forge.build.gradle.GradleRepository;
 
-import java.util.Collection;
+import org.grails.forge.build.gradle.GradleRepository;
 
 public interface DependencyContext {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java
index 6df627bc3c2..3e845fc79d0 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.dependencies;
 
+import java.util.Objects;
+
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.Ordered;
 
-import java.util.Objects;
-
 @Introspected
 public class DependencyCoordinate implements Coordinate, Ordered {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java
index 87a9f5c1ef8..5d445d9acba 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java
@@ -18,18 +18,6 @@
  */
 package org.grails.forge.build.dependencies;
 
-import io.micronaut.core.annotation.NonNull;
-import io.micronaut.core.io.ResourceResolver;
-import io.micronaut.core.util.StringUtils;
-import jakarta.inject.Singleton;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -38,6 +26,20 @@
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+import io.micronaut.core.io.ResourceResolver;
+import io.micronaut.core.util.StringUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
 @Singleton
 public class PomDependencyVersionResolver implements CoordinateResolver {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java
index 67a619d9ae3..d1878a56ef6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.dependencies;
 
-import io.micronaut.core.annotation.NonNull;
-
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
+import io.micronaut.core.annotation.NonNull;
+
 public class Scope {
 
     public static final Scope ANNOTATION_PROCESSOR = new Scope(Source.MAIN, Collections.singletonList(Phase.ANNOTATION_PROCESSING));
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java
index 4bcebb23d83..6db443de899 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.gradle;
 
-import io.micronaut.core.annotation.NonNull;
-
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+import io.micronaut.core.annotation.NonNull;
+
 public class DefaultGradleRepository implements GradleRepository {
     private final int order;
     private final String url;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java
index 62afcc40ae6..c16cbc4e9b2 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java
@@ -18,11 +18,6 @@
  */
 package org.grails.forge.build.gradle;
 
-import io.micronaut.core.annotation.NonNull;
-import org.grails.forge.template.Writable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -34,6 +29,12 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import io.micronaut.core.annotation.NonNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.grails.forge.template.Writable;
+
 public class GradleBuild {
     private static final Logger LOG = LoggerFactory.getLogger(GradleBuild.class);
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java
index 82beefc4619..c37844d15d1 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java
@@ -18,15 +18,17 @@
  */
 package org.grails.forge.build.gradle;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
+import jakarta.inject.Singleton;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.order.OrderUtil;
-import jakarta.inject.Singleton;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.options.BuildTool;
 
-import java.util.List;
-import java.util.stream.Collectors;
-
 @Singleton
 public class GradleBuildCreator {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java
index a4b43954c8c..cfee3593883 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java
@@ -18,14 +18,15 @@
  */
 package org.grails.forge.build.gradle;
 
+import java.util.Optional;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.order.Ordered;
+
 import org.grails.forge.build.dependencies.Phase;
 import org.grails.forge.build.dependencies.Scope;
 import org.grails.forge.options.DevelopmentReloading;
 
-import java.util.Optional;
-
 public enum GradleConfiguration implements Ordered {
     CLASSPATH("classpath", -2),
     PROFILE("profile", -1),
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java
index 0f72ed14a4b..5f25714b34c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java
@@ -18,20 +18,21 @@
  */
 package org.grails.forge.build.gradle;
 
+import static org.grails.forge.build.gradle.GradleConfiguration.INTEGRATION_TEST_IMPLEMENTATION_TEST_FIXTURES;
+
+import java.util.Comparator;
+import java.util.Objects;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.OrderUtil;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.build.dependencies.DependencyCoordinate;
 import org.grails.forge.template.Writable;
 
-import java.util.Comparator;
-import java.util.Objects;
-
-import static org.grails.forge.build.gradle.GradleConfiguration.INTEGRATION_TEST_IMPLEMENTATION_TEST_FIXTURES;
-
 public class GradleDependency extends DependencyCoordinate {
 
     public static final Comparator COMPARATOR = (o1, o2) -> {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java
index bd85c6ba142..a8c214b3ee7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java
@@ -18,18 +18,22 @@
  */
 package org.grails.forge.build.gradle;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.build.BuildPlugin;
-import org.grails.forge.build.dependencies.*;
+import org.grails.forge.build.dependencies.Coordinate;
+import org.grails.forge.build.dependencies.CoordinateResolver;
+import org.grails.forge.build.dependencies.LookupFailedException;
+import org.grails.forge.build.dependencies.Scope;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.template.Writable;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
 public class GradlePlugin implements BuildPlugin {
 
     private final String id;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java
index 06ab59206b5..a7f816088df 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.build.gradle;
 
-import io.micronaut.core.annotation.NonNull;
-import io.micronaut.core.order.Ordered;
-
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import io.micronaut.core.annotation.NonNull;
+import io.micronaut.core.order.Ordered;
+
 public interface GradleRepository extends Ordered {
     @NonNull
     String toSnippet(String basePadding);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java
index 16e549a42f1..6999e687fc4 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.client.github.oauth;
 
+import jakarta.validation.constraints.NotNull;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.micronaut.core.annotation.Introspected;
 
-import jakarta.validation.constraints.NotNull;
-
 /**
  * @author Pavol Gressa
  * @since 6.0.0
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java
index 5916bfab3a7..ff1b00c99a6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java
@@ -47,4 +47,3 @@ public String getKeyId() {
         return keyId;
     }
 }
-
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java
index ce3836943ca..a05cd0aeb98 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java
@@ -38,7 +38,7 @@ public class GitHubUser {
     @JsonCreator
     public GitHubUser(
             @JsonProperty("login") String login,
-            @JsonProperty("email")  String email,
+            @JsonProperty("email") String email,
             @JsonProperty("name") String name) {
         this.login = login;
         this.email = email;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java
index e95f19f5809..e4b8d2e495d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.client.github.v3;
 
+import java.util.List;
+
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.micronaut.core.annotation.Introspected;
 
-import java.util.List;
-
 /**
  * GitHub workflow runs.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java
index b6e95a2e9d3..0b45573c63f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java
@@ -20,6 +20,7 @@
 
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Introspected;
+
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.options.DevelopmentReloading;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java
index 62a2d4aeab0..5583f2ad6e4 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java
@@ -18,11 +18,18 @@
  */
 package org.grails.forge.diff;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.inject.Singleton;
+
 import com.github.difflib.DiffUtils;
 import com.github.difflib.UnifiedDiffUtils;
 import com.github.difflib.patch.Patch;
 import io.micronaut.core.annotation.Nullable;
-import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.Project;
@@ -32,11 +39,6 @@
 import org.grails.forge.io.MapOutputHandler;
 import org.grails.forge.options.Options;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
 /**
  * Methods for diffing projects and features.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java
index 2ae4e2c080b..263aa8c35c6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature;
 
 import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.generator.GeneratorContext;
 
 public interface ApplicationFeature extends Feature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java
index e3aac954790..94d8800df89 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.feature;
 
-import io.micronaut.core.annotation.NonNull;
-
 import java.util.Optional;
 import java.util.stream.Stream;
 
+import io.micronaut.core.annotation.NonNull;
+
 public interface AvailableFeatures extends Iterable {
 
     Optional findFeature(@NonNull String name);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java
index e1d19144070..a208a668b4d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java
@@ -18,9 +18,6 @@
  */
 package org.grails.forge.feature;
 
-import io.micronaut.core.annotation.NonNull;
-import org.grails.forge.application.ApplicationType;
-
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -30,6 +27,10 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import io.micronaut.core.annotation.NonNull;
+
+import org.grails.forge.application.ApplicationType;
+
 public class BaseAvailableFeatures implements AvailableFeatures {
     private final Map features;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java
index ea5ff9e9983..5d992362fd6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java
@@ -25,35 +25,35 @@
  * @since 6.0.0
  */
 public class Category {
-    public static final String API                  = "API";
-    public static final String BPM                  = "BPM";
-    public static final String CACHE                = "Cache";
-    public static final String CICD                 = "CI/CD";
-    public static final String CLIENT               = "Client";
-    public static final String CLOUD                = "Cloud";
-    public static final String CONFIGURATION        = "Configuration";
-    public static final String DATABASE             = "Database";
-    public static final String DEV_TOOLS            = "Development Tools";
-    public static final String DISTRIBUTED_CONFIG   = "Distributed Configuration";
-    public static final String DOCUMENTATION        = "Documentation";
-    public static final String IOT                  = "Internet of Things";
-    public static final String LANGUAGES            = "Languages";
-    public static final String LOGGING              = "Logging";
-    public static final String MANAGEMENT           = "Management";
-    public static final String MESSAGING            = "Messaging";
-    public static final String OTHER                = "Other";
-    public static final String PACKAGING            = "Packaging";
-    public static final String REACTIVE             = "Reactive";
-    public static final String RESILIENCE           = "Resilience";
-    public static final String SEARCH               = "Search Engine";
-    public static final String SECURITY             = "Security";
-    public static final String SERVER               = "Server";
-    public static final String SERVERLESS           = "Serverless";
-    public static final String SERVICE_DISCOVERY    = "Service Discovery";
-    public static final String SPRING               = "Spring Framework";
-    public static final String SSL                  = "SSL";
-    public static final String TESTING              = "Testing";
-    public static final String TRACING              = "Distributed Tracing";
-    public static final String VALIDATION           = "Validation";
-    public static final String VIEW                 = "View Rendering";
+    public static final String API = "API";
+    public static final String BPM = "BPM";
+    public static final String CACHE = "Cache";
+    public static final String CICD = "CI/CD";
+    public static final String CLIENT = "Client";
+    public static final String CLOUD = "Cloud";
+    public static final String CONFIGURATION = "Configuration";
+    public static final String DATABASE = "Database";
+    public static final String DEV_TOOLS = "Development Tools";
+    public static final String DISTRIBUTED_CONFIG = "Distributed Configuration";
+    public static final String DOCUMENTATION = "Documentation";
+    public static final String IOT = "Internet of Things";
+    public static final String LANGUAGES = "Languages";
+    public static final String LOGGING = "Logging";
+    public static final String MANAGEMENT = "Management";
+    public static final String MESSAGING = "Messaging";
+    public static final String OTHER = "Other";
+    public static final String PACKAGING = "Packaging";
+    public static final String REACTIVE = "Reactive";
+    public static final String RESILIENCE = "Resilience";
+    public static final String SEARCH = "Search Engine";
+    public static final String SECURITY = "Security";
+    public static final String SERVER = "Server";
+    public static final String SERVERLESS = "Serverless";
+    public static final String SERVICE_DISCOVERY = "Service Discovery";
+    public static final String SPRING = "Spring Framework";
+    public static final String SSL = "SSL";
+    public static final String TESTING = "Testing";
+    public static final String TRACING = "Distributed Tracing";
+    public static final String VALIDATION = "Validation";
+    public static final String VIEW = "View Rendering";
 }
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java
index 54b1473cce9..7ae949e37d9 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.feature;
 
+import java.util.Set;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 /**
  * A default feature is one that should be applied to a
  * project conditionally without being explicitly selected.
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java
index 2abe72d73a1..9a9e655cd78 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java
@@ -24,6 +24,7 @@
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
 import io.micronaut.core.order.Ordered;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
index f8dea471f4e..e4177b278ac 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
@@ -18,7 +18,18 @@
  */
 package org.grails.forge.feature;
 
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toSet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Set;
+
 import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.feature.reloading.ReloadingFeature;
@@ -27,11 +38,6 @@
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.Options;
 
-import java.util.*;
-
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toSet;
-
 public class FeatureContext {
 
     private final ApplicationType applicationType;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java
index 75cded6bf65..dc29eacba43 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java
@@ -18,6 +18,12 @@
  */
 package org.grails.forge.feature;
 
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.lang.LanguageFeature;
 import org.grails.forge.feature.reloading.ReloadingFeature;
@@ -27,12 +33,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.ArrayList;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 public class Features extends ArrayList {
 
     private final Set featureList;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java
index 869bdd76c9c..7b31822f088 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.asciidoctor;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java
index 78c47bc36f5..fe8282abc58 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java
@@ -18,8 +18,13 @@
  */
 package org.grails.forge.feature.assetPipeline;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.List;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.CoordinateResolver;
@@ -31,9 +36,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
-import java.util.Set;
-import java.util.List;
-
 @Singleton
 public class AssetPipeline implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java
index cf213384a9c..2cdcdf63d32 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.feature.build.gradle;
 
-import io.micronaut.core.annotation.NonNull;
-import io.micronaut.core.annotation.Nullable;
-
 import java.util.ArrayList;
 import java.util.List;
 
+import io.micronaut.core.annotation.NonNull;
+import io.micronaut.core.annotation.Nullable;
+
 public class Dockerfile {
     @Nullable
     private String baseImage;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java
index fc71a88a464..c6749ef7f2e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java
@@ -18,7 +18,11 @@
  */
 package org.grails.forge.feature.build.gradle;
 
+import java.util.Set;
+import java.util.function.Function;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -39,9 +43,6 @@
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.Set;
-import java.util.function.Function;
-
 @Singleton
 public class Gradle implements BuildFeature {
     private static final String WRAPPER_JAR = "gradle/wrapper/gradle-wrapper.jar";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java
index b3046a01770..53286b94255 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.build.gradle;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.CoordinateResolver;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java
index afc86b0fe6a..28317031d4f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.build.gradle;
 
+import java.util.function.Function;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -30,8 +33,6 @@
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.function.Function;
-
 @Singleton
 public class GradleSettingsFile implements GradleSettingsFileFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
index b933875e843..9eb43a97d97 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
@@ -18,12 +18,13 @@
  */
 package org.grails.forge.feature.cache;
 
+import java.util.Map;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
-import java.util.Map;
-
 @Singleton
 public class EHCache implements CacheFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java
index 09f91bde398..f307e8d1cb4 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.cache;
 
+import java.util.Map;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -26,8 +29,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.Map;
-
 @Singleton
 public class GrailsCache implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
index 7313f52a028..db174624c4f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
@@ -18,15 +18,15 @@
  */
 package org.grails.forge.feature.config;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.util.CollectionUtils;
 import io.micronaut.core.util.StringUtils;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-
 /**
  * Models application environment configuration to specify where the configuration is rooted
  * for the given configuration values (key/value pairs).
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java
index 0020b375bc8..4470642e2a3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.feature.config;
 
+import java.util.function.Function;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.OneOfFeature;
 import org.grails.forge.template.Template;
 
-import java.util.function.Function;
-
 public interface ConfigurationFeature extends OneOfFeature {
 
     String ENVIRONMENTS_KEY = "environments";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java
index 080c423ef21..f48ef0c4a4d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java
@@ -18,14 +18,15 @@
  */
 package org.grails.forge.feature.config;
 
+import java.util.function.Function;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.FeaturePhase;
 import org.grails.forge.template.PropertiesTemplate;
 import org.grails.forge.template.Template;
 
-import java.util.function.Function;
-
 @Singleton
 public class Properties implements ConfigurationFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java
index 28cc738f7e7..792570e1874 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java
@@ -18,7 +18,11 @@
  */
 package org.grails.forge.feature.config;
 
+import java.util.Set;
+import java.util.function.Function;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
@@ -27,9 +31,6 @@
 import org.grails.forge.template.Template;
 import org.grails.forge.template.YamlTemplate;
 
-import java.util.Set;
-import java.util.function.Function;
-
 @Singleton
 public class Yaml implements ConfigurationFeature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
index 4fc8641e0b5..d1f1e8628c9 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
@@ -18,18 +18,18 @@
  */
 package org.grails.forge.feature.database;
 
-import org.grails.forge.feature.Feature;
-
-import java.util.Map;
-import java.util.Optional;
-
 import static org.grails.forge.feature.config.ConfigurationFeature.DEV_ENVIRONMENT_KEY;
-import static org.grails.forge.feature.config.ConfigurationFeature.TEST_ENVIRONMENT_KEY;
-import static org.grails.forge.feature.config.ConfigurationFeature.PROD_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.config.ConfigurationFeature.ENVIRONMENTS_KEY;
+import static org.grails.forge.feature.config.ConfigurationFeature.PROD_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.config.ConfigurationFeature.PROPERTIES_KEY;
+import static org.grails.forge.feature.config.ConfigurationFeature.TEST_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.database.HibernateGorm.PREFIX;
 
+import java.util.Map;
+import java.util.Optional;
+
+import org.grails.forge.feature.Feature;
+
 /**
  * A feature that configures a datasource with a driver
  */
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java
index ead67ce4ba3..895c699d7cb 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.feature.database;
 
+import java.util.Collections;
+import java.util.Map;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.feature.OneOfFeature;
 
-import java.util.Collections;
-import java.util.Map;
-
 public abstract class DatabaseDriverFeature implements OneOfFeature {
 
     private final TestContainers testContainers;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java
index 6fb6af98166..728b0d6fd83 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.feature.database;
 
+import java.util.Map;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.DefaultFeature;
 
-import java.util.Map;
-
 public abstract class GormFeature implements DefaultFeature {
 
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java
index fb958659208..53bc73ccb1c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java
@@ -18,8 +18,10 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.core.annotation.Nullable;
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java
index 93e924e9d70..413df0fa1cc 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.context.annotation.Primary;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.context.annotation.Primary;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +31,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 @Primary
 public class H2 extends DatabaseDriverFeature implements DefaultFeature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java
index 568030e73f1..9969e6a91a7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java
@@ -18,8 +18,13 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.context.annotation.Primary;
+import java.util.Map;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.context.annotation.Primary;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,9 +33,6 @@
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.Options;
 
-import java.util.Map;
-import java.util.Set;
-
 @Primary
 @Singleton
 public class HibernateGorm extends GormFeature implements DatabaseDriverConfigurationFeature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java
index d81b0e1523f..4a787541cf5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java
@@ -18,8 +18,13 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.core.annotation.Nullable;
+import java.util.Map;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,9 +33,6 @@
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.Options;
 
-import java.util.Map;
-import java.util.Set;
-
 @Singleton
 public class MongoGorm extends GormOneOfFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java
index 6ce42eef78e..a421acd3ced 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java
@@ -18,14 +18,15 @@
  */
 package org.grails.forge.feature.database;
 
+import java.util.Map;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.feature.Category;
 
-import java.util.Map;
-
 @Singleton
 public class MongoSync extends MongoFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java
index 6518bc3ae06..7e76c2bc445 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java
@@ -18,8 +18,10 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.core.annotation.NonNull;
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java
index 7c06dd46f9d..2465ab3f048 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java
@@ -18,8 +18,10 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.core.annotation.NonNull;
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java
index 040905a7906..a1d444ee21e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java
@@ -18,8 +18,10 @@
  */
 package org.grails.forge.feature.database;
 
-import io.micronaut.core.annotation.NonNull;
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java
index 10b4b6e8d57..7562f0b8998 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java
@@ -18,9 +18,13 @@
  */
 package org.grails.forge.feature.database;
 
+import java.util.Optional;
+
+import jakarta.inject.Singleton;
+
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,8 +35,6 @@
 import org.grails.forge.feature.test.Spock;
 import org.grails.forge.template.StringTemplate;
 
-import java.util.Optional;
-
 @Singleton
 public class TestContainers implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java
index 8d7e3e210f6..1b2b8496161 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.feature.github.workflows;
 
+import java.util.Collections;
+import java.util.List;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.Feature;
 
-import java.util.Collections;
-import java.util.List;
-
 /**
  * GitHub workflow feature.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java
index ab01213311e..d9cfce37fef 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.github.workflows.plain;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.github.workflows.GitHubWorkflowFeature;
 import org.grails.forge.feature.github.workflows.plain.templates.plainGithubWorkflow;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java
index a784fc573a5..96717f97556 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.grails;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,8 +31,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
-import java.util.Set;
-
 @Singleton
 public class GrailsBase implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java
index 4ab1fdc74e0..8371553190b 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.grails;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -26,8 +29,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class GrailsConsole implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java
index fa87cac0c27..054a59261c5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java
@@ -18,7 +18,11 @@
  */
 package org.grails.forge.feature.grails;
 
+import java.util.Arrays;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,9 +32,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
-import java.util.Arrays;
-import java.util.Set;
-
 @Singleton
 public class GrailsDefaultPlugins implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java
index 1a3c0400288..3080fea8288 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.grails;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.CoordinateResolver;
@@ -30,8 +33,6 @@
 import org.grails.forge.feature.web.GrailsWeb;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 class GrailsGradlePlugin implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java
index ca51e392ca6..14154b16ced 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java
@@ -18,16 +18,17 @@
  */
 package org.grails.forge.feature.grails;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
+import org.grails.forge.feature.grails.templates.urlMappings;
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
-import org.grails.forge.feature.grails.templates.urlMappings;
-
-import java.util.Set;
 
 @Singleton
 public class GrailsUrlMappings implements DefaultFeature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java
index 5c81045d989..2f6d124d325 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java
@@ -18,15 +18,16 @@
  */
 package org.grails.forge.feature.grails;
 
+import java.util.Map;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.Feature;
 
-import java.util.Map;
-
 @Singleton
 public class GrailsWebConsole implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java
index 53806b0ba3d..99315373420 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java
@@ -18,7 +18,11 @@
  */
 package org.grails.forge.feature.grailsProfiles;
 
+import java.util.Map;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,9 +32,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Map;
-import java.util.Set;
-
 @Singleton
 public class GrailsProfiles implements DefaultFeature {
     @Override
@@ -55,8 +56,6 @@ public boolean supports(ApplicationType applicationType) {
 
     @Override
     public void apply(GeneratorContext generatorContext) {
-
-
         final Map config = generatorContext.getConfiguration();
         // Required by profile commands when package is not set
         config.put("grails.codegen.defaultPackage", generatorContext.getProject().getPackageName());
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java
index 569db93881c..68a098a8ff7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.grailsWrapper;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -28,8 +31,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.BinaryTemplate;
 
-import java.util.Set;
-
 @Singleton
 public class GrailsWrapper implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java
index 964d8534809..4ee6e1224a0 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.lang.groovy;
 
-import io.micronaut.core.annotation.Nullable;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.Nullable;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.gradle.GradlePlugin;
@@ -30,8 +34,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.Set;
-
 @Singleton
 public class GrailsApplication implements GrailsApplicationFeature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java
index 23e340a951d..808fd66f4b3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.logging;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -29,8 +32,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.Set;
-
 @Singleton
 public class Logback implements LoggingFeature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java
index 7e849717ed6..fb2e9b571a7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.micronaut;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Optional;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -30,8 +34,6 @@
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.options.JdkVersion;
 
-import java.util.Optional;
-
 @Singleton
 public class GrailsMicronaut implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java
index 8b2315dbb78..3dfba102234 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.micronaut;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Optional;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -30,8 +34,6 @@
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.options.JdkVersion;
 
-import java.util.Optional;
-
 @Singleton
 public class MicronautHttpClient implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java
index 413d849cbab..8b946ae8f1f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.migration;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.feature.migration.templates.dbMigrationGradle;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java
index 0677e277093..cfa81250421 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java
@@ -18,7 +18,11 @@
  */
 package org.grails.forge.feature.other;
 
+import java.util.Map;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.DefaultFeature;
@@ -26,9 +30,6 @@
 import org.grails.forge.feature.FeaturePhase;
 import org.grails.forge.options.Options;
 
-import java.util.Map;
-import java.util.Set;
-
 @Singleton
 public class AppName implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java
index bcc607cca8b..70c929642e5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.other;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java
index ca7d76baf0c..3d048436612 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.other;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java
index c82545081c8..873738880ef 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java
@@ -18,8 +18,16 @@
  */
 package org.grails.forge.feature.other;
 
-import io.micronaut.core.annotation.NonNull;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.DefaultFeature;
@@ -32,12 +40,6 @@
 import org.grails.forge.template.Template;
 import org.grails.forge.template.Writable;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 @Singleton
 public class Readme implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java
index 4181f191bb6..599cc3e4d81 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java
@@ -18,8 +18,10 @@
  */
 package org.grails.forge.feature.other;
 
-import io.micronaut.core.annotation.NonNull;
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.gradle.GradlePlugin;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java
index 274f271d673..327cceee08c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.reloading;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.gradle.GradlePlugin;
@@ -26,8 +29,6 @@
 import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class Jrebel implements ReloadingFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java
index d00b1d93b39..ea9cdc4135f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java
@@ -18,6 +18,8 @@
  */
 package org.grails.forge.feature.reloading;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
 
 import org.grails.forge.application.ApplicationType;
@@ -31,8 +33,6 @@
 import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class SpringBootDevTools implements ReloadingFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java
index 73fd1dc66a3..fe322f9c22e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java
@@ -19,6 +19,7 @@
 package org.grails.forge.feature.sitemesh3;
 
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java
index 33f00095f24..1b962326def 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.spring;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +30,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class SpringBootAutoconfigure implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java
index cd9175a322e..219a2bf8e86 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.spring;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +31,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.options.ServletImpl;
 
-import java.util.Set;
-
 @Singleton
 public class SpringBootJettyFeature extends SpringBootEmbeddedServlet {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java
index bb833b238fd..5cde71f42f8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.spring;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -26,8 +29,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class SpringBootStarterFeature implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java
index f74ef4cfb3d..ec1cd8e447a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java
@@ -18,9 +18,13 @@
  */
 package org.grails.forge.feature.spring;
 
+import java.util.Set;
+
+import jakarta.inject.Singleton;
+
 import io.micronaut.context.annotation.Primary;
 import io.micronaut.core.annotation.NonNull;
-import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,8 +32,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.options.ServletImpl;
 
-import java.util.Set;
-
 @Primary
 @Singleton
 public class SpringBootTomcatFeature extends SpringBootEmbeddedServlet {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java
index 3d946901aaa..843762ab22d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.spring;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +31,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.options.ServletImpl;
 
-import java.util.Set;
-
 @Singleton
 public class SpringBootUndertowFeature extends SpringBootEmbeddedServlet {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java
index 8d19a87e668..f8fe65695ca 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java
@@ -18,12 +18,13 @@
  */
 package org.grails.forge.feature.spring;
 
+import java.util.Map;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 
-import java.util.Map;
-
 @Singleton
 public class SpringBootVirtualThreads implements SpringThreadingFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java
index 79eb8285248..27155ef3786 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.spring;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.Category;
@@ -28,8 +31,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.Set;
-
 @Singleton
 public class SpringResources implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java
index d91f61c9096..5d2c70e4b2f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.test;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.Project;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -29,11 +33,12 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.feature.FeaturePhase;
-import org.grails.forge.options.*;
+import org.grails.forge.options.DefaultTestRockerModelProvider;
+import org.grails.forge.options.Options;
+import org.grails.forge.options.TestFramework;
+import org.grails.forge.options.TestRockerModelProvider;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.Set;
-
 @Singleton
 public class GebWithTestcontainers implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java
index c27ee16d777..5076eb68710 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java
@@ -18,21 +18,28 @@
  */
 package org.grails.forge.feature.test;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.stream.Stream;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.Project;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.build.gradle.GradlePlugin;
-import org.grails.forge.feature.*;
+import org.grails.forge.feature.Category;
+import org.grails.forge.feature.Feature;
+import org.grails.forge.feature.FeatureContext;
+import org.grails.forge.feature.FeaturePhase;
+import org.grails.forge.feature.test.template.gebConfig;
 import org.grails.forge.feature.test.template.webdriverBinariesPlugin;
-import org.grails.forge.options.*;
+import org.grails.forge.options.DefaultTestRockerModelProvider;
+import org.grails.forge.options.TestFramework;
+import org.grails.forge.options.TestRockerModelProvider;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.RockerWritable;
-import org.grails.forge.feature.test.template.gebConfig;
-
-import java.util.stream.Stream;
 
 @Singleton
 public class GebWithWebDriverBinaries implements Feature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java
index 47f7b7de1fd..e854153b3e5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.test;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +30,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class GormTestingSupport implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java
index b88dc39da6d..793b840d828 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.test;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +30,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class GrailsWebTestingSupport implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java
index 02cf19a9376..91da385437d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.test;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +30,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class Mockito implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java
index 6acafa48f62..2c3d1f3dae5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java
@@ -18,14 +18,15 @@
  */
 package org.grails.forge.feature.test;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.validation.FeatureValidator;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class MockitoValidator implements FeatureValidator {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java
index 53ce37d421a..b2fe04c0510 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java
@@ -18,8 +18,12 @@
  */
 package org.grails.forge.feature.test;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +31,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class Spock implements Feature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java
index f1946b4a513..fe9f0ed5d00 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.test;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,8 +30,6 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class ViewsJsonTestingSupport implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java
index e5d16f60b34..fde4574989a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java
@@ -18,15 +18,17 @@
  */
 package org.grails.forge.feature.validation;
 
-import io.micronaut.context.annotation.Primary;
+import java.util.List;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.context.annotation.Primary;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.List;
-import java.util.Set;
-
 @Primary
 @Singleton
 public class CompositeFeatureValidator implements FeatureValidator {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java
index 77f77d73f9a..599b6a14ae2 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.feature.validation;
 
+import java.util.Set;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 public interface FeatureValidator {
 
     void validatePreProcessing(Options options, ApplicationType applicationType, Set features);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java
index 4561b6fec5f..7bf0a110ef7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java
@@ -18,16 +18,17 @@
  */
 package org.grails.forge.feature.validation;
 
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.OneOfFeature;
 import org.grails.forge.options.Options;
 
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 @Singleton
 public class OneOfFeatureValidator implements FeatureValidator {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java
index 207777d7a29..ec3428aaa55 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java
@@ -18,8 +18,14 @@
  */
 package org.grails.forge.feature.view;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -32,10 +38,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
 @Singleton
 public class GrailsGsp implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java
index e0ea7078a59..0385eed5f37 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java
@@ -18,7 +18,10 @@
  */
 package org.grails.forge.feature.view;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -28,8 +31,6 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.Set;
-
 @Singleton
 public class Scaffolding implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java
index 82b6d16a107..0f9df588485 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java
@@ -18,8 +18,14 @@
  */
 package org.grails.forge.feature.view.json;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -27,15 +33,15 @@
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.view.GrailsViews;
-import org.grails.forge.feature.view.json.templates.*;
+import org.grails.forge.feature.view.json.templates._errors;
+import org.grails.forge.feature.view.json.templates._object;
+import org.grails.forge.feature.view.json.templates.error;
+import org.grails.forge.feature.view.json.templates.index;
+import org.grails.forge.feature.view.json.templates.notFound;
 import org.grails.forge.feature.web.GrailsWeb;
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
 @Singleton
 public class ViewJson extends GrailsViews implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java
index 76260932fba..730c21e7062 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java
@@ -18,20 +18,26 @@
  */
 package org.grails.forge.feature.view.markup;
 
-import io.micronaut.core.annotation.NonNull;
+import java.util.Arrays;
+import java.util.Map;
+
 import jakarta.inject.Singleton;
+
+import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.build.gradle.GradlePlugin;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.view.GrailsViews;
-import org.grails.forge.feature.view.markup.templates.*;
+import org.grails.forge.feature.view.markup.templates._errors;
+import org.grails.forge.feature.view.markup.templates._object;
+import org.grails.forge.feature.view.markup.templates.error;
+import org.grails.forge.feature.view.markup.templates.index;
+import org.grails.forge.feature.view.markup.templates.notFound;
 import org.grails.forge.feature.web.GrailsWeb;
 import org.grails.forge.template.RockerTemplate;
 
-import java.util.Arrays;
-import java.util.Map;
-
 @Singleton
 public class ViewMarkup extends GrailsViews implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java
index faf85e9bdf7..bddc07dad3f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java
@@ -18,14 +18,15 @@
  */
 package org.grails.forge.feature.web;
 
+import java.util.Set;
+
 import jakarta.inject.Singleton;
+
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
-import java.util.Set;
-
 @Singleton
 public class GrailsWeb implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java
index 54620a607fc..8e8f86db483 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.io;
 
-import org.grails.forge.template.Template;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+import org.grails.forge.template.Template;
+
 public class MapOutputHandler implements OutputHandler {
 
     private final Map templates;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java
index 9586fbcb0d6..ba80515e47a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.io;
 
-import org.grails.forge.template.Template;
-
 import java.io.Closeable;
 import java.io.IOException;
 
+import org.grails.forge.template.Template;
+
 public interface OutputHandler extends Closeable {
 
     boolean exists(String path);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java
index 301dbbffe84..8a66ad6b1e1 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java
@@ -18,13 +18,6 @@
  */
 package org.grails.forge.io;
 
-import io.micronaut.core.util.StringUtils;
-import org.apache.commons.compress.archivers.zip.UnixStat;
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.grails.forge.application.Project;
-import org.grails.forge.template.Template;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -35,6 +28,14 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import io.micronaut.core.util.StringUtils;
+import org.apache.commons.compress.archivers.zip.UnixStat;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+
+import org.grails.forge.application.Project;
+import org.grails.forge.template.Template;
+
 public class ZipOutputHandler implements OutputHandler {
 
     private final ZipArchiveOutputStream zipOutputStream;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java
index 0d064083c23..b878892c4c4 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java
@@ -18,14 +18,15 @@
  */
 package org.grails.forge.options;
 
-import io.micronaut.core.annotation.NonNull;
-import org.grails.forge.application.Project;
-import org.grails.forge.build.gradle.GradleDsl;
-
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
 
+import io.micronaut.core.annotation.NonNull;
+
+import org.grails.forge.application.Project;
+import org.grails.forge.build.gradle.GradleDsl;
+
 public enum BuildTool {
     GRADLE("build/libs", "build.gradle", "-*-all.jar");
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java
index e6896565a53..24771c41613 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java
@@ -18,10 +18,10 @@
  */
 package org.grails.forge.options;
 
-import io.micronaut.core.annotation.NonNull;
-
 import java.util.Locale;
 
+import io.micronaut.core.annotation.NonNull;
+
 public enum DevelopmentReloading {
 
     DEVTOOLS("Spring Boot DevTools"),
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
index a110247a311..5a5b980df67 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
@@ -18,15 +18,16 @@
  */
 package org.grails.forge.options;
 
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Set;
+
 import io.micronaut.core.annotation.NonNull;
+
 import org.grails.forge.defaults.IncludesDefaults;
 import org.grails.forge.defaults.LanguageDefaults;
 import org.grails.forge.feature.Feature;
 
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.Set;
-
 public enum Language implements IncludesDefaults {
     GROOVY("groovy", new LanguageDefaults(DevelopmentReloading.DEVTOOLS, BuildTool.GRADLE));
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java
index b3ab6a01bb3..3062d1c7f6a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java
@@ -18,14 +18,19 @@
  */
 package org.grails.forge.options;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
 import io.micronaut.core.convert.ArgumentConversionContext;
 import io.micronaut.core.convert.value.ConvertibleValues;
 import io.micronaut.core.convert.value.ConvertibleValuesMap;
+
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.util.VersionInfo;
 
-import java.util.*;
-
 public class Options implements ConvertibleValues {
 
     private final OperatingSystem operatingSystem;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java
index 32f75e126fd..efce46973f5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.options;
 
-import io.micronaut.core.annotation.NonNull;
-
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 
+import io.micronaut.core.annotation.NonNull;
+
 public enum TestFramework {
     SPOCK;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java
index 1a9d72b8384..4d1e93cbb92 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java
@@ -18,15 +18,15 @@
  */
 package org.grails.forge.template;
 
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigRenderOptions;
-
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigRenderOptions;
+
 public class Config4kTemplate implements Template {
     private final String path;
     private final Config config;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java
index bc82ef30a15..d6df3de665c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.template;
 
-import org.grails.forge.io.OutputHandler;
-
 import java.io.IOException;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.grails.forge.io.OutputHandler;
+
 public class DefaultTemplateRenderer implements TemplateRenderer {
 
     private final Map replacements;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java
index 4ba35df5f55..f9ed0823f25 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java
@@ -18,10 +18,10 @@
  */
 package org.grails.forge.template;
 
-import com.fizzed.rocker.RockerModel;
-
 import java.io.OutputStream;
 
+import com.fizzed.rocker.RockerModel;
+
 public class RockerTemplate implements Template {
 
     private final String path;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java
index 14943d3ef0c..ebbf31c6093 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.template;
 
+import java.io.OutputStream;
+
 import com.fizzed.rocker.RockerModel;
 import com.fizzed.rocker.runtime.OutputStreamOutput;
 
-import java.io.OutputStream;
-
 public class RockerWritable implements Writable {
 
     private final RockerModel model;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java
index 3eb8b7d4ef4..ac32eeb6744 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.template;
 
-import org.grails.forge.application.Project;
-import org.grails.forge.io.OutputHandler;
-
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.Collections;
 
+import org.grails.forge.application.Project;
+import org.grails.forge.io.OutputHandler;
+
 public interface TemplateRenderer extends Closeable {
 
     default RenderResult render(Template template) throws IOException {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java
index e933423c032..b0789c811c8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java
@@ -18,9 +18,6 @@
  */
 package org.grails.forge.template;
 
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -28,6 +25,9 @@
 import java.util.Map;
 import java.util.regex.Pattern;
 
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
 public class YamlTemplate implements Template {
 
     private static final Pattern DOT_PATTERN = Pattern.compile("\\.");
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java
index 0df87f80386..33829d88e98 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java
@@ -18,22 +18,24 @@
  */
 package org.grails.forge.util;
 
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import jakarta.validation.constraints.NotNull;
+
 import io.micronaut.core.util.StringUtils;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.transport.PushResult;
 import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+
 import org.grails.forge.client.github.v3.GitHubRepository;
 import org.grails.forge.client.github.v3.GitHubUser;
 
-import jakarta.validation.constraints.NotNull;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
 /**
  * Utility class for GitHub operations.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java
index 0dc11099a0c..6c5e2ff674f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java
@@ -18,15 +18,20 @@
  */
 package org.grails.forge.util;
 
-import org.grails.forge.application.generator.GeneratorContext;
-import org.grails.forge.template.URLTemplate;
-
 import java.io.IOException;
 import java.net.URI;
-import java.nio.file.*;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.ProviderNotFoundException;
 import java.util.function.BiFunction;
 import java.util.stream.Stream;
 
+import org.grails.forge.application.generator.GeneratorContext;
+import org.grails.forge.template.URLTemplate;
+
 /**
  * Feature Utility class for IO operations.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java
index 8e33ff63615..8150329c319 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java
@@ -18,10 +18,6 @@
  */
 package org.grails.forge.util;
 
-import io.micronaut.core.util.StringUtils;
-import org.grails.forge.application.Project;
-import org.grails.forge.application.ProjectIdentifier;
-
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -31,6 +27,11 @@
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import io.micronaut.core.util.StringUtils;
+
+import org.grails.forge.application.Project;
+import org.grails.forge.application.ProjectIdentifier;
+
 public final class NameUtils {
     public static final String MICRONAUT = "micronaut";
     private static final String PROPERTY_SET_PREFIX = "set";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java
index 29078abbd61..5f4581f284a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java
@@ -18,9 +18,6 @@
  */
 package org.grails.forge.util;
 
-import io.micronaut.core.annotation.NonNull;
-import org.grails.forge.options.JdkVersion;
-
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
@@ -32,6 +29,10 @@
 import java.util.Map;
 import java.util.Properties;
 
+import io.micronaut.core.annotation.NonNull;
+
+import org.grails.forge.options.JdkVersion;
+
 public class VersionInfo {
 
     private static final Properties VERSIONS = new Properties();
diff --git a/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java b/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java
index 049be55a3fa..43f2608b5ec 100644
--- a/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java
+++ b/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java
@@ -18,17 +18,18 @@
  */
 package org.grails.forge.netty.analytics;
 
+import java.util.concurrent.CompletableFuture;
+
 import io.micronaut.context.annotation.Requires;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.http.HttpStatus;
 import io.micronaut.http.annotation.Body;
 import io.micronaut.http.annotation.Post;
 import io.micronaut.http.client.annotation.Client;
+
 import org.grails.forge.analytics.Generated;
 import org.grails.forge.api.analytics.AnalyticsOperations;
 
-import java.util.concurrent.CompletableFuture;
-
 @Requires(property = AnalyticsClient.SERVICE_ANALYTICS)
 @Client("analytics")
 public interface AnalyticsClient extends AnalyticsOperations {
diff --git a/grails-gradle/gradlew.bat b/grails-gradle/gradlew.bat
index aa5f10b069f..24c62d56f2d 100755
--- a/grails-gradle/gradlew.bat
+++ b/grails-gradle/gradlew.bat
@@ -1,82 +1,82 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem      https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-@rem SPDX-License-Identifier: Apache-2.0
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables, and ensure extensions are enabled
-setlocal EnableExtensions
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:execute
-@rem Setup the command line
-
-
-
-@rem Execute Gradle
-@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
-@rem which allows us to clear the local environment before executing the java command
-endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-
-:exitWithErrorLevel
-@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
-"%COMSPEC%" /c exit %ERRORLEVEL%
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
+
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%
diff --git a/grails-profiles/profile/skeleton/gradlew.bat b/grails-profiles/profile/skeleton/gradlew.bat
index aa5f10b069f..24c62d56f2d 100755
--- a/grails-profiles/profile/skeleton/gradlew.bat
+++ b/grails-profiles/profile/skeleton/gradlew.bat
@@ -1,82 +1,82 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem      https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-@rem SPDX-License-Identifier: Apache-2.0
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables, and ensure extensions are enabled
-setlocal EnableExtensions
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:execute
-@rem Setup the command line
-
-
-
-@rem Execute Gradle
-@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
-@rem which allows us to clear the local environment before executing the java command
-endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-
-:exitWithErrorLevel
-@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
-"%COMSPEC%" /c exit %ERRORLEVEL%
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
+
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%
diff --git a/grails-shell-cli/src/test/resources/gradle-sample/gradlew.bat b/grails-shell-cli/src/test/resources/gradle-sample/gradlew.bat
index aa5f10b069f..24c62d56f2d 100644
--- a/grails-shell-cli/src/test/resources/gradle-sample/gradlew.bat
+++ b/grails-shell-cli/src/test/resources/gradle-sample/gradlew.bat
@@ -1,82 +1,82 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem      https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-@rem SPDX-License-Identifier: Apache-2.0
-@rem
-
-@if "%DEBUG%"=="" @echo off
-@rem ##########################################################################
-@rem
-@rem  Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables, and ensure extensions are enabled
-setlocal EnableExtensions
-
-set DIRNAME=%~dp0
-if "%DIRNAME%"=="" set DIRNAME=.
-@rem This is normally unused
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if %ERRORLEVEL% equ 0 goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo. 1>&2
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
-echo. 1>&2
-echo Please set the JAVA_HOME variable in your environment to match the 1>&2
-echo location of your Java installation. 1>&2
-
-"%COMSPEC%" /c exit 1
-
-:execute
-@rem Setup the command line
-
-
-
-@rem Execute Gradle
-@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
-@rem which allows us to clear the local environment before executing the java command
-endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
-
-:exitWithErrorLevel
-@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
-"%COMSPEC%" /c exit %ERRORLEVEL%
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables, and ensure extensions are enabled
+setlocal EnableExtensions
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+"%COMSPEC%" /c exit 1
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
+@rem which allows us to clear the local environment before executing the java command
+endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
+
+:exitWithErrorLevel
+@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
+"%COMSPEC%" /c exit %ERRORLEVEL%

From 4149f44554d324795e4b7c9fd3995604d06d8e30 Mon Sep 17 00:00:00 2001
From: Walter Duque de Estrada 
Date: Sun, 31 May 2026 10:01:12 -0500
Subject: [PATCH 09/16] Fix grails-forge code style: drop conflicting bespoke
 Spotless

The bespoke Spotless config in grails-forge fought Checkstyle (static
import position and the merged grails import group it cannot express)
and gated checkstyleMain behind spotlessCheck, hiding pre-existing
violations. Remove the Spotless application/config so grails-forge
relies on Checkstyle + CodeNarc via the shared grails-code-style
plugin, matching the root build. Fix the violations this surfaces
(whitespace, import order, annotation-array indentation).

Co-Authored-By: Claude Opus 4.8 (1M context) 
---
 grails-forge/gradle/code-style-config.gradle  | 23 --------
 .../analytics/postgres/FeatureRepository.java |  8 +--
 .../grails/forge/api/SelectOptionsDTO.java    |  1 -
 .../api/bind/RequestInfoArgumentBinder.java   |  4 +-
 .../create/github/GitHubCreateController.java | 52 ++++++++++---------
 .../grails/forge/api/preview/PreviewDTO.java  |  2 +-
 .../org/grails/forge/cli/Application.java     | 45 ++++++++--------
 .../grails/forge/cli/InteractiveShell.java    |  4 +-
 .../forge/cli/command/AddPropertyCommand.java |  1 -
 .../forge/cli/util/GrailsVersionProvider.java |  4 +-
 .../grails/forge/feature/FeatureContext.java  |  6 +--
 .../grails/forge/feature/cache/EHCache.java   |  2 +-
 .../forge/feature/config/Configuration.java   |  2 +-
 .../DatabaseDriverConfigurationFeature.java   | 10 ++--
 .../org/grails/forge/options/Language.java    |  2 +-
 15 files changed, 71 insertions(+), 95 deletions(-)

diff --git a/grails-forge/gradle/code-style-config.gradle b/grails-forge/gradle/code-style-config.gradle
index dfa51bbca1c..684128b1dd7 100644
--- a/grails-forge/gradle/code-style-config.gradle
+++ b/grails-forge/gradle/code-style-config.gradle
@@ -17,34 +17,14 @@
  *  under the License.
  */
 
-import com.diffplug.gradle.spotless.SpotlessExtension
 import io.spring.nohttp.gradle.NoHttpExtension
 
 apply plugin: 'checkstyle'
 apply plugin: 'codenarc'
-apply plugin: 'com.diffplug.spotless'
 apply plugin: 'io.spring.nohttp' // enforce https everywhere
 apply plugin: 'org.apache.grails.gradle.grails-code-style'
 apply plugin: 'org.apache.grails.gradle.grails-code-analysis'
 
-extensions.configure(SpotlessExtension) {
-    // Explicit `it` is required in extension configuration block
-    it.java {
-        target('src/main/java/**/*.java')
-        importOrder(
-                'java',
-                'javax',
-                'groovy', 'org.apache.groovy', 'org.codehaus.groovy',
-                'jakarta',
-                '',
-                'io.spring', 'org.springframework',
-                'grails', 'org.apache.grails', 'org.grails'
-        )
-        removeUnusedImports()
-        licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java'))
-    }
-}
-
 extensions.configure(NoHttpExtension) {
     // Explicit `it` is required in extension configuration block
     it.source.exclude(
@@ -55,6 +35,3 @@ extensions.configure(NoHttpExtension) {
     )
 }
 
-tasks.named('checkstyleMain') {
-    dependsOn('spotlessCheck')
-}
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java
index d86d094bfcc..d0b3b042990 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java
@@ -52,10 +52,10 @@ List topFeatures() {
         return this.jdbcOperations
                 .prepareStatement(query("name", "feature"),
                         statement -> {
-            try (ResultSet resultSet = statement.executeQuery()) {
-                return resultSetToTotals(resultSet);
-            }
-        });
+                            try (ResultSet resultSet = statement.executeQuery()) {
+                                return resultSetToTotals(resultSet);
+                            }
+                        });
     }
 
     @ReadOnly
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java
index 0e0c99d1be6..fb9ab283d57 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java
@@ -172,7 +172,6 @@ public static SelectOptionsDTO make(MessageSource messageSource, MessageSource.M
                 new ServletImplDTO(ServletImpl.DEFAULT_OPTION, messageSource, messageContext)
         );
 
-
         return new SelectOptionsDTO(applicationOpts, jdkVersionOpts, languageOpts, developmentReloadingOpts, gormImplOpts, servletImplOpts);
 
     }
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java
index 4bf52db9484..ca97e246a21 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java
@@ -76,8 +76,8 @@ private String resolveUrl(HttpRequest request) {
                 return "https://" + url + cp;
             }
         } else {
-           String hostname = request.getUri().getHost();
-           String host;
+            String hostname = request.getUri().getHost();
+            String host;
             if (hostname != null) {
                 host = hostname;
             } else {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java
index 0026deb3d8b..0049b3c8078 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java
@@ -89,23 +89,24 @@ public GitHubCreateController(GitHubCreateService gitHubCreateService,
     @Override
     @Get(uri = "/github/{type}/{name}{?features,gorm,servlet,build,reloading,javaVersion,code,state}", produces = MediaType.APPLICATION_JSON)
     @ApiResponses(value = {
-            @ApiResponse(
-                    responseCode = "200",
-                    description = "Created GitHub repository containing the generated application. In case " +
-                            "the configuration contains launcher URI the redirect to launcher is sent.",
-                    content = @Content(
-                            mediaType = MediaType.APPLICATION_JSON
-                    )
-            ),
-            @ApiResponse(
-                    responseCode = "307",
-                    description = "Redirects to GitHub OAuth API to obtain user authorisation code before creating " +
-                            "the GitHub repository."
-            ),
-            @ApiResponse(
-                    responseCode = "307",
-                    description = "Redirects back to launcher in case of successfully created GitHub repository."
-            )})
+        @ApiResponse(
+                responseCode = "200",
+                description = "Created GitHub repository containing the generated application. In case " +
+                        "the configuration contains launcher URI the redirect to launcher is sent.",
+                content = @Content(
+                        mediaType = MediaType.APPLICATION_JSON
+                )
+        ),
+        @ApiResponse(
+                responseCode = "307",
+                description = "Redirects to GitHub OAuth API to obtain user authorisation code before creating " +
+                        "the GitHub repository."
+        ),
+        @ApiResponse(
+                responseCode = "307",
+                description = "Redirects back to launcher in case of successfully created GitHub repository."
+        )
+    })
     public HttpResponse createApp(
             @NonNull ApplicationType type,
             @Pattern(regexp = "[\\w\\d-_\\.]+") String name,
@@ -156,14 +157,15 @@ public HttpResponse createApp(
      */
     @Get(uri = "/github{?error,error_description}", produces = MediaType.APPLICATION_JSON)
     @ApiResponses(value = {
-            @ApiResponse(
-                    responseCode = "307",
-                    description = "Forwarded GitHub OAuth error message."
-            ),
-            @ApiResponse(
-                    responseCode = "200",
-                    description = "Returns GitHub OAuth application callback error."
-            )})
+        @ApiResponse(
+                responseCode = "307",
+                description = "Forwarded GitHub OAuth error message."
+        ),
+        @ApiResponse(
+                responseCode = "200",
+                description = "Returns GitHub OAuth application callback error."
+        )
+    })
     public HttpResponse handleCallback(
             @Nullable String error,
             @Nullable @QueryValue("error_description") String errorDescription) {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java
index cd312c6584d..a2fa31f9ec0 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java
@@ -34,7 +34,7 @@
  */
 @Introspected
 @Schema(name = "Preview", description = "Previews the contents of the generated ZIP")
-public class PreviewDTO extends Linkable  {
+public class PreviewDTO extends Linkable {
 
     @JsonInclude
     private Map contents;
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java
index 5ce5ac7dea8..77a4090c953 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java
@@ -43,38 +43,37 @@
 import org.grails.forge.cli.command.ServletImplConverter;
 import org.grails.forge.io.ConsoleOutput;
 
-
 @CommandLine.Command(name = "grails-forge-cli", description = {
-        "Grails Forge CLI command line interface for generating projects and services.",
-        "Application generation commands are:",
-        "",
-        "*  @|bold create-app|@ @|yellow NAME|@",
-        "*  @|bold create-webapp|@ @|yellow NAME|@",
-        "*  @|bold create-restapi|@ @|yellow NAME|@",
-        "*  @|bold create-plugin|@ @|yellow NAME|@",
-        "*  @|bold create-web-plugin|@ @|yellow NAME|@"
+    "Grails Forge CLI command line interface for generating projects and services.",
+    "Application generation commands are:",
+    "",
+    "*  @|bold create-app|@ @|yellow NAME|@",
+    "*  @|bold create-webapp|@ @|yellow NAME|@",
+    "*  @|bold create-restapi|@ @|yellow NAME|@",
+    "*  @|bold create-plugin|@ @|yellow NAME|@",
+    "*  @|bold create-web-plugin|@ @|yellow NAME|@"
 },
         synopsisHeading = "@|bold,underline Usage:|@ ",
         optionListHeading = "%n@|bold,underline Options:|@%n",
         commandListHeading = "%n@|bold,underline Commands:|@%n",
         subcommands = {
-                // Creation commands
-                CreateAppCommand.class,
-                CreateWebappCommand.class,
-                CreatePluginCommand.class,
-                CreateWebPluginCommand.class,
-                CreateRestApiCommand.class
+            // Creation commands
+            CreateAppCommand.class,
+            CreateWebappCommand.class,
+            CreatePluginCommand.class,
+            CreateWebPluginCommand.class,
+            CreateRestApiCommand.class
         })
 @Prototype
 @TypeHint({
-        Application.class,
-        GormImplCandidates.class,
-        GormImplConverter.class,
-        ServletImplCandidates.class,
-        ServletImplConverter.class,
-        CommonOptionsMixin.class,
-        DevelopmentReloadingCandidates.class,
-        DevelopmentReloadingConverter.class
+    Application.class,
+    GormImplCandidates.class,
+    GormImplConverter.class,
+    ServletImplCandidates.class,
+    ServletImplConverter.class,
+    CommonOptionsMixin.class,
+    DevelopmentReloadingCandidates.class,
+    DevelopmentReloadingConverter.class
 })
 public class Application extends BaseCommand implements Callable {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
index 38ef3ea2382..9250e84cc1d 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
@@ -18,8 +18,6 @@
  */
 package org.grails.forge.cli;
 
-import static picocli.CommandLine.Help.Ansi.AUTO;
-
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 
@@ -36,6 +34,8 @@
 import picocli.CommandLine;
 import picocli.shell.jline3.PicocliJLineCompleter;
 
+import static picocli.CommandLine.Help.Ansi.AUTO;
+
 public class InteractiveShell {
 
     private static final String DEFAULT_PROMPT = "@|blue grails>|@ ";
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
index 9e7f2bc585f..7e1be5a1c21 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
@@ -33,7 +33,6 @@
 import grails.codegen.model.AbstractMemberDefinition;
 import grails.codegen.model.DomainFieldModifier;
 import grails.codegen.model.PropertyDefinition;
-
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.io.ConsoleOutput;
 import org.grails.forge.io.FileSystemOutputHandler;
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
index 55ad440900b..eb4090d8a65 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
@@ -51,8 +51,8 @@ public class GrailsVersionProvider implements IVersionProvider {
 
     public String[] getVersion() {
         return new String[] {
-                "Grails Version: " + VersionInfo.getGrailsVersion(),
-                "JVM Version: " + Objects.requireNonNullElse(System.getProperty("java.version"), "")
+            "Grails Version: " + VersionInfo.getGrailsVersion(),
+            "JVM Version: " + Objects.requireNonNullElse(System.getProperty("java.version"), "")
         };
     }
 }
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
index e4177b278ac..4acbcad6a25 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
@@ -18,9 +18,6 @@
  */
 package org.grails.forge.feature;
 
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toSet;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -38,6 +35,9 @@
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.Options;
 
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toSet;
+
 public class FeatureContext {
 
     private final ApplicationType applicationType;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
index 9eb43a97d97..c2a868b7bdb 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
@@ -46,7 +46,7 @@ public String getDescription() {
 
     @Override
     public void apply(GeneratorContext generatorContext) {
-        Map config  = generatorContext.getConfiguration();
+        Map config = generatorContext.getConfiguration();
         config.put("grails.cache.ehcache.ehcacheXmlLocation", "classpath:ehcache.xml");
         config.put("grails.cache.ehcache.lockTimeout", 200);
         generatorContext.addDependency(Dependency.builder()
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
index db174624c4f..3f11813959a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
@@ -50,7 +50,7 @@ public class Configuration extends LinkedHashMap {
      */
     public Configuration(@NonNull String sourceSet, @NonNull String fileName, @NonNull String templateKey, @Nullable String environment) {
         super();
-        this.path = environment != null && environment.equals("test") ? "src/" + sourceSet  + "/resources/" : "grails-app/conf/";
+        this.path = environment != null && environment.equals("test") ? "src/" + sourceSet + "/resources/" : "grails-app/conf/";
         this.fileName = fileName;
         this.templateKey = templateKey;
         this.environment = environment;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
index d1f1e8628c9..e87044e4113 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
@@ -18,6 +18,11 @@
  */
 package org.grails.forge.feature.database;
 
+import java.util.Map;
+import java.util.Optional;
+
+import org.grails.forge.feature.Feature;
+
 import static org.grails.forge.feature.config.ConfigurationFeature.DEV_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.config.ConfigurationFeature.ENVIRONMENTS_KEY;
 import static org.grails.forge.feature.config.ConfigurationFeature.PROD_ENVIRONMENT_KEY;
@@ -25,11 +30,6 @@
 import static org.grails.forge.feature.config.ConfigurationFeature.TEST_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.database.HibernateGorm.PREFIX;
 
-import java.util.Map;
-import java.util.Optional;
-
-import org.grails.forge.feature.Feature;
-
 /**
  * A feature that configures a datasource with a driver
  */
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
index 5a5b980df67..e4d957156c4 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
@@ -69,7 +69,7 @@ public String getTestSrcDir() {
     }
 
     public String getIntegrationSrcDir() {
-        return  "src/integration-test/" + getName();
+        return "src/integration-test/" + getName();
     }
 
     public String getSourcePath(String path) {

From 327cdcbfa04e5af8472353f650a1a76e00c6ddda Mon Sep 17 00:00:00 2001
From: Walter Duque de Estrada 
Date: Sun, 31 May 2026 21:34:22 -0500
Subject: [PATCH 10/16] chore: address PR feedback on code-analysis properties
 and directory names

---
 .agents/skills/violation-fixer/SKILL.md       | 28 +++++++++----------
 .github/workflows/codeanalysis.yml            |  4 +--
 .../apache/grails/buildsrc/GradleUtils.groovy |  4 +--
 .../GrailsCodeAnalysisExtension.groovy        |  8 +++---
 .../buildsrc/GrailsCodeAnalysisPlugin.groovy  | 12 ++++----
 .../GrailsViolationAggregationPlugin.groovy   |  2 +-
 6 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/.agents/skills/violation-fixer/SKILL.md b/.agents/skills/violation-fixer/SKILL.md
index 5176120eebd..adf1b764e3c 100644
--- a/.agents/skills/violation-fixer/SKILL.md
+++ b/.agents/skills/violation-fixer/SKILL.md
@@ -31,7 +31,7 @@ Activate this skill when:
 | Plugin | Applied to | Responsibility |
 |--------|-----------|----------------|
 | `org.apache.grails.gradle.grails-code-style` | Every subproject | Applies Checkstyle and CodeNarc; registers per-project `codeStyle` task; redirects XML reports to root `build/reports/codestyle/` |
-| `org.apache.grails.gradle.grails-code-analysis` | Every subproject | Applies PMD and SpotBugs (both opt-in); registers per-project `codeAnalysis` task; redirects XML reports to root `build/reports/codeanalysis/` |
+| `org.apache.grails.gradle.grails-code-analysis` | Every subproject | Applies PMD and SpotBugs (both opt-in); registers per-project `codeAnalysis` task; redirects XML reports to root `build/reports/code-analysis/` |
 | `org.apache.grails.gradle.grails-jacoco` | Every subproject | Applies JaCoCo; wires `jacocoTestReport` to run after each `test` task |
 | `org.apache.grails.gradle.grails-violation-aggregation` | **Root project only** | Registers `aggregateViolations` and `aggregateJacocoCoverage` tasks; writes Markdown summaries to `build/reports/violations/` |
 
@@ -54,7 +54,7 @@ Activate this skill when:
 ./gradlew :grails-core:codeStyle
 
 # Check a single module (analysis — must be enabled via properties)
-./gradlew :grails-core:codeAnalysis -Pgrails.codeanalysis.enabled.pmd=true
+./gradlew :grails-core:codeAnalysis -Pgrails.code-analysis.enabled.pmd=true
 
 # Full multi-module check + report
 ./gradlew aggregateViolations
@@ -63,10 +63,10 @@ Activate this skill when:
 ./gradlew aggregateViolations -Pgrails.codestyle.enabled.tests=true
 
 # Include test sources in analysis
-./gradlew aggregateViolations -Pgrails.codeanalysis.enabled.tests=true
+./gradlew aggregateViolations -Pgrails.code-analysis.enabled.tests=true
 
 # Ignore failures (collect reports without failing the build)
-./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.codeanalysis.ignoreFailures=true
+./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.code-analysis.ignoreFailures=true
 
 # Auto-fix some CodeNarc violations before running checks
 ./gradlew codenarcFix codeStyle
@@ -142,13 +142,13 @@ Common violations:
 
 ### PMD (Java/Groovy — opt-in)
 
-Enable: `-Pgrails.codeanalysis.enabled.pmd=true`
+Enable: `-Pgrails.code-analysis.enabled.pmd=true`
 
-Rule file: `build/codeanalysis/pmd/pmd.xml`.
+Rule file: `build/code-analysis/pmd/pmd.xml`.
 
 ### SpotBugs (Java bytecode — opt-in)
 
-Enable: `-Pgrails.codeanalysis.enabled.spotbugs=true`
+Enable: `-Pgrails.code-analysis.enabled.spotbugs=true`
 
 Runs at `Effort.MAX` / `Confidence.HIGH`. Only high-confidence bugs are reported.
 
@@ -185,18 +185,18 @@ All properties can be set in `gradle.properties` or passed as `-P` flags:
 
 | Property | Default | Description |
 |----------|---------|-------------|
-| `grails.codeanalysis.enabled.pmd` | `false` | Enable PMD |
-| `grails.codeanalysis.enabled.spotbugs` | `false` | Enable SpotBugs |
-| `grails.codeanalysis.enabled.tests` | `false` | Also analyse test source sets |
-| `grails.codeanalysis.ignoreFailures` | `false` | Collect reports without failing build |
-| `grails.codeanalysis.dir.pmd` | (auto) | Custom path to PMD config dir |
+| `grails.code-analysis.enabled.pmd` | `false` | Enable PMD |
+| `grails.code-analysis.enabled.spotbugs` | `false` | Enable SpotBugs |
+| `grails.code-analysis.enabled.tests` | `false` | Also analyse test source sets |
+| `grails.code-analysis.ignoreFailures` | `false` | Collect reports without failing build |
+| `grails.code-analysis.dir.pmd` | (auto) | Custom path to PMD config dir |
 | `skipCodeStyle` | unset | If present, all analysis tasks are also skipped |
 
 ---
 
 ## Fixing Violations Workflow
 
-1. Run `./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.codeanalysis.ignoreFailures=true`
+1. Run `./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.code-analysis.ignoreFailures=true`
 2. Open `build/reports/violations/CODENARC_VIOLATIONS.md` and `build/reports/violations/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
@@ -218,7 +218,7 @@ build/reports/codestyle/        ← XML inputs for style aggregation
     ├── grails-core-codenarcMain.xml
     └── ...
 
-build/reports/codeanalysis/     ← XML inputs for analysis aggregation (if enabled)
+build/reports/code-analysis/     ← XML inputs for analysis aggregation (if enabled)
 ├── pmd/
 └── spotbugs/
 
diff --git a/.github/workflows/codeanalysis.yml b/.github/workflows/codeanalysis.yml
index 6800eff8c0c..cff9c5faf22 100644
--- a/.github/workflows/codeanalysis.yml
+++ b/.github/workflows/codeanalysis.yml
@@ -45,7 +45,7 @@ jobs:
           cache-provider: basic # 'basic' uses the MIT-licensed, open-source cache provider; the default 'enhanced' provider (v6+) is proprietary (Gradle commercial Terms of Use)
           develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
       - name: "🔎 Check Core Projects"
-        run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true -Pgrails.codeanalysis.ignoreFailures=true
+        run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.code-analysis.enabled.pmd=true -Pgrails.code-analysis.enabled.spotbugs=true -Pgrails.code-analysis.ignoreFailures=true
       - name: "📤 Upload Reports"
         if: always()
         uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -80,7 +80,7 @@ jobs:
           develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
       - name: "🔎 Check Gradle Plugin Projects"
         working-directory: grails-gradle
-        run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.codeanalysis.enabled.pmd=true -Pgrails.codeanalysis.enabled.spotbugs=true -Pgrails.codeanalysis.ignoreFailures=true
+        run: ./gradlew aggregateAnalysisViolations --continue -Pgrails.code-analysis.enabled.pmd=true -Pgrails.code-analysis.enabled.spotbugs=true -Pgrails.code-analysis.ignoreFailures=true
       - name: "📤 Upload Reports"
         if: always()
         uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy
index f556d634e23..924958d4390 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy
@@ -40,7 +40,7 @@ class GradleUtils {
 
     static Provider booleanProvider(Project project, String name, boolean defaultValue = false) {
         project.providers.gradleProperty(name)
-                .map { Boolean.parseBoolean(it as String) }
+                .map { String it -> it.trim().toBoolean() }
                 .orElse(defaultValue)
     }
 
@@ -57,7 +57,7 @@ class GradleUtils {
         }
         if (type && (type == Boolean || type == boolean.class)) {
             def v = findProperty(project, name)
-            return v == null ? null : Boolean.parseBoolean(v as String) as T
+            return v == null ? null : (v as String).trim().toBoolean() as T
         }
 
         findProperty(project, name) as T
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy
index cf21bc87432..911b85b7815 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisExtension.groovy
@@ -30,13 +30,13 @@ import org.gradle.api.model.ObjectFactory
 class GrailsCodeAnalysisExtension {
 
     /**
-     * Defaults to project.rootProject.buildDir/codeanalysis/pmd.
+     * Defaults to rootProject.layout.buildDirectory/code-analysis/pmd.
      * Directory for PMD configuration files (e.g. pmd.xml).
      */
     final DirectoryProperty pmdDirectory
 
     /**
-     * Defaults to rootProject.buildDir/reports/codeanalysis.
+     * Defaults to rootProject.layout.buildDirectory/reports/code-analysis.
      * PMD and SpotBugs XML reports will be written here.
      */
     final DirectoryProperty reportsDirectory
@@ -44,10 +44,10 @@ class GrailsCodeAnalysisExtension {
     @Inject
     GrailsCodeAnalysisExtension(ObjectFactory objects, Project project) {
         pmdDirectory = objects.directoryProperty().convention(
-                project.rootProject.layout.buildDirectory.dir('codeanalysis/pmd')
+                project.rootProject.layout.buildDirectory.dir('code-analysis/pmd')
         )
         reportsDirectory = objects.directoryProperty().convention(
-                project.rootProject.layout.buildDirectory.dir('reports/codeanalysis')
+                project.rootProject.layout.buildDirectory.dir('reports/code-analysis')
         )
     }
 }
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
index a4d1ee17d12..dae4b7495fe 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
@@ -45,14 +45,14 @@ import com.github.spotbugs.snom.SpotBugsTask
 @CompileStatic
 class GrailsCodeAnalysisPlugin implements Plugin {
 
-    static String PMD_DIR_PROPERTY = 'grails.codeanalysis.dir.pmd'
-    static String PMD_ENABLED_PROPERTY = 'grails.codeanalysis.enabled.pmd'
+    static String PMD_DIR_PROPERTY = 'grails.code-analysis.dir.pmd'
+    static String PMD_ENABLED_PROPERTY = 'grails.code-analysis.enabled.pmd'
     static String PMD_CONFIG_FILE_NAME = 'pmd.xml'
 
-    static String SPOTBUGS_ENABLED_PROPERTY = 'grails.codeanalysis.enabled.spotbugs'
+    static String SPOTBUGS_ENABLED_PROPERTY = 'grails.code-analysis.enabled.spotbugs'
 
-    static String IGNORE_FAILURES_PROPERTY = 'grails.codeanalysis.ignoreFailures'
-    static String TEST_ANALYSIS_PROPERTY = 'grails.codeanalysis.enabled.tests'
+    static String IGNORE_FAILURES_PROPERTY = 'grails.code-analysis.ignoreFailures'
+    static String TEST_ANALYSIS_PROPERTY = 'grails.code-analysis.enabled.tests'
 
     static String BASE_RESOURCE_PATH = '/META-INF/org.apache.grails.buildsrc.grails-code-analysis'
 
@@ -78,7 +78,7 @@ class GrailsCodeAnalysisPlugin implements Plugin {
         gca.pmdDirectory.set(project.provider {
             def directory = project.hasProperty(PMD_DIR_PROPERTY) ?
                     project.rootProject.layout.projectDirectory.dir(project.property(PMD_DIR_PROPERTY) as String) :
-                    project.rootProject.layout.buildDirectory.get().dir('codeanalysis').dir('pmd')
+                    project.rootProject.layout.buildDirectory.get().dir('code-analysis').dir('pmd')
 
             def toCreate = directory.asFile.toPath()
             Files.createDirectories(toCreate)
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
index e689d8d8148..7e634d64ec5 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
@@ -86,7 +86,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
 
         Provider violationsDir = project.layout.buildDirectory.dir('reports/violations')
         Provider styleXmlDir = project.layout.buildDirectory.dir('reports/codestyle')
-        Provider analysisXmlDir = project.layout.buildDirectory.dir('reports/codeanalysis')
+        Provider analysisXmlDir = project.layout.buildDirectory.dir('reports/code-analysis')
 
         TaskProvider styleTask = registerStyleAggregation(project, styleXmlDir, violationsDir)
         TaskProvider analysisTask = registerAnalysisAggregation(project, analysisXmlDir, violationsDir)

From fc63cd05c59135b03fc665fbf443f69433972a6c Mon Sep 17 00:00:00 2001
From: Walter Duque de Estrada 
Date: Mon, 1 Jun 2026 14:59:47 -0500
Subject: [PATCH 11/16] chore: address review feedback on code style and
 analysis configuration

- Replace deprecated buildDir with layout.buildDirectory in analysis plugin
- Rename codestyle properties and directories to code-style for consistency
- Extract duplicate secure XML slurper and report writer logic into helpers
- Simplify TaskOutcome references and remove explicit closure parameter
- Fix build directory exclusion check for Windows platform compatibility
- Revert unintended IntelliJ project code style configuration changes
---
 .agents/skills/violation-fixer/SKILL.md       |  32 +--
 .idea/codeStyles/Project.xml                  | 198 +++++++++---------
 .idea/codeStyles/codeStyleConfig.xml          |  22 +-
 .../apache/grails/buildsrc/GradleUtils.groovy |   2 +-
 .../buildsrc/GrailsCodeAnalysisPlugin.groovy  |  20 +-
 .../buildsrc/GrailsCodeStyleExtension.groovy  |  12 +-
 .../buildsrc/GrailsCodeStylePlugin.groovy     |  30 +--
 .../GrailsViolationAggregationPlugin.groovy   | 140 +++++--------
 .../buildsrc/GrailsCodeStylePluginSpec.groovy |  13 +-
 grails-forge/gradle.properties                |   2 +-
 10 files changed, 233 insertions(+), 238 deletions(-)

diff --git a/.agents/skills/violation-fixer/SKILL.md b/.agents/skills/violation-fixer/SKILL.md
index adf1b764e3c..d8742d19646 100644
--- a/.agents/skills/violation-fixer/SKILL.md
+++ b/.agents/skills/violation-fixer/SKILL.md
@@ -30,7 +30,7 @@ Activate this skill when:
 
 | Plugin | Applied to | Responsibility |
 |--------|-----------|----------------|
-| `org.apache.grails.gradle.grails-code-style` | Every subproject | Applies Checkstyle and CodeNarc; registers per-project `codeStyle` task; redirects XML reports to root `build/reports/codestyle/` |
+| `org.apache.grails.gradle.grails-code-style` | Every subproject | Applies Checkstyle and CodeNarc; registers per-project `codeStyle` task; redirects XML reports to root `build/reports/code-style/` |
 | `org.apache.grails.gradle.grails-code-analysis` | Every subproject | Applies PMD and SpotBugs (both opt-in); registers per-project `codeAnalysis` task; redirects XML reports to root `build/reports/code-analysis/` |
 | `org.apache.grails.gradle.grails-jacoco` | Every subproject | Applies JaCoCo; wires `jacocoTestReport` to run after each `test` task |
 | `org.apache.grails.gradle.grails-violation-aggregation` | **Root project only** | Registers `aggregateViolations` and `aggregateJacocoCoverage` tasks; writes Markdown summaries to `build/reports/violations/` |
@@ -60,13 +60,13 @@ Activate this skill when:
 ./gradlew aggregateViolations
 
 # Include test sources in style checks
-./gradlew aggregateViolations -Pgrails.codestyle.enabled.tests=true
+./gradlew aggregateViolations -Pgrails.code-style.enabled.tests=true
 
 # Include test sources in analysis
 ./gradlew aggregateViolations -Pgrails.code-analysis.enabled.tests=true
 
 # Ignore failures (collect reports without failing the build)
-./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.code-analysis.ignoreFailures=true
+./gradlew aggregateViolations -Pgrails.code-style.ignoreFailures=true -Pgrails.code-analysis.ignoreFailures=true
 
 # Auto-fix some CodeNarc violations before running checks
 ./gradlew codenarcFix codeStyle
@@ -104,7 +104,7 @@ Each file is a Markdown table grouped by module, with columns: **Class**, **Tool
 
 ### CodeNarc (Groovy — always enabled)
 
-Rule file: `build/codestyle/codenarc/codenarc.groovy` (generated by the plugin during setup; not intended to be edited directly).
+Rule file: `build/code-style/codenarc/codenarc.groovy` (generated by the plugin during setup; not intended to be edited directly).
 
 Most common violations and how to fix them:
 
@@ -126,7 +126,7 @@ Auto-fixable via `codenarcFix`: `ClassStartsWithBlankLine`, `SpaceAroundMapEntry
 
 ### Checkstyle (Java — always enabled)
 
-Rule file: `build/codestyle/checkstyle/checkstyle.xml`.
+Rule file: `build/code-style/checkstyle/checkstyle.xml`.
 
 Common violations:
 
@@ -154,7 +154,7 @@ Runs at `Effort.MAX` / `Confidence.HIGH`. Only high-confidence bugs are reported
 
 ### Spotless (Java auto-formatting — opt-in)
 
-Enable: `-Pgrails.codestyle.enabled.spotless=true`
+Enable: `-Pgrails.code-style.enabled.spotless=true`
 
 Uses Palantir Java Format. Can auto-fix by running:
 ```bash
@@ -171,14 +171,14 @@ 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.spotless` | `false` | Enable Spotless |
-| `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.code-style.enabled.checkstyle` | `true` | Enable Checkstyle |
+| `grails.code-style.enabled.codenarc` | `true` | Enable CodeNarc |
+| `grails.code-style.enabled.spotless` | `false` | Enable Spotless |
+| `grails.code-style.enabled.tests` | `false` | Also check test source sets |
+| `grails.code-style.ignoreFailures` | `false` | Collect reports without failing build |
+| `grails.code-style.codenarc.fix` | `false` | Run `codenarcFix` before CodeNarc tasks |
+| `grails.code-style.dir.checkstyle` | (auto) | Custom path to Checkstyle config dir |
+| `grails.code-style.dir.codenarc` | (auto) | Custom path to CodeNarc config dir |
 | `skipCodeStyle` | unset | If present, all style tasks are skipped |
 
 ### `grails-code-analysis` plugin (PMD + SpotBugs)
@@ -196,7 +196,7 @@ All properties can be set in `gradle.properties` or passed as `-P` flags:
 
 ## Fixing Violations Workflow
 
-1. Run `./gradlew aggregateViolations -Pgrails.codestyle.ignoreFailures=true -Pgrails.code-analysis.ignoreFailures=true`
+1. Run `./gradlew aggregateViolations -Pgrails.code-style.ignoreFailures=true -Pgrails.code-analysis.ignoreFailures=true`
 2. Open `build/reports/violations/CODENARC_VIOLATIONS.md` and `build/reports/violations/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
@@ -209,7 +209,7 @@ All properties can be set in `gradle.properties` or passed as `-P` flags:
 
 All XML reports are consolidated at:
 ```
-build/reports/codestyle/        ← XML inputs for style aggregation
+build/reports/code-style/        ← XML inputs for style aggregation
 ├── checkstyle/
 │   ├── grails-core-checkstyleMain.xml
 │   ├── grails-web-mvc-checkstyleMain.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 898ed70de84..ab13aa909ae 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,97 +1,105 @@
+
 
-  
-    
+    
+        
 
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index f23d524925f..52768fe1ae3 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,25 @@
+
 
   
-    
 
\ No newline at end of file
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy
index 924958d4390..906740662a7 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GradleUtils.groovy
@@ -40,7 +40,7 @@ class GradleUtils {
 
     static Provider booleanProvider(Project project, String name, boolean defaultValue = false) {
         project.providers.gradleProperty(name)
-                .map { String it -> it.trim().toBoolean() }
+                .map { it.trim().toBoolean() }
                 .orElse(defaultValue)
     }
 
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
index dae4b7495fe..6b88166d909 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
@@ -94,7 +94,7 @@ class GrailsCodeAnalysisPlugin implements Plugin {
     }
 
     private static void createOrLoad(Path expectedPath, String defaultResource, Project project) {
-        boolean defaultPath = expectedPath.startsWith(project.rootProject.buildDir.toPath())
+        def defaultPath = expectedPath.startsWith(project.rootProject.layout.buildDirectory.get().asFile.toPath())
         if (!Files.exists(expectedPath) || expectedPath.size() == 0 || defaultPath) {
             def defaultValue = GrailsCodeAnalysisPlugin.getResourceAsStream(defaultResource)
             if (!defaultValue) {
@@ -106,15 +106,15 @@ class GrailsCodeAnalysisPlugin implements Plugin {
     }
 
     static void configurePmd(Project project) {
-        Provider pmdEnabled = GradleUtils.booleanProvider(project, PMD_ENABLED_PROPERTY)
+        def pmdEnabled = GradleUtils.booleanProvider(project, PMD_ENABLED_PROPERTY)
         if (!pmdEnabled.get()) {
             return
         }
 
         project.pluginManager.apply(PmdPlugin)
 
-        Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
-        Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_ANALYSIS_PROPERTY)
+        def ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
+        def testStylingEnabled = GradleUtils.booleanProvider(project, TEST_ANALYSIS_PROPERTY)
 
         project.extensions.configure(PmdExtension) {
             it.ruleSetFiles = project.files(project.extensions.getByType(GrailsCodeAnalysisExtension).pmdDirectory.file(PMD_CONFIG_FILE_NAME))
@@ -144,15 +144,15 @@ class GrailsCodeAnalysisPlugin implements Plugin {
     }
 
     static void configureSpotbugs(Project project) {
-        Provider spotbugsEnabled = GradleUtils.booleanProvider(project, SPOTBUGS_ENABLED_PROPERTY)
+        def spotbugsEnabled = GradleUtils.booleanProvider(project, SPOTBUGS_ENABLED_PROPERTY)
         if (!spotbugsEnabled.get()) {
             return
         }
 
         project.pluginManager.apply(SpotBugsPlugin)
 
-        Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
-        Provider testStylingEnabled = GradleUtils.booleanProvider(project, TEST_ANALYSIS_PROPERTY)
+        def ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
+        def testStylingEnabled = GradleUtils.booleanProvider(project, TEST_ANALYSIS_PROPERTY)
 
         project.extensions.configure(SpotBugsExtension) {
             it.effort.set(Effort.valueOf('MAX'))
@@ -162,10 +162,10 @@ class GrailsCodeAnalysisPlugin implements Plugin {
 
         project.tasks.withType(SpotBugsTask).configureEach { SpotBugsTask task ->
             task.group = 'verification'
-            NamedDomainObjectContainer spotBugsReports = task.reports
-            SpotBugsReport htmlReport = spotBugsReports.maybeCreate('html')
+            def spotBugsReports = task.reports
+            def htmlReport = spotBugsReports.maybeCreate('html')
             htmlReport.required.set(true)
-            SpotBugsReport xmlReport = spotBugsReports.maybeCreate('xml')
+            def xmlReport = spotBugsReports.maybeCreate('xml')
             xmlReport.required.set(true)
             xmlReport.outputLocation.set(
                 project.extensions.getByType(GrailsCodeAnalysisExtension)
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy
index 599e9c5ca3c..b52965ed7f9 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStyleExtension.groovy
@@ -30,19 +30,19 @@ import org.gradle.api.model.ObjectFactory
 class GrailsCodeStyleExtension {
 
     /**
-     * Defaults to project.rootProject.buildDir/codestyle/checkstyle.
+     * Defaults to rootProject.layout.buildDirectory/code-style/checkstyle.
      * Default checkstyle files will be written here and used from this location.
      */
     final DirectoryProperty checkstyleDirectory
 
     /**
-     * Defaults to project.rootProject.buildDir/codestyle/codenarc.
+     * Defaults to rootProject.layout.buildDirectory/code-style/codenarc.
      * Default codenarc files will be written here and used from this location.
      */
     final DirectoryProperty codenarcDirectory
 
     /**
-     * Defaults to rootProject.buildDir/reports/codestyle.
+     * Defaults to rootProject.layout.buildDirectory/reports/code-style.
      * All Checkstyle and Codenarc reports will be written here.
      */
     final DirectoryProperty reportsDirectory
@@ -50,13 +50,13 @@ class GrailsCodeStyleExtension {
     @Inject
     GrailsCodeStyleExtension(ObjectFactory objects, Project project) {
         checkstyleDirectory = objects.directoryProperty().convention(
-                project.rootProject.layout.buildDirectory.dir('codestyle/checkstyle')
+                project.rootProject.layout.buildDirectory.dir('code-style/checkstyle')
         )
         codenarcDirectory = objects.directoryProperty().convention(
-                project.rootProject.layout.buildDirectory.dir('codestyle/codenarc')
+                project.rootProject.layout.buildDirectory.dir('code-style/codenarc')
         )
         reportsDirectory = objects.directoryProperty().convention(
-                project.rootProject.layout.buildDirectory.dir('reports/codestyle')
+                project.rootProject.layout.buildDirectory.dir('reports/code-style')
         )
     }
 }
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy
index 0941c0b0ed7..1b6e8e7fabf 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy
@@ -40,20 +40,20 @@ import org.gradle.api.provider.Provider
 @CompileStatic
 class GrailsCodeStylePlugin implements Plugin {
 
-    static String CHECKSTYLE_DIR_PROPERTY = 'grails.codestyle.dir.checkstyle'
-    static String CHECKSTYLE_ENABLED_PROPERTY = 'grails.codestyle.enabled.checkstyle'
+    static String CHECKSTYLE_DIR_PROPERTY = 'grails.code-style.dir.checkstyle'
+    static String CHECKSTYLE_ENABLED_PROPERTY = 'grails.code-style.enabled.checkstyle'
     static String CHECKSTYLE_CONFIG_FILE_NAME = 'checkstyle.xml'
     static String CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME = 'checkstyle-suppressions.xml'
 
-    static String CODENARC_DIR_PROPERTY = 'grails.codestyle.dir.codenarc'
-    static String CODENARC_ENABLED_PROPERTY = 'grails.codestyle.enabled.codenarc'
+    static String CODENARC_DIR_PROPERTY = 'grails.code-style.dir.codenarc'
+    static String CODENARC_ENABLED_PROPERTY = 'grails.code-style.enabled.codenarc'
     static String CODENARC_CONFIG_FILE_NAME = 'codenarc.groovy'
 
-    static String CODENARC_FIX_PROPERTY = 'grails.codestyle.codenarc.fix'
+    static String CODENARC_FIX_PROPERTY = 'grails.code-style.codenarc.fix'
 
-    static String IGNORE_FAILURES_PROPERTY = 'grails.codestyle.ignoreFailures'
+    static String IGNORE_FAILURES_PROPERTY = 'grails.code-style.ignoreFailures'
 
-    static String TEST_STYLING_PROPERTY = 'grails.codestyle.enabled.tests'
+    static String TEST_STYLING_PROPERTY = 'grails.code-style.enabled.tests'
 
     static String BASE_RESOURCE_PATH = '/META-INF/org.apache.grails.buildsrc.grails-code-style'
 
@@ -71,7 +71,7 @@ class GrailsCodeStylePlugin implements Plugin {
         gce.checkstyleDirectory.set(project.provider {
             def directory = project.hasProperty(CHECKSTYLE_DIR_PROPERTY) ?
                     project.rootProject.layout.projectDirectory.dir(project.property(CHECKSTYLE_DIR_PROPERTY) as String) :
-                    project.rootProject.layout.buildDirectory.get().dir('codestyle').dir('checkstyle')
+                    project.rootProject.layout.buildDirectory.get().dir('code-style').dir('checkstyle')
 
             def toCreate = directory.asFile.toPath()
             Files.createDirectories(toCreate)
@@ -91,7 +91,7 @@ class GrailsCodeStylePlugin implements Plugin {
         gce.codenarcDirectory.set(project.provider {
             def directory = project.hasProperty(CODENARC_DIR_PROPERTY) ?
                     project.rootProject.layout.projectDirectory.dir(project.property(CODENARC_DIR_PROPERTY) as String) :
-                    project.rootProject.layout.buildDirectory.get().dir('codestyle').dir('codenarc')
+                    project.rootProject.layout.buildDirectory.get().dir('code-style').dir('codenarc')
 
             def toCreate = directory.asFile.toPath()
             Files.createDirectories(toCreate)
@@ -134,11 +134,11 @@ class GrailsCodeStylePlugin implements Plugin {
     static void configureCheckstyle(Project project) {
         project.pluginManager.apply(CheckstylePlugin)
 
-        Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
+        def ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
 
         project.extensions.configure(CheckstyleExtension) {
             // Explicit `it` is required in extension configuration
-            it.getConfigDirectory().set(project.extensions.getByType(GrailsCodeStyleExtension).checkstyleDirectory)
+            it.configDirectory.set(project.extensions.getByType(GrailsCodeStyleExtension).checkstyleDirectory)
             it.maxWarnings = 0
             it.showViolations = true
             it.ignoreFailures = ignoreFailures.get()
@@ -154,8 +154,10 @@ class GrailsCodeStylePlugin implements Plugin {
                 task.enabled = false
             }
 
+            // Exclude build directory from Checkstyle task sources to ignore generated sources (e.g. for grails-forge)
+            // Checked via absolute path to ensure platform-independent separator handling
             task.exclude { org.gradle.api.file.FileTreeElement element ->
-                element.getFile().getAbsolutePath().contains("/build/")
+                element.file.absolutePath.contains(File.separator + 'build' + File.separator)
             }
 
             // Redirect XML report output to a single directory to consolidate
@@ -174,8 +176,8 @@ class GrailsCodeStylePlugin implements Plugin {
 
         registerCodenarcFixTask(project)
 
-        Provider ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
-        Provider codenarcFix = GradleUtils.booleanProvider(project, CODENARC_FIX_PROPERTY)
+        def ignoreFailures = GradleUtils.booleanProvider(project, IGNORE_FAILURES_PROPERTY)
+        def codenarcFix = GradleUtils.booleanProvider(project, CODENARC_FIX_PROPERTY)
 
         project.extensions.configure(CodeNarcExtension) {
             it.configFile = project.extensions.getByType(GrailsCodeStyleExtension)
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
index 7e634d64ec5..f02a71310a3 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
@@ -21,8 +21,10 @@ package org.apache.grails.buildsrc
 import java.time.LocalDateTime
 import java.time.format.DateTimeFormatter
 
+import com.github.spotbugs.snom.SpotBugsTask
 import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
+import groovy.xml.XmlSlurper
 
 import org.gradle.api.GradleException
 import org.gradle.api.Plugin
@@ -40,9 +42,6 @@ import org.gradle.api.provider.Provider
 import org.gradle.api.tasks.TaskProvider
 import org.gradle.testing.jacoco.tasks.JacocoReport
 
-import com.github.spotbugs.snom.SpotBugsTask
-import groovy.xml.XmlSlurper
-
 /**
  * Root-only convention plugin that aggregates code-style violation XML reports and JaCoCo coverage
  * CSV reports into human-readable Markdown files under build/reports/violations/.
@@ -84,9 +83,9 @@ class GrailsViolationAggregationPlugin implements Plugin {
             )
         }
 
-        Provider violationsDir = project.layout.buildDirectory.dir('reports/violations')
-        Provider styleXmlDir = project.layout.buildDirectory.dir('reports/codestyle')
-        Provider analysisXmlDir = project.layout.buildDirectory.dir('reports/code-analysis')
+        def violationsDir = project.layout.buildDirectory.dir('reports/violations')
+        def styleXmlDir = project.layout.buildDirectory.dir('reports/code-style')
+        def analysisXmlDir = project.layout.buildDirectory.dir('reports/code-analysis')
 
         TaskProvider styleTask = registerStyleAggregation(project, styleXmlDir, violationsDir)
         TaskProvider analysisTask = registerAnalysisAggregation(project, analysisXmlDir, violationsDir)
@@ -195,24 +194,57 @@ class GrailsViolationAggregationPlugin implements Plugin {
         }
     }
 
-    @CompileDynamic
-    private static void parseStyleViolations(Directory styleXmlDir, Directory violationsDir,
-            boolean checkStyleTests, boolean codenarcEnabled, boolean checkstyleEnabled) {
+    private static XmlSlurper createSecureSlurper() {
         def slurper = new XmlSlurper()
         slurper.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true)
         slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false)
         slurper.setFeature('http://xml.org/sax/features/external-general-entities', false)
         slurper.setFeature('http://xml.org/sax/features/external-parameter-entities', false)
         slurper.setFeature('http://xml.org/sax/features/namespaces', false)
+        return slurper
+    }
 
-        def getModule = { String fileName ->
-            def lastDash = fileName.lastIndexOf('-')
-            lastDash != -1 ? fileName.substring(0, lastDash) : fileName
-        }
+    private static String getModule(String fileName) {
+        def lastDash = fileName.lastIndexOf('-')
+        lastDash != -1 ? fileName.substring(0, lastDash) : fileName
+    }
+
+    private static boolean isTestFile(String fileName) {
+        fileName.toLowerCase().contains('test') || fileName.toLowerCase().contains('integrationtest')
+    }
+
+    @CompileDynamic
+    private static void writeReport(Directory violationsDir, String fileName, List violations, String title) {
+        def outDir = violationsDir.asFile
+        outDir.mkdirs()
+        def reportFile = new File(outDir, fileName)
+        def out = new StringBuilder()
+        out.append("# ${title}\n")
+        out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n")
 
-        def isTestFile = { String fileName ->
-            fileName.toLowerCase().contains('test') || fileName.toLowerCase().contains('integrationtest')
+        if (violations.isEmpty()) {
+            out.append('No violations found! 🎉\n')
+        } else {
+            def uniqueViolations = violations.unique().sort { v -> "${v.module}:${v.className}:${v.line}" }
+            def groupedByModule = uniqueViolations.groupBy { it.module }.sort()
+            groupedByModule.each { module, modViolations ->
+                out.append("## Module: ${module}\n")
+                out.append('| Class | Tool | Violation | Line | Message |\n')
+                out.append('| :--- | :--- | :--- | :--- | :--- |\n')
+                modViolations.each { v ->
+                    out.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n")
+                }
+                out.append('\n')
+            }
         }
+        reportFile.text = out.toString()
+        LOGGER.lifecycle("Aggregated report generated: ${reportFile.absolutePath}")
+    }
+
+    @CompileDynamic
+    private static void parseStyleViolations(Directory styleXmlDir, Directory violationsDir,
+            boolean checkStyleTests, boolean codenarcEnabled, boolean checkstyleEnabled) {
+        def slurper = createSecureSlurper()
 
         def shouldSkipClass = { boolean includeTests, String className, String filePath = null ->
             if (includeTests) {
@@ -224,33 +256,6 @@ class GrailsViolationAggregationPlugin implements Plugin {
             !filePath && (className.contains('Spec') || className.contains('Test') || className.contains('Tests'))
         }
 
-        def writeReport = { String fileName, List violations, String title ->
-            def outDir = violationsDir.asFile
-            outDir.mkdirs()
-            def reportFile = new File(outDir, fileName)
-            def out = new StringBuilder()
-            out.append("# ${title}\n")
-            out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n")
-
-            if (violations.isEmpty()) {
-                out.append('No violations found! 🎉\n')
-            } else {
-                def uniqueViolations = violations.unique().sort { v -> "${v.module}:${v.className}:${v.line}" }
-                def groupedByModule = uniqueViolations.groupBy { it.module }.sort()
-                groupedByModule.each { module, modViolations ->
-                    out.append("## Module: ${module}\n")
-                    out.append('| Class | Tool | Violation | Line | Message |\n')
-                    out.append('| :--- | :--- | :--- | :--- | :--- |\n')
-                    modViolations.each { v ->
-                        out.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n")
-                    }
-                    out.append('\n')
-                }
-            }
-            reportFile.text = out.toString()
-            LOGGER.lifecycle("Aggregated report generated: ${reportFile.absolutePath}")
-        }
-
         // CodeNarc
         def codenarcViolations = []
         def codenarcDir = styleXmlDir.dir('codenarc').asFile
@@ -284,7 +289,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 }
             }
         }
-        writeReport('CODENARC_VIOLATIONS.md', codenarcViolations, 'CodeNarc Violations Summary')
+        writeReport(violationsDir, 'CODENARC_VIOLATIONS.md', codenarcViolations, 'CodeNarc Violations Summary')
 
         // Checkstyle
         def checkstyleViolations = []
@@ -320,27 +325,13 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 }
             }
         }
-        writeReport('CHECKSTYLE_VIOLATIONS.md', checkstyleViolations, 'Checkstyle Violations Summary')
+        writeReport(violationsDir, 'CHECKSTYLE_VIOLATIONS.md', checkstyleViolations, 'Checkstyle Violations Summary')
     }
 
     @CompileDynamic
     private static void parseAnalysisViolations(Directory analysisXmlDir, Directory violationsDir,
             boolean checkAnalysisTests, boolean pmdEnabled, boolean spotbugsEnabled) {
-        def slurper = new XmlSlurper()
-        slurper.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true)
-        slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false)
-        slurper.setFeature('http://xml.org/sax/features/external-general-entities', false)
-        slurper.setFeature('http://xml.org/sax/features/external-parameter-entities', false)
-        slurper.setFeature('http://xml.org/sax/features/namespaces', false)
-
-        def getModule = { String fileName ->
-            def lastDash = fileName.lastIndexOf('-')
-            lastDash != -1 ? fileName.substring(0, lastDash) : fileName
-        }
-
-        def isTestFile = { String fileName ->
-            fileName.toLowerCase().contains('test') || fileName.toLowerCase().contains('integrationtest')
-        }
+        def slurper = createSecureSlurper()
 
         def shouldSkipClass = { boolean includeTests, String className ->
             if (includeTests) {
@@ -349,33 +340,6 @@ class GrailsViolationAggregationPlugin implements Plugin {
             className.contains('Spec') || className.contains('Test') || className.contains('Tests')
         }
 
-        def writeReport = { String fileName, List violations, String title ->
-            def outDir = violationsDir.asFile
-            outDir.mkdirs()
-            def reportFile = new File(outDir, fileName)
-            def out = new StringBuilder()
-            out.append("# ${title}\n")
-            out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n")
-
-            if (violations.isEmpty()) {
-                out.append('No violations found! 🎉\n')
-            } else {
-                def uniqueViolations = violations.unique().sort { v -> "${v.module}:${v.className}:${v.line}" }
-                def groupedByModule = uniqueViolations.groupBy { it.module }.sort()
-                groupedByModule.each { module, modViolations ->
-                    out.append("## Module: ${module}\n")
-                    out.append('| Class | Tool | Violation | Line | Message |\n')
-                    out.append('| :--- | :--- | :--- | :--- | :--- |\n')
-                    modViolations.each { v ->
-                        out.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n")
-                    }
-                    out.append('\n')
-                }
-            }
-            reportFile.text = out.toString()
-            LOGGER.lifecycle("Aggregated report generated: ${reportFile.absolutePath}")
-        }
-
         // PMD
         def pmdViolations = []
         def pmdDir = analysisXmlDir.dir('pmd').asFile
@@ -404,7 +368,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 }
             }
         }
-        writeReport('PMD_VIOLATIONS.md', pmdViolations, 'PMD Violations Summary')
+        writeReport(violationsDir, 'PMD_VIOLATIONS.md', pmdViolations, 'PMD Violations Summary')
 
         // SpotBugs
         def spotbugsViolations = []
@@ -432,7 +396,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 }
             }
         }
-        writeReport('SPOTBUGS_VIOLATIONS.md', spotbugsViolations, 'SpotBugs Violations Summary')
+        writeReport(violationsDir, 'SPOTBUGS_VIOLATIONS.md', spotbugsViolations, 'SpotBugs Violations Summary')
     }
 
     @CompileDynamic
diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy
index 3620c119c16..46c9246992a 100644
--- a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy
+++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsCodeStylePluginSpec.groovy
@@ -19,6 +19,7 @@
 package org.apache.grails.buildsrc
 
 import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
 import spock.lang.Specification
 import spock.lang.TempDir
 import java.nio.file.Path
@@ -70,7 +71,7 @@ class Test{
                 .build()
 
         then: "task finished successfully"
-        result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS
+        result.task(':codenarcFix').outcome == TaskOutcome.SUCCESS
 
         and: "violations are fixed"
         def fixedContent = groovyFile.text
@@ -101,7 +102,7 @@ class Test {
                 .build()
 
         then: "task finished successfully"
-        result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS
+        result.task(':codenarcFix').outcome == TaskOutcome.SUCCESS
 
         and: "strings with single quotes are NOT changed to single quotes (which would break them)"
         def content = groovyFile.text
@@ -127,7 +128,7 @@ class Test {
                 .build()
 
         then: "task finished successfully"
-        result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS
+        result.task(':codenarcFix').outcome == TaskOutcome.SUCCESS
 
         and: "escaped quotes are NOT broken"
         groovyFile.text.contains('"\\"\\$it\\""')
@@ -153,7 +154,7 @@ class Test {
                 .build()
 
         then: "task finished successfully"
-        result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS
+        result.task(':codenarcFix').outcome == TaskOutcome.SUCCESS
 
         and: "method references are NOT broken"
         def content = groovyFile.text
@@ -184,7 +185,7 @@ class Test {
                 .build()
 
         then: "task finished successfully"
-        result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS
+        result.task(':codenarcFix').outcome == TaskOutcome.SUCCESS
 
         and: "adjacent GString boundaries are NOT fused"
         def content = groovyFile.text
@@ -212,7 +213,7 @@ class Test {
                 .build()
 
         then: "task finished successfully"
-        result.task(':codenarcFix').outcome == org.gradle.testkit.runner.TaskOutcome.SUCCESS
+        result.task(':codenarcFix').outcome == TaskOutcome.SUCCESS
 
         and: "double quotes inside single-quoted strings are NOT changed"
         def content = groovyFile.text
diff --git a/grails-forge/gradle.properties b/grails-forge/gradle.properties
index 0a3e6f66906..7e7d48df5fc 100644
--- a/grails-forge/gradle.properties
+++ b/grails-forge/gradle.properties
@@ -60,7 +60,7 @@ testRetryVersion=1.6.2
 typesafeConfigVersion=1.4.3
 
 # custom checkstyle configuration for forge
-grails.codestyle.dir.checkstyle=config/checkstyle
+grails.code-style.dir.checkstyle=config/checkstyle
 
 org.gradle.parallel=true
 org.gradle.caching=true

From 6d79c8addcb7cc1eb3300a588db14a44dbcafba4 Mon Sep 17 00:00:00 2001
From: James Fredley 
Date: Mon, 1 Jun 2026 18:22:23 -0400
Subject: [PATCH 12/16] Limit grails-code-analysis to its original scope

The grails-code-analysis (PMD + SpotBugs) convention plugin had been
applied to 96 subprojects. Its original Hibernate 7 scope was a single
module, so applying it project-wide surfaced thousands of findings and
expanded this PR well beyond its intent.

Remove the grails-code-analysis plugin application from every subproject.
The convention plugin stays registered in build-logic as available
infrastructure and will be re-applied to the relevant module(s) when the
Hibernate 7 work is merged back in.

Assisted-by: claude-code:claude-opus-4-8
---
 grails-async/core/build.gradle                           | 1 -
 grails-async/gpars/build.gradle                          | 1 -
 grails-async/plugin/build.gradle                         | 1 -
 grails-async/rxjava/build.gradle                         | 1 -
 grails-async/rxjava2/build.gradle                        | 1 -
 grails-async/rxjava3/build.gradle                        | 1 -
 grails-bootstrap/build.gradle                            | 1 -
 grails-cache/build.gradle                                | 1 -
 grails-codecs-core/build.gradle                          | 1 -
 grails-codecs/build.gradle                               | 1 -
 grails-common/build.gradle                               | 1 -
 grails-console/build.gradle                              | 1 -
 grails-controllers/build.gradle                          | 1 -
 grails-converters/build.gradle                           | 1 -
 grails-core/build.gradle                                 | 1 -
 grails-data-hibernate5/boot-plugin/build.gradle          | 1 -
 grails-data-hibernate5/core/build.gradle                 | 1 -
 grails-data-hibernate5/dbmigration/build.gradle          | 1 -
 grails-data-hibernate5/grails-plugin/build.gradle        | 1 -
 grails-data-hibernate5/spring-orm/build.gradle           | 1 -
 grails-data-mongodb/boot-plugin/build.gradle             | 1 -
 grails-data-mongodb/bson/build.gradle                    | 1 -
 grails-data-mongodb/core/build.gradle                    | 1 -
 grails-data-mongodb/ext/build.gradle                     | 1 -
 grails-data-mongodb/grails-plugin/build.gradle           | 1 -
 grails-data-mongodb/gson-templates/build.gradle          | 1 -
 grails-data-simple/build.gradle                          | 1 -
 grails-databinding-core/build.gradle                     | 1 -
 grails-databinding/build.gradle                          | 1 -
 grails-datamapping-async/build.gradle                    | 1 -
 grails-datamapping-core/build.gradle                     | 1 -
 grails-datamapping-rx/build.gradle                       | 1 -
 grails-datamapping-support/build.gradle                  | 1 -
 grails-datamapping-tck/build.gradle                      | 1 -
 grails-datamapping-validation/build.gradle               | 1 -
 grails-datasource/build.gradle                           | 1 -
 grails-datastore-async/build.gradle                      | 1 -
 grails-datastore-core/build.gradle                       | 1 -
 grails-datastore-web/build.gradle                        | 1 -
 grails-domain-class/build.gradle                         | 1 -
 grails-encoder/build.gradle                              | 1 -
 grails-events/core/build.gradle                          | 1 -
 grails-events/gpars/build.gradle                         | 1 -
 grails-events/plugin/build.gradle                        | 1 -
 grails-events/rxjava/build.gradle                        | 1 -
 grails-events/rxjava2/build.gradle                       | 1 -
 grails-events/rxjava3/build.gradle                       | 1 -
 grails-events/spring/build.gradle                        | 1 -
 grails-events/transforms/build.gradle                    | 1 -
 grails-fields/build.gradle                               | 1 -
 grails-geb/build.gradle                                  | 1 -
 grails-gradle/common/build.gradle                        | 1 -
 grails-gradle/model/build.gradle                         | 1 -
 grails-gradle/plugins/build.gradle                       | 1 -
 grails-gradle/tasks/build.gradle                         | 1 -
 grails-gsp/core/build.gradle                             | 1 -
 grails-gsp/grails-layout/build.gradle                    | 1 -
 grails-gsp/grails-sitemesh3/build.gradle                 | 1 -
 grails-gsp/grails-taglib/build.gradle                    | 1 -
 grails-gsp/grails-web-gsp-taglib/build.gradle            | 1 -
 grails-gsp/grails-web-gsp/build.gradle                   | 1 -
 grails-gsp/grails-web-jsp/build.gradle                   | 1 -
 grails-gsp/grails-web-taglib/build.gradle                | 1 -
 grails-gsp/plugin/build.gradle                           | 1 -
 grails-i18n/build.gradle                                 | 1 -
 grails-interceptors/build.gradle                         | 1 -
 grails-logging/build.gradle                              | 1 -
 grails-mimetypes/build.gradle                            | 1 -
 grails-rest-transforms/build.gradle                      | 1 -
 grails-scaffolding/build.gradle                          | 1 -
 grails-services/build.gradle                             | 1 -
 grails-shell-cli/build.gradle                            | 1 -
 grails-spring/build.gradle                               | 1 -
 grails-test-core/build.gradle                            | 1 -
 grails-test-suite-base/build.gradle                      | 1 -
 grails-testing-support-core/build.gradle                 | 1 -
 grails-testing-support-datamapping/build.gradle          | 1 -
 grails-testing-support-dbcleanup-core/build.gradle       | 1 -
 grails-testing-support-dbcleanup-h2/build.gradle         | 1 -
 grails-testing-support-dbcleanup-postgresql/build.gradle | 1 -
 grails-testing-support-http-client/build.gradle          | 1 -
 grails-testing-support-mongodb/build.gradle              | 1 -
 grails-testing-support-views-gson/build.gradle           | 1 -
 grails-testing-support-web/build.gradle                  | 1 -
 grails-url-mappings/build.gradle                         | 1 -
 grails-validation/build.gradle                           | 1 -
 grails-views-core/build.gradle                           | 1 -
 grails-views-gson/build.gradle                           | 1 -
 grails-views-markup/build.gradle                         | 1 -
 grails-web-boot/build.gradle                             | 1 -
 grails-web-common/build.gradle                           | 1 -
 grails-web-core/build.gradle                             | 1 -
 grails-web-databinding/build.gradle                      | 1 -
 grails-web-mvc/build.gradle                              | 1 -
 grails-web-url-mappings/build.gradle                     | 1 -
 grails-wrapper/build.gradle                              | 1 -
 96 files changed, 96 deletions(-)

diff --git a/grails-async/core/build.gradle b/grails-async/core/build.gradle
index b2f5f45bc13..cee4816f2ea 100644
--- a/grails-async/core/build.gradle
+++ b/grails-async/core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-async/gpars/build.gradle b/grails-async/gpars/build.gradle
index e30f7d2e281..8c8d001b266 100644
--- a/grails-async/gpars/build.gradle
+++ b/grails-async/gpars/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-async/plugin/build.gradle b/grails-async/plugin/build.gradle
index 73984e20e09..c6d1f34085a 100644
--- a/grails-async/plugin/build.gradle
+++ b/grails-async/plugin/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-async/rxjava/build.gradle b/grails-async/rxjava/build.gradle
index 9494becc598..0bc5e0a8c71 100644
--- a/grails-async/rxjava/build.gradle
+++ b/grails-async/rxjava/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-async/rxjava2/build.gradle b/grails-async/rxjava2/build.gradle
index aa269ef1b8d..1e3d564320a 100644
--- a/grails-async/rxjava2/build.gradle
+++ b/grails-async/rxjava2/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-async/rxjava3/build.gradle b/grails-async/rxjava3/build.gradle
index 25e643124b4..d5c36cb6f4b 100644
--- a/grails-async/rxjava3/build.gradle
+++ b/grails-async/rxjava3/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-bootstrap/build.gradle b/grails-bootstrap/build.gradle
index 22b423f1494..8326c9da519 100644
--- a/grails-bootstrap/build.gradle
+++ b/grails-bootstrap/build.gradle
@@ -29,7 +29,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-cache/build.gradle b/grails-cache/build.gradle
index 45c83921c40..9d607d16ca0 100644
--- a/grails-cache/build.gradle
+++ b/grails-cache/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-codecs-core/build.gradle b/grails-codecs-core/build.gradle
index 8b952e765f4..a6e2562f863 100644
--- a/grails-codecs-core/build.gradle
+++ b/grails-codecs-core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-codecs/build.gradle b/grails-codecs/build.gradle
index 47fbaab85cd..0e612cbb19b 100644
--- a/grails-codecs/build.gradle
+++ b/grails-codecs/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-common/build.gradle b/grails-common/build.gradle
index f6ca3c40f17..8957177a9ab 100644
--- a/grails-common/build.gradle
+++ b/grails-common/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-console/build.gradle b/grails-console/build.gradle
index 21b341638da..d3ec60a3f1d 100644
--- a/grails-console/build.gradle
+++ b/grails-console/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-controllers/build.gradle b/grails-controllers/build.gradle
index 962430281be..dc68dacf8fe 100644
--- a/grails-controllers/build.gradle
+++ b/grails-controllers/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-converters/build.gradle b/grails-converters/build.gradle
index 22e3e605e1a..0bb79ca3763 100644
--- a/grails-converters/build.gradle
+++ b/grails-converters/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-core/build.gradle b/grails-core/build.gradle
index bbea195d0db..7e486bfaaef 100644
--- a/grails-core/build.gradle
+++ b/grails-core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-hibernate5/boot-plugin/build.gradle b/grails-data-hibernate5/boot-plugin/build.gradle
index 6dfcb4389df..2c6c0aa6273 100644
--- a/grails-data-hibernate5/boot-plugin/build.gradle
+++ b/grails-data-hibernate5/boot-plugin/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-hibernate5/core/build.gradle b/grails-data-hibernate5/core/build.gradle
index 4838afb4afd..1f77e3657d3 100644
--- a/grails-data-hibernate5/core/build.gradle
+++ b/grails-data-hibernate5/core/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-hibernate5/dbmigration/build.gradle b/grails-data-hibernate5/dbmigration/build.gradle
index 342dbcfb17a..3a74dd04290 100644
--- a/grails-data-hibernate5/dbmigration/build.gradle
+++ b/grails-data-hibernate5/dbmigration/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-hibernate5/grails-plugin/build.gradle b/grails-data-hibernate5/grails-plugin/build.gradle
index dd0a1a13dea..22fd52fe58e 100644
--- a/grails-data-hibernate5/grails-plugin/build.gradle
+++ b/grails-data-hibernate5/grails-plugin/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-hibernate5/spring-orm/build.gradle b/grails-data-hibernate5/spring-orm/build.gradle
index 6e65fbdc636..3713dfb9ccf 100644
--- a/grails-data-hibernate5/spring-orm/build.gradle
+++ b/grails-data-hibernate5/spring-orm/build.gradle
@@ -28,7 +28,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-mongodb/boot-plugin/build.gradle b/grails-data-mongodb/boot-plugin/build.gradle
index 31a76648f24..572e90fa09e 100644
--- a/grails-data-mongodb/boot-plugin/build.gradle
+++ b/grails-data-mongodb/boot-plugin/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-mongodb/bson/build.gradle b/grails-data-mongodb/bson/build.gradle
index 6c1e0243bb8..1ac2663ee71 100644
--- a/grails-data-mongodb/bson/build.gradle
+++ b/grails-data-mongodb/bson/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-mongodb/core/build.gradle b/grails-data-mongodb/core/build.gradle
index 94c1e6d97e1..f080478090f 100644
--- a/grails-data-mongodb/core/build.gradle
+++ b/grails-data-mongodb/core/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-mongodb/ext/build.gradle b/grails-data-mongodb/ext/build.gradle
index 982b44960db..f8271315be4 100644
--- a/grails-data-mongodb/ext/build.gradle
+++ b/grails-data-mongodb/ext/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-mongodb/grails-plugin/build.gradle b/grails-data-mongodb/grails-plugin/build.gradle
index c22e6dca21e..1ace1bc70db 100644
--- a/grails-data-mongodb/grails-plugin/build.gradle
+++ b/grails-data-mongodb/grails-plugin/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-mongodb/gson-templates/build.gradle b/grails-data-mongodb/gson-templates/build.gradle
index da0d0758faa..445f6f36760 100644
--- a/grails-data-mongodb/gson-templates/build.gradle
+++ b/grails-data-mongodb/gson-templates/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-data-simple/build.gradle b/grails-data-simple/build.gradle
index 1290a63ad55..22567f865ca 100644
--- a/grails-data-simple/build.gradle
+++ b/grails-data-simple/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-databinding-core/build.gradle b/grails-databinding-core/build.gradle
index cee4c8051b6..cf2bf90b51d 100644
--- a/grails-databinding-core/build.gradle
+++ b/grails-databinding-core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-databinding/build.gradle b/grails-databinding/build.gradle
index 363c0012853..86b4fe0f048 100644
--- a/grails-databinding/build.gradle
+++ b/grails-databinding/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datamapping-async/build.gradle b/grails-datamapping-async/build.gradle
index 00c2afdff4a..a2731948935 100644
--- a/grails-datamapping-async/build.gradle
+++ b/grails-datamapping-async/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datamapping-core/build.gradle b/grails-datamapping-core/build.gradle
index 700db6df885..9eb9a7412ce 100644
--- a/grails-datamapping-core/build.gradle
+++ b/grails-datamapping-core/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datamapping-rx/build.gradle b/grails-datamapping-rx/build.gradle
index e0d5c9d6ea9..66157ce4594 100644
--- a/grails-datamapping-rx/build.gradle
+++ b/grails-datamapping-rx/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datamapping-support/build.gradle b/grails-datamapping-support/build.gradle
index 78a342a5c8d..95656e2b87d 100644
--- a/grails-datamapping-support/build.gradle
+++ b/grails-datamapping-support/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datamapping-tck/build.gradle b/grails-datamapping-tck/build.gradle
index bc42a8baa44..15e7de95097 100644
--- a/grails-datamapping-tck/build.gradle
+++ b/grails-datamapping-tck/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datamapping-validation/build.gradle b/grails-datamapping-validation/build.gradle
index accbf04ac20..0748bcffd95 100644
--- a/grails-datamapping-validation/build.gradle
+++ b/grails-datamapping-validation/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datasource/build.gradle b/grails-datasource/build.gradle
index c6cf03293e3..a6ed818743b 100644
--- a/grails-datasource/build.gradle
+++ b/grails-datasource/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datastore-async/build.gradle b/grails-datastore-async/build.gradle
index edb0d968a26..68f9ed6685b 100644
--- a/grails-datastore-async/build.gradle
+++ b/grails-datastore-async/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datastore-core/build.gradle b/grails-datastore-core/build.gradle
index 85da8ab7a1c..8750516d37a 100644
--- a/grails-datastore-core/build.gradle
+++ b/grails-datastore-core/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-datastore-web/build.gradle b/grails-datastore-web/build.gradle
index 7589e7531e9..138497f193b 100644
--- a/grails-datastore-web/build.gradle
+++ b/grails-datastore-web/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-domain-class/build.gradle b/grails-domain-class/build.gradle
index 95103142436..a34f2607f95 100644
--- a/grails-domain-class/build.gradle
+++ b/grails-domain-class/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-encoder/build.gradle b/grails-encoder/build.gradle
index 692cf98566a..a1cac6930e8 100644
--- a/grails-encoder/build.gradle
+++ b/grails-encoder/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/core/build.gradle b/grails-events/core/build.gradle
index fed99b5dd2d..0c68efd5606 100644
--- a/grails-events/core/build.gradle
+++ b/grails-events/core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/gpars/build.gradle b/grails-events/gpars/build.gradle
index 3e80b36094f..ad365eceee4 100644
--- a/grails-events/gpars/build.gradle
+++ b/grails-events/gpars/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/plugin/build.gradle b/grails-events/plugin/build.gradle
index 5069cad90fe..d2cc1e24455 100644
--- a/grails-events/plugin/build.gradle
+++ b/grails-events/plugin/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/rxjava/build.gradle b/grails-events/rxjava/build.gradle
index d53e072abcd..312477fefae 100644
--- a/grails-events/rxjava/build.gradle
+++ b/grails-events/rxjava/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/rxjava2/build.gradle b/grails-events/rxjava2/build.gradle
index 43791ba91fb..5a107dd9241 100644
--- a/grails-events/rxjava2/build.gradle
+++ b/grails-events/rxjava2/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/rxjava3/build.gradle b/grails-events/rxjava3/build.gradle
index 2daa711d671..efca93c18dd 100644
--- a/grails-events/rxjava3/build.gradle
+++ b/grails-events/rxjava3/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/spring/build.gradle b/grails-events/spring/build.gradle
index caefaf3ef6c..c568f926238 100644
--- a/grails-events/spring/build.gradle
+++ b/grails-events/spring/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-events/transforms/build.gradle b/grails-events/transforms/build.gradle
index b8797a4699e..778980c0951 100644
--- a/grails-events/transforms/build.gradle
+++ b/grails-events/transforms/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-fields/build.gradle b/grails-fields/build.gradle
index 1b30c8c623f..1ed72931b9b 100644
--- a/grails-fields/build.gradle
+++ b/grails-fields/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-geb/build.gradle b/grails-geb/build.gradle
index db3b5b47ea5..160bdf8e955 100644
--- a/grails-geb/build.gradle
+++ b/grails-geb/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gradle/common/build.gradle b/grails-gradle/common/build.gradle
index 9ec66022fff..7d05cb8211f 100644
--- a/grails-gradle/common/build.gradle
+++ b/grails-gradle/common/build.gradle
@@ -24,7 +24,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gradle/model/build.gradle b/grails-gradle/model/build.gradle
index 2cd0762d4de..23f4e81e021 100644
--- a/grails-gradle/model/build.gradle
+++ b/grails-gradle/model/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gradle/plugins/build.gradle b/grails-gradle/plugins/build.gradle
index 78bca0abee3..405b5d4462e 100644
--- a/grails-gradle/plugins/build.gradle
+++ b/grails-gradle/plugins/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gradle/tasks/build.gradle b/grails-gradle/tasks/build.gradle
index 5970381fa23..a994c5f868c 100644
--- a/grails-gradle/tasks/build.gradle
+++ b/grails-gradle/tasks/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/core/build.gradle b/grails-gsp/core/build.gradle
index a032e6f9742..e55a044be70 100644
--- a/grails-gsp/core/build.gradle
+++ b/grails-gsp/core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-layout/build.gradle b/grails-gsp/grails-layout/build.gradle
index 59e02446ec0..32eb8c13c35 100644
--- a/grails-gsp/grails-layout/build.gradle
+++ b/grails-gsp/grails-layout/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-sitemesh3/build.gradle b/grails-gsp/grails-sitemesh3/build.gradle
index 494e1dd0c92..676039b0355 100644
--- a/grails-gsp/grails-sitemesh3/build.gradle
+++ b/grails-gsp/grails-sitemesh3/build.gradle
@@ -26,7 +26,6 @@ plugins {
     // TODO: id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-taglib/build.gradle b/grails-gsp/grails-taglib/build.gradle
index 6ddf4cdd5c5..55c91cfe45a 100644
--- a/grails-gsp/grails-taglib/build.gradle
+++ b/grails-gsp/grails-taglib/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-web-gsp-taglib/build.gradle b/grails-gsp/grails-web-gsp-taglib/build.gradle
index e29c66a4ae4..869592160cd 100644
--- a/grails-gsp/grails-web-gsp-taglib/build.gradle
+++ b/grails-gsp/grails-web-gsp-taglib/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-web-gsp/build.gradle b/grails-gsp/grails-web-gsp/build.gradle
index b5c19fef864..f9df4c2edd1 100644
--- a/grails-gsp/grails-web-gsp/build.gradle
+++ b/grails-gsp/grails-web-gsp/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-web-jsp/build.gradle b/grails-gsp/grails-web-jsp/build.gradle
index 92a20f8bcd2..77760958190 100644
--- a/grails-gsp/grails-web-jsp/build.gradle
+++ b/grails-gsp/grails-web-jsp/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/grails-web-taglib/build.gradle b/grails-gsp/grails-web-taglib/build.gradle
index f6c5fed7d1e..a69196b1140 100644
--- a/grails-gsp/grails-web-taglib/build.gradle
+++ b/grails-gsp/grails-web-taglib/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-gsp/plugin/build.gradle b/grails-gsp/plugin/build.gradle
index 82e924f5a12..767a130825b 100644
--- a/grails-gsp/plugin/build.gradle
+++ b/grails-gsp/plugin/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-i18n/build.gradle b/grails-i18n/build.gradle
index c08aa68d99e..ad7785dbfc6 100644
--- a/grails-i18n/build.gradle
+++ b/grails-i18n/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-interceptors/build.gradle b/grails-interceptors/build.gradle
index a54d1af3542..7d18d14b91e 100644
--- a/grails-interceptors/build.gradle
+++ b/grails-interceptors/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-logging/build.gradle b/grails-logging/build.gradle
index 40ca7b5ae21..9ba07de8269 100644
--- a/grails-logging/build.gradle
+++ b/grails-logging/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-mimetypes/build.gradle b/grails-mimetypes/build.gradle
index 20cd89b716d..0391a333643 100644
--- a/grails-mimetypes/build.gradle
+++ b/grails-mimetypes/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-rest-transforms/build.gradle b/grails-rest-transforms/build.gradle
index ad80cb4057f..3cbfdba682f 100644
--- a/grails-rest-transforms/build.gradle
+++ b/grails-rest-transforms/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-scaffolding/build.gradle b/grails-scaffolding/build.gradle
index 93dfa5f2a48..49020837a18 100644
--- a/grails-scaffolding/build.gradle
+++ b/grails-scaffolding/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-services/build.gradle b/grails-services/build.gradle
index c13a91ef248..eda69a8eafd 100644
--- a/grails-services/build.gradle
+++ b/grails-services/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-shell-cli/build.gradle b/grails-shell-cli/build.gradle
index b63e2a865ce..1843aa8825c 100644
--- a/grails-shell-cli/build.gradle
+++ b/grails-shell-cli/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-spring/build.gradle b/grails-spring/build.gradle
index 45048ac9c32..574091c26e5 100644
--- a/grails-spring/build.gradle
+++ b/grails-spring/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-test-core/build.gradle b/grails-test-core/build.gradle
index f23de34dc12..82af7708ce1 100644
--- a/grails-test-core/build.gradle
+++ b/grails-test-core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-test-suite-base/build.gradle b/grails-test-suite-base/build.gradle
index 6e5b9a320d0..453cb33570f 100644
--- a/grails-test-suite-base/build.gradle
+++ b/grails-test-suite-base/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.dependency-validator'
     id 'org.apache.grails.buildsrc.compile'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-core/build.gradle b/grails-testing-support-core/build.gradle
index 223b2a9ba9d..11d60439dd5 100644
--- a/grails-testing-support-core/build.gradle
+++ b/grails-testing-support-core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-datamapping/build.gradle b/grails-testing-support-datamapping/build.gradle
index 715fbe3f983..09f4203521e 100755
--- a/grails-testing-support-datamapping/build.gradle
+++ b/grails-testing-support-datamapping/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-dbcleanup-core/build.gradle b/grails-testing-support-dbcleanup-core/build.gradle
index 70f9682077e..7368f6dee10 100644
--- a/grails-testing-support-dbcleanup-core/build.gradle
+++ b/grails-testing-support-dbcleanup-core/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 
diff --git a/grails-testing-support-dbcleanup-h2/build.gradle b/grails-testing-support-dbcleanup-h2/build.gradle
index 2bc1cc0adff..c12e761a303 100644
--- a/grails-testing-support-dbcleanup-h2/build.gradle
+++ b/grails-testing-support-dbcleanup-h2/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 
diff --git a/grails-testing-support-dbcleanup-postgresql/build.gradle b/grails-testing-support-dbcleanup-postgresql/build.gradle
index 6ff298cbc1e..3644ad14619 100644
--- a/grails-testing-support-dbcleanup-postgresql/build.gradle
+++ b/grails-testing-support-dbcleanup-postgresql/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-http-client/build.gradle b/grails-testing-support-http-client/build.gradle
index 7d8119d07d2..ddb22c96564 100644
--- a/grails-testing-support-http-client/build.gradle
+++ b/grails-testing-support-http-client/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-mongodb/build.gradle b/grails-testing-support-mongodb/build.gradle
index cad012a5cb0..be2333a4500 100644
--- a/grails-testing-support-mongodb/build.gradle
+++ b/grails-testing-support-mongodb/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-views-gson/build.gradle b/grails-testing-support-views-gson/build.gradle
index c847e79679a..7bfcc80cfec 100644
--- a/grails-testing-support-views-gson/build.gradle
+++ b/grails-testing-support-views-gson/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-testing-support-web/build.gradle b/grails-testing-support-web/build.gradle
index 6b362c056de..385b7bca5da 100755
--- a/grails-testing-support-web/build.gradle
+++ b/grails-testing-support-web/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-url-mappings/build.gradle b/grails-url-mappings/build.gradle
index 9e548d1212b..720b4ba50dd 100644
--- a/grails-url-mappings/build.gradle
+++ b/grails-url-mappings/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-validation/build.gradle b/grails-validation/build.gradle
index 38b907bf6d2..22cf4c820a1 100644
--- a/grails-validation/build.gradle
+++ b/grails-validation/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-views-core/build.gradle b/grails-views-core/build.gradle
index d30a0d560da..3da0370d06d 100644
--- a/grails-views-core/build.gradle
+++ b/grails-views-core/build.gradle
@@ -26,7 +26,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-views-gson/build.gradle b/grails-views-gson/build.gradle
index de8b38ed5f6..3848ebd373a 100644
--- a/grails-views-gson/build.gradle
+++ b/grails-views-gson/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-views-markup/build.gradle b/grails-views-markup/build.gradle
index 48de6f7f0cb..6d6bc3da1bd 100644
--- a/grails-views-markup/build.gradle
+++ b/grails-views-markup/build.gradle
@@ -25,7 +25,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-web-boot/build.gradle b/grails-web-boot/build.gradle
index 3dbbd9fde67..755fe01739f 100644
--- a/grails-web-boot/build.gradle
+++ b/grails-web-boot/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-web-common/build.gradle b/grails-web-common/build.gradle
index ff03053790d..1053fba613f 100644
--- a/grails-web-common/build.gradle
+++ b/grails-web-common/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-web-core/build.gradle b/grails-web-core/build.gradle
index cd9b52c6580..2b60e56ea90 100644
--- a/grails-web-core/build.gradle
+++ b/grails-web-core/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-web-databinding/build.gradle b/grails-web-databinding/build.gradle
index 92b7aecc41e..3fc3cd3578f 100644
--- a/grails-web-databinding/build.gradle
+++ b/grails-web-databinding/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-web-mvc/build.gradle b/grails-web-mvc/build.gradle
index d16e9f41f32..ac72a8621b2 100644
--- a/grails-web-mvc/build.gradle
+++ b/grails-web-mvc/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-web-url-mappings/build.gradle b/grails-web-url-mappings/build.gradle
index 06c6b87870d..adcd1f6579c 100644
--- a/grails-web-url-mappings/build.gradle
+++ b/grails-web-url-mappings/build.gradle
@@ -27,7 +27,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion
diff --git a/grails-wrapper/build.gradle b/grails-wrapper/build.gradle
index 71a80b3ee42..d51388ab06d 100644
--- a/grails-wrapper/build.gradle
+++ b/grails-wrapper/build.gradle
@@ -24,7 +24,6 @@ plugins {
     id 'org.apache.grails.buildsrc.publish'
     id 'org.apache.grails.buildsrc.sbom'
     id 'org.apache.grails.gradle.grails-code-style'
-    id 'org.apache.grails.gradle.grails-code-analysis'
 }
 
 version = projectVersion

From b08441587dc3b1e01173d2e7cf7da0bfb22dde16 Mon Sep 17 00:00:00 2001
From: James Fredley 
Date: Mon, 1 Jun 2026 18:22:58 -0400
Subject: [PATCH 13/16] Restore code style configuration to the 8.0.x baseline

This PR is meant to add code-analysis tooling, not to change existing
code style. It had diverged from 8.0.x in grails-forge and in the
grails-code-style plugin; revert that divergence.

- grails-forge: restore to byte-identical 8.0.x. This brings back its own
  Checkstyle ruleset and Spotless configuration and discards the
  reformatting of 217 source files. grails-forge keeps its separate, more
  lenient rule set, so its code style job passes as before.
- grails-code-style plugin: keep the legacy 'grails.codestyle.dir.*'
  property-override keys. grails-forge/gradle.properties (now identical to
  8.0.x) is the only setter, and the plugin is the only reader; renaming
  them would make grails-forge fall back to the bundled strict ruleset.
- Revert createOrLoad() to the original create-only-if-missing behavior
  (per review feedback from @jdaugherty).
- codestyle.yml: the Forge job runs 'codeStyle' again, since grails-forge
  no longer applies the violation-aggregation plugin.
- Update the violation-fixer skill doc to the legacy property keys.

Assisted-by: claude-code:claude-opus-4-8
---
 .agents/skills/violation-fixer/SKILL.md       |   4 +-
 .github/workflows/codestyle.yml               |  16 +-
 .../buildsrc/GrailsCodeStylePlugin.groovy     |  24 +-
 grails-forge/build.gradle                     |   1 -
 .../checkstyle/checkstyle-suppressions.xml    |  39 ++-
 grails-forge/config/checkstyle/checkstyle.xml | 260 ++++++++++++++----
 grails-forge/gradle.properties                |   2 +-
 grails-forge/gradle/code-style-config.gradle  |  28 +-
 .../postgres/AnalyticsController.java         |  10 +-
 .../forge/analytics/postgres/Application.java |  20 +-
 .../postgres/ApplicationRepository.java       |   4 +-
 .../forge/analytics/postgres/Feature.java     |   4 +-
 .../analytics/postgres/FeatureRepository.java |  18 +-
 .../postgres/gcp/GoogleCloudSqlSetup.java     |   4 +-
 .../forge/api/ApplicationController.java      |  35 +--
 .../grails/forge/api/ApplicationTypeDTO.java  |   5 +-
 .../grails/forge/api/ApplicationTypeList.java |   4 +-
 .../forge/api/ApplicationTypeOperations.java  |   1 -
 .../forge/api/DevelopmentReloading.java       |   4 +-
 .../forge/api/DevelopmentReloadingDTO.java    |   1 -
 .../java/org/grails/forge/api/FeatureDTO.java |   3 +-
 .../org/grails/forge/api/FeatureList.java     |   4 +-
 .../grails/forge/api/FeatureOperations.java   |   6 +-
 .../org/grails/forge/api/FeatureService.java  |  16 +-
 .../org/grails/forge/api/GormImplDTO.java     |   1 -
 .../forge/api/GrailsForgeConfiguration.java   |   8 +-
 .../org/grails/forge/api/JdkVersionDTO.java   |   3 +-
 .../org/grails/forge/api/LanguageDTO.java     |   3 +-
 .../java/org/grails/forge/api/Linkable.java   |   6 +-
 .../org/grails/forge/api/Relationship.java    |   4 +-
 .../org/grails/forge/api/RequestInfo.java     |   7 +-
 .../org/grails/forge/api/SelectOptionDTO.java |   4 +-
 .../grails/forge/api/SelectOptionsDTO.java    |  22 +-
 .../org/grails/forge/api/ServletImplDTO.java  |   1 -
 .../org/grails/forge/api/UserAgentParser.java |   7 +-
 .../java/org/grails/forge/api/VersionDTO.java |   5 +-
 .../api/analytics/AnalyticsOperations.java    |   5 +-
 .../api/analytics/GenerationListener.java     |  14 +-
 .../api/bind/RequestInfoArgumentBinder.java   |  16 +-
 .../api/create/AbstractCreateController.java  |  20 +-
 .../create/github/GitHubCreateController.java |  68 +++--
 .../create/github/GitHubCreateOperation.java  |  10 +-
 .../create/github/GitHubCreateService.java    |  30 +-
 .../create/github/GitHubRedirectService.java  |  18 +-
 .../api/create/zip/ZipCreateController.java   |  26 +-
 .../api/create/zip/ZipCreateOperation.java    |  10 +-
 .../grails/forge/api/diff/DiffController.java |  33 +--
 .../grails/forge/api/diff/DiffOperations.java |  20 +-
 .../api/event/ApplicationGeneratingEvent.java |   1 -
 .../options/ApplicationTypeSelectOptions.java |   7 +-
 .../DevelopmentReloadingSelectOptions.java    |   7 +-
 .../api/options/GormImplSelectOptions.java    |   5 +-
 .../api/options/JdkVersionSelectOptions.java  |   7 +-
 .../api/options/LanguageSelectOptions.java    |   7 +-
 .../api/options/SelectOptionsController.java  |   6 +-
 .../api/options/SelectOptionsOperations.java  |   3 +-
 .../api/options/ServletImplSelectOptions.java |   5 +-
 .../forge/api/preview/PreviewController.java  |  25 +-
 .../grails/forge/api/preview/PreviewDTO.java  |   7 +-
 .../forge/api/preview/PreviewOperations.java  |   9 +-
 .../org/grails/forge/cli/Application.java     |  67 ++---
 .../org/grails/forge/cli/CodeGenConfig.java   |  23 +-
 .../grails/forge/cli/CommonOptionsMixin.java  |   3 +-
 .../forge/cli/GrailsPicocliFactory.java       |   4 +-
 .../grails/forge/cli/InteractiveShell.java    |   6 +-
 .../forge/cli/command/AddPropertyCommand.java |  22 +-
 .../grails/forge/cli/command/BaseCommand.java |   7 +-
 .../forge/cli/command/CodeGenCommand.java     |  12 +-
 .../forge/cli/command/CreateAppCommand.java   |   9 +-
 .../forge/cli/command/CreateCommand.java      |  19 +-
 .../cli/command/CreateControllerCommand.java  |  10 +-
 .../cli/command/CreateDomainClassCommand.java |  10 +-
 .../cli/command/CreateInterceptorCommand.java |  10 +-
 .../forge/cli/command/CreateJobCommand.java   |   9 +-
 .../cli/command/CreatePluginCommand.java      |   9 +-
 .../cli/command/CreateRestApiCommand.java     |   9 +-
 .../cli/command/CreateServiceCommand.java     |  10 +-
 .../cli/command/CreateTagLibCommand.java      |  10 +-
 .../cli/command/CreateWebPluginCommand.java   |   9 +-
 .../cli/command/CreateWebappCommand.java      |   9 +-
 .../DevelopmentReloadingCandidates.java       |   4 +-
 .../DevelopmentReloadingConverter.java        |   3 +-
 .../forge/cli/command/GormImplCandidates.java |   4 +-
 .../forge/cli/command/GormImplConverter.java  |   3 +-
 .../forge/cli/command/LanguageCandidates.java |   4 +-
 .../forge/cli/command/LanguageConverter.java  |   3 +-
 .../forge/cli/command/ListFeatures.java       |  17 +-
 .../cli/command/ServletImplCandidates.java    |   4 +-
 .../cli/command/ServletImplConverter.java     |   3 +-
 .../forge/cli/util/GrailsVersionProvider.java |  10 +-
 grails-forge/grails-forge-core/build.gradle   |   2 +-
 .../org/grails/forge/analytics/Generated.java |  14 +-
 .../forge/application/ApplicationType.java    |   4 +-
 .../forge/application/ContextFactory.java     |  21 +-
 .../application/PluginAvailableFeatures.java  |   5 +-
 .../org/grails/forge/application/Project.java |   4 +-
 .../application/RestApiAvailableFeatures.java |   5 +-
 .../application/WebAvailableFeatures.java     |   5 +-
 .../WebPluginAvailableFeatures.java           |   5 +-
 .../generator/DefaultProjectGenerator.java    |  14 +-
 .../generator/GeneratorContext.java           |  31 +--
 .../generator/ProjectGenerator.java           |   5 +-
 .../org/grails/forge/build/BuildPlugin.java   |   1 -
 .../forge/build/dependencies/Coordinate.java  |   4 +-
 .../DefaultCoordinateResolver.java            |   9 +-
 .../forge/build/dependencies/Dependency.java  |   5 +-
 .../build/dependencies/DependencyContext.java |   5 +-
 .../dependencies/DependencyCoordinate.java    |   4 +-
 .../PomDependencyVersionResolver.java         |  26 +-
 .../forge/build/dependencies/Scope.java       |   4 +-
 .../build/gradle/DefaultGradleRepository.java |   4 +-
 .../forge/build/gradle/GradleBuild.java       |  11 +-
 .../build/gradle/GradleBuildCreator.java      |  10 +-
 .../build/gradle/GradleConfiguration.java     |   5 +-
 .../forge/build/gradle/GradleDependency.java  |  11 +-
 .../forge/build/gradle/GradlePlugin.java      |  16 +-
 .../forge/build/gradle/GradleRepository.java  |   6 +-
 .../client/github/oauth/AccessToken.java      |   4 +-
 .../github/v3/GitHubSecretsPublicKey.java     |   1 +
 .../forge/client/github/v3/GitHubUser.java    |   2 +-
 .../client/github/v3/GitHubWorkflowRuns.java  |   4 +-
 .../forge/defaults/LanguageDefaults.java      |   1 -
 .../org/grails/forge/diff/FeatureDiffer.java  |  14 +-
 .../forge/feature/ApplicationFeature.java     |   1 -
 .../forge/feature/AvailableFeatures.java      |   4 +-
 .../forge/feature/BaseAvailableFeatures.java  |   7 +-
 .../org/grails/forge/feature/Category.java    |  62 ++---
 .../grails/forge/feature/DefaultFeature.java  |   4 +-
 .../org/grails/forge/feature/Feature.java     |   1 -
 .../grails/forge/feature/FeatureContext.java  |  10 +-
 .../org/grails/forge/feature/Features.java    |  12 +-
 .../feature/asciidoctor/Asciidoctor.java      |   1 -
 .../feature/assetPipeline/AssetPipeline.java  |  10 +-
 .../feature/build/gradle/Dockerfile.java      |   6 +-
 .../forge/feature/build/gradle/Gradle.java    |   7 +-
 .../feature/build/gradle/GradleBuildSrc.java  |   1 -
 .../build/gradle/GradleSettingsFile.java      |   5 +-
 .../grails/forge/feature/cache/EHCache.java   |   7 +-
 .../forge/feature/cache/GrailsCache.java      |   5 +-
 .../forge/feature/config/Configuration.java   |  10 +-
 .../feature/config/ConfigurationFeature.java  |   4 +-
 .../forge/feature/config/Properties.java      |   5 +-
 .../org/grails/forge/feature/config/Yaml.java |   7 +-
 .../DatabaseDriverConfigurationFeature.java   |   8 +-
 .../database/DatabaseDriverFeature.java       |   6 +-
 .../forge/feature/database/GormFeature.java   |   4 +-
 .../forge/feature/database/GraphqlGorm.java   |   4 +-
 .../org/grails/forge/feature/database/H2.java |   8 +-
 .../forge/feature/database/HibernateGorm.java |  10 +-
 .../forge/feature/database/MongoGorm.java     |  10 +-
 .../forge/feature/database/MongoSync.java     |   5 +-
 .../grails/forge/feature/database/MySQL.java  |   4 +-
 .../forge/feature/database/PostgreSQL.java    |   4 +-
 .../forge/feature/database/SQLServer.java     |   4 +-
 .../feature/database/TestContainers.java      |   8 +-
 .../workflows/GitHubWorkflowFeature.java      |   6 +-
 .../plain/PlainGithubWorkflowFeature.java     |   1 -
 .../forge/feature/grails/GrailsBase.java      |   5 +-
 .../forge/feature/grails/GrailsConsole.java   |   5 +-
 .../feature/grails/GrailsDefaultPlugins.java  |   7 +-
 .../feature/grails/GrailsGradlePlugin.java    |   5 +-
 .../feature/grails/GrailsUrlMappings.java     |   7 +-
 .../feature/grails/GrailsWebConsole.java      |   5 +-
 .../grailsProfiles/GrailsProfiles.java        |   9 +-
 .../feature/grailsWrapper/GrailsWrapper.java  |   5 +-
 .../lang/groovy/GrailsApplication.java        |   8 +-
 .../grails/forge/feature/logging/Logback.java |   5 +-
 .../feature/micronaut/GrailsMicronaut.java    |   8 +-
 .../micronaut/MicronautHttpClient.java        |   8 +-
 .../migration/DatabaseMigrationPlugin.java    |   1 -
 .../grails/forge/feature/other/AppName.java   |   7 +-
 .../forge/feature/other/GrailsQuartz.java     |   1 -
 .../feature/other/HibernateValidator.java     |   1 -
 .../grails/forge/feature/other/Readme.java    |  16 +-
 .../forge/feature/other/ShadePlugin.java      |   4 +-
 .../forge/feature/reloading/Jrebel.java       |   5 +-
 .../feature/reloading/SpringBootDevTools.java |   4 +-
 .../forge/feature/sitemesh3/Sitemesh3.java    |   1 -
 .../spring/SpringBootAutoconfigure.java       |   5 +-
 .../spring/SpringBootJettyFeature.java        |   8 +-
 .../spring/SpringBootStarterFeature.java      |   5 +-
 .../spring/SpringBootTomcatFeature.java       |   8 +-
 .../spring/SpringBootUndertowFeature.java     |   8 +-
 .../spring/SpringBootVirtualThreads.java      |   5 +-
 .../forge/feature/spring/SpringResources.java |   5 +-
 .../feature/test/GebWithTestcontainers.java   |  13 +-
 .../test/GebWithWebDriverBinaries.java        |  19 +-
 .../feature/test/GormTestingSupport.java      |   5 +-
 .../feature/test/GrailsWebTestingSupport.java |   5 +-
 .../grails/forge/feature/test/Mockito.java    |   5 +-
 .../forge/feature/test/MockitoValidator.java  |   5 +-
 .../org/grails/forge/feature/test/Spock.java  |   8 +-
 .../feature/test/ViewsJsonTestingSupport.java |   5 +-
 .../validation/CompositeFeatureValidator.java |  10 +-
 .../feature/validation/FeatureValidator.java  |   4 +-
 .../validation/OneOfFeatureValidator.java     |   9 +-
 .../grails/forge/feature/view/GrailsGsp.java  |  12 +-
 .../forge/feature/view/Scaffolding.java       |   5 +-
 .../forge/feature/view/json/ViewJson.java     |  18 +-
 .../forge/feature/view/markup/ViewMarkup.java |  16 +-
 .../grails/forge/feature/web/GrailsWeb.java   |   5 +-
 .../org/grails/forge/io/MapOutputHandler.java |   4 +-
 .../org/grails/forge/io/OutputHandler.java    |   4 +-
 .../org/grails/forge/io/ZipOutputHandler.java |  15 +-
 .../org/grails/forge/options/BuildTool.java   |   9 +-
 .../forge/options/DevelopmentReloading.java   |   4 +-
 .../org/grails/forge/options/Language.java    |  11 +-
 .../org/grails/forge/options/Options.java     |   9 +-
 .../grails/forge/options/TestFramework.java   |   4 +-
 .../forge/template/Config4kTemplate.java      |   8 +-
 .../template/DefaultTemplateRenderer.java     |   4 +-
 .../grails/forge/template/RockerTemplate.java |   4 +-
 .../grails/forge/template/RockerWritable.java |   4 +-
 .../forge/template/TemplateRenderer.java      |   6 +-
 .../grails/forge/template/YamlTemplate.java   |   6 +-
 .../org/grails/forge/util/GitHubUtil.java     |  16 +-
 .../org/grails/forge/util/IOFeatureUtil.java  |  13 +-
 .../java/org/grails/forge/util/NameUtils.java |   9 +-
 .../org/grails/forge/util/VersionInfo.java    |   7 +-
 .../netty/analytics/AnalyticsClient.java      |   5 +-
 220 files changed, 1039 insertions(+), 1186 deletions(-)

diff --git a/.agents/skills/violation-fixer/SKILL.md b/.agents/skills/violation-fixer/SKILL.md
index d8742d19646..f22596e3b07 100644
--- a/.agents/skills/violation-fixer/SKILL.md
+++ b/.agents/skills/violation-fixer/SKILL.md
@@ -177,8 +177,8 @@ All properties can be set in `gradle.properties` or passed as `-P` flags:
 | `grails.code-style.enabled.tests` | `false` | Also check test source sets |
 | `grails.code-style.ignoreFailures` | `false` | Collect reports without failing build |
 | `grails.code-style.codenarc.fix` | `false` | Run `codenarcFix` before CodeNarc tasks |
-| `grails.code-style.dir.checkstyle` | (auto) | Custom path to Checkstyle config dir |
-| `grails.code-style.dir.codenarc` | (auto) | Custom path to CodeNarc config dir |
+| `grails.codestyle.dir.checkstyle` | (auto) | Custom path to Checkstyle config dir |
+| `grails.codestyle.dir.codenarc` | (auto) | Custom path to CodeNarc config dir |
 | `skipCodeStyle` | unset | If present, all style tasks are skipped |
 
 ### `grails-code-analysis` plugin (PMD + SpotBugs)
diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml
index 4738be734a8..28fa6438592 100644
--- a/.github/workflows/codestyle.yml
+++ b/.github/workflows/codestyle.yml
@@ -80,20 +80,24 @@ jobs:
           develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
       - name: "🔎 Check Forge Projects"
         working-directory: grails-forge
-        run: ./gradlew aggregateStyleViolations --continue
-      - name: "📤 Upload Reports"
+        run: ./gradlew codeStyle
+      - name: "📤 Upload Failure Reports"
         if: always()
         uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
         with:
           name: forge-reports
-          path: grails-forge/build/reports/violations/
+          path: grails-forge/build/reports/code-style/
       - name: "📋 Publish Code Style Report in Job Summary"
         if: always()
         run: |
           echo "## 🔎 Code Style Report - Forge Projects" >> $GITHUB_STEP_SUMMARY
-          for report in CODENARC_VIOLATIONS.md CHECKSTYLE_VIOLATIONS.md; do
-            file="grails-forge/build/reports/violations/$report"
-            [ -f "$file" ] && cat "$file" >> $GITHUB_STEP_SUMMARY || true
+          for file in grails-forge/build/reports/code-style/checkstyle/*.xml grails-forge/build/reports/code-style/codenarc/*.xml; do
+            [ -f "$file" ] || continue
+            if grep -q "> $GITHUB_STEP_SUMMARY
+              grep "> $GITHUB_STEP_SUMMARY
+              grep "> $GITHUB_STEP_SUMMARY
+            fi
           done
   check_gradle_plugin_projects:
     name: "Gradle Plugin Projects"
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy
index 1b6e8e7fabf..605c8149db3 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeStylePlugin.groovy
@@ -40,12 +40,14 @@ import org.gradle.api.provider.Provider
 @CompileStatic
 class GrailsCodeStylePlugin implements Plugin {
 
-    static String CHECKSTYLE_DIR_PROPERTY = 'grails.code-style.dir.checkstyle'
+    // The directory-override keys keep the legacy 'grails.codestyle.dir.*' names so existing
+    // project configuration (e.g. grails-forge's custom checkstyle dir) keeps working unchanged.
+    static String CHECKSTYLE_DIR_PROPERTY = 'grails.codestyle.dir.checkstyle'
     static String CHECKSTYLE_ENABLED_PROPERTY = 'grails.code-style.enabled.checkstyle'
     static String CHECKSTYLE_CONFIG_FILE_NAME = 'checkstyle.xml'
     static String CHECKSTYLE_SUPPRESSION_CONFIG_FILE_NAME = 'checkstyle-suppressions.xml'
 
-    static String CODENARC_DIR_PROPERTY = 'grails.code-style.dir.codenarc'
+    static String CODENARC_DIR_PROPERTY = 'grails.codestyle.dir.codenarc'
     static String CODENARC_ENABLED_PROPERTY = 'grails.code-style.enabled.codenarc'
     static String CODENARC_CONFIG_FILE_NAME = 'codenarc.groovy'
 
@@ -105,17 +107,13 @@ class GrailsCodeStylePlugin implements Plugin {
         })
     }
 
-   private static void createOrLoad(Path expectedPath, String defaultResource) {
-        def defaultValue = GrailsCodeStylePlugin.getResourceAsStream(defaultResource)
-        if (!defaultValue) {
-            throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}")
-        }
-    
-        String defaultText = defaultValue.text
-        boolean missing = !Files.exists(expectedPath) || expectedPath.size() == 0
-        
-        if (missing || expectedPath.text != defaultText) {
-            expectedPath.text = defaultText
+    private static void createOrLoad(Path expectedPath, String defaultResource) {
+        if (!Files.exists(expectedPath) || expectedPath.size() == 0) {
+            def defaultValue = GrailsCodeStylePlugin.getResourceAsStream(defaultResource)
+            if (!defaultValue) {
+                throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}")
+            }
+            expectedPath.text = defaultValue.text
         }
     }
 
diff --git a/grails-forge/build.gradle b/grails-forge/build.gradle
index a7ac18ca668..d262f97fab9 100644
--- a/grails-forge/build.gradle
+++ b/grails-forge/build.gradle
@@ -25,7 +25,6 @@ import java.time.format.DateTimeFormatter
 plugins {
     id 'org.apache.grails.buildsrc.properties'
     id 'org.apache.grails.buildsrc.dependency-validator'
-    id 'org.apache.grails.gradle.grails-violation-aggregation'
 }
 
 ext {
diff --git a/grails-forge/config/checkstyle/checkstyle-suppressions.xml b/grails-forge/config/checkstyle/checkstyle-suppressions.xml
index 58ee65cc408..c36038ae6ba 100644
--- a/grails-forge/config/checkstyle/checkstyle-suppressions.xml
+++ b/grails-forge/config/checkstyle/checkstyle-suppressions.xml
@@ -1,22 +1,31 @@
 
 
-
+
+
 
+    
+    
+    
 
diff --git a/grails-forge/config/checkstyle/checkstyle.xml b/grails-forge/config/checkstyle/checkstyle.xml
index d88270afa10..54300e23d0b 100644
--- a/grails-forge/config/checkstyle/checkstyle.xml
+++ b/grails-forge/config/checkstyle/checkstyle.xml
@@ -1,91 +1,231 @@
 
 
-
+
+
+
+
 
+    
 
-    
-    
-        
+    
+
+    
+    
+    
+
+    
+    
+    
+        
     
 
-    
-    
+    
+    
+    
+
+    
+    
+    
+
+    
+    
     
+
+    
+    
+    
+
+    
+    
     
 
-    
+    
+    
+        
+        
+    
+
     
 
+        
         
 
-        
-        
+        
+        
+        
+            
+            
+        
+        
+        
+
+        
+            
+        
+
+        
+        
+        
+        
+        
+        
+        
+        
+        
+
+        
+        
+        
+         
         
         
             
         
-        
-            
-            
-            
-            
-            
-            
+
+        
+        
+        
+        
+            
         
 
-        
-        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
+        
         
-            
-            
             
-            
+            
+            
         
-        
-        
         
-        
-        
-            
+
+        
+        
+        
+        
+            
         
-        
-        
-        
-            
+
+        
+        
+        
+        
+        
+        
+        
+
+        
+        
+        
+        
+        
+        
+        
+            
+            
+        
+        
+        
+        
+
+        
+        
+        
+            
         
-        
-        
-            
-            
+
+        
+        
+        
+            
+            
         
-        
-        
-        
-        
-            
-            
-            
-            
+        
+        
+            
+            
+        
+        
+        
+        
+
+        
+        
+        
+        
+        
+
+        
+        
+        
+            
         
     
 
-
\ No newline at end of file
+
diff --git a/grails-forge/gradle.properties b/grails-forge/gradle.properties
index 7e7d48df5fc..0a3e6f66906 100644
--- a/grails-forge/gradle.properties
+++ b/grails-forge/gradle.properties
@@ -60,7 +60,7 @@ testRetryVersion=1.6.2
 typesafeConfigVersion=1.4.3
 
 # custom checkstyle configuration for forge
-grails.code-style.dir.checkstyle=config/checkstyle
+grails.codestyle.dir.checkstyle=config/checkstyle
 
 org.gradle.parallel=true
 org.gradle.caching=true
diff --git a/grails-forge/gradle/code-style-config.gradle b/grails-forge/gradle/code-style-config.gradle
index 684128b1dd7..c8d7bbaf83d 100644
--- a/grails-forge/gradle/code-style-config.gradle
+++ b/grails-forge/gradle/code-style-config.gradle
@@ -17,13 +17,36 @@
  *  under the License.
  */
 
+import com.diffplug.gradle.spotless.SpotlessExtension
 import io.spring.nohttp.gradle.NoHttpExtension
 
 apply plugin: 'checkstyle'
 apply plugin: 'codenarc'
+apply plugin: 'com.diffplug.spotless'
 apply plugin: 'io.spring.nohttp' // enforce https everywhere
 apply plugin: 'org.apache.grails.gradle.grails-code-style'
-apply plugin: 'org.apache.grails.gradle.grails-code-analysis'
+
+extensions.configure(SpotlessExtension) {
+    // Explicit `it` is required in extension configuration block
+    it.java {
+        target('src/main/java/**/*.java')
+        // Formatters:
+        licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java'))
+    }
+    it.groovy {
+        target('src/main/groovy/**')
+        // Formatters:
+        licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java'))
+    }
+    it.format('javaMisc') {
+        target(
+                'src/main/**/module-info.java',
+                'src/main/**/package-info.java',
+        )
+        // Formatters:
+        licenseHeaderFile(rootProject.layout.projectDirectory.file('config/spotless.license.java'), '\\/\\*\\*')
+    }
+}
 
 extensions.configure(NoHttpExtension) {
     // Explicit `it` is required in extension configuration block
@@ -35,3 +58,6 @@ extensions.configure(NoHttpExtension) {
     )
 }
 
+tasks.named('checkstyleMain') {
+    dependsOn('spotlessCheck')
+}
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java
index cccb1c518db..2ac0279773d 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/AnalyticsController.java
@@ -18,11 +18,6 @@
  */
 package org.grails.forge.analytics.postgres;
 
-import java.util.List;
-import java.util.stream.Collectors;
-
-import jakarta.transaction.Transactional;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.http.HttpStatus;
 import io.micronaut.http.annotation.Body;
@@ -31,9 +26,12 @@
 import io.micronaut.http.annotation.Post;
 import io.micronaut.scheduling.TaskExecutors;
 import io.micronaut.scheduling.annotation.ExecuteOn;
-
 import org.grails.forge.analytics.Generated;
 
+import jakarta.transaction.Transactional;
+import java.util.List;
+import java.util.stream.Collectors;
+
 @Controller("/analytics")
 @ExecuteOn(TaskExecutors.IO)
 public class AnalyticsController {
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java
index 8ff3b61909b..2e3fb86be75 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Application.java
@@ -18,27 +18,21 @@
  */
 package org.grails.forge.analytics.postgres;
 
-import java.time.LocalDateTime;
-import java.util.Collections;
-import java.util.Objects;
-import java.util.Set;
-
-import jakarta.validation.constraints.NotBlank;
-
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-import io.micronaut.data.annotation.DateCreated;
-import io.micronaut.data.annotation.GeneratedValue;
-import io.micronaut.data.annotation.Id;
-import io.micronaut.data.annotation.MappedEntity;
-import io.micronaut.data.annotation.Relation;
-
+import io.micronaut.data.annotation.*;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.JdkVersion;
 
+import jakarta.validation.constraints.NotBlank;
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
 /**
  * Models a generated application.
  *
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java
index 392e1f219be..38193cdfbec 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/ApplicationRepository.java
@@ -18,8 +18,6 @@
  */
 package org.grails.forge.analytics.postgres;
 
-import java.util.List;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.data.annotation.Id;
 import io.micronaut.data.annotation.Join;
@@ -28,6 +26,8 @@
 import io.micronaut.data.model.query.builder.sql.Dialect;
 import io.micronaut.data.repository.PageableRepository;
 
+import java.util.List;
+
 /**
  * Repository for storing generated applications.
  *
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java
index 58bbdc97517..f92ad7df488 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/Feature.java
@@ -18,8 +18,6 @@
  */
 package org.grails.forge.analytics.postgres;
 
-import java.util.Objects;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.data.annotation.GeneratedValue;
@@ -27,6 +25,8 @@
 import io.micronaut.data.annotation.MappedEntity;
 import io.micronaut.data.annotation.Relation;
 
+import java.util.Objects;
+
 /**
  * Models a selected application feature.
  *
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java
index d0b3b042990..c9b0f3a5951 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/FeatureRepository.java
@@ -18,11 +18,6 @@
  */
 package org.grails.forge.analytics.postgres;
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.data.annotation.Id;
 import io.micronaut.data.jdbc.annotation.JdbcRepository;
@@ -31,6 +26,11 @@
 import io.micronaut.data.repository.CrudRepository;
 import io.micronaut.transaction.annotation.ReadOnly;
 
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
 @JdbcRepository(dialect = Dialect.POSTGRES)
 public abstract class FeatureRepository implements CrudRepository {
 
@@ -52,10 +52,10 @@ List topFeatures() {
         return this.jdbcOperations
                 .prepareStatement(query("name", "feature"),
                         statement -> {
-                            try (ResultSet resultSet = statement.executeQuery()) {
-                                return resultSetToTotals(resultSet);
-                            }
-                        });
+            try (ResultSet resultSet = statement.executeQuery()) {
+                return resultSetToTotals(resultSet);
+            }
+        });
     }
 
     @ReadOnly
diff --git a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java
index 15f2e7be2c6..9a952343b7b 100644
--- a/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java
+++ b/grails-forge/grails-forge-analytics-postgres/src/main/java/org/grails/forge/analytics/postgres/gcp/GoogleCloudSqlSetup.java
@@ -18,8 +18,6 @@
  */
 package org.grails.forge.analytics.postgres.gcp;
 
-import jakarta.inject.Singleton;
-
 import io.micronaut.configuration.jdbc.hikari.DatasourceConfiguration;
 import io.micronaut.context.annotation.Property;
 import io.micronaut.context.annotation.Requires;
@@ -27,6 +25,8 @@
 import io.micronaut.context.event.BeanCreatedEvent;
 import io.micronaut.context.event.BeanCreatedEventListener;
 
+import jakarta.inject.Singleton;
+
 /**
  * Configuration for the Cloud SQL environment.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java
index 7ffd24c31aa..c3182db1e4e 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationController.java
@@ -18,16 +18,6 @@
  */
 package org.grails.forge.api;
 
-import java.io.OutputStream;
-import java.io.Writer;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
 import io.micronaut.context.MessageSource;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.io.Writable;
@@ -37,6 +27,12 @@
 import io.micronaut.http.annotation.Controller;
 import io.micronaut.http.annotation.Get;
 import io.micronaut.http.annotation.Produces;
+import org.grails.forge.application.ApplicationType;
+import org.grails.forge.application.OperatingSystem;
+import org.grails.forge.options.*;
+import org.grails.forge.template.RockerWritable;
+import org.grails.forge.template.api.grailsForgeApi;
+import org.grails.forge.util.VersionInfo;
 import io.swagger.v3.oas.annotations.OpenAPIDefinition;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.info.Info;
@@ -44,16 +40,15 @@
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 
-import org.grails.forge.application.ApplicationType;
-import org.grails.forge.application.OperatingSystem;
-import org.grails.forge.options.FeatureFilter;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
-import org.grails.forge.template.RockerWritable;
-import org.grails.forge.template.api.grailsForgeApi;
-import org.grails.forge.util.VersionInfo;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Main interface on the Grails Application Forge API.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java
index a7482ee284e..91a4042e4a6 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeDTO.java
@@ -18,8 +18,6 @@
  */
 package org.grails.forge.api;
 
-import java.util.List;
-
 import io.micronaut.context.MessageSource;
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Internal;
@@ -27,9 +25,10 @@
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
+import org.grails.forge.application.ApplicationType;
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.grails.forge.application.ApplicationType;
+import java.util.List;
 
 /**
  * DTO objects for {@link ApplicationType}.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java
index 93aad4e6400..7b597fe360d 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeList.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.api;
 
-import java.util.List;
-
 import io.micronaut.core.annotation.Introspected;
 import io.swagger.v3.oas.annotations.media.Schema;
 
+import java.util.List;
+
 /**
  * Models a list of application types.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java
index 25b8b19cabd..e05f853c13e 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ApplicationTypeOperations.java
@@ -21,7 +21,6 @@
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.http.annotation.Get;
 import io.swagger.v3.oas.annotations.Parameter;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.FeatureFilter;
 
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java
index 3ee45eaed9e..120d98631c5 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloading.java
@@ -18,10 +18,10 @@
  */
 package org.grails.forge.api;
 
-import java.util.Locale;
-
 import io.micronaut.core.annotation.NonNull;
 
+import java.util.Locale;
+
 public enum DevelopmentReloading {
     DEVTOOLS,
     JREBEL,
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java
index aec2f5a9c1b..412bab03f1c 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/DevelopmentReloadingDTO.java
@@ -26,7 +26,6 @@
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
 import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.util.NameUtils;
 
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java
index 62f2e38888c..6a6fd1ffcb9 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureDTO.java
@@ -23,9 +23,8 @@
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
-import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.feature.Feature;
+import io.swagger.v3.oas.annotations.media.Schema;
 
 /**
  * Represents an application feature.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java
index f71dcc6cae5..25a1e9132e9 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureList.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.api;
 
-import java.util.List;
-
 import io.micronaut.core.annotation.Introspected;
 import io.swagger.v3.oas.annotations.media.Schema;
 
+import java.util.List;
+
 /**
  * Models a list of features.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java
index 168b2616933..4029f4906c1 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureOperations.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.api;
 
-import java.util.List;
-import java.util.Locale;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.Options;
 
+import java.util.List;
+import java.util.Locale;
+
 /**
  * API to expose information about features.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java
index 8868f66c290..69beabf3a5b 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/FeatureService.java
@@ -18,24 +18,22 @@
  */
 package org.grails.forge.api;
 
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.stream.Collectors;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.BeanLocator;
 import io.micronaut.context.MessageSource;
 import io.micronaut.inject.qualifiers.Qualifiers;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.AvailableFeatures;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
 /**
  * Implements the {@link FeatureOperations} interface.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java
index 36a1be9ab03..af0e8a9a343 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GormImplDTO.java
@@ -26,7 +26,6 @@
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
 import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.options.GormImpl;
 
 /**
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java
index 3cfb282463a..e2dd74b468e 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/GrailsForgeConfiguration.java
@@ -18,15 +18,15 @@
  */
 package org.grails.forge.api;
 
+import io.micronaut.context.annotation.ConfigurationProperties;
+import io.micronaut.context.env.Environment;
+import io.micronaut.core.annotation.Nullable;
+
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
 import java.util.Optional;
 
-import io.micronaut.context.annotation.ConfigurationProperties;
-import io.micronaut.context.env.Environment;
-import io.micronaut.core.annotation.Nullable;
-
 /**
  * Allows configuration of the the links exposed in URLs.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java
index aefa6a27ebb..002edde6352 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/JdkVersionDTO.java
@@ -25,9 +25,8 @@
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
-import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.options.JdkVersion;
+import io.swagger.v3.oas.annotations.media.Schema;
 
 /**
  * DTO objects for {@link JdkVersion}.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java
index dfcb9db10a1..ae9a9064377 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/LanguageDTO.java
@@ -25,12 +25,11 @@
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
-import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.defaults.IncludesDefaults;
 import org.grails.forge.defaults.LanguageDefaults;
 import org.grails.forge.options.Language;
 import org.grails.forge.util.NameUtils;
+import io.swagger.v3.oas.annotations.media.Schema;
 
 /**
  * DTO objects for {@link Language}.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java
index 7b4cb186546..9b17685cd7c 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Linkable.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.api;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.swagger.v3.oas.annotations.media.Schema;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 /**
  * A linkable type.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java
index 80c429a8519..6955dd79012 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/Relationship.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.api;
 
-import java.util.Locale;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.naming.Named;
 
+import java.util.Locale;
+
 /**
  * Relationship types.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java
index 3139a583d81..a16c5338505 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/RequestInfo.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.api;
 
-import java.util.Locale;
-import java.util.Objects;
-
 import io.micronaut.http.HttpParameters;
+import org.grails.forge.application.ApplicationType;
 import io.swagger.v3.oas.annotations.Hidden;
 
-import org.grails.forge.application.ApplicationType;
+import java.util.Locale;
+import java.util.Objects;
 
 /**
  * The server URL.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java
index c7e2ef189f6..ae4136f7604 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionDTO.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.api;
 
-import java.util.List;
-
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Introspected;
 import io.swagger.v3.oas.annotations.media.ArraySchema;
 import io.swagger.v3.oas.annotations.media.Schema;
 
+import java.util.List;
+
 /**
  * Supported Option
  * @param  The underlying option type
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java
index fb9ab283d57..f25ee04940f 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/SelectOptionsDTO.java
@@ -18,27 +18,18 @@
  */
 package org.grails.forge.api;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
 import io.micronaut.context.MessageSource;
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Introspected;
 import io.swagger.v3.oas.annotations.media.Schema;
-
-import org.grails.forge.api.options.ApplicationTypeSelectOptions;
-import org.grails.forge.api.options.DevelopmentReloadingSelectOptions;
-import org.grails.forge.api.options.GormImplSelectOptions;
-import org.grails.forge.api.options.JdkVersionSelectOptions;
-import org.grails.forge.api.options.LanguageSelectOptions;
-import org.grails.forge.api.options.ServletImplSelectOptions;
+import org.grails.forge.api.options.*;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Language;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Aggregator for {@link SelectOptionDTO}.
@@ -172,6 +163,7 @@ public static SelectOptionsDTO make(MessageSource messageSource, MessageSource.M
                 new ServletImplDTO(ServletImpl.DEFAULT_OPTION, messageSource, messageContext)
         );
 
+
         return new SelectOptionsDTO(applicationOpts, jdkVersionOpts, languageOpts, developmentReloadingOpts, gormImplOpts, servletImplOpts);
 
     }
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java
index 0f75a98fead..f1c72e6c598 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/ServletImplDTO.java
@@ -26,7 +26,6 @@
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
 import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.options.ServletImpl;
 
 /**
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java
index 0421dae7f08..dd89db12834 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/UserAgentParser.java
@@ -18,14 +18,13 @@
  */
 package org.grails.forge.api;
 
+import io.micronaut.core.util.StringUtils;
+import org.grails.forge.application.OperatingSystem;
+
 import java.util.Arrays;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import io.micronaut.core.util.StringUtils;
-
-import org.grails.forge.application.OperatingSystem;
-
 public class UserAgentParser {
 
     private static final Pattern[] WINDOWS_PATTERNS = new Pattern[] { Pattern.compile("Windows"), Pattern.compile("Win ?(95|98|3.1|NT|ME|2000)") };
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java
index ef2e82feef1..f85067524e5 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/VersionDTO.java
@@ -18,12 +18,11 @@
  */
 package org.grails.forge.api;
 
-import java.util.Map;
-
 import io.micronaut.core.annotation.Introspected;
+import org.grails.forge.util.VersionInfo;
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.grails.forge.util.VersionInfo;
+import java.util.Map;
 
 /**
  * Information about the application.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java
index b6ea713f262..367d0ef5b12 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/AnalyticsOperations.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.api.analytics;
 
-import java.util.concurrent.CompletableFuture;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.http.HttpStatus;
-
 import org.grails.forge.analytics.Generated;
 
+import java.util.concurrent.CompletableFuture;
+
 /**
  * Interface to implement to provide analytics.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java
index b4156fb106d..5a31e7f966a 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/analytics/GenerationListener.java
@@ -18,20 +18,18 @@
  */
 package org.grails.forge.api.analytics;
 
-import java.util.List;
-import java.util.stream.Collectors;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.annotation.Requires;
 import io.micronaut.runtime.event.annotation.EventListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.grails.forge.analytics.Generated;
 import org.grails.forge.analytics.SelectedFeature;
 import org.grails.forge.api.event.ApplicationGeneratingEvent;
 import org.grails.forge.application.generator.GeneratorContext;
+import jakarta.inject.Singleton;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.stream.Collectors;
 
 @Singleton
 @Requires(beans = AnalyticsOperations.class)
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java
index ca97e246a21..8c1125119f1 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/bind/RequestInfoArgumentBinder.java
@@ -18,20 +18,18 @@
  */
 package org.grails.forge.api.bind;
 
-import java.util.Locale;
-import java.util.Optional;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.convert.ArgumentConversionContext;
 import io.micronaut.core.io.socket.SocketUtils;
 import io.micronaut.core.type.Argument;
 import io.micronaut.http.HttpHeaders;
 import io.micronaut.http.HttpRequest;
 import io.micronaut.http.bind.binders.TypedRequestArgumentBinder;
-
-import org.grails.forge.api.GrailsForgeConfiguration;
 import org.grails.forge.api.RequestInfo;
+import org.grails.forge.api.GrailsForgeConfiguration;
+import jakarta.inject.Singleton;
+
+import java.util.Locale;
+import java.util.Optional;
 
 /**
  * Binds the Server URL.
@@ -76,8 +74,8 @@ private String resolveUrl(HttpRequest request) {
                 return "https://" + url + cp;
             }
         } else {
-            String hostname = request.getUri().getHost();
-            String host;
+           String hostname = request.getUri().getHost();
+           String host;
             if (hostname != null) {
                 host = hostname;
             } else {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java
index 4cdb2d6db90..bf9286a94a7 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/AbstractCreateController.java
@@ -18,20 +18,12 @@
  */
 package org.grails.forge.api.create;
 
-import java.util.Collections;
-import java.util.List;
-
-import jakarta.validation.constraints.Pattern;
-
 import io.micronaut.context.event.ApplicationEventPublisher;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.http.HttpHeaders;
 import io.micronaut.http.HttpStatus;
 import io.micronaut.http.annotation.Header;
 import io.micronaut.http.exceptions.HttpStatusException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.UserAgentParser;
 import org.grails.forge.api.event.ApplicationGeneratingEvent;
@@ -41,12 +33,14 @@
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.application.generator.ProjectGenerator;
 import org.grails.forge.io.ConsoleOutput;
-import org.grails.forge.options.BuildTool;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
 import org.grails.forge.util.NameUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.validation.constraints.Pattern;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Abstract implementation of a create controller.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java
index 0049b3c8078..b217f4ccb0d 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateController.java
@@ -18,11 +18,6 @@
  */
 package org.grails.forge.api.create.github;
 
-import java.net.URI;
-import java.util.List;
-
-import jakarta.validation.constraints.Pattern;
-
 import io.micronaut.context.annotation.Requires;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
@@ -40,17 +35,20 @@
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.RequestInfo;
+import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.client.github.v3.GitHubRepository;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.ServletImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.validation.constraints.Pattern;
+import java.net.URI;
+import java.util.List;
 
 /**
  * GitHub create controller.
@@ -89,24 +87,23 @@ public GitHubCreateController(GitHubCreateService gitHubCreateService,
     @Override
     @Get(uri = "/github/{type}/{name}{?features,gorm,servlet,build,reloading,javaVersion,code,state}", produces = MediaType.APPLICATION_JSON)
     @ApiResponses(value = {
-        @ApiResponse(
-                responseCode = "200",
-                description = "Created GitHub repository containing the generated application. In case " +
-                        "the configuration contains launcher URI the redirect to launcher is sent.",
-                content = @Content(
-                        mediaType = MediaType.APPLICATION_JSON
-                )
-        ),
-        @ApiResponse(
-                responseCode = "307",
-                description = "Redirects to GitHub OAuth API to obtain user authorisation code before creating " +
-                        "the GitHub repository."
-        ),
-        @ApiResponse(
-                responseCode = "307",
-                description = "Redirects back to launcher in case of successfully created GitHub repository."
-        )
-    })
+            @ApiResponse(
+                    responseCode = "200",
+                    description = "Created GitHub repository containing the generated application. In case " +
+                            "the configuration contains launcher URI the redirect to launcher is sent.",
+                    content = @Content(
+                            mediaType = MediaType.APPLICATION_JSON
+                    )
+            ),
+            @ApiResponse(
+                    responseCode = "307",
+                    description = "Redirects to GitHub OAuth API to obtain user authorisation code before creating " +
+                            "the GitHub repository."
+            ),
+            @ApiResponse(
+                    responseCode = "307",
+                    description = "Redirects back to launcher in case of successfully created GitHub repository."
+            )})
     public HttpResponse createApp(
             @NonNull ApplicationType type,
             @Pattern(regexp = "[\\w\\d-_\\.]+") String name,
@@ -157,15 +154,14 @@ public HttpResponse createApp(
      */
     @Get(uri = "/github{?error,error_description}", produces = MediaType.APPLICATION_JSON)
     @ApiResponses(value = {
-        @ApiResponse(
-                responseCode = "307",
-                description = "Forwarded GitHub OAuth error message."
-        ),
-        @ApiResponse(
-                responseCode = "200",
-                description = "Returns GitHub OAuth application callback error."
-        )
-    })
+            @ApiResponse(
+                    responseCode = "307",
+                    description = "Forwarded GitHub OAuth error message."
+            ),
+            @ApiResponse(
+                    responseCode = "200",
+                    description = "Returns GitHub OAuth application callback error."
+            )})
     public HttpResponse handleCallback(
             @Nullable String error,
             @Nullable @QueryValue("error_description") String errorDescription) {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java
index dc1dfd22851..6800efa71f6 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateOperation.java
@@ -18,24 +18,22 @@
  */
 package org.grails.forge.api.create.github;
 
-import java.util.List;
-
-import jakarta.validation.constraints.Pattern;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.http.HttpHeaders;
 import io.micronaut.http.HttpResponse;
 import io.micronaut.http.annotation.Header;
-
-import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.RequestInfo;
+import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.ServletImpl;
 
+import jakarta.validation.constraints.Pattern;
+import java.util.List;
+
 /**
  * Defines the signature for creating an application in Github repository.
  *
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java
index cd65b3e9b1b..ba40f554a7a 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubCreateService.java
@@ -18,28 +18,14 @@
  */
 package org.grails.forge.api.create.github;
 
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Comparator;
-import java.util.List;
-import java.util.stream.Stream;
-
-import jakarta.inject.Singleton;
-import jakarta.validation.constraints.NotNull;
-
 import io.micronaut.context.annotation.Requires;
 import io.micronaut.context.event.ApplicationEventPublisher;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.http.client.exceptions.HttpClientResponseException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.grails.forge.api.DevelopmentReloading;
+import jakarta.inject.Singleton;
 import org.grails.forge.api.GrailsForgeConfiguration;
+import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.create.AbstractCreateController;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -57,6 +43,18 @@
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.ServletImpl;
 import org.grails.forge.util.GitHubUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.validation.constraints.NotNull;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Stream;
 
 /**
  * GitHub create service.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java
index dd36f198fd2..388f220e3c4 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/github/GitHubRedirectService.java
@@ -18,22 +18,20 @@
  */
 package org.grails.forge.api.create.github;
 
-import java.net.URI;
-import java.util.UUID;
-
-import jakarta.inject.Singleton;
-import jakarta.validation.constraints.NotNull;
-
 import io.micronaut.context.annotation.Property;
 import io.micronaut.context.annotation.Requires;
 import io.micronaut.http.uri.UriBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.grails.forge.api.GrailsForgeConfiguration;
 import org.grails.forge.api.RequestInfo;
+import org.grails.forge.api.GrailsForgeConfiguration;
 import org.grails.forge.client.github.oauth.GitHubOAuthClient;
 import org.grails.forge.client.github.v3.GitHubRepository;
+import jakarta.inject.Singleton;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.validation.constraints.NotNull;
+import java.net.URI;
+import java.util.UUID;
 
 /**
  * Redirect service.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java
index 3f4a38071f0..f2682c1a199 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateController.java
@@ -18,16 +18,6 @@
  */
 package org.grails.forge.api.create.zip;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.List;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
-
 import io.micronaut.context.event.ApplicationEventPublisher;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
@@ -41,12 +31,8 @@
 import io.micronaut.http.annotation.Header;
 import io.micronaut.scheduling.TaskExecutors;
 import io.micronaut.scheduling.annotation.ExecuteOn;
-import io.micronaut.validation.Validated;
 import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.create.AbstractCreateController;
 import org.grails.forge.application.ApplicationType;
@@ -58,6 +44,18 @@
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.ServletImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.micronaut.validation.Validated;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.List;
 
 /**
  * Implements the {@link ZipCreateOperation} interface for applications.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java
index 21ea2417a8c..3d74bd1470d 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/create/zip/ZipCreateOperation.java
@@ -18,22 +18,20 @@
  */
 package org.grails.forge.api.create.zip;
 
-import java.util.List;
-
-import jakarta.validation.constraints.Pattern;
-
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.io.Writable;
 import io.micronaut.http.HttpHeaders;
 import io.micronaut.http.HttpResponse;
 import io.micronaut.http.annotation.Header;
-
 import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.JdkVersion;
+
+import jakarta.validation.constraints.Pattern;
+import java.util.List;
 
 /**
  * Defines the signature for creating an application.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java
index c854c67ca2a..4f71dc63d54 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffController.java
@@ -18,14 +18,6 @@
  */
 package org.grails.forge.api.diff;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.http.HttpStatus;
@@ -33,12 +25,6 @@
 import io.micronaut.http.annotation.Controller;
 import io.micronaut.http.annotation.Get;
 import io.micronaut.http.exceptions.HttpStatusException;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import org.reactivestreams.Publisher;
-import reactor.core.publisher.Flux;
-
 import org.grails.forge.api.RequestInfo;
 import org.grails.forge.api.UserAgentParser;
 import org.grails.forge.application.ApplicationType;
@@ -47,13 +33,20 @@
 import org.grails.forge.application.generator.ProjectGenerator;
 import org.grails.forge.diff.FeatureDiffer;
 import org.grails.forge.io.ConsoleOutput;
-import org.grails.forge.options.BuildTool;
-import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
 import org.grails.forge.util.NameUtils;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * A controller for performing Diffs.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java
index 28861f357d3..17cafc7fd26 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/diff/DiffOperations.java
@@ -18,24 +18,18 @@
  */
 package org.grails.forge.api.diff;
 
-import java.io.IOException;
-import java.util.List;
-
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
+import org.grails.forge.api.RequestInfo;
+import org.grails.forge.application.ApplicationType;
+import org.grails.forge.options.*;
 import io.swagger.v3.oas.annotations.Parameter;
 import org.reactivestreams.Publisher;
 
-import org.grails.forge.api.RequestInfo;
-import org.grails.forge.application.ApplicationType;
-import org.grails.forge.options.BuildTool;
-import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.ServletImpl;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.io.IOException;
+import java.util.List;
 
 /**
  * Operations for performing diffs.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java
index 0e3fa74ec4d..3f3c77fed65 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/event/ApplicationGeneratingEvent.java
@@ -19,7 +19,6 @@
 package org.grails.forge.api.event;
 
 import io.micronaut.context.event.ApplicationEvent;
-
 import org.grails.forge.application.generator.GeneratorContext;
 
 /**
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java
index a909e74214e..1fcc1b99679 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ApplicationTypeSelectOptions.java
@@ -18,12 +18,11 @@
  */
 package org.grails.forge.api.options;
 
-import java.util.List;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.api.ApplicationTypeDTO;
 import org.grails.forge.api.SelectOptionDTO;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.List;
 
 @Schema(name = "ApplicationTypeSelectOptions")
 public class ApplicationTypeSelectOptions extends SelectOptionDTO {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java
index e2a6ef54517..cdaf421ad6d 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/DevelopmentReloadingSelectOptions.java
@@ -18,12 +18,11 @@
  */
 package org.grails.forge.api.options;
 
-import java.util.List;
-
 import io.swagger.v3.oas.annotations.media.Schema;
-
-import org.grails.forge.api.DevelopmentReloadingDTO;
 import org.grails.forge.api.SelectOptionDTO;
+import org.grails.forge.api.DevelopmentReloadingDTO;
+
+import java.util.List;
 
 @Schema(name = "DevelopmentReloadingSelectOptions")
 public class DevelopmentReloadingSelectOptions extends SelectOptionDTO {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java
index c4d2f227029..dfae59161b1 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/GormImplSelectOptions.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.api.options;
 
-import java.util.List;
-
 import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.api.GormImplDTO;
 import org.grails.forge.api.SelectOptionDTO;
 
+import java.util.List;
+
 @Schema(name = "GormImplSelectOptions")
 public class GormImplSelectOptions extends SelectOptionDTO {
     public GormImplSelectOptions(List options, GormImplDTO defaultOption) {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java
index 1ef6123ec38..48cb400ed64 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/JdkVersionSelectOptions.java
@@ -18,12 +18,11 @@
  */
 package org.grails.forge.api.options;
 
-import java.util.List;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.api.JdkVersionDTO;
 import org.grails.forge.api.SelectOptionDTO;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.List;
 
 @Schema(name = "JdkVersionSelectOptions")
 public class JdkVersionSelectOptions extends SelectOptionDTO {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java
index 1ba3c635309..9b83f2ce787 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/LanguageSelectOptions.java
@@ -18,12 +18,11 @@
  */
 package org.grails.forge.api.options;
 
-import java.util.List;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.api.LanguageDTO;
 import org.grails.forge.api.SelectOptionDTO;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.List;
 
 @Schema(name = "LanguageSelectOptions")
 public class LanguageSelectOptions extends SelectOptionDTO {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java
index dda22db9d0b..d4f4fe84e90 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsController.java
@@ -18,17 +18,15 @@
  */
 package org.grails.forge.api.options;
 
-import jakarta.inject.Inject;
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.MessageSource;
 import io.micronaut.context.i18n.ResourceBundleMessageSource;
 import io.micronaut.http.MediaType;
 import io.micronaut.http.annotation.Controller;
 import io.micronaut.http.annotation.Get;
-
 import org.grails.forge.api.RequestInfo;
 import org.grails.forge.api.SelectOptionsDTO;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
 
 /**
  * Gets Information about select options for the Grails Forge.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java
index bf2c116f59c..60a5e5e6f76 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/SelectOptionsOperations.java
@@ -18,10 +18,9 @@
  */
 package org.grails.forge.api.options;
 
-import io.swagger.v3.oas.annotations.Parameter;
-
 import org.grails.forge.api.RequestInfo;
 import org.grails.forge.api.SelectOptionsDTO;
+import io.swagger.v3.oas.annotations.Parameter;
 
 public interface SelectOptionsOperations {
     SelectOptionsDTO selectOptions(@Parameter(hidden = true) RequestInfo serverURL);
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java
index 1662718967b..159a2d3031b 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/options/ServletImplSelectOptions.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.api.options;
 
-import java.util.List;
-
 import io.swagger.v3.oas.annotations.media.Schema;
-
 import org.grails.forge.api.SelectOptionDTO;
 import org.grails.forge.api.ServletImplDTO;
 
+import java.util.List;
+
 @Schema(name = "ServletImplSelectOptions")
 public class ServletImplSelectOptions extends SelectOptionDTO {
     public ServletImplSelectOptions(List options, ServletImplDTO defaultOption) {
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java
index ad85fb4571b..5f92955ddd0 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewController.java
@@ -18,11 +18,6 @@
  */
 package org.grails.forge.api.preview;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
 import io.micronaut.context.event.ApplicationEventPublisher;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.http.HttpStatus;
@@ -30,25 +25,25 @@
 import io.micronaut.http.annotation.Controller;
 import io.micronaut.http.annotation.Get;
 import io.micronaut.http.exceptions.HttpStatusException;
-import io.swagger.v3.oas.annotations.Parameter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.Relationship;
 import org.grails.forge.api.RequestInfo;
+import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.create.AbstractCreateController;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.Project;
 import org.grails.forge.application.generator.ProjectGenerator;
 import org.grails.forge.io.ConsoleOutput;
 import org.grails.forge.io.MapOutputHandler;
-import org.grails.forge.options.BuildTool;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
 import org.grails.forge.util.NameUtils;
+import io.swagger.v3.oas.annotations.Parameter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 /**
  * Previews an application contents.
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java
index a2fa31f9ec0..b1548db17bd 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewDTO.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.api.preview;
 
-import java.util.Map;
-
 import com.fasterxml.jackson.annotation.JsonInclude;
 import io.micronaut.core.annotation.Introspected;
+import org.grails.forge.api.Linkable;
 import io.swagger.v3.oas.annotations.media.Schema;
 
-import org.grails.forge.api.Linkable;
+import java.util.Map;
 
 /**
  * A preview of the contents.
@@ -34,7 +33,7 @@
  */
 @Introspected
 @Schema(name = "Preview", description = "Previews the contents of the generated ZIP")
-public class PreviewDTO extends Linkable {
+public class PreviewDTO extends Linkable  {
 
     @JsonInclude
     private Map contents;
diff --git a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java
index 14b86e094c7..e16700b32da 100644
--- a/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java
+++ b/grails-forge/grails-forge-api/src/main/java/org/grails/forge/api/preview/PreviewOperations.java
@@ -18,21 +18,20 @@
  */
 package org.grails.forge.api.preview;
 
-import java.io.IOException;
-import java.util.List;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.swagger.v3.oas.annotations.Parameter;
-
-import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.api.RequestInfo;
+import org.grails.forge.api.DevelopmentReloading;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.ServletImpl;
 
+import java.io.IOException;
+import java.util.List;
+
 public interface PreviewOperations {
     /**
      * Previews an application.
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java
index 77a4090c953..43732af4e38 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/Application.java
@@ -18,62 +18,51 @@
  */
 package org.grails.forge.cli;
 
-import java.util.concurrent.Callable;
-import java.util.function.BiFunction;
-
 import io.micronaut.context.ApplicationContext;
 import io.micronaut.context.BeanContext;
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.TypeHint;
 import io.micronaut.inject.BeanDefinition;
+import org.grails.forge.cli.command.*;
+import org.grails.forge.io.ConsoleOutput;
 import picocli.CommandLine;
 
-import org.grails.forge.cli.command.BaseCommand;
-import org.grails.forge.cli.command.CodeGenCommand;
-import org.grails.forge.cli.command.CreateAppCommand;
-import org.grails.forge.cli.command.CreatePluginCommand;
-import org.grails.forge.cli.command.CreateRestApiCommand;
-import org.grails.forge.cli.command.CreateWebPluginCommand;
-import org.grails.forge.cli.command.CreateWebappCommand;
-import org.grails.forge.cli.command.DevelopmentReloadingCandidates;
-import org.grails.forge.cli.command.DevelopmentReloadingConverter;
-import org.grails.forge.cli.command.GormImplCandidates;
-import org.grails.forge.cli.command.GormImplConverter;
-import org.grails.forge.cli.command.ServletImplCandidates;
-import org.grails.forge.cli.command.ServletImplConverter;
-import org.grails.forge.io.ConsoleOutput;
+import java.util.concurrent.Callable;
+import java.util.function.BiFunction;
+
+
 
 @CommandLine.Command(name = "grails-forge-cli", description = {
-    "Grails Forge CLI command line interface for generating projects and services.",
-    "Application generation commands are:",
-    "",
-    "*  @|bold create-app|@ @|yellow NAME|@",
-    "*  @|bold create-webapp|@ @|yellow NAME|@",
-    "*  @|bold create-restapi|@ @|yellow NAME|@",
-    "*  @|bold create-plugin|@ @|yellow NAME|@",
-    "*  @|bold create-web-plugin|@ @|yellow NAME|@"
+        "Grails Forge CLI command line interface for generating projects and services.",
+        "Application generation commands are:",
+        "",
+        "*  @|bold create-app|@ @|yellow NAME|@",
+        "*  @|bold create-webapp|@ @|yellow NAME|@",
+        "*  @|bold create-restapi|@ @|yellow NAME|@",
+        "*  @|bold create-plugin|@ @|yellow NAME|@",
+        "*  @|bold create-web-plugin|@ @|yellow NAME|@"
 },
         synopsisHeading = "@|bold,underline Usage:|@ ",
         optionListHeading = "%n@|bold,underline Options:|@%n",
         commandListHeading = "%n@|bold,underline Commands:|@%n",
         subcommands = {
-            // Creation commands
-            CreateAppCommand.class,
-            CreateWebappCommand.class,
-            CreatePluginCommand.class,
-            CreateWebPluginCommand.class,
-            CreateRestApiCommand.class
+                // Creation commands
+                CreateAppCommand.class,
+                CreateWebappCommand.class,
+                CreatePluginCommand.class,
+                CreateWebPluginCommand.class,
+                CreateRestApiCommand.class
         })
 @Prototype
 @TypeHint({
-    Application.class,
-    GormImplCandidates.class,
-    GormImplConverter.class,
-    ServletImplCandidates.class,
-    ServletImplConverter.class,
-    CommonOptionsMixin.class,
-    DevelopmentReloadingCandidates.class,
-    DevelopmentReloadingConverter.class
+        Application.class,
+        GormImplCandidates.class,
+        GormImplConverter.class,
+        ServletImplCandidates.class,
+        ServletImplConverter.class,
+        CommonOptionsMixin.class,
+        DevelopmentReloadingCandidates.class,
+        DevelopmentReloadingConverter.class
 })
 public class Application extends BaseCommand implements Callable {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java
index 3bc8ef964d2..6420468b2c3 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CodeGenConfig.java
@@ -18,33 +18,28 @@
  */
 package org.grails.forge.cli;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.beans.BeanIntrospection;
 import io.micronaut.inject.qualifiers.Qualifiers;
-import org.yaml.snakeyaml.Yaml;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.AvailableFeatures;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.io.ConsoleOutput;
 import org.grails.forge.io.FileSystemOutputHandler;
-import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.Language;
 import org.grails.forge.options.Options;
+import org.grails.forge.options.DevelopmentReloading;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Introspected
 public class CodeGenConfig {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java
index 046156a033d..9d2d4f1f4c6 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/CommonOptionsMixin.java
@@ -19,11 +19,10 @@
 package org.grails.forge.cli;
 
 import io.micronaut.core.annotation.ReflectiveAccess;
+import org.grails.forge.cli.util.GrailsVersionProvider;
 import picocli.CommandLine;
 import picocli.CommandLine.Option;
 
-import org.grails.forge.cli.util.GrailsVersionProvider;
-
 /**
  * Mixin that adds help, version and other common options to a command. Example usage:
  * 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java
index 92f54565186..c91fcdfafd5 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/GrailsPicocliFactory.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.cli;
 
-import java.util.Optional;
-
 import io.micronaut.context.ApplicationContext;
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.TypeHint;
 import picocli.CommandLine;
 
+import java.util.Optional;
+
 /**
  * Picocli factory implementation that uses a Micronaut BeanContext to obtain bean instances.
  */
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
index 9250e84cc1d..618b1cecd8b 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/InteractiveShell.java
@@ -18,9 +18,6 @@
  */
 package org.grails.forge.cli;
 
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-
 import org.fusesource.jansi.AnsiConsole;
 import org.jline.reader.EndOfFileException;
 import org.jline.reader.LineReader;
@@ -34,6 +31,9 @@
 import picocli.CommandLine;
 import picocli.shell.jline3.PicocliJLineCompleter;
 
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
 import static picocli.CommandLine.Help.Ansi.AUTO;
 
 public class InteractiveShell {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
index 7e1be5a1c21..14e060e44cd 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/AddPropertyCommand.java
@@ -18,25 +18,23 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.File;
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
-import io.micronaut.context.annotation.Parameter;
-import io.micronaut.core.annotation.ReflectiveAccess;
-import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine.Command;
-import picocli.CommandLine.Option;
-import picocli.CommandLine.Parameters;
-
 import grails.codegen.model.AbstractMemberDefinition;
 import grails.codegen.model.DomainFieldModifier;
 import grails.codegen.model.PropertyDefinition;
+import io.micronaut.context.annotation.Parameter;
+import io.micronaut.core.annotation.ReflectiveAccess;
+import io.micronaut.core.util.functional.ThrowingSupplier;
+import jakarta.inject.Inject;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.io.ConsoleOutput;
 import org.grails.forge.io.FileSystemOutputHandler;
 import org.grails.forge.io.OutputHandler;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+import picocli.CommandLine.Parameters;
+
+import java.io.File;
+import java.io.IOException;
 
 /**
  * CLI command to add a property to an existing domain class.
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java
index 9c938ed68e6..7abdfa429fb 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/BaseCommand.java
@@ -18,16 +18,15 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.Locale;
-
 import io.micronaut.context.env.CachedEnvironment;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.annotation.ReflectiveAccess;
-import picocli.CommandLine;
-
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.cli.CommonOptionsMixin;
 import org.grails.forge.io.ConsoleOutput;
+import picocli.CommandLine;
+
+import java.util.Locale;
 
 public class BaseCommand implements ConsoleOutput {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java
index db12d6194bf..7c501201cdd 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CodeGenCommand.java
@@ -18,16 +18,9 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-import java.util.concurrent.Callable;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.io.ConsoleOutput;
@@ -35,6 +28,11 @@
 import org.grails.forge.io.OutputHandler;
 import org.grails.forge.template.TemplateRenderer;
 import org.grails.forge.util.NameUtils;
+import jakarta.inject.Inject;
+import picocli.CommandLine;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
 
 public abstract class CodeGenCommand extends BaseCommand implements Callable {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java
index c3a599d26bd..34c2ce476d1 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateAppCommand.java
@@ -18,18 +18,17 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
-import picocli.CommandLine;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.WebAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
+import picocli.CommandLine;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @CommandLine.Command(name = CreateAppCommand.NAME, description = "Creates an application")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java
index 12aa1e236e7..aa478ae6749 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateCommand.java
@@ -18,16 +18,9 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.StringUtils;
-import picocli.CommandLine;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.Project;
@@ -35,12 +28,14 @@
 import org.grails.forge.feature.AvailableFeatures;
 import org.grails.forge.io.FileSystemOutputHandler;
 import org.grails.forge.io.OutputHandler;
-import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
 import org.grails.forge.util.NameUtils;
+import picocli.CommandLine;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
 
 public abstract class CreateCommand extends BaseCommand implements Callable {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java
index 151106354eb..ebf0682f6be 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateControllerCommand.java
@@ -18,15 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
+import jakarta.inject.Inject;
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.controller;
@@ -36,6 +31,9 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
+import picocli.CommandLine;
+
+import java.io.IOException;
 
 @CommandLine.Command(name = CreateControllerCommand.NAME, description = "Creates a Grails Controller")
 public class CreateControllerCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java
index 7ba6e6b6c1c..5c37809c6b1 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateDomainClassCommand.java
@@ -18,15 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
+import jakarta.inject.Inject;
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.domain;
@@ -36,6 +31,9 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
+import picocli.CommandLine;
+
+import java.io.IOException;
 
 @CommandLine.Command(name = CreateDomainClassCommand.NAME, description = "Creates a Domain Class")
 public class CreateDomainClassCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java
index 0d708b20566..6e42d947e5f 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateInterceptorCommand.java
@@ -18,15 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
+import jakarta.inject.Inject;
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.interceptor;
@@ -36,6 +31,9 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
+import picocli.CommandLine;
+
+import java.io.IOException;
 
 @CommandLine.Command(name = CreateInterceptorCommand.NAME, description = "Creates a Interceptor Class")
 public class CreateInterceptorCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java
index d33aedb39e6..81e3efc8bcb 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateJobCommand.java
@@ -18,15 +18,11 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
+import jakarta.inject.Inject;
+import java.io.IOException;
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.job;
@@ -35,6 +31,7 @@
 import org.grails.forge.io.OutputHandler;
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
+import picocli.CommandLine;
 
 @CommandLine.Command(name = CreateJobCommand.NAME, description = "Creates a new Quartz scheduled job")
 public class CreateJobCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java
index 713d870d318..f88b4c90677 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreatePluginCommand.java
@@ -18,18 +18,17 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
-import picocli.CommandLine;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.PluginAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
+import picocli.CommandLine;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @CommandLine.Command(name = CreatePluginCommand.NAME, description = "Creates an Grails Plugin")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java
index 218e2357a37..9f7f9b26023 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateRestApiCommand.java
@@ -18,18 +18,17 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
-import picocli.CommandLine;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.RestApiAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
+import picocli.CommandLine;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @CommandLine.Command(name = CreateRestApiCommand.NAME, description = "Creates an REST API")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java
index 9fa939d75d4..4c6640e19d8 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateServiceCommand.java
@@ -18,15 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
+import jakarta.inject.Inject;
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.service;
@@ -36,6 +31,9 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
+import picocli.CommandLine;
+
+import java.io.IOException;
 
 @CommandLine.Command(name = CreateServiceCommand.NAME, description = "Creates a Service Class")
 public class CreateServiceCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java
index 003631be3eb..70eea1dadec 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateTagLibCommand.java
@@ -18,15 +18,10 @@
  */
 package org.grails.forge.cli.command;
 
-import java.io.IOException;
-
-import jakarta.inject.Inject;
-
 import io.micronaut.context.annotation.Parameter;
 import io.micronaut.core.annotation.ReflectiveAccess;
 import io.micronaut.core.util.functional.ThrowingSupplier;
-import picocli.CommandLine;
-
+import jakarta.inject.Inject;
 import org.grails.forge.application.Project;
 import org.grails.forge.cli.CodeGenConfig;
 import org.grails.forge.cli.command.templates.taglib;
@@ -36,6 +31,9 @@
 import org.grails.forge.template.RenderResult;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.TemplateRenderer;
+import picocli.CommandLine;
+
+import java.io.IOException;
 
 @CommandLine.Command(name = CreateTagLibCommand.NAME, description = "Creates a Grails TagLib")
 public class CreateTagLibCommand extends CodeGenCommand {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java
index b6df720233d..693e7e10eb2 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebPluginCommand.java
@@ -18,18 +18,17 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
-import picocli.CommandLine;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.WebPluginAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
+import picocli.CommandLine;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @CommandLine.Command(name = CreateWebPluginCommand.NAME, description = "Creates an Grails Web Plugin")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java
index 8d7c66acccd..465544bd908 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/CreateWebappCommand.java
@@ -18,18 +18,17 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.context.annotation.Prototype;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.ReflectiveAccess;
-import picocli.CommandLine;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.WebAvailableFeatures;
 import org.grails.forge.application.generator.ProjectGenerator;
+import picocli.CommandLine;
+
+import java.util.ArrayList;
+import java.util.List;
 
 @CommandLine.Command(name = CreateWebappCommand.NAME, description = "Creates an application")
 @Prototype
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java
index f8ef80293c0..49e80e4c65d 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
+import org.grails.forge.options.DevelopmentReloading;
+
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.grails.forge.options.DevelopmentReloading;
-
 public class DevelopmentReloadingCandidates extends ArrayList {
 
     public DevelopmentReloadingCandidates() {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java
index 1542a973bdb..fb2a5211bb9 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/DevelopmentReloadingConverter.java
@@ -18,9 +18,8 @@
  */
 package org.grails.forge.cli.command;
 
-import picocli.CommandLine;
-
 import org.grails.forge.options.DevelopmentReloading;
+import picocli.CommandLine;
 
 public class DevelopmentReloadingConverter implements CommandLine.ITypeConverter {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java
index 38d7c836d37..55246650308 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
+import org.grails.forge.options.GormImpl;
+
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.grails.forge.options.GormImpl;
-
 public class GormImplCandidates extends ArrayList {
     public GormImplCandidates() {
         super(Stream.of(GormImpl.values()).map(gi -> gi.toString().toLowerCase()).collect(Collectors.toList()));
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java
index c0c47e9e9b0..5b802d3b38e 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/GormImplConverter.java
@@ -19,9 +19,8 @@
 package org.grails.forge.cli.command;
 
 import io.micronaut.core.annotation.Introspected;
-import picocli.CommandLine;
-
 import org.grails.forge.options.GormImpl;
+import picocli.CommandLine;
 
 @Introspected
 public class GormImplConverter implements CommandLine.ITypeConverter {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java
index 4596278d60c..8f202915fa7 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
+import org.grails.forge.options.Language;
+
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.grails.forge.options.Language;
-
 public class LanguageCandidates extends ArrayList {
     public LanguageCandidates() {
         super(Stream.of(Language.values()).map(l -> l.toString().toLowerCase()).collect(Collectors.toList()));
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java
index 4bda0860c24..373f53b9d8d 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/LanguageConverter.java
@@ -18,9 +18,8 @@
  */
 package org.grails.forge.cli.command;
 
-import picocli.CommandLine;
-
 import org.grails.forge.options.Language;
+import picocli.CommandLine;
 
 public class LanguageConverter implements CommandLine.ITypeConverter {
 
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java
index 38a9443c093..a7ba128b482 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ListFeatures.java
@@ -18,16 +18,7 @@
  */
 package org.grails.forge.cli.command;
 
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.stream.Collectors;
-
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.OperatingSystem;
@@ -38,6 +29,14 @@
 import org.grails.forge.io.ConsoleOutput;
 import org.grails.forge.options.Options;
 
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
 public class ListFeatures {
 
     private final AvailableFeatures availableFeatures;
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java
index 1d7460d7baf..0b6032453a9 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplCandidates.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.cli.command;
 
+import org.grails.forge.options.ServletImpl;
+
 import java.util.ArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.grails.forge.options.ServletImpl;
-
 public class ServletImplCandidates extends ArrayList {
     public ServletImplCandidates() {
         super(Stream.of(ServletImpl.values()).map(servlet -> servlet.toString().toLowerCase()).collect(Collectors.toList()));
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java
index f404c75e374..87e18708306 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/command/ServletImplConverter.java
@@ -19,9 +19,8 @@
 package org.grails.forge.cli.command;
 
 import io.micronaut.core.annotation.Introspected;
-import picocli.CommandLine;
-
 import org.grails.forge.options.ServletImpl;
+import picocli.CommandLine;
 
 @Introspected
 public class ServletImplConverter implements CommandLine.ITypeConverter {
diff --git a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
index eb4090d8a65..7e13a15c721 100644
--- a/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
+++ b/grails-forge/grails-forge-cli/src/main/java/org/grails/forge/cli/util/GrailsVersionProvider.java
@@ -18,13 +18,11 @@
  */
 package org.grails.forge.cli.util;
 
-import java.util.Objects;
-
 import jakarta.inject.Singleton;
-
+import org.grails.forge.util.VersionInfo;
 import picocli.CommandLine.IVersionProvider;
 
-import org.grails.forge.util.VersionInfo;
+import java.util.Objects;
 
 /**
  * Generates version information. Example usage:
@@ -51,8 +49,8 @@ public class GrailsVersionProvider implements IVersionProvider {
 
     public String[] getVersion() {
         return new String[] {
-            "Grails Version: " + VersionInfo.getGrailsVersion(),
-            "JVM Version: " + Objects.requireNonNullElse(System.getProperty("java.version"), "")
+                "Grails Version: " + VersionInfo.getGrailsVersion(),
+                "JVM Version: " + Objects.requireNonNullElse(System.getProperty("java.version"), "")
         };
     }
 }
diff --git a/grails-forge/grails-forge-core/build.gradle b/grails-forge/grails-forge-core/build.gradle
index 1378c370ddd..11445540639 100644
--- a/grails-forge/grails-forge-core/build.gradle
+++ b/grails-forge/grails-forge-core/build.gradle
@@ -128,7 +128,7 @@ nohttp {
     source.exclude('**/pom.rocker.raw')
 }
 
-['processResources', 'sourcesJar', 'checkstyleNohttp'].each { name ->
+['processResources', 'sourcesJar', 'spotlessJavaMisc', 'checkstyleNohttp'].each { name ->
     tasks.named(name).configure {
         it.dependsOn(copyGrailsWrapper, grailsVersionInfoTask)
     }
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java
index 013224b9b1f..408933655ae 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/analytics/Generated.java
@@ -18,21 +18,17 @@
  */
 package org.grails.forge.analytics;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Objects;
-
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.NonNull;
-
 import org.grails.forge.application.ApplicationType;
-import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+
 @Introspected
 public class Generated {
     private final ApplicationType type;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java
index 60ef046c5d1..2d53ab634a9 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ApplicationType.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.application;
 
-import java.util.Locale;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.naming.Named;
 
+import java.util.Locale;
+
 public enum ApplicationType implements Named {
 
     WEB("Web Application", "A Grails® framework Web Application"),
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java
index 32bdb002a41..f499008902b 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/ContextFactory.java
@@ -18,15 +18,8 @@
  */
 package org.grails.forge.application;
 
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.Nullable;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.DefaultCoordinateResolver;
 import org.grails.forge.feature.AvailableFeatures;
@@ -35,12 +28,12 @@
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.feature.validation.FeatureValidator;
 import org.grails.forge.io.ConsoleOutput;
-import org.grails.forge.options.BuildTool;
-import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.Language;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
+import org.grails.forge.options.*;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Set;
 
 @Singleton
 public class ContextFactory {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java
index 49c76e26cb3..61855d3ed77 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/PluginAvailableFeatures.java
@@ -18,14 +18,13 @@
  */
 package org.grails.forge.application;
 
-import java.util.List;
-
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
-
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
+import java.util.List;
+
 @Named("plugin")
 @Singleton
 public class PluginAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java
index db9e2478a8b..8847b9d52d5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/Project.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.application;
 
+import org.grails.forge.util.NameUtils;
+
 import java.util.HashMap;
 import java.util.Map;
 
-import org.grails.forge.util.NameUtils;
-
 public class Project extends ProjectIdentifier {
 
     private static final String PACKAGE_NAME = "packageName";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java
index 856287a2766..206d959267e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/RestApiAvailableFeatures.java
@@ -18,14 +18,13 @@
  */
 package org.grails.forge.application;
 
-import java.util.List;
-
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
-
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
+import java.util.List;
+
 @Named("rest_api")
 @Singleton
 public class RestApiAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java
index 2d3896c4b74..ea6a84209b8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebAvailableFeatures.java
@@ -18,14 +18,13 @@
  */
 package org.grails.forge.application;
 
-import java.util.List;
-
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
-
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
+import java.util.List;
+
 @Named("web")
 @Singleton
 public class WebAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java
index abe8f78303e..25b7c36b462 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/WebPluginAvailableFeatures.java
@@ -18,14 +18,13 @@
  */
 package org.grails.forge.application;
 
-import java.util.List;
-
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
-
 import org.grails.forge.feature.BaseAvailableFeatures;
 import org.grails.forge.feature.Feature;
 
+import java.util.List;
+
 @Named("web_plugin")
 @Singleton
 public class WebPluginAvailableFeatures extends BaseAvailableFeatures {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java
index 9c81866bf66..71502385d3a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/DefaultProjectGenerator.java
@@ -18,17 +18,10 @@
  */
 package org.grails.forge.application.generator;
 
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.function.Function;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.BeanContext;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.inject.qualifiers.Qualifiers;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.ContextFactory;
 import org.grails.forge.application.OperatingSystem;
@@ -46,6 +39,11 @@
 import org.grails.forge.template.Template;
 import org.grails.forge.template.TemplateRenderer;
 
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Function;
+
 @Singleton
 public class DefaultProjectGenerator implements ProjectGenerator {
     private final ContextFactory contextFactory;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java
index a27a41d8216..d0713701b85 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/GeneratorContext.java
@@ -18,31 +18,15 @@
  */
 package org.grails.forge.application.generator;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
 import com.fizzed.rocker.RockerModel;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.Project;
 import org.grails.forge.build.BuildPlugin;
 import org.grails.forge.build.BuildProperties;
-import org.grails.forge.build.dependencies.Coordinate;
-import org.grails.forge.build.dependencies.CoordinateResolver;
-import org.grails.forge.build.dependencies.Dependency;
-import org.grails.forge.build.dependencies.DependencyContext;
-import org.grails.forge.build.dependencies.LookupFailedException;
-import org.grails.forge.build.dependencies.Scope;
+import org.grails.forge.build.dependencies.*;
 import org.grails.forge.build.gradle.GradleRepository;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.Features;
@@ -51,20 +35,15 @@
 import org.grails.forge.feature.config.BootstrapConfiguration;
 import org.grails.forge.feature.config.Configuration;
 import org.grails.forge.feature.other.template.markdownLink;
-import org.grails.forge.options.DevelopmentReloading;
-import org.grails.forge.options.GormImpl;
-import org.grails.forge.options.JdkVersion;
-import org.grails.forge.options.Language;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.ServletImpl;
-import org.grails.forge.options.TestFramework;
-import org.grails.forge.options.TestRockerModelProvider;
+import org.grails.forge.options.*;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.RockerWritable;
 import org.grails.forge.template.Template;
 import org.grails.forge.template.Writable;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.*;
+
 /**
  * A context object used when generating projects.
  *
@@ -315,7 +294,7 @@ public String getIntegrationTestSourcePath(String path) {
     }
 
     RockerModel parseModel(RockerModel javaTemplate, RockerModel groovyTemplate) {
-        return groovyTemplate;
+       return groovyTemplate;
     }
 
     public void addTemplate(String name, String path, TestRockerModelProvider testRockerModelProvider) {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java
index c1b4120edeb..685eab9b22e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/application/generator/ProjectGenerator.java
@@ -18,11 +18,8 @@
  */
 package org.grails.forge.application.generator;
 
-import java.util.List;
-
 import io.micronaut.context.annotation.DefaultImplementation;
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.Project;
@@ -30,6 +27,8 @@
 import org.grails.forge.io.OutputHandler;
 import org.grails.forge.options.Options;
 
+import java.util.List;
+
 @DefaultImplementation(DefaultProjectGenerator.class)
 public interface ProjectGenerator {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java
index a4ade3e5e90..6af46a707a0 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/BuildPlugin.java
@@ -21,7 +21,6 @@
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.Ordered;
-
 import org.grails.forge.build.dependencies.CoordinateResolver;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.template.Writable;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java
index c97e7e5a0b8..5fb61cdf75e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Coordinate.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.dependencies;
 
-import java.util.Comparator;
-
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.OrderUtil;
 
+import java.util.Comparator;
+
 @Introspected
 public interface Coordinate {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java
index 836b064fec9..2ff403db8ee 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DefaultCoordinateResolver.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.build.dependencies;
 
-import java.util.Arrays;
-import java.util.Optional;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.annotation.Primary;
 import io.micronaut.core.annotation.NonNull;
+import jakarta.inject.Singleton;
+
+import java.util.Arrays;
+import java.util.Optional;
 
 @Singleton
 @Primary
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java
index 94603d6e558..1604a9cec2a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Dependency.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.build.dependencies;
 
-import java.util.Objects;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.template.Writable;
 
+import java.util.Objects;
+
 public final class Dependency {
 
     private final Scope scope;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java
index eb4236990ca..8c18b25f5da 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyContext.java
@@ -19,12 +19,11 @@
 package org.grails.forge.build.dependencies;
 
 
-import java.util.Collection;
-
 import io.micronaut.core.annotation.NonNull;
-
 import org.grails.forge.build.gradle.GradleRepository;
 
+import java.util.Collection;
+
 public interface DependencyContext {
 
     @NonNull
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java
index 3e845fc79d0..6df627bc3c2 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/DependencyCoordinate.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.dependencies;
 
-import java.util.Objects;
-
 import io.micronaut.core.annotation.Introspected;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.Ordered;
 
+import java.util.Objects;
+
 @Introspected
 public class DependencyCoordinate implements Coordinate, Ordered {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java
index 5d445d9acba..87a9f5c1ef8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/PomDependencyVersionResolver.java
@@ -18,28 +18,26 @@
  */
 package org.grails.forge.build.dependencies;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.io.ResourceResolver;
 import io.micronaut.core.util.StringUtils;
+import jakarta.inject.Singleton;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
 @Singleton
 public class PomDependencyVersionResolver implements CoordinateResolver {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java
index d1878a56ef6..67a619d9ae3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/dependencies/Scope.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.dependencies;
 
+import io.micronaut.core.annotation.NonNull;
+
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
-import io.micronaut.core.annotation.NonNull;
-
 public class Scope {
 
     public static final Scope ANNOTATION_PROCESSOR = new Scope(Source.MAIN, Collections.singletonList(Phase.ANNOTATION_PROCESSING));
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java
index 6db443de899..4bcebb23d83 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/DefaultGradleRepository.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.build.gradle;
 
+import io.micronaut.core.annotation.NonNull;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-import io.micronaut.core.annotation.NonNull;
-
 public class DefaultGradleRepository implements GradleRepository {
     private final int order;
     private final String url;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java
index c16cbc4e9b2..62afcc40ae6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuild.java
@@ -18,6 +18,11 @@
  */
 package org.grails.forge.build.gradle;
 
+import io.micronaut.core.annotation.NonNull;
+import org.grails.forge.template.Writable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -29,12 +34,6 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import io.micronaut.core.annotation.NonNull;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.grails.forge.template.Writable;
-
 public class GradleBuild {
     private static final Logger LOG = LoggerFactory.getLogger(GradleBuild.class);
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java
index c37844d15d1..82beefc4619 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleBuildCreator.java
@@ -18,17 +18,15 @@
  */
 package org.grails.forge.build.gradle;
 
-import java.util.List;
-import java.util.stream.Collectors;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.order.OrderUtil;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.options.BuildTool;
 
+import java.util.List;
+import java.util.stream.Collectors;
+
 @Singleton
 public class GradleBuildCreator {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java
index cfee3593883..a4b43954c8c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleConfiguration.java
@@ -18,15 +18,14 @@
  */
 package org.grails.forge.build.gradle;
 
-import java.util.Optional;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.order.Ordered;
-
 import org.grails.forge.build.dependencies.Phase;
 import org.grails.forge.build.dependencies.Scope;
 import org.grails.forge.options.DevelopmentReloading;
 
+import java.util.Optional;
+
 public enum GradleConfiguration implements Ordered {
     CLASSPATH("classpath", -2),
     PROFILE("profile", -1),
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java
index 5f25714b34c..0f72ed14a4b 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleDependency.java
@@ -18,21 +18,20 @@
  */
 package org.grails.forge.build.gradle;
 
-import static org.grails.forge.build.gradle.GradleConfiguration.INTEGRATION_TEST_IMPLEMENTATION_TEST_FIXTURES;
-
-import java.util.Comparator;
-import java.util.Objects;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.order.OrderUtil;
-
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.build.dependencies.DependencyCoordinate;
 import org.grails.forge.template.Writable;
 
+import java.util.Comparator;
+import java.util.Objects;
+
+import static org.grails.forge.build.gradle.GradleConfiguration.INTEGRATION_TEST_IMPLEMENTATION_TEST_FIXTURES;
+
 public class GradleDependency extends DependencyCoordinate {
 
     public static final Comparator COMPARATOR = (o1, o2) -> {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java
index a8c214b3ee7..bd85c6ba142 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradlePlugin.java
@@ -18,22 +18,18 @@
  */
 package org.grails.forge.build.gradle;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.build.BuildPlugin;
-import org.grails.forge.build.dependencies.Coordinate;
-import org.grails.forge.build.dependencies.CoordinateResolver;
-import org.grails.forge.build.dependencies.LookupFailedException;
-import org.grails.forge.build.dependencies.Scope;
+import org.grails.forge.build.dependencies.*;
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.template.Writable;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
 public class GradlePlugin implements BuildPlugin {
 
     private final String id;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java
index a7f816088df..06ab59206b5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/build/gradle/GradleRepository.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.build.gradle;
 
+import io.micronaut.core.annotation.NonNull;
+import io.micronaut.core.order.Ordered;
+
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import io.micronaut.core.annotation.NonNull;
-import io.micronaut.core.order.Ordered;
-
 public interface GradleRepository extends Ordered {
     @NonNull
     String toSnippet(String basePadding);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java
index 6999e687fc4..16e549a42f1 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/oauth/AccessToken.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.client.github.oauth;
 
-import jakarta.validation.constraints.NotNull;
-
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.micronaut.core.annotation.Introspected;
 
+import jakarta.validation.constraints.NotNull;
+
 /**
  * @author Pavol Gressa
  * @since 6.0.0
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java
index ff1b00c99a6..5916bfab3a7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubSecretsPublicKey.java
@@ -47,3 +47,4 @@ public String getKeyId() {
         return keyId;
     }
 }
+
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java
index a05cd0aeb98..ce3836943ca 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubUser.java
@@ -38,7 +38,7 @@ public class GitHubUser {
     @JsonCreator
     public GitHubUser(
             @JsonProperty("login") String login,
-            @JsonProperty("email") String email,
+            @JsonProperty("email")  String email,
             @JsonProperty("name") String name) {
         this.login = login;
         this.email = email;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java
index e4b8d2e495d..e95f19f5809 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/client/github/v3/GitHubWorkflowRuns.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.client.github.v3;
 
-import java.util.List;
-
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.micronaut.core.annotation.Introspected;
 
+import java.util.List;
+
 /**
  * GitHub workflow runs.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java
index 0b45573c63f..b6e95a2e9d3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/defaults/LanguageDefaults.java
@@ -20,7 +20,6 @@
 
 import io.micronaut.core.annotation.Creator;
 import io.micronaut.core.annotation.Introspected;
-
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.options.DevelopmentReloading;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java
index 5583f2ad6e4..62a2d4aeab0 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/diff/FeatureDiffer.java
@@ -18,18 +18,11 @@
  */
 package org.grails.forge.diff;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import jakarta.inject.Singleton;
-
 import com.github.difflib.DiffUtils;
 import com.github.difflib.UnifiedDiffUtils;
 import com.github.difflib.patch.Patch;
 import io.micronaut.core.annotation.Nullable;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.Project;
@@ -39,6 +32,11 @@
 import org.grails.forge.io.MapOutputHandler;
 import org.grails.forge.options.Options;
 
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
 /**
  * Methods for diffing projects and features.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java
index 263aa8c35c6..2ae4e2c080b 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/ApplicationFeature.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature;
 
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.application.generator.GeneratorContext;
 
 public interface ApplicationFeature extends Feature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java
index 94d8800df89..e3aac954790 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/AvailableFeatures.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.feature;
 
+import io.micronaut.core.annotation.NonNull;
+
 import java.util.Optional;
 import java.util.stream.Stream;
 
-import io.micronaut.core.annotation.NonNull;
-
 public interface AvailableFeatures extends Iterable {
 
     Optional findFeature(@NonNull String name);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java
index a208a668b4d..e1d19144070 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/BaseAvailableFeatures.java
@@ -18,6 +18,9 @@
  */
 package org.grails.forge.feature;
 
+import io.micronaut.core.annotation.NonNull;
+import org.grails.forge.application.ApplicationType;
+
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -27,10 +30,6 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import io.micronaut.core.annotation.NonNull;
-
-import org.grails.forge.application.ApplicationType;
-
 public class BaseAvailableFeatures implements AvailableFeatures {
     private final Map features;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java
index 5d992362fd6..ea5ff9e9983 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Category.java
@@ -25,35 +25,35 @@
  * @since 6.0.0
  */
 public class Category {
-    public static final String API = "API";
-    public static final String BPM = "BPM";
-    public static final String CACHE = "Cache";
-    public static final String CICD = "CI/CD";
-    public static final String CLIENT = "Client";
-    public static final String CLOUD = "Cloud";
-    public static final String CONFIGURATION = "Configuration";
-    public static final String DATABASE = "Database";
-    public static final String DEV_TOOLS = "Development Tools";
-    public static final String DISTRIBUTED_CONFIG = "Distributed Configuration";
-    public static final String DOCUMENTATION = "Documentation";
-    public static final String IOT = "Internet of Things";
-    public static final String LANGUAGES = "Languages";
-    public static final String LOGGING = "Logging";
-    public static final String MANAGEMENT = "Management";
-    public static final String MESSAGING = "Messaging";
-    public static final String OTHER = "Other";
-    public static final String PACKAGING = "Packaging";
-    public static final String REACTIVE = "Reactive";
-    public static final String RESILIENCE = "Resilience";
-    public static final String SEARCH = "Search Engine";
-    public static final String SECURITY = "Security";
-    public static final String SERVER = "Server";
-    public static final String SERVERLESS = "Serverless";
-    public static final String SERVICE_DISCOVERY = "Service Discovery";
-    public static final String SPRING = "Spring Framework";
-    public static final String SSL = "SSL";
-    public static final String TESTING = "Testing";
-    public static final String TRACING = "Distributed Tracing";
-    public static final String VALIDATION = "Validation";
-    public static final String VIEW = "View Rendering";
+    public static final String API                  = "API";
+    public static final String BPM                  = "BPM";
+    public static final String CACHE                = "Cache";
+    public static final String CICD                 = "CI/CD";
+    public static final String CLIENT               = "Client";
+    public static final String CLOUD                = "Cloud";
+    public static final String CONFIGURATION        = "Configuration";
+    public static final String DATABASE             = "Database";
+    public static final String DEV_TOOLS            = "Development Tools";
+    public static final String DISTRIBUTED_CONFIG   = "Distributed Configuration";
+    public static final String DOCUMENTATION        = "Documentation";
+    public static final String IOT                  = "Internet of Things";
+    public static final String LANGUAGES            = "Languages";
+    public static final String LOGGING              = "Logging";
+    public static final String MANAGEMENT           = "Management";
+    public static final String MESSAGING            = "Messaging";
+    public static final String OTHER                = "Other";
+    public static final String PACKAGING            = "Packaging";
+    public static final String REACTIVE             = "Reactive";
+    public static final String RESILIENCE           = "Resilience";
+    public static final String SEARCH               = "Search Engine";
+    public static final String SECURITY             = "Security";
+    public static final String SERVER               = "Server";
+    public static final String SERVERLESS           = "Serverless";
+    public static final String SERVICE_DISCOVERY    = "Service Discovery";
+    public static final String SPRING               = "Spring Framework";
+    public static final String SSL                  = "SSL";
+    public static final String TESTING              = "Testing";
+    public static final String TRACING              = "Distributed Tracing";
+    public static final String VALIDATION           = "Validation";
+    public static final String VIEW                 = "View Rendering";
 }
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java
index 7ae949e37d9..54b1473cce9 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/DefaultFeature.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.feature;
 
-import java.util.Set;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 /**
  * A default feature is one that should be applied to a
  * project conditionally without being explicitly selected.
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java
index 9a9e655cd78..2abe72d73a1 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Feature.java
@@ -24,7 +24,6 @@
 import io.micronaut.core.naming.Described;
 import io.micronaut.core.naming.Named;
 import io.micronaut.core.order.Ordered;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
index 4acbcad6a25..f8dea471f4e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/FeatureContext.java
@@ -18,15 +18,7 @@
  */
 package org.grails.forge.feature;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-
 import io.micronaut.core.annotation.Nullable;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.feature.reloading.ReloadingFeature;
@@ -35,6 +27,8 @@
 import org.grails.forge.options.JdkVersion;
 import org.grails.forge.options.Options;
 
+import java.util.*;
+
 import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.toSet;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java
index dc29eacba43..75cded6bf65 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/Features.java
@@ -18,12 +18,6 @@
  */
 package org.grails.forge.feature;
 
-import java.util.ArrayList;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.lang.LanguageFeature;
 import org.grails.forge.feature.reloading.ReloadingFeature;
@@ -33,6 +27,12 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 public class Features extends ArrayList {
 
     private final Set featureList;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java
index 7b31822f088..869bdd76c9c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/asciidoctor/Asciidoctor.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.asciidoctor;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java
index fe8282abc58..78c47bc36f5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/assetPipeline/AssetPipeline.java
@@ -18,13 +18,8 @@
  */
 package org.grails.forge.feature.assetPipeline;
 
-import java.util.List;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.CoordinateResolver;
@@ -36,6 +31,9 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
+import java.util.Set;
+import java.util.List;
+
 @Singleton
 public class AssetPipeline implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java
index 2cdcdf63d32..cf213384a9c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Dockerfile.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.feature.build.gradle;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class Dockerfile {
     @Nullable
     private String baseImage;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java
index c6749ef7f2e..fc71a88a464 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/Gradle.java
@@ -18,11 +18,7 @@
  */
 package org.grails.forge.feature.build.gradle;
 
-import java.util.Set;
-import java.util.function.Function;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -43,6 +39,9 @@
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.Set;
+import java.util.function.Function;
+
 @Singleton
 public class Gradle implements BuildFeature {
     private static final String WRAPPER_JAR = "gradle/wrapper/gradle-wrapper.jar";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java
index 53286b94255..b3046a01770 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleBuildSrc.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.build.gradle;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.CoordinateResolver;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java
index 28317031d4f..afc86b0fe6a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/GradleSettingsFile.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.build.gradle;
 
-import java.util.function.Function;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -33,6 +30,8 @@
 import org.grails.forge.options.BuildTool;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.function.Function;
+
 @Singleton
 public class GradleSettingsFile implements GradleSettingsFileFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
index c2a868b7bdb..b933875e843 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/EHCache.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.feature.cache;
 
-import java.util.Map;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
+import java.util.Map;
+
 @Singleton
 public class EHCache implements CacheFeature {
 
@@ -46,7 +45,7 @@ public String getDescription() {
 
     @Override
     public void apply(GeneratorContext generatorContext) {
-        Map config = generatorContext.getConfiguration();
+        Map config  = generatorContext.getConfiguration();
         config.put("grails.cache.ehcache.ehcacheXmlLocation", "classpath:ehcache.xml");
         config.put("grails.cache.ehcache.lockTimeout", 200);
         generatorContext.addDependency(Dependency.builder()
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java
index f307e8d1cb4..09f91bde398 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/cache/GrailsCache.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.cache;
 
-import java.util.Map;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -29,6 +26,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.Map;
+
 @Singleton
 public class GrailsCache implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
index 3f11813959a..7313f52a028 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Configuration.java
@@ -18,15 +18,15 @@
  */
 package org.grails.forge.feature.config;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
 import io.micronaut.core.util.CollectionUtils;
 import io.micronaut.core.util.StringUtils;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
 /**
  * Models application environment configuration to specify where the configuration is rooted
  * for the given configuration values (key/value pairs).
@@ -50,7 +50,7 @@ public class Configuration extends LinkedHashMap {
      */
     public Configuration(@NonNull String sourceSet, @NonNull String fileName, @NonNull String templateKey, @Nullable String environment) {
         super();
-        this.path = environment != null && environment.equals("test") ? "src/" + sourceSet + "/resources/" : "grails-app/conf/";
+        this.path = environment != null && environment.equals("test") ? "src/" + sourceSet  + "/resources/" : "grails-app/conf/";
         this.fileName = fileName;
         this.templateKey = templateKey;
         this.environment = environment;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java
index 4470642e2a3..0020b375bc8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/ConfigurationFeature.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.feature.config;
 
-import java.util.function.Function;
-
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.OneOfFeature;
 import org.grails.forge.template.Template;
 
+import java.util.function.Function;
+
 public interface ConfigurationFeature extends OneOfFeature {
 
     String ENVIRONMENTS_KEY = "environments";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java
index f48ef0c4a4d..080c423ef21 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Properties.java
@@ -18,15 +18,14 @@
  */
 package org.grails.forge.feature.config;
 
-import java.util.function.Function;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.FeaturePhase;
 import org.grails.forge.template.PropertiesTemplate;
 import org.grails.forge.template.Template;
 
+import java.util.function.Function;
+
 @Singleton
 public class Properties implements ConfigurationFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java
index 792570e1874..28cc738f7e7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/config/Yaml.java
@@ -18,11 +18,7 @@
  */
 package org.grails.forge.feature.config;
 
-import java.util.Set;
-import java.util.function.Function;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
@@ -31,6 +27,9 @@
 import org.grails.forge.template.Template;
 import org.grails.forge.template.YamlTemplate;
 
+import java.util.Set;
+import java.util.function.Function;
+
 @Singleton
 public class Yaml implements ConfigurationFeature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
index e87044e4113..4fc8641e0b5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverConfigurationFeature.java
@@ -18,16 +18,16 @@
  */
 package org.grails.forge.feature.database;
 
+import org.grails.forge.feature.Feature;
+
 import java.util.Map;
 import java.util.Optional;
 
-import org.grails.forge.feature.Feature;
-
 import static org.grails.forge.feature.config.ConfigurationFeature.DEV_ENVIRONMENT_KEY;
-import static org.grails.forge.feature.config.ConfigurationFeature.ENVIRONMENTS_KEY;
+import static org.grails.forge.feature.config.ConfigurationFeature.TEST_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.config.ConfigurationFeature.PROD_ENVIRONMENT_KEY;
+import static org.grails.forge.feature.config.ConfigurationFeature.ENVIRONMENTS_KEY;
 import static org.grails.forge.feature.config.ConfigurationFeature.PROPERTIES_KEY;
-import static org.grails.forge.feature.config.ConfigurationFeature.TEST_ENVIRONMENT_KEY;
 import static org.grails.forge.feature.database.HibernateGorm.PREFIX;
 
 /**
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java
index 895c699d7cb..ead67ce4ba3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/DatabaseDriverFeature.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Collections;
-import java.util.Map;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.feature.OneOfFeature;
 
+import java.util.Collections;
+import java.util.Map;
+
 public abstract class DatabaseDriverFeature implements OneOfFeature {
 
     private final TestContainers testContainers;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java
index 728b0d6fd83..6fb6af98166 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GormFeature.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Map;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.DefaultFeature;
 
+import java.util.Map;
+
 public abstract class GormFeature implements DefaultFeature {
 
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java
index 53bc73ccb1c..fb958659208 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/GraphqlGorm.java
@@ -18,10 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.Nullable;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java
index 413df0fa1cc..93e924e9d70 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/H2.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.annotation.Primary;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 @Primary
 public class H2 extends DatabaseDriverFeature implements DefaultFeature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java
index 9969e6a91a7..568030e73f1 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/HibernateGorm.java
@@ -18,13 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Map;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.annotation.Primary;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -33,6 +28,9 @@
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.Options;
 
+import java.util.Map;
+import java.util.Set;
+
 @Primary
 @Singleton
 public class HibernateGorm extends GormFeature implements DatabaseDriverConfigurationFeature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java
index 4a787541cf5..d81b0e1523f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoGorm.java
@@ -18,13 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Map;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.Nullable;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -33,6 +28,9 @@
 import org.grails.forge.options.GormImpl;
 import org.grails.forge.options.Options;
 
+import java.util.Map;
+import java.util.Set;
+
 @Singleton
 public class MongoGorm extends GormOneOfFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java
index a421acd3ced..6ce42eef78e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MongoSync.java
@@ -18,15 +18,14 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Map;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.feature.Category;
 
+import java.util.Map;
+
 @Singleton
 public class MongoSync extends MongoFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java
index 7e76c2bc445..6518bc3ae06 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/MySQL.java
@@ -18,10 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java
index 2465ab3f048..7c06dd46f9d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/PostgreSQL.java
@@ -18,10 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java
index a1d444ee21e..040905a7906 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/SQLServer.java
@@ -18,10 +18,8 @@
  */
 package org.grails.forge.feature.database;
 
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java
index 7562f0b8998..10b4b6e8d57 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/database/TestContainers.java
@@ -18,13 +18,9 @@
  */
 package org.grails.forge.feature.database;
 
-import java.util.Optional;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.core.annotation.Nullable;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -35,6 +31,8 @@
 import org.grails.forge.feature.test.Spock;
 import org.grails.forge.template.StringTemplate;
 
+import java.util.Optional;
+
 @Singleton
 public class TestContainers implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java
index 1b2b8496161..8d7e3e210f6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/GitHubWorkflowFeature.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.feature.github.workflows;
 
-import java.util.Collections;
-import java.util.List;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.Feature;
 
+import java.util.Collections;
+import java.util.List;
+
 /**
  * GitHub workflow feature.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java
index d9cfce37fef..ab01213311e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/github/workflows/plain/PlainGithubWorkflowFeature.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.github.workflows.plain;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.github.workflows.GitHubWorkflowFeature;
 import org.grails.forge.feature.github.workflows.plain.templates.plainGithubWorkflow;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java
index 96717f97556..a784fc573a5 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsBase.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.grails;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,6 +28,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
+import java.util.Set;
+
 @Singleton
 public class GrailsBase implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java
index 8371553190b..4ab1fdc74e0 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsConsole.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.grails;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -29,6 +26,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class GrailsConsole implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java
index 054a59261c5..fa87cac0c27 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsDefaultPlugins.java
@@ -18,11 +18,7 @@
  */
 package org.grails.forge.feature.grails;
 
-import java.util.Arrays;
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -32,6 +28,9 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
+import java.util.Arrays;
+import java.util.Set;
+
 @Singleton
 public class GrailsDefaultPlugins implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java
index 3080fea8288..1a3c0400288 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsGradlePlugin.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.grails;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.CoordinateResolver;
@@ -33,6 +30,8 @@
 import org.grails.forge.feature.web.GrailsWeb;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 class GrailsGradlePlugin implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java
index 14154b16ced..ca51e392ca6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsUrlMappings.java
@@ -18,17 +18,16 @@
  */
 package org.grails.forge.feature.grails;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
-import org.grails.forge.feature.grails.templates.urlMappings;
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
+import org.grails.forge.feature.grails.templates.urlMappings;
+
+import java.util.Set;
 
 @Singleton
 public class GrailsUrlMappings implements DefaultFeature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java
index 2f6d124d325..5c81045d989 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grails/GrailsWebConsole.java
@@ -18,16 +18,15 @@
  */
 package org.grails.forge.feature.grails;
 
-import java.util.Map;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.feature.Category;
 import org.grails.forge.feature.Feature;
 
+import java.util.Map;
+
 @Singleton
 public class GrailsWebConsole implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java
index 99315373420..53806b0ba3d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsProfiles/GrailsProfiles.java
@@ -18,11 +18,7 @@
  */
 package org.grails.forge.feature.grailsProfiles;
 
-import java.util.Map;
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -32,6 +28,9 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Map;
+import java.util.Set;
+
 @Singleton
 public class GrailsProfiles implements DefaultFeature {
     @Override
@@ -56,6 +55,8 @@ public boolean supports(ApplicationType applicationType) {
 
     @Override
     public void apply(GeneratorContext generatorContext) {
+
+
         final Map config = generatorContext.getConfiguration();
         // Required by profile commands when package is not set
         config.put("grails.codegen.defaultPackage", generatorContext.getProject().getPackageName());
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java
index 68a098a8ff7..569db93881c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/grailsWrapper/GrailsWrapper.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.grailsWrapper;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -31,6 +28,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.BinaryTemplate;
 
+import java.util.Set;
+
 @Singleton
 public class GrailsWrapper implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java
index 4ee6e1224a0..964d8534809 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/lang/groovy/GrailsApplication.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.lang.groovy;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.Nullable;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.gradle.GradlePlugin;
@@ -34,6 +30,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.Set;
+
 @Singleton
 public class GrailsApplication implements GrailsApplicationFeature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java
index 808fd66f4b3..23e340a951d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/logging/Logback.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.logging;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -32,6 +29,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.Set;
+
 @Singleton
 public class Logback implements LoggingFeature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java
index fb2e9b571a7..7e849717ed6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/GrailsMicronaut.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.micronaut;
 
-import java.util.Optional;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -34,6 +30,8 @@
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.options.JdkVersion;
 
+import java.util.Optional;
+
 @Singleton
 public class GrailsMicronaut implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java
index 3dfba102234..8b2315dbb78 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/micronaut/MicronautHttpClient.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.micronaut;
 
-import java.util.Optional;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Coordinate;
@@ -34,6 +30,8 @@
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.options.JdkVersion;
 
+import java.util.Optional;
+
 @Singleton
 public class MicronautHttpClient implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java
index 8b946ae8f1f..413d849cbab 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/migration/DatabaseMigrationPlugin.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.migration;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.feature.migration.templates.dbMigrationGradle;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java
index cfa81250421..0677e277093 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/AppName.java
@@ -18,11 +18,7 @@
  */
 package org.grails.forge.feature.other;
 
-import java.util.Map;
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.DefaultFeature;
@@ -30,6 +26,9 @@
 import org.grails.forge.feature.FeaturePhase;
 import org.grails.forge.options.Options;
 
+import java.util.Map;
+import java.util.Set;
+
 @Singleton
 public class AppName implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java
index 70c929642e5..bcc607cca8b 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/GrailsQuartz.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.other;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java
index 3d048436612..ca7d76baf0c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/HibernateValidator.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.other;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java
index 873738880ef..c82545081c8 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/Readme.java
@@ -18,16 +18,8 @@
  */
 package org.grails.forge.feature.other;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.DefaultFeature;
@@ -40,6 +32,12 @@
 import org.grails.forge.template.Template;
 import org.grails.forge.template.Writable;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 @Singleton
 public class Readme implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java
index 599cc3e4d81..4181f191bb6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/other/ShadePlugin.java
@@ -18,10 +18,8 @@
  */
 package org.grails.forge.feature.other;
 
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.gradle.GradlePlugin;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java
index 327cceee08c..274f271d673 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/Jrebel.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.reloading;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.gradle.GradlePlugin;
@@ -29,6 +26,8 @@
 import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class Jrebel implements ReloadingFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java
index ea9cdc4135f..d00b1d93b39 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/reloading/SpringBootDevTools.java
@@ -18,8 +18,6 @@
  */
 package org.grails.forge.feature.reloading;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
 
 import org.grails.forge.application.ApplicationType;
@@ -33,6 +31,8 @@
 import org.grails.forge.options.DevelopmentReloading;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class SpringBootDevTools implements ReloadingFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java
index fe322f9c22e..73fd1dc66a3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/sitemesh3/Sitemesh3.java
@@ -19,7 +19,6 @@
 package org.grails.forge.feature.sitemesh3;
 
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java
index 1b962326def..33f00095f24 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootAutoconfigure.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -30,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class SpringBootAutoconfigure implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java
index 219a2bf8e86..cd9175a322e 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootJettyFeature.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,6 +27,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.options.ServletImpl;
 
+import java.util.Set;
+
 @Singleton
 public class SpringBootJettyFeature extends SpringBootEmbeddedServlet {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java
index 5cde71f42f8..bb833b238fd 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootStarterFeature.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -29,6 +26,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class SpringBootStarterFeature implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java
index ec1cd8e447a..f74ef4cfb3d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootTomcatFeature.java
@@ -18,13 +18,9 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.annotation.Primary;
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -32,6 +28,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.options.ServletImpl;
 
+import java.util.Set;
+
 @Primary
 @Singleton
 public class SpringBootTomcatFeature extends SpringBootEmbeddedServlet {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java
index 843762ab22d..3d946901aaa 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootUndertowFeature.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,6 +27,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.options.ServletImpl;
 
+import java.util.Set;
+
 @Singleton
 public class SpringBootUndertowFeature extends SpringBootEmbeddedServlet {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java
index f8fe65695ca..8d19a87e668 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringBootVirtualThreads.java
@@ -18,13 +18,12 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Map;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 
+import java.util.Map;
+
 @Singleton
 public class SpringBootVirtualThreads implements SpringThreadingFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java
index 27155ef3786..79eb8285248 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/spring/SpringResources.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.spring;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.feature.Category;
@@ -31,6 +28,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.Set;
+
 @Singleton
 public class SpringResources implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java
index 5d2c70e4b2f..d91f61c9096 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithTestcontainers.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.Project;
 import org.grails.forge.application.generator.GeneratorContext;
@@ -33,12 +29,11 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.FeatureContext;
 import org.grails.forge.feature.FeaturePhase;
-import org.grails.forge.options.DefaultTestRockerModelProvider;
-import org.grails.forge.options.Options;
-import org.grails.forge.options.TestFramework;
-import org.grails.forge.options.TestRockerModelProvider;
+import org.grails.forge.options.*;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.Set;
+
 @Singleton
 public class GebWithTestcontainers implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java
index 5076eb68710..c27ee16d777 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GebWithWebDriverBinaries.java
@@ -18,28 +18,21 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.stream.Stream;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.Project;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.build.gradle.GradlePlugin;
-import org.grails.forge.feature.Category;
-import org.grails.forge.feature.Feature;
-import org.grails.forge.feature.FeatureContext;
-import org.grails.forge.feature.FeaturePhase;
-import org.grails.forge.feature.test.template.gebConfig;
+import org.grails.forge.feature.*;
 import org.grails.forge.feature.test.template.webdriverBinariesPlugin;
-import org.grails.forge.options.DefaultTestRockerModelProvider;
-import org.grails.forge.options.TestFramework;
-import org.grails.forge.options.TestRockerModelProvider;
+import org.grails.forge.options.*;
 import org.grails.forge.template.RockerTemplate;
 import org.grails.forge.template.RockerWritable;
+import org.grails.forge.feature.test.template.gebConfig;
+
+import java.util.stream.Stream;
 
 @Singleton
 public class GebWithWebDriverBinaries implements Feature {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java
index e854153b3e5..47f7b7de1fd 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GormTestingSupport.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -30,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class GormTestingSupport implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java
index 793b840d828..b88dc39da6d 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/GrailsWebTestingSupport.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -30,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class GrailsWebTestingSupport implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java
index 91da385437d..02cf19a9376 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Mockito.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -30,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class Mockito implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java
index 2c3d1f3dae5..6acafa48f62 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/MockitoValidator.java
@@ -18,15 +18,14 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.validation.FeatureValidator;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class MockitoValidator implements FeatureValidator {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java
index b2fe04c0510..53ce37d421a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/Spock.java
@@ -18,12 +18,8 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class Spock implements Feature, DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java
index fe9f0ed5d00..f1946b4a513 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/test/ViewsJsonTestingSupport.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.test;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -30,6 +27,8 @@
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class ViewsJsonTestingSupport implements DefaultFeature {
     @Override
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java
index fde4574989a..e5d16f60b34 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/CompositeFeatureValidator.java
@@ -18,17 +18,15 @@
  */
 package org.grails.forge.feature.validation;
 
-import java.util.List;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.context.annotation.Primary;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.List;
+import java.util.Set;
+
 @Primary
 @Singleton
 public class CompositeFeatureValidator implements FeatureValidator {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java
index 599b6a14ae2..77f77d73f9a 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/FeatureValidator.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.feature.validation;
 
-import java.util.Set;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 public interface FeatureValidator {
 
     void validatePreProcessing(Options options, ApplicationType applicationType, Set features);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java
index 7bf0a110ef7..4561b6fec5f 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/validation/OneOfFeatureValidator.java
@@ -18,17 +18,16 @@
  */
 package org.grails.forge.feature.validation;
 
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.OneOfFeature;
 import org.grails.forge.options.Options;
 
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 @Singleton
 public class OneOfFeatureValidator implements FeatureValidator {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java
index ec3428aaa55..207777d7a29 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/GrailsGsp.java
@@ -18,14 +18,8 @@
  */
 package org.grails.forge.feature.view;
 
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -38,6 +32,10 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.template.URLTemplate;
 
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
 @Singleton
 public class GrailsGsp implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java
index 0385eed5f37..e0ea7078a59 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/Scaffolding.java
@@ -18,10 +18,7 @@
  */
 package org.grails.forge.feature.view;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -31,6 +28,8 @@
 import org.grails.forge.options.Options;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.Set;
+
 @Singleton
 public class Scaffolding implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java
index 0f9df588485..82b6d16a107 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/json/ViewJson.java
@@ -18,14 +18,8 @@
  */
 package org.grails.forge.feature.view.json;
 
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
@@ -33,15 +27,15 @@
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.view.GrailsViews;
-import org.grails.forge.feature.view.json.templates._errors;
-import org.grails.forge.feature.view.json.templates._object;
-import org.grails.forge.feature.view.json.templates.error;
-import org.grails.forge.feature.view.json.templates.index;
-import org.grails.forge.feature.view.json.templates.notFound;
+import org.grails.forge.feature.view.json.templates.*;
 import org.grails.forge.feature.web.GrailsWeb;
 import org.grails.forge.options.Options;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
+
 @Singleton
 public class ViewJson extends GrailsViews implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java
index 730c21e7062..76260932fba 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/view/markup/ViewMarkup.java
@@ -18,26 +18,20 @@
  */
 package org.grails.forge.feature.view.markup;
 
-import java.util.Arrays;
-import java.util.Map;
-
-import jakarta.inject.Singleton;
-
 import io.micronaut.core.annotation.NonNull;
-
+import jakarta.inject.Singleton;
 import org.grails.forge.application.generator.GeneratorContext;
 import org.grails.forge.build.dependencies.Dependency;
 import org.grails.forge.build.gradle.GradlePlugin;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.feature.view.GrailsViews;
-import org.grails.forge.feature.view.markup.templates._errors;
-import org.grails.forge.feature.view.markup.templates._object;
-import org.grails.forge.feature.view.markup.templates.error;
-import org.grails.forge.feature.view.markup.templates.index;
-import org.grails.forge.feature.view.markup.templates.notFound;
+import org.grails.forge.feature.view.markup.templates.*;
 import org.grails.forge.feature.web.GrailsWeb;
 import org.grails.forge.template.RockerTemplate;
 
+import java.util.Arrays;
+import java.util.Map;
+
 @Singleton
 public class ViewMarkup extends GrailsViews implements Feature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java
index bddc07dad3f..faf85e9bdf7 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/web/GrailsWeb.java
@@ -18,15 +18,14 @@
  */
 package org.grails.forge.feature.web;
 
-import java.util.Set;
-
 import jakarta.inject.Singleton;
-
 import org.grails.forge.application.ApplicationType;
 import org.grails.forge.feature.DefaultFeature;
 import org.grails.forge.feature.Feature;
 import org.grails.forge.options.Options;
 
+import java.util.Set;
+
 @Singleton
 public class GrailsWeb implements DefaultFeature {
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java
index 8e8f86db483..54620a607fc 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/MapOutputHandler.java
@@ -18,14 +18,14 @@
  */
 package org.grails.forge.io;
 
+import org.grails.forge.template.Template;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-import org.grails.forge.template.Template;
-
 public class MapOutputHandler implements OutputHandler {
 
     private final Map templates;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java
index ba80515e47a..9586fbcb0d6 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/OutputHandler.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.io;
 
+import org.grails.forge.template.Template;
+
 import java.io.Closeable;
 import java.io.IOException;
 
-import org.grails.forge.template.Template;
-
 public interface OutputHandler extends Closeable {
 
     boolean exists(String path);
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java
index 8a66ad6b1e1..301dbbffe84 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/io/ZipOutputHandler.java
@@ -18,6 +18,13 @@
  */
 package org.grails.forge.io;
 
+import io.micronaut.core.util.StringUtils;
+import org.apache.commons.compress.archivers.zip.UnixStat;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.grails.forge.application.Project;
+import org.grails.forge.template.Template;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -28,14 +35,6 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import io.micronaut.core.util.StringUtils;
-import org.apache.commons.compress.archivers.zip.UnixStat;
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-
-import org.grails.forge.application.Project;
-import org.grails.forge.template.Template;
-
 public class ZipOutputHandler implements OutputHandler {
 
     private final ZipArchiveOutputStream zipOutputStream;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java
index b878892c4c4..0d064083c23 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/BuildTool.java
@@ -18,15 +18,14 @@
  */
 package org.grails.forge.options;
 
-import java.util.Locale;
-import java.util.Objects;
-import java.util.Optional;
-
 import io.micronaut.core.annotation.NonNull;
-
 import org.grails.forge.application.Project;
 import org.grails.forge.build.gradle.GradleDsl;
 
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Optional;
+
 public enum BuildTool {
     GRADLE("build/libs", "build.gradle", "-*-all.jar");
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java
index 24771c41613..e6896565a53 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/DevelopmentReloading.java
@@ -18,10 +18,10 @@
  */
 package org.grails.forge.options;
 
-import java.util.Locale;
-
 import io.micronaut.core.annotation.NonNull;
 
+import java.util.Locale;
+
 public enum DevelopmentReloading {
 
     DEVTOOLS("Spring Boot DevTools"),
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
index e4d957156c4..a110247a311 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Language.java
@@ -18,16 +18,15 @@
  */
 package org.grails.forge.options;
 
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.Set;
-
 import io.micronaut.core.annotation.NonNull;
-
 import org.grails.forge.defaults.IncludesDefaults;
 import org.grails.forge.defaults.LanguageDefaults;
 import org.grails.forge.feature.Feature;
 
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Set;
+
 public enum Language implements IncludesDefaults {
     GROOVY("groovy", new LanguageDefaults(DevelopmentReloading.DEVTOOLS, BuildTool.GRADLE));
 
@@ -69,7 +68,7 @@ public String getTestSrcDir() {
     }
 
     public String getIntegrationSrcDir() {
-        return "src/integration-test/" + getName();
+        return  "src/integration-test/" + getName();
     }
 
     public String getSourcePath(String path) {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java
index 3062d1c7f6a..b3ab6a01bb3 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/Options.java
@@ -18,19 +18,14 @@
  */
 package org.grails.forge.options;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-
 import io.micronaut.core.convert.ArgumentConversionContext;
 import io.micronaut.core.convert.value.ConvertibleValues;
 import io.micronaut.core.convert.value.ConvertibleValuesMap;
-
 import org.grails.forge.application.OperatingSystem;
 import org.grails.forge.util.VersionInfo;
 
+import java.util.*;
+
 public class Options implements ConvertibleValues {
 
     private final OperatingSystem operatingSystem;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java
index efce46973f5..32f75e126fd 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/options/TestFramework.java
@@ -18,12 +18,12 @@
  */
 package org.grails.forge.options;
 
+import io.micronaut.core.annotation.NonNull;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 
-import io.micronaut.core.annotation.NonNull;
-
 public enum TestFramework {
     SPOCK;
 
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java
index 4d1e93cbb92..1a9d72b8384 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/Config4kTemplate.java
@@ -18,15 +18,15 @@
  */
 package org.grails.forge.template;
 
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigRenderOptions;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigRenderOptions;
-
 public class Config4kTemplate implements Template {
     private final String path;
     private final Config config;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java
index d6df3de665c..bc82ef30a15 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/DefaultTemplateRenderer.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.template;
 
+import org.grails.forge.io.OutputHandler;
+
 import java.io.IOException;
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.grails.forge.io.OutputHandler;
-
 public class DefaultTemplateRenderer implements TemplateRenderer {
 
     private final Map replacements;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java
index f9ed0823f25..4ba35df5f55 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerTemplate.java
@@ -18,10 +18,10 @@
  */
 package org.grails.forge.template;
 
-import java.io.OutputStream;
-
 import com.fizzed.rocker.RockerModel;
 
+import java.io.OutputStream;
+
 public class RockerTemplate implements Template {
 
     private final String path;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java
index ebbf31c6093..14943d3ef0c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/RockerWritable.java
@@ -18,11 +18,11 @@
  */
 package org.grails.forge.template;
 
-import java.io.OutputStream;
-
 import com.fizzed.rocker.RockerModel;
 import com.fizzed.rocker.runtime.OutputStreamOutput;
 
+import java.io.OutputStream;
+
 public class RockerWritable implements Writable {
 
     private final RockerModel model;
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java
index ac32eeb6744..3eb8b7d4ef4 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/TemplateRenderer.java
@@ -18,13 +18,13 @@
  */
 package org.grails.forge.template;
 
+import org.grails.forge.application.Project;
+import org.grails.forge.io.OutputHandler;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.Collections;
 
-import org.grails.forge.application.Project;
-import org.grails.forge.io.OutputHandler;
-
 public interface TemplateRenderer extends Closeable {
 
     default RenderResult render(Template template) throws IOException {
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java
index b0789c811c8..e933423c032 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/template/YamlTemplate.java
@@ -18,6 +18,9 @@
  */
 package org.grails.forge.template;
 
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -25,9 +28,6 @@
 import java.util.Map;
 import java.util.regex.Pattern;
 
-import org.yaml.snakeyaml.DumperOptions;
-import org.yaml.snakeyaml.Yaml;
-
 public class YamlTemplate implements Template {
 
     private static final Pattern DOT_PATTERN = Pattern.compile("\\.");
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java
index 33829d88e98..0df87f80386 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/GitHubUtil.java
@@ -18,24 +18,22 @@
  */
 package org.grails.forge.util;
 
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import jakarta.validation.constraints.NotNull;
-
 import io.micronaut.core.util.StringUtils;
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.transport.PushResult;
 import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
-
 import org.grails.forge.client.github.v3.GitHubRepository;
 import org.grails.forge.client.github.v3.GitHubUser;
 
+import jakarta.validation.constraints.NotNull;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
 /**
  * Utility class for GitHub operations.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java
index 6c5e2ff674f..0dc11099a0c 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/IOFeatureUtil.java
@@ -18,20 +18,15 @@
  */
 package org.grails.forge.util;
 
+import org.grails.forge.application.generator.GeneratorContext;
+import org.grails.forge.template.URLTemplate;
+
 import java.io.IOException;
 import java.net.URI;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.ProviderNotFoundException;
+import java.nio.file.*;
 import java.util.function.BiFunction;
 import java.util.stream.Stream;
 
-import org.grails.forge.application.generator.GeneratorContext;
-import org.grails.forge.template.URLTemplate;
-
 /**
  * Feature Utility class for IO operations.
  *
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java
index 8150329c319..8e33ff63615 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/NameUtils.java
@@ -18,6 +18,10 @@
  */
 package org.grails.forge.util;
 
+import io.micronaut.core.util.StringUtils;
+import org.grails.forge.application.Project;
+import org.grails.forge.application.ProjectIdentifier;
+
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -27,11 +31,6 @@
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
-import io.micronaut.core.util.StringUtils;
-
-import org.grails.forge.application.Project;
-import org.grails.forge.application.ProjectIdentifier;
-
 public final class NameUtils {
     public static final String MICRONAUT = "micronaut";
     private static final String PROPERTY_SET_PREFIX = "set";
diff --git a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java
index 5f4581f284a..29078abbd61 100644
--- a/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java
+++ b/grails-forge/grails-forge-core/src/main/java/org/grails/forge/util/VersionInfo.java
@@ -18,6 +18,9 @@
  */
 package org.grails.forge.util;
 
+import io.micronaut.core.annotation.NonNull;
+import org.grails.forge.options.JdkVersion;
+
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
@@ -29,10 +32,6 @@
 import java.util.Map;
 import java.util.Properties;
 
-import io.micronaut.core.annotation.NonNull;
-
-import org.grails.forge.options.JdkVersion;
-
 public class VersionInfo {
 
     private static final Properties VERSIONS = new Properties();
diff --git a/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java b/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java
index 43f2608b5ec..049be55a3fa 100644
--- a/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java
+++ b/grails-forge/grails-forge-web-netty/src/main/java/org/grails/forge/netty/analytics/AnalyticsClient.java
@@ -18,18 +18,17 @@
  */
 package org.grails.forge.netty.analytics;
 
-import java.util.concurrent.CompletableFuture;
-
 import io.micronaut.context.annotation.Requires;
 import io.micronaut.core.annotation.NonNull;
 import io.micronaut.http.HttpStatus;
 import io.micronaut.http.annotation.Body;
 import io.micronaut.http.annotation.Post;
 import io.micronaut.http.client.annotation.Client;
-
 import org.grails.forge.analytics.Generated;
 import org.grails.forge.api.analytics.AnalyticsOperations;
 
+import java.util.concurrent.CompletableFuture;
+
 @Requires(property = AnalyticsClient.SERVICE_ANALYTICS)
 @Client("analytics")
 public interface AnalyticsClient extends AnalyticsOperations {

From 3b808a9bb8645e3e17264dcda0e557d7024fcff2 Mon Sep 17 00:00:00 2001
From: James Fredley 
Date: Mon, 1 Jun 2026 18:23:25 -0400
Subject: [PATCH 14/16] Fix code-style report path in violation-aggregation
 spec

The aggregation plugin reads style reports from build/reports/code-style,
but this spec still pre-populated and asserted against the old
build/reports/codestyle location after the report directory was renamed,
so the test failed. Align the test paths with the plugin.

Assisted-by: claude-code:claude-opus-4-8
---
 .../buildsrc/GrailsViolationAggregationPluginSpec.groovy    | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy
index 3c6f50cbb61..beb8d66908e 100644
--- a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy
+++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPluginSpec.groovy
@@ -100,8 +100,8 @@ class GrailsViolationAggregationPluginSpec extends Specification {
         srcFile.parentFile.mkdirs()
         srcFile.text = 'package com.example\nclass AppClass {}'
 
-        // Pre-populate XML reports in the standard consolidated location (build/reports/codestyle/)
-        def checkstyleDir = testProjectDir.resolve('build/reports/codestyle/checkstyle').toFile()
+        // Pre-populate XML reports in the standard consolidated location (build/reports/code-style/)
+        def checkstyleDir = testProjectDir.resolve('build/reports/code-style/checkstyle').toFile()
         checkstyleDir.mkdirs()
         new File(checkstyleDir, 'app-module-checkstyleMain.xml').text = """
 
@@ -110,7 +110,7 @@ class GrailsViolationAggregationPluginSpec extends Specification {
 
 
 """
-        def codenarcDir = testProjectDir.resolve('build/reports/codestyle/codenarc').toFile()
+        def codenarcDir = testProjectDir.resolve('build/reports/code-style/codenarc').toFile()
         codenarcDir.mkdirs()
         new File(codenarcDir, 'app-module-codenarcMain.xml').text = """
 

From 8b850a6fde16f3c5fc919ef8a3415c12303660fc Mon Sep 17 00:00:00 2001
From: Mattias Reichel 
Date: Wed, 3 Jun 2026 09:46:27 +0200
Subject: [PATCH 15/16] refactor(build): update
 GrailsViolationAggregationPlugin plugin

---
 .../GrailsViolationAggregationPlugin.groovy   | 195 +++++++++---------
 1 file changed, 101 insertions(+), 94 deletions(-)

diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
index f02a71310a3..a5b70265499 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsViolationAggregationPlugin.groovy
@@ -34,7 +34,6 @@ import org.gradle.api.file.Directory
 import org.gradle.api.file.FileCollection
 import org.gradle.api.logging.Logger
 import org.gradle.api.logging.Logging
-import org.gradle.api.plugins.AppliedPlugin
 import org.gradle.api.plugins.quality.Checkstyle
 import org.gradle.api.plugins.quality.CodeNarc
 import org.gradle.api.plugins.quality.Pmd
@@ -58,6 +57,7 @@ import org.gradle.testing.jacoco.tasks.JacocoReport
 @CompileStatic
 class GrailsViolationAggregationPlugin implements Plugin {
 
+    private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss')
     private static final Logger LOGGER = Logging.getLogger(GrailsViolationAggregationPlugin)
 
     /**
@@ -87,8 +87,8 @@ class GrailsViolationAggregationPlugin implements Plugin {
         def styleXmlDir = project.layout.buildDirectory.dir('reports/code-style')
         def analysisXmlDir = project.layout.buildDirectory.dir('reports/code-analysis')
 
-        TaskProvider styleTask = registerStyleAggregation(project, styleXmlDir, violationsDir)
-        TaskProvider analysisTask = registerAnalysisAggregation(project, analysisXmlDir, violationsDir)
+        def styleTask = registerStyleAggregation(project, styleXmlDir, violationsDir)
+        def analysisTask = registerAnalysisAggregation(project, analysisXmlDir, violationsDir)
         registerJacocoAggregation(project, violationsDir)
 
         project.tasks.register('aggregateViolations') { Task task ->
@@ -101,29 +101,29 @@ class GrailsViolationAggregationPlugin implements Plugin {
     private static TaskProvider registerStyleAggregation(Project root, Provider styleXmlDir, Provider violationsDir) {
         // Wire property flags as Providers — values are resolved at task execution time, not at apply() time,
         // and Providers are configuration-cache safe to capture in task actions
-        Provider checkStyleTests = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.TEST_STYLING_PROPERTY)
-        Provider codenarcEnabled = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.CODENARC_ENABLED_PROPERTY, true)
-        Provider checkstyleEnabled = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.CHECKSTYLE_ENABLED_PROPERTY, true)
-
-        TaskProvider aggregateTask = root.tasks.register('aggregateStyleViolations') { Task task ->
-            task.group = 'verification'
-            task.description = 'Aggregates CodeNarc and Checkstyle violation reports into build/reports/violations/'
-            task.outputs.file(root.file('build/reports/violations/CODENARC_VIOLATIONS.md'))
-            task.outputs.file(root.file('build/reports/violations/CHECKSTYLE_VIOLATIONS.md'))
-            task.doLast {
+        def checkStyleTests = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.TEST_STYLING_PROPERTY)
+        def codenarcEnabled = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.CODENARC_ENABLED_PROPERTY, true)
+        def checkstyleEnabled = GradleUtils.booleanProvider(root, GrailsCodeStylePlugin.CHECKSTYLE_ENABLED_PROPERTY, true)
+
+        def aggregateTask = root.tasks.register('aggregateStyleViolations') {
+            it.group = 'verification'
+            it.description = 'Aggregates CodeNarc and Checkstyle violation reports into build/reports/violations/'
+            it.outputs.file(root.file('build/reports/violations/CODENARC_VIOLATIONS.md'))
+            it.outputs.file(root.file('build/reports/violations/CHECKSTYLE_VIOLATIONS.md'))
+            it.doLast {
                 parseStyleViolations(styleXmlDir.get(), violationsDir.get(),
                     checkStyleTests.get(), codenarcEnabled.get(), checkstyleEnabled.get())
             }
         }
         root.subprojects { Project sub ->
-            sub.pluginManager.withPlugin('codenarc') { AppliedPlugin p ->
-                aggregateTask.configure { Task task ->
-                    task.dependsOn(sub.tasks.withType(CodeNarc))
+            sub.pluginManager.withPlugin('codenarc') {
+                aggregateTask.configure {
+                    it.dependsOn(sub.tasks.withType(CodeNarc))
                 }
             }
-            sub.pluginManager.withPlugin('checkstyle') { AppliedPlugin p ->
-                aggregateTask.configure { Task task ->
-                    task.dependsOn(sub.tasks.withType(Checkstyle))
+            sub.pluginManager.withPlugin('checkstyle') {
+                aggregateTask.configure {
+                    it.dependsOn(sub.tasks.withType(Checkstyle))
                 }
             }
         }
@@ -131,29 +131,29 @@ class GrailsViolationAggregationPlugin implements Plugin {
     }
 
     private static TaskProvider registerAnalysisAggregation(Project root, Provider analysisXmlDir, Provider violationsDir) {
-        Provider checkAnalysisTests = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.TEST_ANALYSIS_PROPERTY)
-        Provider pmdEnabled = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.PMD_ENABLED_PROPERTY)
-        Provider spotbugsEnabled = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.SPOTBUGS_ENABLED_PROPERTY)
-
-        TaskProvider aggregateTask = root.tasks.register('aggregateAnalysisViolations') { Task task ->
-            task.group = 'verification'
-            task.description = 'Aggregates PMD and SpotBugs violation reports into build/reports/violations/'
-            task.outputs.file(root.file('build/reports/violations/PMD_VIOLATIONS.md'))
-            task.outputs.file(root.file('build/reports/violations/SPOTBUGS_VIOLATIONS.md'))
-            task.doLast {
+        def checkAnalysisTests = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.TEST_ANALYSIS_PROPERTY)
+        def pmdEnabled = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.PMD_ENABLED_PROPERTY)
+        def spotbugsEnabled = GradleUtils.booleanProvider(root, GrailsCodeAnalysisPlugin.SPOTBUGS_ENABLED_PROPERTY)
+
+        def aggregateTask = root.tasks.register('aggregateAnalysisViolations') {
+            it.group = 'verification'
+            it.description = 'Aggregates PMD and SpotBugs violation reports into build/reports/violations/'
+            it.outputs.file(root.file('build/reports/violations/PMD_VIOLATIONS.md'))
+            it.outputs.file(root.file('build/reports/violations/SPOTBUGS_VIOLATIONS.md'))
+            it.doLast {
                 parseAnalysisViolations(analysisXmlDir.get(), violationsDir.get(),
                     checkAnalysisTests.get(), pmdEnabled.get(), spotbugsEnabled.get())
             }
         }
         root.subprojects { Project sub ->
-            sub.pluginManager.withPlugin('pmd') { AppliedPlugin p ->
-                aggregateTask.configure { Task task ->
-                    task.dependsOn(sub.tasks.withType(Pmd))
+            sub.pluginManager.withPlugin('pmd') {
+                aggregateTask.configure {
+                    it.dependsOn(sub.tasks.withType(Pmd))
                 }
             }
-            sub.pluginManager.withPlugin('com.github.spotbugs') { AppliedPlugin p ->
-                aggregateTask.configure { Task task ->
-                    task.dependsOn(sub.tasks.withType(SpotBugsTask))
+            sub.pluginManager.withPlugin('com.github.spotbugs') {
+                aggregateTask.configure {
+                    it.dependsOn(sub.tasks.withType(SpotBugsTask))
                 }
             }
         }
@@ -162,50 +162,50 @@ class GrailsViolationAggregationPlugin implements Plugin {
 
     private static void registerJacocoAggregation(Project root, Provider violationsDir) {
         // Collect all potential CSV paths at configuration time — Project must not be referenced from task actions
-        FileCollection jacocoCsvFiles = root.files(
-            root.allprojects.collect { Project p -> p.file('build/reports/jacoco/test/jacocoTestReport.csv') }
+        def jacocoCsvFiles = root.files(
+            root.allprojects.collect { it.file('build/reports/jacoco/test/jacocoTestReport.csv') }
         )
 
         // Resolve the excluded class-name prefixes as a Provider so the value is captured
         // configuration-cache-safely and read at task execution time.
-        Provider> excludedClassPrefixes = root.providers
+        def excludedClassPrefixes = root.providers
             .gradleProperty(JACOCO_EXCLUDED_CLASS_PREFIXES_PROPERTY)
             .orElse(DEFAULT_JACOCO_EXCLUDED_CLASS_PREFIXES)
-            .map { String value ->
-                value.split(',').collect { it.trim() }.findAll { !it.isEmpty() }
+            .map {
+                it.split(',')*.trim().findAll()
             }
 
-        TaskProvider aggregateTask = root.tasks.register('aggregateJacocoCoverage') { Task task ->
-            task.group = 'verification'
-            task.description = 'Aggregates JaCoCo coverage reports from all subprojects into build/reports/violations/'
-            task.inputs.files(jacocoCsvFiles).optional(true)
-            task.inputs.property('excludedClassPrefixes', excludedClassPrefixes)
-            task.outputs.file(root.file('build/reports/violations/JACOCO_COVERAGE.md'))
-            task.doLast {
+        def aggregateTask = root.tasks.register('aggregateJacocoCoverage') {
+            it.group = 'verification'
+            it.description = 'Aggregates JaCoCo coverage reports from all subprojects into build/reports/violations/'
+            it.inputs.files(jacocoCsvFiles).optional(true)
+            it.inputs.property('excludedClassPrefixes', excludedClassPrefixes)
+            it.outputs.file(root.file('build/reports/violations/JACOCO_COVERAGE.md'))
+            it.doLast {
                 parseJacocoCoverage(jacocoCsvFiles, violationsDir.get(), excludedClassPrefixes.get())
             }
         }
         root.subprojects { Project sub ->
-            sub.pluginManager.withPlugin('jacoco') { AppliedPlugin p ->
-                aggregateTask.configure { Task task ->
-                    task.dependsOn(sub.tasks.withType(JacocoReport))
+            sub.pluginManager.withPlugin('jacoco') {
+                aggregateTask.configure {
+                    it.dependsOn(sub.tasks.withType(JacocoReport))
                 }
             }
         }
     }
 
     private static XmlSlurper createSecureSlurper() {
-        def slurper = new XmlSlurper()
-        slurper.setFeature('http://apache.org/xml/features/disallow-doctype-decl', true)
-        slurper.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false)
-        slurper.setFeature('http://xml.org/sax/features/external-general-entities', false)
-        slurper.setFeature('http://xml.org/sax/features/external-parameter-entities', false)
-        slurper.setFeature('http://xml.org/sax/features/namespaces', false)
-        return slurper
+        new XmlSlurper().tap {
+            setFeature('http://apache.org/xml/features/disallow-doctype-decl', true)
+            setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false)
+            setFeature('http://xml.org/sax/features/external-general-entities', false)
+            setFeature('http://xml.org/sax/features/external-parameter-entities', false)
+            setFeature('http://xml.org/sax/features/namespaces', false)
+        }
     }
 
-    private static String getModule(String fileName) {
-        def lastDash = fileName.lastIndexOf('-')
+    private static String resolveModule(String fileName) {
+        int lastDash = fileName.lastIndexOf('-')
         lastDash != -1 ? fileName.substring(0, lastDash) : fileName
     }
 
@@ -215,30 +215,31 @@ class GrailsViolationAggregationPlugin implements Plugin {
 
     @CompileDynamic
     private static void writeReport(Directory violationsDir, String fileName, List violations, String title) {
-        def outDir = violationsDir.asFile
-        outDir.mkdirs()
-        def reportFile = new File(outDir, fileName)
-        def out = new StringBuilder()
-        out.append("# ${title}\n")
-        out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n")
+        def reportFile = new File(
+                violationsDir.asFile.tap { it.mkdirs() },
+                fileName
+        )
+        def text = new StringBuilder()
+        text.append("# ${title}\n")
+        text.append("Generated on: ${LocalDateTime.now().format(TIMESTAMP_FORMAT)}\n\n")
 
         if (violations.isEmpty()) {
-            out.append('No violations found! 🎉\n')
+            text.append('No violations found! 🎉\n')
         } else {
             def uniqueViolations = violations.unique().sort { v -> "${v.module}:${v.className}:${v.line}" }
             def groupedByModule = uniqueViolations.groupBy { it.module }.sort()
             groupedByModule.each { module, modViolations ->
-                out.append("## Module: ${module}\n")
-                out.append('| Class | Tool | Violation | Line | Message |\n')
-                out.append('| :--- | :--- | :--- | :--- | :--- |\n')
+                text.append("## Module: ${module}\n")
+                text.append('| Class | Tool | Violation | Line | Message |\n')
+                text.append('| :--- | :--- | :--- | :--- | :--- |\n')
                 modViolations.each { v ->
-                    out.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n")
+                    text.append("| ${v.className} | ${v.tool} | ${v.type} | ${v.line} | ${v.message.replaceAll(/\|/, '\\|')} |\n")
                 }
-                out.append('\n')
+                text.append('\n')
             }
         }
-        reportFile.text = out.toString()
-        LOGGER.lifecycle("Aggregated report generated: ${reportFile.absolutePath}")
+        reportFile.text = text
+        LOGGER.lifecycle('Aggregated report generated: {}', reportFile.absolutePath)
     }
 
     @CompileDynamic
@@ -264,14 +265,16 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 if (file.size() == 0 || (!checkStyleTests && isTestFile(file.name))) {
                     return
                 }
-                def module = getModule(file.name)
+                def module = resolveModule(file.name)
                 def xml = slurper.parse(file)
                 xml.Package.each { pkg ->
                     pkg.File.each { f ->
                         def pkgName = pkg.@name.text()
                         def fileName = f.@name.text()
                         def className = pkgName ? "${pkgName}.${fileName}" : fileName
-                        className = className.replace('.groovy', '').replace('.java', '')
+                        className = className
+                                .replace('.groovy', '')
+                                .replace('.java', '')
                         if (shouldSkipClass(checkStyleTests, className, f.@name.text())) {
                             return
                         }
@@ -299,16 +302,19 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 if (file.size() == 0 || (!checkStyleTests && isTestFile(file.name))) {
                     return
                 }
-                def module = getModule(file.name)
+                def module = resolveModule(file.name)
                 def xml = slurper.parse(file)
                 xml.file.each { f ->
-                    def filePath = f.@name.text()
+                    String filePath = f.@name.text()
                     def className = filePath.contains('src/main/groovy/') ? filePath.split('src/main/groovy/')[1] :
                                     filePath.contains('src/main/java/')   ? filePath.split('src/main/java/')[1] :
                                     filePath.contains('src/test/groovy/') ? filePath.split('src/test/groovy/')[1] :
                                     filePath.contains('src/test/java/')   ? filePath.split('src/test/java/')[1] :
                                     filePath.split('/').last()
-                    className = className.replace('.groovy', '').replace('.java', '').replace('/', '.')
+                    className = className
+                            .replace('.groovy', '')
+                            .replace('.java', '')
+                            .replace('/', '.')
                     if (shouldSkipClass(checkStyleTests, className)) {
                         return
                     }
@@ -348,7 +354,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 if (file.size() == 0 || (!checkAnalysisTests && isTestFile(file.name))) {
                     return
                 }
-                def module = getModule(file.name)
+                def module = resolveModule(file.name)
                 def xml = slurper.parse(file)
                 xml.file.each { f ->
                     f.violation.each { v ->
@@ -378,7 +384,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
                 if (file.size() == 0 || (!checkAnalysisTests && isTestFile(file.name))) {
                     return
                 }
-                def module = getModule(file.name)
+                def module = resolveModule(file.name)
                 def xml = slurper.parse(file)
                 xml.BugInstance.each { b ->
                     def className = b.Class.@classname.text()
@@ -404,7 +410,7 @@ class GrailsViolationAggregationPlugin implements Plugin {
         def jacocoCoverage = []
         csvFiles.each { File csvReport ->
             if (csvReport.exists()) {
-                LOGGER.debug("Processing JaCoCo report: ${csvReport.absolutePath}")
+                LOGGER.debug('Processing JaCoCo report: {}', csvReport.absolutePath)
                 csvReport.splitEachLine(',') { fields ->
                     if (fields.size() < 5 || fields[0] == 'GROUP') {
                         return
@@ -442,24 +448,25 @@ class GrailsViolationAggregationPlugin implements Plugin {
             jacocoCoverage.removeIf { entry -> excludedClassPrefixes.any { prefix -> entry.className.startsWith(prefix) } }
         }
 
-        def outDir = violationsDir.asFile
-        outDir.mkdirs()
-        def reportFile = new File(outDir, 'JACOCO_COVERAGE.md')
-        def out = new StringBuilder()
-        out.append('# JaCoCo Coverage Report\n')
-        out.append("Generated on: ${LocalDateTime.now().format(DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss'))}\n\n")
+        def reportFile = new File(
+                violationsDir.asFile.tap { it.mkdirs() },
+                'JACOCO_COVERAGE.md'
+        )
+        def text = new StringBuilder()
+        text.append('# JaCoCo Coverage Report\n')
+        text.append("Generated on: ${LocalDateTime.now().format(TIMESTAMP_FORMAT)}\n\n")
 
         def groupedByModule = jacocoCoverage.groupBy { it.module }.sort()
         groupedByModule.each { module, coverageList ->
-            out.append("## Module: ${module}\n")
-            out.append('| Class | % Instructions Covered |\n')
-            out.append('| :--- | :--- |\n')
+            text.append("## Module: ${module}\n")
+            text.append('| Class | % Instructions Covered |\n')
+            text.append('| :--- | :--- |\n')
             coverageList.sort { it.percent }.each { c ->
-                out.append("| ${c.className} | ${c.percent}% |\n")
+                text.append("| ${c.className} | ${c.percent}% |\n")
             }
-            out.append('\n')
+            text.append('\n')
         }
-        reportFile.text = out.toString()
-        LOGGER.lifecycle("Aggregated JaCoCo report generated: ${reportFile.absolutePath}")
+        reportFile.text = text
+        LOGGER.lifecycle('Aggregated JaCoCo report generated: {}', reportFile.absolutePath)
     }
 }

From cee8dec034baeba0ec755858ea0dfbdf2e0b7518 Mon Sep 17 00:00:00 2001
From: Mattias Reichel 
Date: Wed, 3 Jun 2026 10:07:11 +0200
Subject: [PATCH 16/16] refactor(build): update GrailsCodeAnalysisPlugin

---
 .../buildsrc/GrailsCodeAnalysisPlugin.groovy  | 70 ++++++++++---------
 1 file changed, 36 insertions(+), 34 deletions(-)

diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
index 6b88166d909..fdfdfde58b9 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsCodeAnalysisPlugin.groovy
@@ -23,20 +23,19 @@ import java.nio.file.Path
 
 import groovy.transform.CompileStatic
 
-import org.gradle.api.NamedDomainObjectContainer
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.plugins.quality.Pmd
-import org.gradle.api.plugins.quality.PmdExtension
-import org.gradle.api.plugins.quality.PmdPlugin
-import org.gradle.api.provider.Provider
-
 import com.github.spotbugs.snom.Confidence
 import com.github.spotbugs.snom.Effort
 import com.github.spotbugs.snom.SpotBugsExtension
 import com.github.spotbugs.snom.SpotBugsPlugin
-import com.github.spotbugs.snom.SpotBugsReport
 import com.github.spotbugs.snom.SpotBugsTask
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.logging.Logger
+import org.gradle.api.logging.Logging
+import org.gradle.api.plugins.quality.Pmd
+import org.gradle.api.plugins.quality.PmdExtension
+import org.gradle.api.plugins.quality.PmdPlugin
 
 /**
  * Convention plugin for Grails byte code analysis (PMD and SpotBugs).
@@ -45,6 +44,8 @@ import com.github.spotbugs.snom.SpotBugsTask
 @CompileStatic
 class GrailsCodeAnalysisPlugin implements Plugin {
 
+    private static final Logger LOGGER = Logging.getLogger(GrailsViolationAggregationPlugin)
+
     static String PMD_DIR_PROPERTY = 'grails.code-analysis.dir.pmd'
     static String PMD_ENABLED_PROPERTY = 'grails.code-analysis.enabled.pmd'
     static String PMD_CONFIG_FILE_NAME = 'pmd.xml'
@@ -64,16 +65,17 @@ class GrailsCodeAnalysisPlugin implements Plugin {
 
         // withType returns a live empty collection when the tool is not enabled,
         // so these dependsOn calls are safe regardless of whether PMD/SpotBugs are active
-        project.tasks.register('codeAnalysis') { task ->
-            task.group = 'verification'
-            task.description = 'Runs code analysis checks (PMD, SpotBugs)'
-            task.dependsOn(project.tasks.withType(Pmd))
-            task.dependsOn(project.tasks.withType(SpotBugsTask))
+        project.tasks.register('codeAnalysis') {
+            it.group = 'verification'
+            it.description = 'Runs code analysis checks (PMD, SpotBugs)'
+            it.dependsOn(project.tasks.withType(Pmd))
+            it.dependsOn(project.tasks.withType(SpotBugsTask))
         }
     }
 
     private static void initExtension(Project project) {
         def gca = project.extensions.create('grailsCodeAnalysis', GrailsCodeAnalysisExtension)
+        def buildDirectory = project.layout.buildDirectory
 
         gca.pmdDirectory.set(project.provider {
             def directory = project.hasProperty(PMD_DIR_PROPERTY) ?
@@ -86,21 +88,21 @@ class GrailsCodeAnalysisPlugin implements Plugin {
             createOrLoad(
                     toCreate.resolve(PMD_CONFIG_FILE_NAME),
                     "${BASE_RESOURCE_PATH}/pmd/${PMD_CONFIG_FILE_NAME}",
-                    project
+                    buildDirectory
             )
 
             directory
         })
     }
 
-    private static void createOrLoad(Path expectedPath, String defaultResource, Project project) {
-        def defaultPath = expectedPath.startsWith(project.rootProject.layout.buildDirectory.get().asFile.toPath())
+    private static void createOrLoad(Path expectedPath, String defaultResource, DirectoryProperty buildDirectory) {
+        def defaultPath = expectedPath.startsWith(buildDirectory.get().asFile.toPath())
         if (!Files.exists(expectedPath) || expectedPath.size() == 0 || defaultPath) {
             def defaultValue = GrailsCodeAnalysisPlugin.getResourceAsStream(defaultResource)
             if (!defaultValue) {
                 throw new IllegalStateException("Could not locate default configuration file: ${defaultResource}")
             }
-            project.logger.info('Replacing code analysis configuration')
+            LOGGER.info('Replacing code analysis configuration')
             expectedPath.text = defaultValue.text
         }
     }
@@ -124,21 +126,21 @@ class GrailsCodeAnalysisPlugin implements Plugin {
             it.toolVersion = project.findProperty('pmdVersion')
         }
 
-        project.tasks.withType(Pmd).configureEach { Pmd task ->
-            task.group = 'verification'
-            task.onlyIf { !project.hasProperty('skipCodeStyle') }
-            task.ignoreFailures = ignoreFailures.get()
+        project.tasks.withType(Pmd).configureEach {
+            it.group = 'verification'
+            it.onlyIf { !project.hasProperty('skipCodeStyle') }
+            it.ignoreFailures = ignoreFailures.get()
 
-            if (task.name.contains('Test') || task.name.contains('test')) {
-                task.enabled = testStylingEnabled.get()
+            if (it.name.contains('Test') || it.name.contains('test')) {
+                it.enabled = testStylingEnabled.get()
             }
 
-            task.reports.xml.required.set(true)
-            task.reports.xml.outputLocation.set(
+            it.reports.xml.required.set(true)
+            it.reports.xml.outputLocation.set(
                     project.extensions.getByType(GrailsCodeAnalysisExtension)
                             .reportsDirectory.get()
                             .dir('pmd')
-                            .file("${project.name}-${task.name}.xml")
+                            .file("${project.name}-${it.name}.xml")
             )
         }
     }
@@ -160,9 +162,9 @@ class GrailsCodeAnalysisPlugin implements Plugin {
             it.ignoreFailures.set(ignoreFailures)
         }
 
-        project.tasks.withType(SpotBugsTask).configureEach { SpotBugsTask task ->
-            task.group = 'verification'
-            def spotBugsReports = task.reports
+        project.tasks.withType(SpotBugsTask).configureEach {
+            it.group = 'verification'
+            def spotBugsReports = it.reports
             def htmlReport = spotBugsReports.maybeCreate('html')
             htmlReport.required.set(true)
             def xmlReport = spotBugsReports.maybeCreate('xml')
@@ -171,12 +173,12 @@ class GrailsCodeAnalysisPlugin implements Plugin {
                 project.extensions.getByType(GrailsCodeAnalysisExtension)
                         .reportsDirectory.get()
                         .dir('spotbugs')
-                        .file("${project.name}-${task.name}.xml")
+                        .file("${project.name}-${it.name}.xml")
             )
-            task.onlyIf { !project.hasProperty('skipCodeStyle') }
+            it.onlyIf { !project.hasProperty('skipCodeStyle') }
 
-            if (task.name.contains('Test') || task.name.contains('test')) {
-                task.enabled = testStylingEnabled.get()
+            if (it.name.contains('Test') || it.name.contains('test')) {
+                it.enabled = testStylingEnabled.get()
             }
         }
     }