Skip to content

Generate configuration metadata from Groovy DSL sources - #16048

Open
jamesfredley wants to merge 1 commit into
feature/automated-configuration-metadatafrom
feature/groovy-dsl-configuration-metadata
Open

Generate configuration metadata from Groovy DSL sources#16048
jamesfredley wants to merge 1 commit into
feature/automated-configuration-metadatafrom
feature/groovy-dsl-configuration-metadata

Conversation

@jamesfredley

Copy link
Copy Markdown
Contributor

Summary

  • parse explicitly registered Groovy configuration DSL sources with SourceUnit without executing scripts, resolving dependencies, or running AST transforms
  • merge DSL-derived metadata, typed configuration metadata, and curated overlays with deterministic field-level precedence
  • generate Spring Security metadata from DefaultSecurityConfig and route every remaining in-repo metadata module through one canonical generated JAR resource
  • retain descriptions, hints, legacy properties, and indirect properties in additional-spring-configuration-metadata.json

Relationship

This is a stacked follow-up to #16047 and should be reviewed and merged after it.

It completes the remaining in-repo work for #15469. Asset Pipeline metadata remains in its external repository and existing upstream pull request.

Verification

  • build-logic: check
  • affected module test suites: grails-core, grails-web-core, grails-gsp, grails-data-mongodb, Hibernate 5/7 core and dbmigration, and grails-spring-security - 2,990 tests passed
  • :grails-test-examples-config-report:integrationTest
  • :grails-doc:publishGuide -x aggregateGroovydoc
  • :grails-spring-security:codeStyle
  • focused transform-safety, parser edge-case, incremental, and Spring Security metadata contract specs
  • direct Spring Security JAR inspection: one canonical metadata entry, 14 groups, and 145 properties

Parse registered Groovy DSL sources without executing them and merge all remaining curated metadata through canonical generated resources.

Assisted-by: opencode:gpt-5.6-sol codegraph
Copilot AI review requested due to automatic review settings July 24, 2026 00:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This pull request extends Grails’ configuration metadata generation to also support statically parsing explicitly-registered Groovy DSL sources (without executing them), then deterministically merging DSL-derived metadata, typed @ConfigurationProperties metadata, and curated overlays into a single canonical META-INF/spring-configuration-metadata.json published by each module.

Changes:

  • Add a Groovy DSL metadata parser (via SourceUnit) and integrate its output into the existing metadata generation/merge pipeline with defined precedence.
  • Route more in-repo modules (including Spring Security) through the canonical generated metadata JAR resource and add/refresh curated additional-spring-configuration-metadata.json overlays.
  • Add/adjust tests and docs to validate DSL parsing safety, precedence rules, and the Spring Security metadata contract.

Reviewed changes

Copilot reviewed 16 out of 24 changed files in this pull request and generated no comments.

Show a summary per file
File Description
grails-web-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for web-core properties to be merged into canonical generated metadata.
grails-web-core/build.gradle Applies the configuration metadata build-logic plugin.
grails-spring-security/plugin/src/test/groovy/grails/plugin/springsecurity/ConfigurationMetadataSpec.groovy Adds a contract test asserting Spring Security metadata is present, merged, and complete.
grails-spring-security/plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated Spring Security overlay metadata (groups/properties) used in the merge.
grails-spring-security/plugin/build.gradle Applies the metadata plugin and registers DefaultSecurityConfig.groovy as a DSL source with root prefix mapping.
grails-gsp/plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for GSP/plugin configuration properties.
grails-gsp/plugin/build.gradle Applies the configuration metadata plugin.
grails-doc/src/en/guide/conf/config.adoc Documents DSL-source parsing and the merged canonical metadata resource behavior.
grails-data-mongodb/grails-plugin/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for MongoDB plugin settings.
grails-data-mongodb/grails-plugin/build.gradle Applies the configuration metadata plugin.
grails-data-hibernate7/dbmigration/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for Hibernate7 dbmigration plugin settings.
grails-data-hibernate7/dbmigration/build.gradle Applies the configuration metadata plugin.
grails-data-hibernate7/core/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for Hibernate7 core settings.
grails-data-hibernate7/core/build.gradle Applies the configuration metadata plugin.
grails-data-hibernate5/dbmigration/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for Hibernate5 dbmigration plugin settings.
grails-data-hibernate5/dbmigration/build.gradle Applies the configuration metadata plugin.
grails-data-hibernate5/core/src/main/resources/META-INF/additional-spring-configuration-metadata.json Adds curated overlay metadata for Hibernate5 core settings.
grails-data-hibernate5/core/build.gradle Applies the configuration metadata plugin.
grails-core/src/main/resources/META-INF/spring-configuration-metadata.json Removes the hand-maintained standard metadata file in favor of canonical generation.
grails-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json Expands curated overlays (groups/properties/hints) to be merged into canonical generation.
grails-core/build.gradle Applies the configuration metadata plugin.
build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/ConfigurationMetadataPluginSpec.groovy Adds/extends TestKit coverage for DSL parsing, precedence merging, and incremental behavior.
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GroovyDslConfigurationMetadataParser.groovy Introduces the static Groovy DSL parser that extracts property paths/types/defaults without executing scripts/transforms.
build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/ConfigurationMetadataPlugin.groovy Wires DSL inputs into the task and updates merge logic for DSL vs typed vs overlay precedence.

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

