https://gradle.com/ logo
Join Slack
Powered by
# plugin-development
  • j

    Jonathing

    10/15/2025, 12:52 PM
    Hey folks. I've noticed a few interesting things about how other plugins use injected services. Notably, how some plugins in the wild inject types such as
    Project
    ,
    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?
    m
    v
    • 3
    • 18
  • r

    Rahul Srivastava

    10/27/2025, 8:05 AM
    hi folks i am using
    Copy code
    /**
     * 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
    t
    p
    v
    • 4
    • 3
  • g

    Giuseppe Barbieri

    11/10/2025, 9:31 AM
    I created a small utility to run some command within a plugin
    Copy code
    context(project: Project)
    operator fun String.invoke(): String {
        val output = ByteArrayOutputStream()
        project.providers.exec {
            commandLine(split(Regex("\\s+")))
            standardOutput = output
        }
        return output.toString().trim()
    }
    but whenever I try to execute some command, I do get > An exception occurred applying plugin request [id: 'io.github.theapache64.korduino.gradle', version: '0.0.1'] > > Failed to apply plugin 'io.github.theapache64.korduino.gradle'. > > Could not create provider for value source ProcessOutputValueSource.
    v
    • 2
    • 2
  • t

    thadhouse

    11/10/2025, 6:25 PM
    Is there a way to figure out which email an API key is associated with (Even if some way internal)? We're going to a repackage of all of our artifacts to match our new website setup, and changing the group id of all of our plugins. We know this has to go through approval, but I don't know if any of us remember the email the API key is associated with. The first plugin being changed is currently sitting the manual approval step.
    v
    • 2
    • 2
  • a

    Alex Beggs

    11/11/2025, 12:58 AM
    I am registering tasks to build demos. These are optionally added, so they might or might not exist. So I can't rely on them being there. I would like to call the task at the root. e.g.
    buildMyDemo
    and have it find any
    buildMyDemo
    tasks in the subprojects and execute them. I have come up with two solutions: Option 1: 1. Register
    buildMyDemo
    in every project 2. Configure
    buildMyDemo
    when necessary in the appropriate subproject Option 2: 1. Register
    buildMyDemo
    in the rootProject once 2. Configure
    buildMyDemo
    when necessary in the appropriate subproject My question comes down to performance. How much worse is Option 1 vs 2? I have ~800 subprojects. I'm planning on implementing Option 2, but I wanted to understand the impact of
    register
    across all of the projects.
    v
    • 2
    • 7
  • j

    John

    11/11/2025, 6:08 PM
    I am using artifactView withVariantReselection and it is working when I publish and resolve via maven. But I am having trouble making it work via project dependencies. my
    outgoingVariants
    has this (which is the one I am trying to resolve to)
    Copy code
    Secondary Variants (*)
    
        --------------------------------------------------
        Secondary Variant archRulesElements
        --------------------------------------------------
        
        Attributes
            - org.gradle.category            = library
            - org.gradle.dependency.bundling = external
            - org.gradle.jvm.version         = 21
            - org.gradle.libraryelements     = jar
            - org.gradle.usage               = arch-rules
        Artifacts
    build/libs/library-with-rules-archrules.jar (artifactType = jar, classifier = archrules)
    but when I select
    Copy code
    attributes {
                                                attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named<Category>(Category.LIBRARY))
                                                attribute(Bundling.BUNDLING_ATTRIBUTE, project.objects.named<Bundling>( Bundling.EXTERNAL))
                                                attribute(Usage.USAGE_ATTRIBUTE, project.objects.named<Usage>( "arch-rules"))
                                            }
    it matches no artifacts. any ideas? maybe there is a common gotcha I am missing?
    v
    • 2
    • 39
  • j

    John

    11/20/2025, 8:46 PM
    Is there a proper way to create a task for each source set, without using afterEvaluate? I want to make sure it is created even if the plugin that creates the source set is applied after mine...
    t
    p
    j
    • 4
    • 5
  • j

    John

    12/12/2025, 5:06 PM
    Is there a way to have a settings plugin that applies a plugin (id) to all projects, but that id will be resolved with the buildscript of that project?
    t
    v
    • 3
    • 18
  • a

    Andres Almiray

    12/26/2025, 10:36 PM
    Hello everyone, what’s the recommended way to write DSL elements, say sections of an extension, that behave properly with the configuration cache? I have the need to grab some properties from the
    project
    instance (such as name, description, etc) and other properties defined in
    gradle.properties
    for example. As I understand values should be sources from providers, as well as avoid keeping references to β€œunsactioned” things such as the
    project
    instance and non-serializable types. Is it OK to pass the
    project
    instance to the constructor (using
    @Inject
    of course) and derive all needed providers from there? Or should I pass all required providers as constructor args? TIA
    m
    t
    • 3
    • 8
  • j

    Jonathing

    01/01/2026, 11:23 PM
    Hey folks. I need to make a task which creates a fake local Maven repository (long story, involves Minecraft) which the
    compileJava
    task will depend on. The problem is that the
    compileClaspath
    configuration is resolved before task execution. So, by the time my task, which produces artifacts in a fake Maven repository that's added to the repositories, finishes execution, it will be too late and
    compileJava
    will fail with an error saying it can't find the (package from) dependency it's looking for. Any thoughts on how to better tackle this? I've already tried doing this fake Maven generation in configuration time itself, but that completely breaks Configuration Cache since it involves running
    ExecOperations#javaExec
    .
    m
    t
    +2
    • 5
    • 28
  • r

    Remi Gelinas

    02/15/2026, 3:55 PM
    Do NamedDomainObjectProviders by default register configurations for all of their members? I have one as part of my DSL, and it seems like without doing anything configurations are being created - i.e. if I create a custom member named "example", "exampleRuntimeOnly" exists
    v
    p
    • 3
    • 8
  • l

    Lex Manos

    02/19/2026, 4:57 AM
    What is the best way to hold references to a TaskProvider, allow groovy to configure it. And have intellij know its type correctly? If I use
    tasks.named(name, type){}
    Intellij correctly determines the closure type. When held in a variable it does not. See attached screenshot Both configuration handlers work (the json is printed twice) However when i try to do the same thing that tasks.named does with my own code I run into issues. Long story short, I am trying to write a helper method that registers multiple tasks.
    Copy code
    this.json = tasks.register(name + "Json", InstallerJson.class);
    public TaskProvider<@NotNull InstallerJson> getJson() {
        return this.json;
    }
    public void json(Action<? super InstallerJson> action) {
        getJson().configure(action);
    }
    When I do:
    Copy code
    inst.json {
      prop = value
    }
    IntelliJ sees the argument type correctly, but I get
    Could not set unknown property 'prop' for root project 'root' of type org.gradle.api.Project.
    When I do:
    Copy code
    inst.json.configure {
      prop = value
    }
    IntelliJ says the argument is of type
    T
    but it executes correctly. Any suggestions on how to make both sides happy?
    v
    r
    • 3
    • 5
  • r

    Remi Gelinas

    02/21/2026, 3:13 AM
    What is the most idiomatic way to pass a single named object from a domain object container to a task as an input?
    p
    • 2
    • 6
  • j

    John

    02/27/2026, 7:44 PM
    if there is a dependencyScope configuration and a resolvable configuration that extends it, and I want to add another configuration that extends, is it better to extend the dependency scope or the resolvable, or what factors are there to consider when choosing?
    t
    v
    • 3
    • 4
  • r

    Remi Gelinas

    03/02/2026, 1:48 PM
    I have a task that downloads a large file (basically required assets for a subsequent JavaExec task). During development, I test by publishing my plugin to my local Maven repo and pulling it in my test project, but I don't change the version. Despite setting path sensitivity for the large file task input (as a regularfileproperty), every plugin change results in the task cache being busted and that large file being re-downloaded, despite it not moving or changing at all. Is there a method of development I'm missing that avoids this?
    m
    v
    a
    • 4
    • 58
  • c

    Clayton Walker

    05/07/2026, 4:39 PM
    Is there an api to help download external tools in Gradle? Say a native binary that I need Gradle to switch which os/arch it needs to download depending on OS building the app.
    p
    n
    • 3
    • 10
  • j

    Jonathan Leitschuh

    05/12/2026, 8:47 PM
    PyPI, npm, RubyGems and Crates.io have all adopted OIDC-based trusted publishing from CI, specifically to get long-lived API tokens out of repository secrets in order to reduce the risk of supply chain attacks against their respective industries. This currently looks to be unsupported by the Gradle Plugin Portal Is there any work going on towards trying to make similar improvements in the Gradle Plugin Portal? AFAIK The Gradle Plugin Portal has never had a formal penetration test (beyond the auditing I did when I was an employee back 2019-2022). The portal is critical to the supply chain for the entire Android and Java ecosystem. Given the significant uptick in supply chain attacks we've seen against the NPM any Python ecosystems by actors like TeamPCP and North Korea, what is the Gradle team doing to harden the supply chain infrastructure we all rely upon against exploitation?
    πŸ‘ 1
    l
    • 2
    • 1
  • l

    Leon Linhart

    05/13/2026, 10:31 AM
    Hey there, is there a public way to declare that exception indicates a verification failure (akin to
    org.gradle.internal.exceptions.NonGradleCause
    )? I initially assumed it would be sufficient to use a
    VerificationException
    but that is still reported as if there was a technical build failure rather than a semantic failure. (Example in 🧡)
    t
    v
    • 3
    • 4
  • n

    no

    05/19/2026, 12:29 PM
    Let's say that theoretically there is a Gradle plugin that uses an auth token for a task. The auth token affects the outcome of the task since with an incorrect auth token the task will fail. Therefore the auth token is marked with
    @Input
    . My understanding is that task inputs are hashed and not placed in the build cache in plain text. However running the build with
    --debug
    would print this key in plain text. So the question is: Is it best practice to mark API keys as
    @Input
    or
    @Internal
    ?
    v
    t
    l
    • 4
    • 7
  • c

    Clayton Walker

    05/28/2026, 4:02 PM
    Is there a safe, project-isolation-compatible, recommended way to load a property from the root
    gradle.properties
    file?
    v
    o
    j
    • 4
    • 8
  • l

    Louis Jacomet

    06/03/2026, 1:25 PM
    Hey Gradle plugin authors, We've had reports that older versions of the
    plugin-publish
    plugin may no longer allow publications of plugins to the Gradle plugin portal. The specific version in question is
    0.11.0
    . We will be investigating if we broke compatibility accidentally and then share an update on this. But in the meantime,
    1.0.0
    was released in June 2022 and the latest version is now 2.1.1. We recommend you update this plugin to make sure you do not run in such issues.
    πŸ™ 2
    βž• 3
    • 1
    • 1
  • j

    John

    07/09/2026, 8:42 PM
    If I have a bunch of
    ValueSources
    that do expensive things (like execute git, etc), and I want to share these across multiple plugins so that I don't have to duplicate code, as well as create multiple providers for the same thing, I had an idea to put them in a BuildService. however, it seems like if I create the providers in order to pass them to the service via params, then they get run, even if the build service method that returns that provider never is called. I had an idea to create the providers only when they are accessed via build service, but to do that, id need a reference to ProviderFactory as a param, but I don't think that is serializable (for CC). is there an established pattern here?
    p
    • 2
    • 4
  • j

    John

    07/15/2026, 5:10 PM
    is there a way to use a
    Configuration
    object in a task that is configuration cache safe? I don't want to treat it like files because I want to look at the declared dependencies and resolved dependency tree model
    p
    a
    • 3
    • 7
  • p

    Philip W

    08/05/2026, 7:29 AM
    I want to generate a xml file. The user declares the content via DCL, so I need Definitions classes. The user input is then mapped to BuildModels classes. These BuildModel is then mapped to Tasks inputs and nested classes, and this input is finally mapped to the parameters of my WorkerAction Parameter classes. So the user input needs to be passed to 4 layers using different classes (each layer needs multiple classes). This is really annoying to write and map them. And yes, you cannot reuse Definition classes due to Configuration Cache (or it is a bug). How do you handle it?
    v
    • 2
    • 24
  • j

    John

    08/12/2026, 5:58 PM
    What is the best practice around kotlin-stdlib dependencies in gradle plugins? since gradle provides a stdlib, should these be compileOnly? or is implementation dependency OK? if it is, are there considerations about the version that should be depended on?
    m
    • 2
    • 12
  • t

    tony

    08/13/2026, 10:18 PM
    I have this recollection that Gradle doesn't provide any way to access an artifact classifier via a public API. Am I wrong about that? This has to do with the Dependency Analysis Plugin. It has a "coordinates" concept for modeling a dependency as a unique identity, but currently doesn't account for classifiers at all, which keeps leading to annoying bugs.
    o
    t
    • 3
    • 8
  • l

    Lex Manos

    08/19/2026, 8:44 AM
    I am trying to understand includeBuild, and build-logic vs buildSrc. I was able to get an example working with a single included build producing one plugin But If I attempt to includeBuild a second directory i goes wrong. Specifically in this example (attached zip): build-logic-a, has two sub projects and builds fine. Both plugins can be seen by my app project. build-logic-b, doesn't get built at all, and results in a
    Plugin with id 'my-java-convention-b' not found.
    error. If i comment out the application of
    my-java-convention-b
    in
    app\build.gradle
    and run
    projects
    it shows both includeBuilds loaded. So I am really confused. Yes, I could move
    build-logic-b\convention
    to
    build-logic-a\convention-b
    but that doesn't solve the actual issue. To explain the actual issue, I am trying to reorganize a very large project into multiple projects with shared sources. Using a hybrid of an external java-gradle-plugin and a in-repo build-logic project. I can get the in-repo build-logic to work, and reference the built external plugin, however the issue comes when i try to develop both at the same time.
    Copy code
    includeBuild 'build-logic'
        includeBuild 'forgedev' // Checked out in a sub-directory, could be anywhere
    Results in the normal build-logic gradle file not being able to be compiled with tons of errors saying it cant find groovy. Commenting out the 2nd includeBuild fixes the compile issues. So ya, there are two issues. The first is when trying to make a test workspace, the second is when trying to integrate into a real project. Maybe im missing something really simple, but I tried searching the gradle github and didn't find anything says that only one includeBuild works for build-logic. On the contrary I've found tons of examples of it saying that multiple work. Ive been going at this for all weekend, and finally exhausted what i can figure out myself.
    gradle-build-logic-groovy.zip
    v
    • 2
    • 20
  • m

    Marek

    08/19/2026, 7:12 PM
    Is it standard practice when developing a plugin that the plugin itself applies the base plugin as well? Say I have a very simple plugin that just generates some files. JNI headers in my case but can be anything. One task with an input dir and output dir. Now I would like my plugin to get proper
    clean
    tasks. My understanding is that if my plugin applies the Base plugin as well, I get them for free. Both the global
    clean
    and
    clean<task name>
    for each registered task. Is it a proper approach?
    p
    v
    • 3
    • 7
  • y

    ysb33r

    08/26/2026, 5:59 PM
    Can I use the
    org.gradle.nativeplatform.OperatingSystemFamily
    attributes for publishing JARs that should only be selected on specific operating systems? Or are these purely for native development artifacts?
    v
    j
    • 3
    • 12
  • t

    tony

    08/26/2026, 7:22 PM
    what version of the JVM are being using as the target for their plugins these days? I currently target 11 for most of my plugins, but per the compatibility matrix, it looks like I could bump that to 17, unless I'm misunderstanding?
    o
    y
    m
    • 4
    • 6