This is an automated email from the ASF dual-hosted git repository. jamesfredley pushed a commit to branch feat/automatic-module-names in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 7f4e24d9b0d60e876d9301ff02ddfcd111f1f46f Author: James Fredley <[email protected]> AuthorDate: Fri Jul 10 12:57:55 2026 -0400 Add Automatic-Module-Name jar manifests Generate Automatic-Module-Name entries from build-logic for published modules. Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding] --- .../apache/grails/buildsrc/CompilePlugin.groovy | 16 ++++++++ .../grails/buildsrc/CompilePluginSpec.groovy | 43 ++++++++++++++++++++++ grails-doc/src/en/guide/toc.yml | 1 + .../en/guide/upgrading/automaticModuleNames.adoc | 7 ++++ 4 files changed, 67 insertions(+) diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/CompilePlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/CompilePlugin.groovy index b139dacf16..7253694e79 100644 --- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/CompilePlugin.groovy +++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/CompilePlugin.groovy @@ -83,11 +83,27 @@ class CompilePlugin implements Plugin<Project> { 'Implementation-Version': lookupPropertyByType(project, 'grailsVersion', String), 'Implementation-Vendor': 'grails.apache.org' ) + if (!jar.archiveClassifier.present) { + jar.manifest.attributes('Automatic-Module-Name': automaticModuleName(project)) + } // Explicitly fail since duplicates indicate a double configuration that needs fixed jar.duplicatesStrategy = DuplicatesStrategy.FAIL } } + static String automaticModuleName(Project project) { + String configuredModuleName = project.findProperty('automaticModuleName') as String + if (configuredModuleName) { + return configuredModuleName + } + String groupPrefix = project.group == null ? 'org.apache.grails' : project.group.toString() + return "${groupPrefix}.${project.name}" + .replace('-', '.') + .replaceAll('[^A-Za-z0-9_.]', '.') + .replaceAll('\\.+', '.') + .replaceAll('^\\.|\\.$', '') + } + private static void configureCompiler(Project project) { project.tasks.withType(JavaCompile).configureEach { // Preserve method parameter names in Groovy/Java classes for IDE parameter hints & bean reflection metadata. diff --git a/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/CompilePluginSpec.groovy b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/CompilePluginSpec.groovy new file mode 100644 index 0000000000..3eb7b83888 --- /dev/null +++ b/build-logic/plugins/src/test/groovy/org/apache/grails/buildsrc/CompilePluginSpec.groovy @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.grails.buildsrc + +import org.gradle.testfixtures.ProjectBuilder +import spock.lang.Specification + +class CompilePluginSpec extends Specification { + + void 'automatic module name is derived from group and project name'() { + given: + def project = ProjectBuilder.builder().withName('grails-web-common').build() + project.group = 'org.apache.grails.web' + + expect: + CompilePlugin.automaticModuleName(project) == 'org.apache.grails.web.grails.web.common' + } + + void 'automatic module name can be overridden per project'() { + given: + def project = ProjectBuilder.builder().withName('grails-web-common').build() + project.ext.automaticModuleName = 'org.apache.grails.web.common' + + expect: + CompilePlugin.automaticModuleName(project) == 'org.apache.grails.web.common' + } +} diff --git a/grails-doc/src/en/guide/toc.yml b/grails-doc/src/en/guide/toc.yml index b0e4a5c3ff..2aa8032711 100644 --- a/grails-doc/src/en/guide/toc.yml +++ b/grails-doc/src/en/guide/toc.yml @@ -37,6 +37,7 @@ gettingStarted: upgrading: title: Upgrading from the previous versions upgrading80x: Upgrading from Grails 7 to Grails 8 + automaticModuleNames: Automatic module names upgrading72x: Upgrading from Grails 7.1 to Grails 7.2 upgrading71x: Upgrading from Grails 7.0 to Grails 7.1 upgrading70x: Upgrading from Grails 6 to Grails 7.0 diff --git a/grails-doc/src/en/guide/upgrading/automaticModuleNames.adoc b/grails-doc/src/en/guide/upgrading/automaticModuleNames.adoc new file mode 100644 index 0000000000..c2d9906e61 --- /dev/null +++ b/grails-doc/src/en/guide/upgrading/automaticModuleNames.adoc @@ -0,0 +1,7 @@ +=== Automatic module names + +Grails 8.1 starts publishing `Automatic-Module-Name` manifest entries for the main framework jars produced by the shared compile convention. +By default the module name is derived from the Gradle project group and project name, replacing hyphens with dots. + +Examples include `org.apache.grails.grails.core` for `grails-core` and `org.apache.grails.web.grails.web.common` for `grails-web-common`. +Individual modules may set an `automaticModuleName` project property when a shorter stable JPMS name is agreed for a follow-up slice.
