|
| 1 | +//// |
| 2 | +Licensed to the Apache Software Foundation (ASF) under one |
| 3 | +or more contributor license agreements. See the NOTICE file |
| 4 | +distributed with this work for additional information |
| 5 | +regarding copyright ownership. The ASF licenses this file |
| 6 | +to you under the Apache License, Version 2.0 (the |
| 7 | +"License"); you may not use this file except in compliance |
| 8 | +with the License. You may obtain a copy of the License at |
| 9 | + |
| 10 | +https://www.apache.org/licenses/LICENSE-2.0 |
| 11 | + |
| 12 | +Unless required by applicable law or agreed to in writing, |
| 13 | +software distributed under the License is distributed on an |
| 14 | +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | +KIND, either express or implied. See the License for the |
| 16 | +specific language governing permissions and limitations |
| 17 | +under the License. |
| 18 | +//// |
| 19 | + |
| 20 | +https://codenarc.org/[CodeNarc] is a static analysis tool for Groovy that finds defects, poor coding practices, inconsistencies, style issues, and more. Grails projects can integrate CodeNarc via the Gradle https://docs.gradle.org/current/userguide/codenarc_plugin.html[CodeNarc plugin]. |
| 21 | + |
| 22 | +==== Adding Code Analysis to Your Build |
| 23 | + |
| 24 | +Apply the CodeNarc plugin and configure it using `extensions.configure()`: |
| 25 | + |
| 26 | +[source,groovy] |
| 27 | +---- |
| 28 | +import org.gradle.api.plugins.quality.CodeNarcExtension |
| 29 | +
|
| 30 | +plugins { |
| 31 | + id 'codenarc' |
| 32 | +} |
| 33 | +
|
| 34 | +dependencies { |
| 35 | + codenarc 'org.codenarc:CodeNarc:3.6.0-groovy-4.0' |
| 36 | +} |
| 37 | +
|
| 38 | +extensions.configure(CodeNarcExtension) { |
| 39 | + it.configFile = file('config/codenarc/codenarc.groovy') |
| 40 | + it.maxPriority1Violations = 0 |
| 41 | + it.maxPriority2Violations = 0 |
| 42 | + it.maxPriority3Violations = 0 |
| 43 | +} |
| 44 | +---- |
| 45 | + |
| 46 | +NOTE: Use the `-groovy-4.0` variant of CodeNarc for Grails 7 projects (which use Groovy 4.x). The plain artifact without a `-groovy-4.0` suffix is built for Groovy 3.x and will not work correctly. |
| 47 | + |
| 48 | +You can then run CodeNarc with: |
| 49 | + |
| 50 | +[source,bash] |
| 51 | +---- |
| 52 | +$ ./gradlew codenarcMain |
| 53 | +---- |
| 54 | + |
| 55 | +The HTML report is written to `build/reports/codenarc/main.html`. |
| 56 | + |
| 57 | +==== GORM AST Compatibility |
| 58 | + |
| 59 | +CodeNarc provides pre-built rulesets that can be imported as a group using the `ruleset()` syntax: |
| 60 | + |
| 61 | +[source,groovy] |
| 62 | +---- |
| 63 | +// config/codenarc/codenarc.groovy - DO NOT use this approach in Grails projects |
| 64 | +ruleset { |
| 65 | + ruleset('rulesets/basic.xml') |
| 66 | + ruleset('rulesets/formatting.xml') |
| 67 | + ruleset('rulesets/unused.xml') |
| 68 | +} |
| 69 | +---- |
| 70 | + |
| 71 | +WARNING: Importing entire rulesets with `ruleset('rulesets/xxx.xml')` in a Grails project causes compilation failures. This is because some CodeNarc rules (known as "enhanced" rules) perform semantic analysis at Groovy compiler phase 4. These enhanced rules attempt to resolve AST-transformed classes such as `OrderedGormTransformation` and `ServiceTransformation`, but CodeNarc compiles each source file independently without GORM's AST transformation processors on its classpath. The result is `ClassNotFoundException` or `NoClassDefFoundError` during analysis. |
| 72 | + |
| 73 | +Adding `compilationClasspath` to the CodeNarc Gradle task helps with basic class resolution but does *not* make GORM's transformation processors available, so enhanced rules still fail. |
| 74 | + |
| 75 | +==== Recommended Configuration |
| 76 | + |
| 77 | +The solution is to list individual rules explicitly rather than importing entire rulesets. This avoids pulling in enhanced rules that require GORM's AST infrastructure. The Grails framework's own build uses this approach: |
| 78 | + |
| 79 | +[source,groovy] |
| 80 | +---- |
| 81 | +// config/codenarc/codenarc.groovy |
| 82 | +ruleset { |
| 83 | +
|
| 84 | + description 'A Codenarc ruleset for the Grails codebase' |
| 85 | +
|
| 86 | + BracesForClass |
| 87 | + ClassStartsWithBlankLine { |
| 88 | + ignoreInnerClasses = true |
| 89 | + } |
| 90 | + ClosureStatementOnOpeningLineOfMultipleLineClosure |
| 91 | + ConsecutiveBlankLines |
| 92 | + FileEndsWithoutNewline |
| 93 | + NoTabCharacter |
| 94 | + DuplicateImport |
| 95 | + ImportFromSamePackage |
| 96 | + Indentation |
| 97 | + MisorderedStaticImports { |
| 98 | + comesBefore = false // static imports should come last |
| 99 | + } |
| 100 | + MissingBlankLineAfterImports |
| 101 | + MissingBlankLineAfterPackage |
| 102 | + MissingBlankLineBeforeAnnotatedField |
| 103 | + NoWildcardImports |
| 104 | + SpaceAfterCatch |
| 105 | + SpaceAfterClosingBrace |
| 106 | + SpaceAfterComma |
| 107 | + SpaceAfterFor |
| 108 | + SpaceAfterIf |
| 109 | + SpaceAfterMethodCallName |
| 110 | + SpaceAfterMethodDeclarationName |
| 111 | + SpaceAfterNotOperator |
| 112 | + SpaceAfterOpeningBrace { |
| 113 | + ignoreEmptyBlock = true |
| 114 | + } |
| 115 | + SpaceAfterSemicolon |
| 116 | + SpaceAfterSwitch |
| 117 | + SpaceAfterWhile |
| 118 | + SpaceAroundClosureArrow |
| 119 | + SpaceAroundMapEntryColon { |
| 120 | + characterAfterColonRegex = ' ' |
| 121 | + } |
| 122 | + SpaceAroundOperator { |
| 123 | + ignoreParameterDefaultValueAssignments = false |
| 124 | + } |
| 125 | + SpaceBeforeClosingBrace { |
| 126 | + ignoreEmptyBlock = true |
| 127 | + } |
| 128 | + SpaceBeforeOpeningBrace |
| 129 | + SpaceInsideParentheses |
| 130 | + UnnecessaryConstructor |
| 131 | + UnnecessaryDotClass |
| 132 | + UnnecessaryGroovyImport |
| 133 | + UnnecessaryGString |
| 134 | + UnnecessaryOverridingMethod |
| 135 | + UnnecessaryPublicModifier |
| 136 | + UnnecessarySafeNavigationOperator |
| 137 | + UnnecessarySemicolon |
| 138 | + UnusedImport |
| 139 | +} |
| 140 | +---- |
| 141 | + |
| 142 | +This is the exact ruleset used by the Grails framework's own build. It covers formatting, imports, spacing, and unnecessary code - all without triggering GORM AST compatibility issues. You can add additional individual rules as needed. |
| 143 | + |
| 144 | +TIP: You can find the full list of available CodeNarc rules at https://codenarc.org/codenarc-rules-formatting.html[codenarc.org]. Add individual rules as needed, testing that each one compiles cleanly against your Grails source files. |
| 145 | + |
| 146 | +==== Separate Ruleset for Tests |
| 147 | + |
| 148 | +Spock specifications often use patterns that trigger style rules (method names with spaces, loose typing, mock syntax). You can configure a separate, more lenient ruleset for test sources: |
| 149 | + |
| 150 | +[source,groovy] |
| 151 | +---- |
| 152 | +tasks.named('codenarcTest', CodeNarc) { |
| 153 | + configFile = file('config/codenarc/codenarc-test.groovy') |
| 154 | +} |
| 155 | +---- |
| 156 | + |
| 157 | +==== Reference |
| 158 | + |
| 159 | +The https://github.com/grails-plugins/grails-server-timing[grails-server-timing] plugin provides a complete working example of CodeNarc and Checkstyle configuration using Gradle convention plugins in its `build-logic/` directory. The Grails framework's own CodeNarc ruleset can be found in the https://github.com/apache/grails-core[grails-core] repository under `build-logic/plugins/src/main/resources/META-INF/org.apache.grails.buildsrc.codestyle/codenarc/codenarc.groovy`. Both are reliable starting points for any Grails project. |
0 commit comments