This is an automated email from the ASF dual-hosted git repository.

jamesfredley pushed a commit to branch fix/bom-build-script-cleanups
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit fc7349fa2847993871611a2081bf4f4f4b2d6e79
Author: t <t@t>
AuthorDate: Sat Jul 4 20:19:18 2026 -0400

    Extract shared BOM build conventions
    
    Centralize duplicated BOM publication, constraint extraction, and POM 
customization logic in a build-logic convention plugin. Apply it across the BOM 
modules while keeping generated POM and constraints output byte-identical to 
the current 8.0.x baseline.
    
    Assisted-by: Hephaestus:openai/gpt-5.5 codex-review
---
 build-logic/plugins/build.gradle                   |   5 +
 .../grails/buildsrc/BomConventionsPlugin.groovy    | 261 +++++++++++++++++++++
 dependencies.gradle                                | 169 ++-----------
 grails-bom/base/build.gradle                       | 159 +------------
 grails-bom/default/build.gradle                    | 159 +------------
 grails-bom/hibernate5-micronaut/build.gradle       | 164 +------------
 grails-bom/hibernate5/build.gradle                 | 159 +------------
 grails-bom/hibernate7-micronaut/build.gradle       | 164 +------------
 grails-bom/hibernate7/build.gradle                 | 159 +------------
 grails-bom/micronaut/build.gradle                  | 164 +------------
 10 files changed, 296 insertions(+), 1267 deletions(-)

diff --git a/build-logic/plugins/build.gradle b/build-logic/plugins/build.gradle
index 0b4ffee16e..1faadb35c9 100644
--- a/build-logic/plugins/build.gradle
+++ b/build-logic/plugins/build.gradle
@@ -35,6 +35,7 @@ 
project.layout.projectDirectory.file('../../gradle.properties').asFile.withInput
 }
 
 dependencies {
+    implementation project(':grails-docs-core')
     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}"
@@ -63,6 +64,10 @@ gradlePlugin {
             id = 'org.apache.grails.buildsrc.sbom'
             implementationClass = 'org.apache.grails.buildsrc.SbomPlugin'
         }
