Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build-logic/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ repositories {
}

dependencies {
implementation 'biz.aQute.bnd:biz.aQute.bndlib:6.4.1'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm:4.0.5'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm-pdf:4.0.5'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:6.0.4'
implementation 'org.nosphere.apache:creadur-rat-gradle:0.8.1'
implementation 'com.github.spotbugs.snom:spotbugs-gradle-plugin:6.4.2'
implementation 'me.champeau.jmh:jmh-gradle-plugin:0.7.2'
implementation 'me.champeau.jmh:jmh-gradle-plugin:0.7.3'
implementation 'org.cyclonedx:cyclonedx-gradle-plugin:3.0.2'
implementation "com.fasterxml.jackson:jackson-bom:2.21.3" // later version for cyclonedx
implementation "org.slf4j:slf4j-api:2.0.17" // later version for cyclonedx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ configurations {
}

tasks.withType(AbstractAsciidoctorTask).configureEach {
// asciidoctor-gradle-jvm 4.0.5 stores configuration objects (DefaultDependencyScopeConfiguration
// etc.) inside its extension, which are not serializable by the configuration cache.
// Remove this call once the plugin ships a CC-compatible release.
notCompatibleWithConfigurationCache(
'asciidoctor-gradle-jvm 4.0.5 is not configuration-cache compatible ' +
'(captures Gradle dependency-management state in its extension)'
)
outputs.cacheIf { true }
usesService(ConcurrentExecutionControlBuildService.restrict(AbstractAsciidoctorTask, gradle))
configurations 'asciidocExtensions'
Expand Down
47 changes: 39 additions & 8 deletions build-logic/src/main/groovy/org.apache.groovy-base.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ plugins {
id 'org.apache.groovy-common'
id 'org.apache.groovy-internal'
id 'org.apache.groovy-tested'
id 'org.apache.groovy-asciidoctor'
}

/**
Expand All @@ -47,6 +46,13 @@ if (sharedConfiguration.hasCodeCoverage.get()) {
pluginManager.apply(JacocoPlugin)
}

if (sharedConfiguration.isDocumentationBuild && layout.projectDirectory.dir('src/spec/doc').asFile.isDirectory()) {
// The latest available Asciidoctor Gradle plugins still emit a Gradle 9 deprecation
// during apply, so only documentation builds enable them and suppress that noise.
gradle.startParameter.warningMode = org.gradle.api.logging.configuration.WarningMode.None
pluginManager.apply('org.apache.groovy-asciidoctor')
}

def groovyLibrary = project.extensions.create('groovyLibrary', GroovyLibraryExtension, sharedConfiguration, java)

java {
Expand Down Expand Up @@ -97,6 +103,16 @@ configurations {
}
}
}
asciidocElements {
canBeConsumed = true
canBeResolved = false
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, DocsType.USER_MANUAL))
}
// No artifact — projects without src/spec/doc produce an empty variant.
// org.apache.groovy-asciidoctor.gradle adds the actual artifact when applied.
}
javadocClasspath {
canBeConsumed = true
canBeResolved = false
Expand Down Expand Up @@ -185,10 +201,14 @@ tasks.withType(Jar).configureEach { jar ->
tasks.register('jarjar', JarJarTask) {
String projectName = project.name
from = jar.archiveFile
// Eagerly resolve the module list so the componentFilter closure captures only a
// plain List<String> — never the GroovyLibraryExtension object — keeping the task
// compatible with the Gradle configuration cache.
List<String> repackagedDeps = groovyLibrary.repackagedDependencies.get()
repackagedLibraries.from configurations.runtimeClasspath.incoming.artifactView {
componentFilter { component ->
if (component instanceof ModuleComponentIdentifier) {
return component.module in groovyLibrary.repackagedDependencies.get()
return component.module in repackagedDeps
}
return false
}
Expand All @@ -213,12 +233,23 @@ tasks.register('jarjar', JarJarTask) {
]
outputFile = tasks.named('jar').flatMap { layout.buildDirectory.file("libs/${it.archiveBaseName.get()}-${it.archiveVersion.get()}${(it.archiveClassifier.get() && it.archiveClassifier.get() != 'raw') ? '-' + it.archiveClassifier.get() : ''}.jar") }

withManifest {
String autoModName = "org.apache.${projectName.replace('-','.')}"
attributes('Automatic-Module-Name': autoModName, 'Bundle-Name': "Groovy module: $projectName")
groovyLibrary.configureManifest(it, excludedFromManifest)
classpath = configurations.runtimeClasspath
}
// All manifest data is stored as plain serializable values so the task is
// compatible with the Gradle configuration cache.
bndClasspath.from(configurations.runtimeClasspath)
String gbv = sharedConfiguration.groovyBundleVersion.get()
bndInstruction('Automatic-Module-Name', "org.apache.${projectName.replace('-', '.')}")
bndInstruction('Bundle-Name', "Groovy module: $projectName")
bndInstruction('Bundle-ManifestVersion', '2')
bndInstruction('Bundle-Description', 'Groovy Runtime')
bndInstruction('Bundle-Vendor', 'The Apache Software Foundation')
bndInstruction('Bundle-Version', gbv)
bndInstruction('Bundle-License', 'Apache-2.0')
bndInstruction('Specification-Title', 'Groovy: a powerful, multi-faceted language for the JVM')
bndInstruction('Specification-Vendor', 'The Apache Software Foundation')
bndInstruction('Specification-Version', gbv)
bndInstruction('Implementation-Title', 'Groovy: a powerful, multi-faceted language for the JVM')
bndInstruction('Implementation-Vendor', 'The Apache Software Foundation')
bndInstruction('Implementation-Version', gbv)
}

tasks.withType(AbstractCompile).configureEach {
Expand Down
41 changes: 22 additions & 19 deletions build-logic/src/main/groovy/org.apache.groovy-core.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ tasks.named('jar') {

tasks.named('jarjar') { JarJarTask jjt ->
def groovyBundleVersion = sharedConfiguration.groovyBundleVersion.get()
jjt.withManifest {
instruction '-nouses', 'true'
instruction 'Export-Package', "*;version=${groovyBundleVersion}"
instruction 'Eclipse-ExtensibleAPI', 'true' // GROOVY-8713, GROOVY-11582
}
jjt.bndInstruction('-nouses', 'true')
jjt.bndInstruction('Export-Package', "*;version=${groovyBundleVersion}")
jjt.bndInstruction('Eclipse-ExtensibleAPI', 'true') // GROOVY-8713, GROOVY-11582
jjt.bndInstruction('DynamicImport-Package', '*') // GROOVY-3192
jjt.bndInstruction('Eclipse-BuddyPolicy', 'dependent') // GROOVY-5571
jjt.bndInstruction('Main-Class', 'groovy.ui.GroovyMain')
}

// Gradle classloading magic with Groovy will only work if it finds a *jar*
Expand All @@ -92,9 +93,9 @@ def bootstrapJar = tasks.register('bootstrapJar', Jar) {

// The main Groovy compile tasks has a special setup because
// it uses the "bootstrap compiler"
tasks.withType(GroovyCompile).configureEach {
tasks.withType(GroovyCompile).configureEach { groovyCompileTask ->
groovyClasspath = files(bootstrapJar, groovyClasspath)
if (it.name == 'compileGroovy') {
if (groovyCompileTask.name == 'compileGroovy') {
classpath = files(bootstrapJar, classpath)
}
options.incremental = true
Expand All @@ -112,6 +113,8 @@ interface CoreServices {
}

def execOperations = objects.newInstance(CoreServices).execOperations
def bridgerClasspath = files(rootProject.configurations.tools)
def classesToBridge = groovyCore.classesToBridge

tasks.named('compileJava') {
options.fork = true
Expand All @@ -120,9 +123,9 @@ tasks.named('compileJava') {

doLast {
execOperations.javaexec { spec ->
spec.classpath(rootProject.configurations.tools)
spec.classpath(bridgerClasspath)
spec.mainClass = 'org.jboss.bridger.Bridger'
spec.args(groovyCore.classesToBridge.asList().collect { it.absolutePath })
spec.args(classesToBridge.asList().collect { it.absolutePath })
}
}
}
Expand Down Expand Up @@ -159,16 +162,16 @@ def generateGrammarSourceTask = tasks.named("generateGrammarSource") {

doLast {
def parserFilePattern = 'Groovy*'
def outputPath = generateGrammarSource.outputDirectory.canonicalPath
def parserPackagePath = "${outputPath}/${PARSER_PACKAGE_NAME.replace('.', '/')}"
file(parserPackagePath).mkdirs()
copy {
from outputPath
into parserPackagePath
include parserFilePattern
}
delete fileTree(outputPath) {
include parserFilePattern
File outputPath = outputDirectory
File parserPackagePath = new File(outputPath, PARSER_PACKAGE_NAME.replace('.', '/'))
parserPackagePath.mkdirs()
outputPath.listFiles()?.findAll { it.name.startsWith('Groovy') }?.each { file ->
java.nio.file.Files.copy(
file.toPath(),
new File(parserPackagePath, file.name).toPath(),
java.nio.file.StandardCopyOption.REPLACE_EXISTING
)
file.delete()
}
}
}
Expand Down
38 changes: 26 additions & 12 deletions build-logic/src/main/groovy/org.apache.groovy-distribution.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,15 @@ plugins {
id 'org.apache.groovy-common'
id 'org.apache.groovy-aggregating-project'
id 'org.apache.groovy-doc-aggregator'
id 'org.asciidoctor.jvm.pdf'
}

def distributionExtension = project.extensions.create('distribution', DistributionExtension, project)
def documentationBuild = sharedConfiguration.isDocumentationBuild && layout.projectDirectory.dir('src/spec/doc').asFile.isDirectory()

if (documentationBuild) {
pluginManager.apply('org.apache.groovy-asciidoctor')
pluginManager.apply('org.asciidoctor.jvm.pdf')
}

configurations {
baseProjects {
Expand Down Expand Up @@ -133,6 +138,9 @@ def distBin = tasks.register('distBin', Zip) {

def distSdk = tasks.register("distSdk", Zip) {
def groovyBundleVersion = sharedConfiguration.groovyBundleVersion.get()
// Capture project.version at configuration time: accessing project at execution time
// is an "interrupting" CC problem in Gradle 9.x and causes a Gradle-internal exception.
def projectVersion = project.version.toString()
description = 'Generates the binary, sources, documentation and full distributions'
archiveBaseName = 'apache-groovy'
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
Expand All @@ -149,10 +157,9 @@ def distSdk = tasks.register("distSdk", Zip) {
with distributionExtension.srcSpec
}
doFirst {
def av = project.version.toString()
if ((av.endsWith('SNAPSHOT') && !groovyBundleVersion.endsWith('SNAPSHOT'))
|| (!av.endsWith('SNAPSHOT') && groovyBundleVersion.endsWith('SNAPSHOT'))) {
throw new GradleException("Incoherent versions. Found groovyVersion=$av and groovyBundleVersion=${versions.groovyBundle}")
if ((projectVersion.endsWith('SNAPSHOT') && !groovyBundleVersion.endsWith('SNAPSHOT'))
|| (!projectVersion.endsWith('SNAPSHOT') && groovyBundleVersion.endsWith('SNAPSHOT'))) {
throw new GradleException("Incoherent versions. Found groovyVersion=$projectVersion and groovyBundleVersion=${versions.groovyBundle}")
}
}
}
Expand Down Expand Up @@ -198,21 +205,28 @@ tasks.register("installGroovy", Sync) {
}

tasks.register("doc") {
dependsOn 'javadocAll', 'groovydocAll', 'docGDK', 'asciidocAll', 'asciidoctorPdf'
dependsOn 'javadocAll', 'groovydocAll', 'docGDK'
if (documentationBuild) {
dependsOn 'asciidocAll', 'asciidoctorPdf'
}
}

tasks.register("asciidocAll", Copy) {
from configurations.allAsciidoc
from tasks.named('asciidoctor')
if (documentationBuild) {
from tasks.named('asciidoctor')
}
into layout.buildDirectory.dir("asciidocAll/html5")
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

tasks.named('asciidoctorPdf') {
baseDirFollowsSourceFile()
logDocuments = true
sourceDir = file('src/spec/doc')
outputDir = layout.buildDirectory.dir("asciidocAll/pdf")
if (documentationBuild) {
tasks.named('asciidoctorPdf') {
baseDirFollowsSourceFile()
logDocuments = true
sourceDir = file('src/spec/doc')
outputDir = layout.buildDirectory.dir("asciidocAll/pdf")
}
}

// The Groovy distribution module isn't a Java library
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ tasks.withType(Javadoc).configureEach {
if (JavaVersion.current() >= JavaVersion.VERSION_21) {
addStringOption('-link-modularity-mismatch', 'info')
}
addStringOption('tag', 'apiNote:a:"API Note:"')
addStringOption('tag', 'implSpec:a:"Implementation Requirements:"')
addStringOption('tag', 'implNote:a:"Implementation Note:"')
tags(
'apiNote:a:"API Note:"',
'implSpec:a:"Implementation Requirements:"',
'implNote:a:"Implementation Note:"'
)
windowTitle = "Groovy ${versions.groovy}"
docTitle = "Groovy ${versions.groovy}"
classpath += project.file('src/main/java') // to pick up package.html
Expand Down
22 changes: 10 additions & 12 deletions build-logic/src/main/groovy/org.apache.groovy-library.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,16 @@ dependencies {

tasks.named('jarjar') { JarJarTask jjt ->
def groovyBundleVersion = sharedConfiguration.groovyBundleVersion.get()
jjt.withManifest {
instruction '-nouses', 'true'
instruction 'Export-Package', "*;version=${groovyBundleVersion}"
instruction 'Fragment-Host', 'groovy' // GROOVY-9402, GROOVY-11570
def folder = file("${projectDir}/src/main/resources/META-INF/services")
if (folder.exists() && folder.listFiles().count { it.name ==~ /^(?!(org.codehaus.groovy.transform.ASTTransformation)$).*$/ } > 0) {
instruction 'Require-Capability', 'osgi.extender;filter:="(osgi.extender=osgi.serviceloader.processor)"'
instruction 'Require-Capability', 'osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)"'
folder.eachFileMatch(~/^(?!(org.codehaus.groovy.transform.ASTTransformation)$).*$/) {
instruction 'Require-Capability', "osgi.serviceloader;filter:=\"(osgi.serviceloader=${it.name})\";cardinality:=multiple"
instruction 'Provide-Capability', "osgi.serviceloader;osgi.serviceloader=\"${it.name}\""
}
jjt.bndInstruction('-nouses', 'true')
jjt.bndInstruction('Export-Package', "*;version=${groovyBundleVersion}")
jjt.bndInstruction('Fragment-Host', 'groovy') // GROOVY-9402, GROOVY-11570
def folder = file("${projectDir}/src/main/resources/META-INF/services")
if (folder.exists() && folder.listFiles().count { it.name ==~ /^(?!(org.codehaus.groovy.transform.ASTTransformation)$).*$/ } > 0) {
jjt.bndInstruction('Require-Capability', 'osgi.extender;filter:="(osgi.extender=osgi.serviceloader.processor)"')
jjt.bndInstruction('Require-Capability', 'osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)"')
folder.eachFileMatch(~/^(?!(org.codehaus.groovy.transform.ASTTransformation)$).*$/) {
jjt.bndInstruction('Require-Capability', "osgi.serviceloader;filter:=\"(osgi.serviceloader=${it.name})\";cardinality:=multiple")
jjt.bndInstruction('Provide-Capability', "osgi.serviceloader;osgi.serviceloader=\"${it.name}\"")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
*/

tasks.withType(PublishToMavenRepository).configureEach {
def isReleaseVersion = sharedConfiguration.isReleaseVersion.get()
doLast {
if (sharedConfiguration.isReleaseVersion.get()) {
pluginManager.withPlugin('java') {
project.configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.each {
if (isReleaseVersion) {
def publishedProject = delegate.project
if (publishedProject.pluginManager.hasPlugin('java')) {
publishedProject.configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.each {
if (it.moduleVersion.id.version.endsWith("-SNAPSHOT")) {
throw new GradleException("Found snapshot dependency for non-snapshot Groovy: " + it.moduleVersion)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.cyclonedx.model.License
import org.cyclonedx.model.LicenseChoice
import org.cyclonedx.model.OrganizationalContact
import org.cyclonedx.model.OrganizationalEntity
import org.gradle.api.publish.maven.tasks.PublishToMavenRepository

plugins {
id 'maven-publish'
Expand Down Expand Up @@ -819,17 +820,15 @@ publishing {
}

signing {
required = {
sharedConfiguration.signing.shouldSign(gradle.taskGraph)
}
required = sharedConfiguration.signing.shouldSign()
sign publishing.publications.maven
if (sharedConfiguration.signing.useGpgCmd.get()) {
useGpgCmd()
}
}

gradle.taskGraph.whenReady { taskGraph ->
if (sharedConfiguration.signing.shouldSign(gradle.taskGraph)) {
if (sharedConfiguration.signing.shouldSign()) {
// Use Java 6's console or Swing to read input (not suitable for CI)
if (!sharedConfiguration.signing.hasAllKeyDetails()) {
printf '\n\nWe have to sign some things in this build.' +
Expand Down Expand Up @@ -858,6 +857,12 @@ gradle.taskGraph.whenReady { taskGraph ->
}
}

tasks.withType(PublishToMavenRepository).configureEach {
if (repository.name == 'LocalFile') {
mustRunAfter(rootProject.tasks.named('clean'))
}
}

String promptUser(String prompt) {
def response = ''
if (System.console() != null) {
Expand Down
Loading
Loading