@jamesfredley jamesfredley moved this to In Progress in Apache Grails Jul 24, 2026
@jamesfredley jamesfredley added this to the grails:8.0.0-RC1 milestone Jul 24, 2026
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 51.4815%. Comparing base (b792a3f) to head (d12545a).
⚠️ Report is 308 commits behind head on feature/automated-configuration-metadata.

Additional details and impacted files

Impacted file tree graph

@@                                Coverage Diff                                 @@
##             feature/automated-configuration-metadata     #16048        +/-   ##
==================================================================================
+ Coverage                                     51.4794%   51.4815%   +0.0021%     
  Complexity                                      17793      17793                
==================================================================================
  Files                                            2040       2040                
  Lines                                           95681      95681                
  Branches                                        16610      16610                
==================================================================================
+ Hits                                            49256      49258         +2     
+ Misses                                          39084      39082         -2     
  Partials                                         7341       7341                

see 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jamesfredley jamesfredley moved this from In Progress to Todo in Apache Grails Jul 24, 2026
@testlens-app

testlens-app Bot commented Jul 24, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: d12545a
▶️ Tests: 49094 executed
⚪️ Checks: 57/57 completed


Learn more about TestLens at testlens.app.

@jdaugherty jdaugherty left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I realized this review never got submitted, apologies:

Reviewed the DSL parser, the merge precedence changes, the module wiring, and the metadata moves. Verified the grails-core metadata consolidation is lossless (all groups, properties, and hints from both prior files are present in the merged additional file). A few comments below, mostly about robustness of the parser against ConfigSlurper semantics for future DSL registrations.

if (!conditional && inference.literal) {
property.defaultValue = inference.value
}
properties << property

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duplicate assignments to the same property produce distinct entries here, and the DSL index in mergeNamed (indexByName) fails the task when two entries for one name aren't map-equal. Two patterns that are valid at runtime under ConfigSlurper's last-write-wins semantics trip this:

foo = 'default'
if (Environment.current == Environment.TEST) {
    foo = 'test' // conditional entry has no defaultValue -> conflicts with the unconditional entry
}

and if/else branches whose literals infer different types (e.g. = null in one branch, = true in the other). DefaultSecurityConfig.groovy avoids both today — the password branches assign the same types on both sides — but the next DSL source registered could fail the build on a perfectly legitimate config. Consider collapsing same-name entries before returning (union the type the way sharedType does, keep the unconditional defaultValue), or at least add a spec pinning the conflict failure so it's an explicit contract.

ClosureExpression closure = closureArgument(expression)
String nestedName = expression.methodAsString
if (closure != null && nestedName != null) {
parseStatements(closure.code, "${prefix}.${nestedName}", conditional, properties)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These sources are ConfigSlurper scripts at runtime (SpringSecurityUtils loads DefaultSecurityConfig with new ConfigSlurper(Environment.current.name).parse(...)), so an environments block is valid in them. This branch would treat it as an ordinary nested section and silently emit names like <prefix>.environments.production.foo instead of <prefix>.foo. Nothing hits this today since DefaultSecurityConfig.groovy uses Environment.current if-checks instead, but it may be worth handling an environments call like IfStatement (recurse into each environment closure with the unchanged prefix and conditional = true) — or failing loudly when one is encountered.


expect: 'the complete curated metadata contract is retained'
metadata.get('groups').size() == 14
properties.size() == 145

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

These exact counts mean every future addition to DefaultSecurityConfig.groovy or the curated overlay fails this spec with only a number mismatch. If a deliberate tripwire is the intent that's fine, but consider deriving the expectation from the packaged META-INF/additional-spring-configuration-metadata.json in the same JAR (assert every curated group/property name appears in the canonical file) — the spec then stays self-maintaining and a failure names the missing entry instead of reporting 146 != 145.

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

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

3 participants