+        register('bomConventionsPlugin') {
+            id = 'org.apache.grails.buildsrc.bom-conventions'
+            implementationClass = 
'org.apache.grails.buildsrc.BomConventionsPlugin'
+        }
         register('sharedPropertyPlugin') {
             id = 'org.apache.grails.buildsrc.properties'
             implementationClass = 
'org.apache.grails.buildsrc.SharedPropertyPlugin'
diff --git 
a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/BomConventionsPlugin.groovy
 
b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/BomConventionsPlugin.groovy
new file mode 100644
index 0000000000..4938ddfdb2
--- /dev/null
+++ 
b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/BomConventionsPlugin.groovy
@@ -0,0 +1,261 @@
+/*
+ *  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 groovy.transform.CompileDynamic
+import groovy.transform.CompileStatic
+
+import org.gradle.api.GradleException
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.plugins.JavaPlatformExtension
+import org.gradle.api.tasks.TaskProvider
+
+import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
+import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
+import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
+
+@CompileStatic
+class BomConventionsPlugin implements Plugin<Project> {
+
+    private static final String BASE_CONSTRAINTS_FILE = 
'grails-bom-constraints.adoc'
+
+    private static final Set<String> MICRONAUT_BOM_PROJECTS = [
+            'grails-hibernate5-micronaut-bom',
+            'grails-hibernate7-micronaut-bom',
+            'grails-micronaut-bom',
+    ] as Set<String>
+
+    private static final Map<String, String> GRADLE_BUILD_PROJECTS = [
+            'grails-gradle-plugins': 'org.apache.grails',
+            'grails-gradle-model'  : 'org.apache.grails.gradle',
+            'grails-gradle-common' : 'org.apache.grails.gradle',
+            'grails-gradle-tasks'  : 'org.apache.grails',
+    ]
+
+    @Override
+    void apply(Project project) {
+        applyDependencyDefinitions(project)
+        configureCoordinates(project)
+        configureExtraProperties(project)
+        configurePomCustomization(project)
+
+        project.pluginManager.apply('java-platform')
+        project.extensions.configure(JavaPlatformExtension) { 
JavaPlatformExtension extension ->
+            extension.allowDependencies()
+        }
+        project.pluginManager.apply('org.apache.grails.buildsrc.publish')
+        project.pluginManager.apply('org.apache.grails.buildsrc.sbom')
+
+        configureBomDependencies(project)
+        configureExtractConstraints(project)
+        configureSnapshotValidation(project)
+    }
+
+    private static void applyDependencyDefinitions(Project project) {
+        project.apply([from: 
project.rootProject.layout.projectDirectory.file('dependencies.gradle')])
+    }
+
+    private static void configureCoordinates(Project project) {
+        project.version = project.findProperty('projectVersion')
+        project.group = 'org.apache.grails'
+    }
+
+    private static void configureExtraProperties(Project project) {
+        project.extensions.extraProperties.set('isReleaseBuild', 
System.getenv('GRAILS_PUBLISH_RELEASE') == 'true')
+        project.extensions.extraProperties.set(
+                'isPublishedExternal',
+                System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
+        )
+        project.extensions.extraProperties.set('gradleBuildProjects', new 
LinkedHashMap<String, String>(GRADLE_BUILD_PROJECTS))
+    }
+
+    private static void configureBomDependencies(Project project) {
+        project.configurations.register('bomDependencies') { Configuration 
configuration ->
+            configuration.canBeResolved = true
+            configuration.transitive = true
+            
configuration.extendsFrom(project.configurations.named('api').get())
+        }
+    }
+
+    private static void configureExtractConstraints(Project project) {
+        TaskProvider<ExtractDependenciesTask> extractConstraints = 
project.tasks.register(
+                'extractConstraints',
+                ExtractDependenciesTask
+        ) { ExtractDependenciesTask task ->
+            task.captureProjectServices(project.dependencies, 
project.configurations)
+            
task.setConfiguration(project.configurations.named('bomDependencies'))
+            
task.destination.set(project.layout.buildDirectory.file(constraintsFileName(project)))
+            task.platformDefinitions.set(project.provider { 
getStringMap(project, 'combinedPlatforms') })
+            task.definitions.set(project.provider { getStringMap(project, 
'combinedDependencies') })
+            task.projectName.set(project.name)
+            task.versions.set(project.provider { getStringMap(project, 
'combinedVersions') })
+            
task.autoRegisterTransitivePlatforms.set(MICRONAUT_BOM_PROJECTS.contains(project.name))
+
+            project.rootProject.subprojects.each { Project subproject ->
+                project.evaluationDependsOn(subproject.path)
+            }
+            task.projectArtifactIds.set(project.provider { 
projectArtifactIds(project) })
+            task.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
+            task.projectCoordinateProperties.set(project.provider { 
projectCoordinateProperties(project) })
+            task.dependsOn('generateMetadataFileForMavenPublication', 
'generatePomFileForMavenPublication')
+        }
+
+        project.tasks.named('check') { Task task ->
+            task.dependsOn(extractConstraints)
+        }
+    }
+
+    private static String constraintsFileName(Project project) {
+        project.name == 'grails-base-bom' ? BASE_CONSTRAINTS_FILE : 
"${project.name}-constraints.adoc"
+    }
+
+    private static Map<String, String> projectArtifactIds(Project project) {
+        Map<String, String> artifactIdMappings = [:]
+        project.rootProject.subprojects.each { Project subproject ->
+            artifactIdMappings[subproject.name] = 
(subproject.findProperty('pomArtifactId') ?: subproject.name).toString()
+        }
+
+        getGradleBuildProjects(project).each { String dependencyName, String 
dependencyGroup ->
+            artifactIdMappings[dependencyName] = dependencyName
+        }
+
+        artifactIdMappings
+    }
+
+    private static Map<String, String> projectCoordinateProperties(Project 
project) {
+        Map<String, String> projectCoordinates = [:]
+        project.rootProject.subprojects.each { Project subproject ->
+            String artifactId = (subproject.findProperty('pomArtifactId') ?: 
subproject.name).toString()
+            String baseVersionName = artifactId.replaceAll('[.]', '-')
+            
projectCoordinates["${subproject.group}:${artifactId}:${subproject.version}".toString()]
 = baseVersionName
+        }
+
+        getGradleBuildProjects(project).each { String dependencyName, String 
dependencyGroup ->
+            
projectCoordinates["${dependencyGroup}:${dependencyName}:${project.version}".toString()]
 = dependencyName
+        }
+
+        projectCoordinates
+    }
+
+    private static void configureSnapshotValidation(Project project) {
+        TaskProvider<Task> validateNoSnapshotDependencies = 
project.tasks.register('validateNoSnapshotDependencies') { Task task ->
+            task.group = 'publishing'
+            task.description = 'Validates that no snapshot dependencies are 
present in the project when performing a release.'
+
+            task.doLast {
+                project.configurations.each { Configuration configuration ->
+                    configuration.allDependencies.each { Dependency dependency 
->
+                        if (dependency.version && 
dependency.version.contains('-SNAPSHOT')) {
+                            throw new GradleException(
+                                    "Releases cannot have a snapshot 
dependency: ${dependency.group}:${dependency.name} (${dependency.version})"
+                            )
+                        }
+                    }
+                }
+            }
+        }
+
+        if (project.extensions.extraProperties.get('isReleaseBuild') &&
+                project.extensions.extraProperties.get('isPublishedExternal')) 
{
+            project.tasks.matching { Task task ->
+                task.name in ['generateMetadataFileForMavenPublication', 
'generatePomFileForMavenPublication']
+            }.configureEach { Task task ->
+                task.dependsOn(validateNoSnapshotDependencies)
+            }
+        }
+    }
+
+    private static void configurePomCustomization(Project project) {
+        project.extensions.extraProperties.set('pomCustomization', 
createPomCustomization(project))
+    }
+
+    @CompileDynamic
+    private static Closure createPomCustomization(Project project) {
+        { xml ->
+            def root = xml.asNode()
+
+            def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
+
+            def depMgmt = root.dependencyManagement?.getAt(0)
+            def deps = depMgmt?.dependencies?.getAt(0)
+            if (deps) {
+                PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(
+                        getStringMap(project, 'combinedPlatforms'),
+                        getStringMap(project, 'combinedDependencies'),
+                        getStringMap(project, 'combinedVersions')
+                )
+                
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
+                
propertyNameCalculator.addProjects(project.rootProject.subprojects)
+                for (String gradleArtifactId : 
project.ext.gradleBuildProjects) {
+                    propertyNameCalculator.addProject(
+                            'org.apache.grails.gradle',
+                            gradleArtifactId,
+                            project.version as String,
+                            gradleArtifactId
+                    )
+                }
+
+                Map<String, String> pomProperties = [:]
+                deps.dependency.each { dep ->
+                    String groupId = dep.groupId.text().trim()
+                    String artifactId = dep.artifactId.text().trim()
+                    boolean isBom = dep.scope.text().trim() == 'import'
+
+                    String inlineVersion = dep.version.text().trim()
+                    if (inlineVersion == 'null') {
+                        inlineVersion = null
+                    }
+
+                    if (inlineVersion) {
+                        ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(
+                                groupId,
+                                artifactId,
+                                inlineVersion,
+                                isBom
+                        )
+                        if (extractedConstraint?.versionPropertyReference) {
+                            dep.version[0].value = 
extractedConstraint.versionPropertyReference
+                            
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
+                        }
+                    } else if (!inlineVersion) {
+                        throw new GradleException("Dependency 
$groupId:$artifactId does not have a version.")
+                    }
+                }
+
+                for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
+                    propertiesNode.appendNode(property.key, property.value)
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings('unchecked')
+    private static Map<String, String> getStringMap(Project project, String 
propertyName) {
+        (Map<String, String>) 
project.extensions.extraProperties.get(propertyName)
+    }
+
+    private static Map<String, String> getGradleBuildProjects(Project project) 
{
+        getStringMap(project, 'gradleBuildProjects')
+    }
+}
diff --git a/dependencies.gradle b/dependencies.gradle
index 0a8b10fb17..9d48cdbe27 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -20,6 +20,18 @@
 
 // This file provides the 'grails-bom' dependencies, while 
grails-gradle/dependencies.gradle provides the 'grails-gradle-bom' dependencies
 // These files are split to facilitate separation of build vs application 
dependencies. These are the application dependencies.
+static Map<String, String> groovyModuleDependencies(String groovyVersion) {
+    [
+            '', '-ant', '-astbuilder', '-cli-commons', '-cli-picocli', 
'-console', '-contracts', '-datetime',
+            '-dateutil', '-docgenerator', '-ginq', '-groovydoc', '-groovysh', 
'-jmx', '-json', '-jsr223',
+            '-macro', '-macro-library', '-nio', '-servlet', '-sql', '-swing', 
'-templates', '-test',
+            '-test-junit5', '-testng', '-toml', '-typecheckers', '-xml', 
'-yaml',
+    ].collectEntries { String moduleSuffix ->
+        String artifactId = "groovy${moduleSuffix}"
+        [(artifactId): 
"org.apache.groovy:${artifactId}:${groovyVersion}".toString()]
+    }
+}
+
 ext {
     gradleBomDependencyVersions = [
             'ant.version'                   : '1.10.17',
@@ -263,37 +275,7 @@ ext {
                 'spock.version'              : '2.4-groovy-5.0',
         ]
         combinedVersions += customBomVersions
-        customBomDependencies = [
-                'groovy'               : 
"org.apache.groovy:groovy:${combinedVersions['groovy.version']}",
-                'groovy-ant'           : 
"org.apache.groovy:groovy-ant:${combinedVersions['groovy.version']}",
-                'groovy-astbuilder'    : 
"org.apache.groovy:groovy-astbuilder:${combinedVersions['groovy.version']}",
-                'groovy-cli-commons'   : 
"org.apache.groovy:groovy-cli-commons:${combinedVersions['groovy.version']}",
-                'groovy-cli-picocli'   : 
"org.apache.groovy:groovy-cli-picocli:${combinedVersions['groovy.version']}",
-                'groovy-console'       : 
"org.apache.groovy:groovy-console:${combinedVersions['groovy.version']}",
-                'groovy-contracts'     : 
"org.apache.groovy:groovy-contracts:${combinedVersions['groovy.version']}",
-                'groovy-datetime'      : 
"org.apache.groovy:groovy-datetime:${combinedVersions['groovy.version']}",
-                'groovy-dateutil'      : 
"org.apache.groovy:groovy-dateutil:${combinedVersions['groovy.version']}",
-                'groovy-docgenerator'  : 
"org.apache.groovy:groovy-docgenerator:${combinedVersions['groovy.version']}",
-                'groovy-ginq'          : 
"org.apache.groovy:groovy-ginq:${combinedVersions['groovy.version']}",
-                'groovy-groovydoc'     : 
"org.apache.groovy:groovy-groovydoc:${combinedVersions['groovy.version']}",
-                'groovy-groovysh'      : 
"org.apache.groovy:groovy-groovysh:${combinedVersions['groovy.version']}",
-                'groovy-jmx'           : 
"org.apache.groovy:groovy-jmx:${combinedVersions['groovy.version']}",
-                'groovy-json'          : 
"org.apache.groovy:groovy-json:${combinedVersions['groovy.version']}",
-                'groovy-jsr223'        : 
"org.apache.groovy:groovy-jsr223:${combinedVersions['groovy.version']}",
-                'groovy-macro'         : 
"org.apache.groovy:groovy-macro:${combinedVersions['groovy.version']}",
-                'groovy-macro-library' : 
"org.apache.groovy:groovy-macro-library:${combinedVersions['groovy.version']}",
-                'groovy-nio'           : 
"org.apache.groovy:groovy-nio:${combinedVersions['groovy.version']}",
-                'groovy-servlet'       : 
"org.apache.groovy:groovy-servlet:${combinedVersions['groovy.version']}",
-                'groovy-sql'           : 
"org.apache.groovy:groovy-sql:${combinedVersions['groovy.version']}",
-                'groovy-swing'         : 
"org.apache.groovy:groovy-swing:${combinedVersions['groovy.version']}",
-                'groovy-templates'     : 
"org.apache.groovy:groovy-templates:${combinedVersions['groovy.version']}",
-                'groovy-test'          : 
"org.apache.groovy:groovy-test:${combinedVersions['groovy.version']}",
-                'groovy-test-junit5'   : 
"org.apache.groovy:groovy-test-junit5:${combinedVersions['groovy.version']}",
-                'groovy-testng'        : 
"org.apache.groovy:groovy-testng:${combinedVersions['groovy.version']}",
-                'groovy-toml'          : 
"org.apache.groovy:groovy-toml:${combinedVersions['groovy.version']}",
-                'groovy-typecheckers'  : 
"org.apache.groovy:groovy-typecheckers:${combinedVersions['groovy.version']}",
-                'groovy-xml'           : 
"org.apache.groovy:groovy-xml:${combinedVersions['groovy.version']}",
-                'groovy-yaml'          : 
"org.apache.groovy:groovy-yaml:${combinedVersions['groovy.version']}",
+        customBomDependencies = 
groovyModuleDependencies(combinedVersions['groovy.version']) + [
                 'hibernate-core-jakarta': 
"org.hibernate:hibernate-core-jakarta:${combinedVersions['hibernate.version']}",
                 'hibernate-ehcache'     : 
"org.hibernate:hibernate-ehcache:${combinedVersions['hibernate.version']}",
                 'hibernate-envers'      : 
"org.hibernate:hibernate-envers:${combinedVersions['hibernate.version']}",
@@ -330,36 +312,7 @@ ext {
         combinedVersions += customBomVersions
         customBomDependencies = [
                 'cache-ri-impl'         : 
"org.jsr107.ri:cache-ri-impl:${combinedVersions['cache-ri-impl.version']}",
-                'groovy'               : 
"org.apache.groovy:groovy:${combinedVersions['groovy.version']}",
-                'groovy-ant'           : 
"org.apache.groovy:groovy-ant:${combinedVersions['groovy.version']}",
-                'groovy-astbuilder'    : 
"org.apache.groovy:groovy-astbuilder:${combinedVersions['groovy.version']}",
-                'groovy-cli-commons'   : 
"org.apache.groovy:groovy-cli-commons:${combinedVersions['groovy.version']}",
-                'groovy-cli-picocli'   : 
"org.apache.groovy:groovy-cli-picocli:${combinedVersions['groovy.version']}",
-                'groovy-console'       : 
"org.apache.groovy:groovy-console:${combinedVersions['groovy.version']}",
-                'groovy-contracts'     : 
"org.apache.groovy:groovy-contracts:${combinedVersions['groovy.version']}",
-                'groovy-datetime'      : 
"org.apache.groovy:groovy-datetime:${combinedVersions['groovy.version']}",
-                'groovy-dateutil'      : 
"org.apache.groovy:groovy-dateutil:${combinedVersions['groovy.version']}",
-                'groovy-docgenerator'  : 
"org.apache.groovy:groovy-docgenerator:${combinedVersions['groovy.version']}",
-                'groovy-ginq'          : 
"org.apache.groovy:groovy-ginq:${combinedVersions['groovy.version']}",
-                'groovy-groovydoc'     : 
"org.apache.groovy:groovy-groovydoc:${combinedVersions['groovy.version']}",
-                'groovy-groovysh'      : 
"org.apache.groovy:groovy-groovysh:${combinedVersions['groovy.version']}",
-                'groovy-jmx'           : 
"org.apache.groovy:groovy-jmx:${combinedVersions['groovy.version']}",
-                'groovy-json'          : 
"org.apache.groovy:groovy-json:${combinedVersions['groovy.version']}",
-                'groovy-jsr223'        : 
"org.apache.groovy:groovy-jsr223:${combinedVersions['groovy.version']}",
-                'groovy-macro'         : 
"org.apache.groovy:groovy-macro:${combinedVersions['groovy.version']}",
-                'groovy-macro-library' : 
"org.apache.groovy:groovy-macro-library:${combinedVersions['groovy.version']}",
-                'groovy-nio'           : 
"org.apache.groovy:groovy-nio:${combinedVersions['groovy.version']}",
-                'groovy-servlet'       : 
"org.apache.groovy:groovy-servlet:${combinedVersions['groovy.version']}",
-                'groovy-sql'           : 
"org.apache.groovy:groovy-sql:${combinedVersions['groovy.version']}",
-                'groovy-swing'         : 
"org.apache.groovy:groovy-swing:${combinedVersions['groovy.version']}",
-                'groovy-templates'     : 
"org.apache.groovy:groovy-templates:${combinedVersions['groovy.version']}",
-                'groovy-test'          : 
"org.apache.groovy:groovy-test:${combinedVersions['groovy.version']}",
-                'groovy-test-junit5'   : 
"org.apache.groovy:groovy-test-junit5:${combinedVersions['groovy.version']}",
-                'groovy-testng'        : 
"org.apache.groovy:groovy-testng:${combinedVersions['groovy.version']}",
-                'groovy-toml'          : 
"org.apache.groovy:groovy-toml:${combinedVersions['groovy.version']}",
-                'groovy-typecheckers'  : 
"org.apache.groovy:groovy-typecheckers:${combinedVersions['groovy.version']}",
-                'groovy-xml'           : 
"org.apache.groovy:groovy-xml:${combinedVersions['groovy.version']}",
-                'groovy-yaml'          : 
"org.apache.groovy:groovy-yaml:${combinedVersions['groovy.version']}",
+        ] + groovyModuleDependencies(combinedVersions['groovy.version']) + [
                 'hibernate-core'        : 
"org.hibernate.orm:hibernate-core:${combinedVersions['hibernate.version']}",
                 'hibernate-envers'      : 
"org.hibernate.orm:hibernate-envers:${combinedVersions['hibernate.version']}",
                 'hibernate-jcache'      : 
"org.hibernate.orm:hibernate-jcache:${combinedVersions['hibernate.version']}",
@@ -390,68 +343,7 @@ ext {
     // grails-micronaut-bom project. Declared with `strictly` in the BOM 
project so
     // they win over Micronaut platform's higher versions when consumers use
     // enforcedPlatform(:grails-micronaut-bom).
-    else if (project.name in (['grails-hibernate7-micronaut-bom'])) {
-        customBomVersions = [
-                'liquibase-hibernate.version': '4.27.0',
-                'liquibase.version'          : '4.27.0',
-                'hibernate.version'          : '5.6.15.Final',
-                'groovy.version'  : '5.0.7',
-                'spock.version'   : '2.4-groovy-5.0',
-                'protobuf.version': '4.30.2',
-                'asm.version'     : '9.10.1',
-        ]
-        combinedVersions += customBomVersions
-        customBomDependencies = [
-                'liquibase'             : 
"org.liquibase:liquibase:${combinedVersions['liquibase.version']}",
-                'liquibase-cdi'         : 
"org.liquibase:liquibase-cdi:${combinedVersions['liquibase.version']}",
-                'liquibase-core'        : 
"org.liquibase:liquibase-core:${combinedVersions['liquibase.version']}",
-                'liquibase-hibernate'   : 
"org.liquibase.ext:liquibase-hibernate5:${combinedVersions['liquibase-hibernate.version']}",
-                'hibernate-core-jakarta': 
"org.hibernate:hibernate-core-jakarta:${combinedVersions['hibernate.version']}",
-                'hibernate-ehcache'     : 
"org.hibernate:hibernate-ehcache:${combinedVersions['hibernate.version']}",
-                'groovy'               : 
"org.apache.groovy:groovy:${combinedVersions['groovy.version']}",
-                'groovy-ant'           : 
"org.apache.groovy:groovy-ant:${combinedVersions['groovy.version']}",
-                'groovy-astbuilder'    : 
"org.apache.groovy:groovy-astbuilder:${combinedVersions['groovy.version']}",
-                'groovy-cli-commons'   : 
"org.apache.groovy:groovy-cli-commons:${combinedVersions['groovy.version']}",
-                'groovy-cli-picocli'   : 
"org.apache.groovy:groovy-cli-picocli:${combinedVersions['groovy.version']}",
-                'groovy-console'       : 
"org.apache.groovy:groovy-console:${combinedVersions['groovy.version']}",
-                'groovy-contracts'     : 
"org.apache.groovy:groovy-contracts:${combinedVersions['groovy.version']}",
-                'groovy-datetime'      : 
"org.apache.groovy:groovy-datetime:${combinedVersions['groovy.version']}",
-                'groovy-dateutil'      : 
"org.apache.groovy:groovy-dateutil:${combinedVersions['groovy.version']}",
-                'groovy-docgenerator'  : 
"org.apache.groovy:groovy-docgenerator:${combinedVersions['groovy.version']}",
-                'groovy-ginq'          : 
"org.apache.groovy:groovy-ginq:${combinedVersions['groovy.version']}",
-                'groovy-groovydoc'     : 
"org.apache.groovy:groovy-groovydoc:${combinedVersions['groovy.version']}",
-                'groovy-groovysh'      : 
"org.apache.groovy:groovy-groovysh:${combinedVersions['groovy.version']}",
-                'groovy-jmx'           : 
"org.apache.groovy:groovy-jmx:${combinedVersions['groovy.version']}",
-                'groovy-json'          : 
"org.apache.groovy:groovy-json:${combinedVersions['groovy.version']}",
-                'groovy-jsr223'        : 
"org.apache.groovy:groovy-jsr223:${combinedVersions['groovy.version']}",
-                'groovy-macro'         : 
"org.apache.groovy:groovy-macro:${combinedVersions['groovy.version']}",
-                'groovy-macro-library' : 
"org.apache.groovy:groovy-macro-library:${combinedVersions['groovy.version']}",
-                'groovy-nio'           : 
"org.apache.groovy:groovy-nio:${combinedVersions['groovy.version']}",
-                'groovy-servlet'       : 
"org.apache.groovy:groovy-servlet:${combinedVersions['groovy.version']}",
-                'groovy-sql'           : 
"org.apache.groovy:groovy-sql:${combinedVersions['groovy.version']}",
-                'groovy-swing'         : 
"org.apache.groovy:groovy-swing:${combinedVersions['groovy.version']}",
-                'groovy-templates'     : 
"org.apache.groovy:groovy-templates:${combinedVersions['groovy.version']}",
-                'groovy-test'          : 
"org.apache.groovy:groovy-test:${combinedVersions['groovy.version']}",
-                'groovy-test-junit5'   : 
"org.apache.groovy:groovy-test-junit5:${combinedVersions['groovy.version']}",
-                'groovy-testng'        : 
"org.apache.groovy:groovy-testng:${combinedVersions['groovy.version']}",
-                'groovy-toml'          : 
"org.apache.groovy:groovy-toml:${combinedVersions['groovy.version']}",
-                'groovy-typecheckers'  : 
"org.apache.groovy:groovy-typecheckers:${combinedVersions['groovy.version']}",
-                'groovy-xml'           : 
"org.apache.groovy:groovy-xml:${combinedVersions['groovy.version']}",
-                'groovy-yaml'          : 
"org.apache.groovy:groovy-yaml:${combinedVersions['groovy.version']}",
-                'protobuf-java'        : 
"com.google.protobuf:protobuf-java:${combinedVersions['protobuf.version']}",
-                'asm'                  : 
"org.ow2.asm:asm:${combinedVersions['asm.version']}",
-                'asm-util'             : 
"org.ow2.asm:asm-util:${combinedVersions['asm.version']}",
-                'spock-core'           : 
"org.spockframework:spock-core:${combinedVersions['spock.version']}",
-                'spock-spring'         : 
"org.spockframework:spock-spring:${combinedVersions['spock.version']}",
-        ]
-        def customBomPlatformDependencies = [
-                'groovy-bom': 
"org.apache.groovy:groovy-bom:${combinedVersions['groovy.version']}",
-                'spock-bom' : 
"org.spockframework:spock-bom:${combinedVersions['spock.version']}",
-        ]
-        bomPlatformDependencies += customBomPlatformDependencies
-        combinedDependencies += customBomDependencies
-        combinedPlatforms += customBomPlatformDependencies
-    } else if (project.name in ['grails-micronaut-bom', 
'grails-hibernate5-micronaut-bom']) {
+    else if (project.name == 'grails-micronaut-bom') {
         customBomVersions = [
                 'liquibase-hibernate.version': '4.27.0',
                 'liquibase.version'          : '4.27.0',
@@ -469,36 +361,7 @@ ext {
                 'liquibase-hibernate'   : 
"org.liquibase.ext:liquibase-hibernate5:${combinedVersions['liquibase-hibernate.version']}",
                 'hibernate-core-jakarta': 
"org.hibernate:hibernate-core-jakarta:${combinedVersions['hibernate.version']}",
                 'hibernate-ehcache'     : 
"org.hibernate:hibernate-ehcache:${combinedVersions['hibernate.version']}",
-                'groovy'               : 
"org.apache.groovy:groovy:${combinedVersions['groovy.version']}",
-                'groovy-ant'           : 
"org.apache.groovy:groovy-ant:${combinedVersions['groovy.version']}",
-                'groovy-astbuilder'    : 
"org.apache.groovy:groovy-astbuilder:${combinedVersions['groovy.version']}",
-                'groovy-cli-commons'   : 
"org.apache.groovy:groovy-cli-commons:${combinedVersions['groovy.version']}",
-                'groovy-cli-picocli'   : 
"org.apache.groovy:groovy-cli-picocli:${combinedVersions['groovy.version']}",
-                'groovy-console'       : 
"org.apache.groovy:groovy-console:${combinedVersions['groovy.version']}",
-                'groovy-contracts'     : 
"org.apache.groovy:groovy-contracts:${combinedVersions['groovy.version']}",
-                'groovy-datetime'      : 
"org.apache.groovy:groovy-datetime:${combinedVersions['groovy.version']}",
-                'groovy-dateutil'      : 
"org.apache.groovy:groovy-dateutil:${combinedVersions['groovy.version']}",
-                'groovy-docgenerator'  : 
"org.apache.groovy:groovy-docgenerator:${combinedVersions['groovy.version']}",
-                'groovy-ginq'          : 
"org.apache.groovy:groovy-ginq:${combinedVersions['groovy.version']}",
-                'groovy-groovydoc'     : 
"org.apache.groovy:groovy-groovydoc:${combinedVersions['groovy.version']}",
-                'groovy-groovysh'      : 
"org.apache.groovy:groovy-groovysh:${combinedVersions['groovy.version']}",
-                'groovy-jmx'           : 
"org.apache.groovy:groovy-jmx:${combinedVersions['groovy.version']}",
-                'groovy-json'          : 
"org.apache.groovy:groovy-json:${combinedVersions['groovy.version']}",
-                'groovy-jsr223'        : 
"org.apache.groovy:groovy-jsr223:${combinedVersions['groovy.version']}",
-                'groovy-macro'         : 
"org.apache.groovy:groovy-macro:${combinedVersions['groovy.version']}",
-                'groovy-macro-library' : 
"org.apache.groovy:groovy-macro-library:${combinedVersions['groovy.version']}",
-                'groovy-nio'           : 
"org.apache.groovy:groovy-nio:${combinedVersions['groovy.version']}",
-                'groovy-servlet'       : 
"org.apache.groovy:groovy-servlet:${combinedVersions['groovy.version']}",
-                'groovy-sql'           : 
"org.apache.groovy:groovy-sql:${combinedVersions['groovy.version']}",
-                'groovy-swing'         : 
"org.apache.groovy:groovy-swing:${combinedVersions['groovy.version']}",
-                'groovy-templates'     : 
"org.apache.groovy:groovy-templates:${combinedVersions['groovy.version']}",
-                'groovy-test'          : 
"org.apache.groovy:groovy-test:${combinedVersions['groovy.version']}",
-                'groovy-test-junit5'   : 
"org.apache.groovy:groovy-test-junit5:${combinedVersions['groovy.version']}",
-                'groovy-testng'        : 
"org.apache.groovy:groovy-testng:${combinedVersions['groovy.version']}",
-                'groovy-toml'          : 
"org.apache.groovy:groovy-toml:${combinedVersions['groovy.version']}",
-                'groovy-typecheckers'  : 
"org.apache.groovy:groovy-typecheckers:${combinedVersions['groovy.version']}",
-                'groovy-xml'           : 
"org.apache.groovy:groovy-xml:${combinedVersions['groovy.version']}",
-                'groovy-yaml'          : 
"org.apache.groovy:groovy-yaml:${combinedVersions['groovy.version']}",
+        ] + groovyModuleDependencies(combinedVersions['groovy.version']) + [
                 'protobuf-java'        : 
"com.google.protobuf:protobuf-java:${combinedVersions['protobuf.version']}",
                 'asm'                  : 
"org.ow2.asm:asm:${combinedVersions['asm.version']}",
                 'asm-util'             : 
"org.ow2.asm:asm-util:${combinedVersions['asm.version']}",
diff --git a/grails-bom/base/build.gradle b/grails-bom/base/build.gradle
index eba2651152..a1a1b75f20 100644
--- a/grails-bom/base/build.gradle
+++ b/grails-bom/base/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 dependencies {
@@ -99,130 +70,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${ artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails BOM (Bill of Materials) for managing dependency 
versions used by Grails Projects'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overridden by project properties (gradle.properties 
or ext['property.name'])
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails BOM (Bill of Materials) for managing dependency 
versions used by Grails Projects'
diff --git a/grails-bom/default/build.gradle b/grails-bom/default/build.gradle
index 9e7f04dbec..b79b42d325 100644
--- a/grails-bom/default/build.gradle
+++ b/grails-bom/default/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 dependencies {
@@ -85,130 +56,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${ artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails BOM (Bill of Materials) for managing dependency 
versions used by Grails Projects'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overriden by the spring boot dependency management 
plugin
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails BOM (Bill of Materials) for managing dependency 
versions used by Grails Projects'
diff --git a/grails-bom/hibernate5-micronaut/build.gradle 
b/grails-bom/hibernate5-micronaut/build.gradle
index 9d91c8b5b8..1fbd070831 100644
--- a/grails-bom/hibernate5-micronaut/build.gradle
+++ b/grails-bom/hibernate5-micronaut/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 // Register the Micronaut platform in combinedPlatforms/combinedVersions so
@@ -124,135 +95,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-hibernate5-micronaut-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    // Micronaut's platform imports many sub-BOMs (micronaut-*-bom, netty-bom, 
etc.) that are
-    // not explicitly registered in dependencies.gradle. Auto-register them so 
extractConstraints
-    // can document their versions without requiring manual entries for every 
transitive platform.
-    // this is required because the micronaut bom format uses gradle modules 
instead of a pom like spring boot
-    it.autoRegisterTransitivePlatforms = true
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails Hibernate 5 Micronaut BOM (Bill of Materials) for 
Grails projects integrating with Micronaut and Hibernate 5. Layers Hibernate 5 
dependency management on top of grails-micronaut-bom; consume as 
enforcedPlatform.'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overridden by the spring boot dependency management 
plugin
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails Hibernate 5 Micronaut BOM (Bill of Materials) for 
Grails projects integrating with Micronaut and Hibernate 5. Layers Hibernate 5 
dependency management on top of grails-micronaut-bom; consume as 
enforcedPlatform.'
diff --git a/grails-bom/hibernate5/build.gradle 
b/grails-bom/hibernate5/build.gradle
index 5c417e4574..e0ff502ac9 100644
--- a/grails-bom/hibernate5/build.gradle
+++ b/grails-bom/hibernate5/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 dependencies {
@@ -85,130 +56,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-hibernate5-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${ artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails Hibernate 5 BOM (Bill of Materials) for managing 
dependency versions used by Grails Projects with Hibernate 5'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overriden by the spring boot dependency management 
plugin
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails Hibernate 5 BOM (Bill of Materials) for managing 
dependency versions used by Grails Projects with Hibernate 5'
diff --git a/grails-bom/hibernate7-micronaut/build.gradle 
b/grails-bom/hibernate7-micronaut/build.gradle
index a6206e0567..37600eae4c 100644
--- a/grails-bom/hibernate7-micronaut/build.gradle
+++ b/grails-bom/hibernate7-micronaut/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 // Register the Micronaut platform in combinedPlatforms/combinedVersions so
@@ -124,135 +95,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-hibernate7-micronaut-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    // Micronaut's platform imports many sub-BOMs (micronaut-*-bom, netty-bom, 
etc.) that are
-    // not explicitly registered in dependencies.gradle. Auto-register them so 
extractConstraints
-    // can document their versions without requiring manual entries for every 
transitive platform.
-    // this is required because the micronaut bom format uses gradle modules 
instead of a pom like spring boot
-    it.autoRegisterTransitivePlatforms = true
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails Hibernate 7 Micronaut BOM (Bill of Materials) for 
Grails projects integrating with Micronaut and Hibernate 7. Layers Hibernate 7 
dependency management on top of grails-base-bom with Micronaut platform; 
consume as enforcedPlatform.'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overridden by the spring boot dependency management 
plugin
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails Hibernate 7 Micronaut BOM (Bill of Materials) for 
Grails projects integrating with Micronaut and Hibernate 7. Layers Hibernate 7 
dependency management on top of grails-base-bom with Micronaut platform; 
consume as enforcedPlatform.'
diff --git a/grails-bom/hibernate7/build.gradle 
b/grails-bom/hibernate7/build.gradle
index 81c5f6c00c..686dfc30eb 100644
--- a/grails-bom/hibernate7/build.gradle
+++ b/grails-bom/hibernate7/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 dependencies {
@@ -81,130 +52,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-hibernate7-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${ artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails Hibernate 7 BOM (Bill of Materials) for managing 
dependency versions used by Grails Projects with Hibernate 7'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overriden by the spring boot dependency management 
plugin
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails Hibernate 7 BOM (Bill of Materials) for managing 
dependency versions used by Grails Projects with Hibernate 7'
diff --git a/grails-bom/micronaut/build.gradle 
b/grails-bom/micronaut/build.gradle
index f3eda80c75..0e8a1bc410 100644
--- a/grails-bom/micronaut/build.gradle
+++ b/grails-bom/micronaut/build.gradle
@@ -17,37 +17,8 @@
  *  under the License.
  */
 
-import org.apache.grails.gradle.tasks.bom.ExtractDependenciesTask
-import org.apache.grails.gradle.tasks.bom.ExtractedDependencyConstraint
-import org.apache.grails.gradle.tasks.bom.PropertyNameCalculator
-
-buildscript {
-    apply from: rootProject.layout.projectDirectory.file('dependencies.gradle')
-}
-
 plugins {
-    id 'java-platform'
-    id 'org.apache.grails.buildsrc.publish'
-    id 'org.apache.grails.buildsrc.sbom'
-}
-
-version = projectVersion
-group = 'org.apache.grails'
-
-javaPlatform {
-    allowDependencies()
-}
-
-ext {
-    isReleaseBuild = System.getenv('GRAILS_PUBLISH_RELEASE') == 'true'
-    isPublishedExternal = 
System.getenv().containsKey('NEXUS_PUBLISH_STAGING_PROFILE_ID')
-    // TODO: It should be possible to pull these build names using 
includedBuild, but I haven't found a way to do so
-    gradleBuildProjects = [
-            'grails-gradle-plugins':'org.apache.grails',
-            'grails-gradle-model':'org.apache.grails.gradle',
-            'grails-gradle-common':'org.apache.grails.gradle',
-            'grails-gradle-tasks':'org.apache.grails',
-    ]
+    id 'org.apache.grails.buildsrc.bom-conventions'
 }
 
 // Register the Micronaut platform in combinedPlatforms/combinedVersions so
@@ -127,135 +98,4 @@ dependencies {
     }
 }
 
