Kelvin Chung
07/03/2025, 6:35 AMval testResultsElements = configurations.consumable("testResultsElementsForJvmTest") {
// This configuration mimics that defined by the "test-suite-base" plugin
description = "Binary results obtained from running the 'jvmTest' suites."
attributes.attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.VERIFICATION))
attributes.attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE, objects.named(VerificationType.TEST_RESULTS))
// FIXME how do we accommodate multiple JVM targets and their respective test suites?
attributes.attribute(TestSuiteName.TEST_SUITE_NAME_ATTRIBUTE, objects.named("test"))
val binaryDir = tasks.named<Test>("jvmTest").flatMap { it.binaryResultsDirectory }
outgoing.artifact(binaryDir) {
type = ArtifactTypeDefinition.DIRECTORY_TYPE
}
}
I'm wondering what I would have to change if I had two source sets that produced JVM code, so I would have two "testResults" configurations. And how that would relate to the test result aggregation plugin since I would need to differentiate them in such a way that the aggregation plugin could pick each of them separately.Vampire
07/09/2025, 11:28 PMwith in the task implemenation?ysb33r
07/13/2025, 7:17 PMterraform test -junit-xml . What I would like to do is to convert those XML files into HTML reports that look-and-feel the same as the ones generated by Test tasks.
Does anyone know whether that can be achieved with what we have available in the Gradle API today (7.3+)?Thomas Broyer
07/15/2025, 3:27 PMgetMessage() lazily using a helper class (from that same third-party lib).
The problem is that, if I don't do anything special, Gradle will somehow "copy" the exception outside of the classLoaderIsolation or back to the Gradle Daemon process, but won't "copy" that helper class, so when Gradle wants to print the error message to the console and calls the exception's getMessage() method, that one will throw a ClassNotFoundException that will shadow the actual error.
How would you recommend handling this?Thomas Broyer
07/16/2025, 3:09 PMConfigurableFileCollection properties be initialized with .convention() or .from()? What do you think?
(I initially went with .convention(), but when the conventional value is a bit convoluted to compute –a file in the output of the processResources task– it's asking too much to the users if they just want to add to the file collection, while on the other hand if initialized with .from() and they don't want that value they can .setFrom() to reinitialize it; what would be the use cases for .convention() then?)Thomas Broyer
07/16/2025, 3:40 PMconvention() or putAll()? (my use-case is initializing it with providers.gradlePropertiesPrefixedBy(…))
I've found one instance of MapProperty in the Gradle codebase that's not left empty, and it's in the build logic (so not in a "public" plugin), and it uses a few calls to `put()`: https://github.com/gradle/gradle/blob/56ac845808133d19b7e03a3fcc1264f21122e37e/bui[…]/src/main/groovy/gradlebuild/docs/GradleReleaseNotesPlugin.javaMartin
07/17/2025, 12:03 PMMapProperty questions:
• Is it possible to have null as a value?
• Having MapProperty<String, Any?> displays an error in my IDE but compiles fine. Where is the disconnect? How come the KIJP knows that the bound is non nullable?Jerome Haltom
07/17/2025, 2:04 PMAlexey Loubyansky
07/22/2025, 4:24 PMruntime or runtimeElements as a base variant but that introduces an ambiguity, which i'm struggling to find a way to avoid. Is there an example how it's supposed to be done?
Here is my playground plugin https://github.com/aloubyansky/playground/blob/gradle-comp-variants/plugin/src/main/java/org/example/PlaygroundPlugin.java
And here is the outcome of running it https://github.com/aloubyansky/playground/tree/gradle-comp-variants.
Thanks!Alexey Loubyansky
07/23/2025, 8:49 PMtestRuntimeClasspath , resolve it and iterate through the resolved artifacts. But if there are test fixtures, it fails with
> Could not resolve all artifacts for configuration ':app:testRuntimeClasspathCopy'.
> Could not resolve project :app.
Required by:
project :app
> Unable to find a variant with the requested capability: feature 'test-fixtures':
- Variant 'testRuntimeClasspathCopy' provides 'playground:app:unspecified'
It looks like something is missing from the copy of the original configuration. Is this expected? Thanks!
I have a little playground project to reproduce the issue here https://github.com/aloubyansky/playground/tree/gradle-copyRecursive-test-fixtures
Commenting out https://github.com/aloubyansky/playground/blob/gradle-copyRecursive-test-fixtures/plugin/src/main/java/org/example/GreetingTask.java#L21 works.
(I realize referencing a Project from a task is a bad practice, this is just a reproducer).Jakub Chrzanowski
07/28/2025, 7:38 PM8.14.3 to 9.0.0-rc-4.
When running integration tests against Gradle 8.x, the plugin fails on java.lang.NoSuchMethodError and java.lang.NoClassDefFoundError.
In my code, I rely on sequenceOf() and yield(), whose signatures slightly changed in Kotlin 2.0:
sequenceOf()
* Exception is:
java.lang.NoSuchMethodError: 'kotlin.sequences.Sequence kotlin.sequences.SequencesKt.sequenceOf(java.lang.Object)'
at org.jetbrains.intellij.platform.gradle.resolvers.path.ModuleDescriptorsPathResolver.<init>(ModuleDescriptorsPathResolver.kt:19)
at Build_gradle.<init>(build.gradle.kts:53)
yield()
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':signPlugin'.
....
Caused by: java.lang.NoClassDefFoundError: kotlin/coroutines/jvm/internal/SpillingKt
at org.jetbrains.intellij.platform.gradle.tasks.SignPluginTask$arguments$1.invokeSuspend(SignPluginTask.kt:208)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
My first though was to build the Gradle plugin targeting Kotlin 1.8 (we support Gradle 8.5+) using:
kotlin {
jvmToolchain(17)
compilerOptions {
apiVersion = KotlinVersion.KOTLIN_1_8
languageVersion = KotlinVersion.KOTLIN_1_8
}
}
but this didn't really help. Any ideas on how to deal with that?Kelvin Chung
07/28/2025, 9:03 PMRepositoryHandler so that it has more conventional NamedDomainObjectContainer semantics? It just seems like with the way Gradle has evolved over the years, something like
repositories {
maven(url) { name = "foobar" }
}
would be a bit clunky compared to
repositories.register<MavenArtifactRepository>("foobar") {
url.set(...)
}
Of course, I recognize that any effort to go in that direction would be nontrivial, since the API appears to not have a thing that is both "ordered" and "an extensible container", but one can dream, right?efemoney
07/31/2025, 9:53 AMSteve Ebersole
07/31/2025, 6:01 PMpublic abstract class HibernateOrmSpec {
...
@Optional
abstract public Property<EnhancementSpec> getEnhancement();
public void enhancement(Action<EnhancementSpec> action) {
EnhancementSpec spec = getObjectFactory().newInstance( EnhancementSpec.class );
action.execute( spec );
getEnhancement().set( spec );
}
}
abstract public class EnhancementSpec {
abstract public Property<Boolean> getEnableLazyInitialization();
...
}
Later, I try to see if the user specified this "enhancement" extension : if ( !getEnhancement().isPresent() ) ...
The odd part is this...
This works as expected:
hibernate {
enhancement {
}
}
However, this does not:
hibernate {
enhancement
}
Now I can easily accept that this second form is "not valid". But the problem I am having is actually being able to recognize this situation to properly handle it (whether that be treat it as the first form, throw an exception, etc.). The problem is that, as far as I can tell, Gradle just ignores it (it being the "enhancement" token). Its not added to ext properties or anything like that.
Any idea what Gradle actually does with that?Jerome Haltom
07/31/2025, 7:40 PMysb33r
08/08/2025, 3:26 PM-i affect a task's class path?
That is the headline question, let me explain. I was testing up-to-date status of some tasks in plugin using testKit. Effectively, what I was doing in the test is something like
GradleRunner.create().withArguments('task1')
GradleRunner.create().withArguments('task2')
basically task2 depend on task1 which depends on task0
Thus in the first invocation task0 and task1 will have an outcome of SUCCESS.
In the 2nd invocation, those two should have an outcome of UP_TO_DATE , and task2 will be SUCCESS . Not problem with that, until I did...
GradleRunner.create().withArguments('task1')
GradleRunner.create().withArguments('task2', '-i')
Suddenly, on the 2nd invocation the outcome of task0 was SUCCESS instead of UP_TO_DATE and Gradle logs stated that
Task ':task0' is not up-to-date because:
Class path of task ':task0' has changed from 58046a25460590d169a1847f193c5177 to b72b7af69ca1f7306a1e3a2dcf54a21a.
I find that unexpected behaviour. WDYT?Vladislav Chesnokov
09/03/2025, 10:14 AMysb33r
09/09/2025, 8:36 PMRené
09/09/2025, 8:42 PMJohn
09/16/2025, 8:52 PMBoris Petrov
09/19/2025, 7:32 AM> No signature of method: org.akhikhl.gretty.LauncherBase.beforeLaunch() is applicable for argument types: () values: []
Possible solutions: beforeLaunch(), afterLaunch()
You can see in the code that there very much is such a method on that class. Even the Possible solutions below the error mention it. The error happens on the super.beforeLaunch() call in DefaultLauncher. The details are not important that much - it's just that every call to super.XXX() (not just here - also in other places) in Gradle 9/Groovy 4 fails with No signature of method ... is applicable for argument types . Something which doesn't happen in Gradle 8/Groovy 3. Does anyone have any idea why that might be?
P.S. Something of note - the plugin is compiled with Gradle 6 (so I think Groovy 2) (for backwards-compatibility). Not sure if it matters. I see the compiled code in the JAR:
CallSite[] arrayOfCallSite = $getCallSiteArray();
Object object = arrayOfCallSite[6].callStatic(DefaultLauncher.class, this.project);
this.runnerClasspath = (Collection<URL>)ScriptBytecodeAdapter.castToType(object, Collection.class);
ScriptBytecodeAdapter.invokeMethodOnSuper0(LauncherBase.class, (GroovyObject)this, "beforeLaunch");
Not sure if this somehow "broke" in Gradle 9/Groovy 4?Jonathan Leitschuh
09/23/2025, 10:13 PMJonathan Leitschuh
09/25/2025, 8:12 PMKelvin Chung
09/30/2025, 12:27 AMIncludedBuild object from gradle.buildPath? It's mainly so that I can get the build's project directory, relative to the root build's project directory, for an internal plugin.Niels Doucet
09/30/2025, 1:50 PMMapProperty is confusing, or I'm doing something wrong.
There seems to be a difference in behavior between using putAll vs individual put invocations when setting lazy Provider instances as values for these keys.
Details in thread 🧵Jeff Wise
10/02/2025, 3:09 PMJonathing
10/03/2025, 12:37 PMruntimeElements)? To make a long story short, I'm using artifact transforms to apply workspace-only changes to dependencies, but I don't want those attributes to appear in the resulting module metadata in publications.Jonathing
10/04/2025, 7:18 PMconfigurations.compileClasspath.dependencySubstitutions {
substitute module('org.example:examplelib') using variant(module('org.example:examplelib')) {
attributes { attribute(MyAttribute.ATTR_1, true) }
}
substitute module('org.example:examplelib') using variant(module('org.example:examplelib')) {
attributes { attribute(MyAttribute.ATTR_2, true) }
}
}
Would the resolver try to select the dependency in a way where both ATTR_1 and ATTR_2 are true?
(I can obviously test it myself but am just checking to see if anyone knew the answer to this before I did some experiments)Jonathing
10/15/2025, 12:52 PMProject, ConfigurationContainer, and SoftwareComponentFactory, despite not being listed in the Service Injection userguide page. So my question is, is this page out-of-date or is injecting those other types unsafe? Does Gradle hold the right to make injecting type Project stop working at any time?Rahul Srivastava
10/27/2025, 8:05 AM/**
* Copyright © 2016-2025 The Thingsboard Authors
*
* Licensed 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
*
* <http://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.
*/
import org.apache.tools.ant.filters.ReplaceTokens
plugins {
id "nebula.ospackage" version "8.6.3"
}
buildDir = projectBuildDir
version = projectVersion
distsDirName = "./"
// OS Package plugin configuration
ospackage {
packageName = pkgName
version = "${project.version}"
release = 1
os = LINUX
type = BINARY
into pkgInstallFolder
user pkgUser
permissionGroup pkgUser
// Copy the actual .jar file
from(mainJar) {
// Strip the version from the jar filename
rename { String fileName ->
"${pkgName}.jar"
}
fileMode 0500
into "bin"
}
if("${pkgCopyInstallScripts}".equalsIgnoreCase("true")) {
// Copy the install files
from("${buildDir}/bin/install/install.sh") {
fileMode 0775
into "bin/install"
}
from("${buildDir}/bin/install/upgrade.sh") {
fileMode 0775
into "bin/install"
}
from("${buildDir}/bin/install/logback.xml") {
into "bin/install"
}
}
// Copy the config files
from("${buildDir}/conf") {
exclude "${pkgName}.conf"
fileType CONFIG | NOREPLACE
fileMode 0754
into "conf"
}
// Copy the data files
from("${buildDir}/data") {
fileType CONFIG | NOREPLACE
fileMode 0754
into "data"
}
// Copy the extensions files
from("${buildDir}/extensions") {
into "extensions"
}
}
// Configure our RPM build task
buildRpm {
arch = NOARCH
archiveVersion = projectVersion.replace('-', '')
archiveFileName = "${pkgName}.rpm"
requires("(java-17 or java-17-headless or jre-17 or jre-17-headless)") // .or() notation does work in RPM plugin
from("${buildDir}/conf") {
include "${pkgName}.conf"
filter(ReplaceTokens, tokens: ['pkg.platform': 'rpm'])
fileType CONFIG | NOREPLACE
fileMode 0754
into "${pkgInstallFolder}/conf"
}
preInstall file("${buildDir}/control/rpm/preinst")
postInstall file("${buildDir}/control/rpm/postinst")
preUninstall file("${buildDir}/control/rpm/prerm")
postUninstall file("${buildDir}/control/rpm/postrm")
user pkgUser
permissionGroup pkgUser
// Copy the system unit files
from("${buildDir}/control/template.service") {
addParentDirs = false
fileMode 0644
into "/usr/lib/systemd/system"
rename { String filename ->
"${pkgName}.service"
}
}
link("${pkgInstallFolder}/bin/${pkgName}.yml", "${pkgInstallFolder}/conf/${pkgName}.yml")
link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf")
}
// Same as the buildRpm task
buildDeb {
arch = "all"
archiveFileName = "${pkgName}.deb"
requires("openjdk-17-jre").or("java17-runtime").or("oracle-java17-installer").or("openjdk-17-jre-headless")
from("${buildDir}/conf") {
include "${pkgName}.conf"
filter(ReplaceTokens, tokens: ['pkg.platform': 'deb'])
fileType CONFIG | NOREPLACE
fileMode 0754
into "${pkgInstallFolder}/conf"
}
configurationFile("${pkgInstallFolder}/conf/${pkgName}.conf")
configurationFile("${pkgInstallFolder}/conf/${pkgName}.yml")
configurationFile("${pkgInstallFolder}/conf/logback.xml")
configurationFile("${pkgInstallFolder}/conf/actor-system.conf")
preInstall file("${buildDir}/control/deb/preinst")
postInstall file("${buildDir}/control/deb/postinst")
preUninstall file("${buildDir}/control/deb/prerm")
postUninstall file("${buildDir}/control/deb/postrm")
user pkgUser
permissionGroup pkgUser
// Copy the system unit files
from("${buildDir}/control/template.service") {
addParentDirs = false
fileMode 0644
into "/lib/systemd/system"
rename { String filename ->
"${pkgName}.service"
}
}
link("${pkgInstallFolder}/bin/${pkgName}.yml", "${pkgInstallFolder}/conf/${pkgName}.yml")
link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf")
}
build.gradle and encountering error
startup failed:General error during conversion: Unsupported class file major version 69 while compiling i am using openjdk version 17 i need help in this i am running this on mac machine