-configurations.register('bomDependencies').configure {
-    it.canBeResolved = true
-    it.transitive = true
-    it.extendsFrom(configurations.named('api').get())
-}
-
-tasks.register('extractConstraints', ExtractDependenciesTask).configure { 
ExtractDependenciesTask it ->
-    it.captureProjectServices(project.dependencies, project.configurations)
-    it.configuration = configurations.named('bomDependencies')
-    it.configurationName = 'bomDependencies'
-    it.destination = 
project.layout.buildDirectory.file('grails-micronaut-bom-constraints.adoc')
-    it.platformDefinitions = combinedPlatforms
-    it.definitions = combinedDependencies
-    it.projectName = project.name
-    it.versions = combinedVersions
-    // Micronaut's platform imports many sub-BOMs (micronaut-*-bom, netty-bom, 
etc.) that are
-    // not explicitly registered in dependencies.gradle. Auto-register them so 
extractConstraints
-    // can document their versions without requiring manual entries for every 
transitive platform.
-    // this is required because the micronaut bom format uses gradle modules 
instead of a pom like spring boot
-    it.autoRegisterTransitivePlatforms = true
-    rootProject.subprojects.each { p ->
-        evaluationDependsOn(p.path)
-    }
-    it.projectArtifactIds.set(project.provider {
-        Map<String, String> artifactIdMappings = [:]
-
-        rootProject.subprojects.each { p ->
-            artifactIdMappings[p.name] = p.findProperty('pomArtifactId') ?: 
p.name
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            artifactIdMappings[dependency.key] = dependency.key
-        }
-
-        artifactIdMappings
-    })
-    it.forcedGroupPrefixes.set(['org.apache.grails.profiles': 
'grails-profile'])
-    it.projectCoordinateProperties.set(project.provider {
-        Map<String, String> projectCoordinates = [:]
-
-        rootProject.subprojects.each { p ->
-            String artifactId = p.findProperty('pomArtifactId') as String ?: 
p.name
-            String baseVersionName = artifactId.replaceAll('[.]', '-')
-            projectCoordinates["${p.group}:${ artifactId}:${p.version}" as 
String] = baseVersionName
-        }
-
-        for (Map.Entry<String, String> dependency : 
project.ext.gradleBuildProjects.entrySet()) {
-            
projectCoordinates["${dependency.value}:${dependency.key}:${project.version}" 
as String] = dependency.key
-        }
-
-        projectCoordinates
-    })
-
-    
it.dependsOn(project.tasks.named('generateMetadataFileForMavenPublication'), 
project.tasks.named('generatePomFileForMavenPublication'))
-}
-
-def validateNoSnapshotDependencies = 
tasks.register('validateNoSnapshotDependencies')
-validateNoSnapshotDependencies.configure { Task it ->
-    it.group = 'publishing'
-    it.description = 'Validates that no snapshot dependencies are present in 
the project when performing a release.'
-
-    it.doLast {
-        configurations.each { config ->
-            config.allDependencies.each { dep ->
-                if (dep.version && dep.version.contains('-SNAPSHOT')) {
-                    throw new GradleException("Releases cannot have a snapshot 
dependency: ${dep.group}:${dep.name} (${dep.version})")
-                }
-            }
-        }
-    }
-}
-
-if (ext.isReleaseBuild && ext.isPublishedExternal) {
-    project.afterEvaluate {
-        tasks.named('generateMetadataFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-        tasks.named('generatePomFileForMavenPublication').configure {
-            dependsOn(validateNoSnapshotDependencies)
-        }
-    }
-}
-
-ext {
-    pomDescription = 'Grails Micronaut BOM (Bill of Materials) for Grails 
projects integrating with Micronaut. Layers Micronaut-specific dependency 
overrides on top of grails-bom; consume as enforcedPlatform.'
-    pomCustomization = { xml ->
-        def root = xml.asNode()
-
-        def propertiesNode = root.properties ? root.properties[0] : 
root.appendNode('properties')
-
-        def depMgmt = root.dependencyManagement?.getAt(0)
-        def deps = depMgmt?.dependencies?.getAt(0)
-        if (deps) {
-            PropertyNameCalculator propertyNameCalculator = new 
PropertyNameCalculator(combinedPlatforms, combinedDependencies, 
combinedVersions)
-            
propertyNameCalculator.addForcedGroupPrefix('org.apache.grails.profiles', 
'grails-profile')
-            propertyNameCalculator.addProjects(rootProject.subprojects)
-            for (String gradleArtifactId : project.ext.gradleBuildProjects) {
-                propertyNameCalculator.addProject('org.apache.grails.gradle', 
gradleArtifactId, project.version as String, gradleArtifactId)
-            }
-
-            Map<String, String> pomProperties = [:]
-            deps.dependency.each { dep ->
-                String groupId = dep.groupId.text().trim()
-                String artifactId = dep.artifactId.text().trim()
-                boolean isBom = dep.scope.text().trim() == 'import'
-
-                String inlineVersion = dep.version.text().trim()
-                if (inlineVersion == 'null') {
-                    inlineVersion = null
-                }
-
-                if (inlineVersion) {
-                    ExtractedDependencyConstraint extractedConstraint = 
propertyNameCalculator.calculate(groupId, artifactId, inlineVersion, isBom)
-                    if (extractedConstraint?.versionPropertyReference) {
-                        // use the property reference instead of the hard 
coded version so that it can be
-                        // overriden by the spring boot dependency management 
plugin
-                        dep.version[0].value = 
extractedConstraint.versionPropertyReference
-
-                        // Add an entry in the <properties> node with the 
actual version number
-                        
pomProperties.put(extractedConstraint.versionPropertyName, inlineVersion)
-                    }
-                } else if (!inlineVersion) {
-                    throw new GradleException("Dependency $groupId:$artifactId 
does not have a version.")
-                }
-            }
-
-            for (Map.Entry<String, String> property : 
pomProperties.entrySet()) {
-                propertiesNode.appendNode(property.key, property.value)
-            }
-        }
-    }
-}
+ext.pomDescription = 'Grails Micronaut BOM (Bill of Materials) for Grails 
projects integrating with Micronaut. Layers Micronaut-specific dependency 
overrides on top of grails-bom; consume as enforcedPlatform.'


Reply via email to