https://kotlinlang.org logo
Title
s

Steve Ramage

12/28/2020, 5:37 PM
I'm trying to have some plugins applied universally across a build: I've essentially created the following block:
plugins {
    ...
    id("io.gitlab.arturbosch.detekt") version "1.15.0" apply true
    // ktlint linter - read more: <https://github.com/JLLeitschuh/ktlint-gradle>
    id("org.jlleitschuh.gradle.ktlint") version "9.4.1" apply true
}

allprojects {
    repositories {
        mavenCentral()
        jcenter()
    }

    apply(plugin = "io.gitlab.arturbosch.detekt")
    apply(plugin = "org.jlleitschuh.gradle.ktlint")

    dependencies {
        detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.14.2")
    }

    // Configure detekt plugin.
    // Read more: <https://detekt.github.io/detekt/kotlindsl.html>
    detekt {
        config = files("${rootProject.projectDir}/detekt-config.yml")
        buildUponDefaultConfig = true

        reports {
            html.enabled = false
            xml.enabled = false
            txt.enabled = false
        }
    }

    tasks {
        withType<Detekt> {
            jvmTarget = "11"
        }
    }
}
I'm getting the following errors:
e: ./build.gradle.kts:74:9: Unresolved reference: detektPlugins
e: ./build.gradle.kts:80:5: Unresolved reference: detekt
e: ./build.gradle.kts:81:9: Unresolved reference: config
e: ./build.gradle.kts:82:9: Unresolved reference: buildUponDefaultConfig
e: ./build.gradle.kts:84:9: Unresolved reference: reports
e: ./build.gradle.kts:85:13: Unresolved reference: html
e: ./build.gradle.kts:85:18: Variable expected
e: ./build.gradle.kts:86:13: Unresolved reference: xml
e: ./build.gradle.kts:86:17: Variable expected
e: ./build.gradle.kts:87:13: Unresolved reference: txt
e: ./build.gradle.kts:87:17: Variable expected
m

mbonnin

12/28/2020, 5:38 PM
You're not getting the accessors generated because subprojects do not use the
plugins {}
block
You can certainly fix this with included plugins builds (these have a name that I can't find again)
s

Steve Ramage

12/28/2020, 5:40 PM
Yeah I was reading that you can't apply plugins using the plugins { } in an allprojects block. Putting one in there says:
^ Using 'plugins(PluginDependenciesSpec.() -> Unit): Nothing' is an error. The plugins {} block must not be used here. If you need to apply a plugin imperatively, please use apply<PluginType>() or apply(plugin = "id") instead.
m

mbonnin

12/28/2020, 5:42 PM
You can also workaround by specifying the extension explicittely:
configure<DetektExtension> {
  ...
}
s

Steve Ramage

12/28/2020, 5:43 PM
What should that wrap exactly?
m

mbonnin

12/28/2020, 5:43 PM
That's the equivalent of
detekt {
}
s

Steve Ramage

12/28/2020, 5:44 PM
Thanks that seems to run.
That's the Gradle way to do to it
s

Steve Ramage

12/28/2020, 5:47 PM
I will settle with what works for the moment as I'm still learning Kotlin and trying to get my project bootstrapped.
m

mbonnin

12/28/2020, 5:47 PM
👍
v

Vampire

12/29/2020, 9:18 AM
Your initial example is perfectly fine. There is no reason why it should not work. It has some superfluous things like
apply true
which is the default anyway. But accessor-wise it works perfectly fine. I even copied your example, pasted it into an empty project, added the import for
Detekt
and removed
...
and it worked without any problem. The only thing I could imagine is, that you have other plugins applied too where the
...
is written and on of these fails to apply during generation of accessors, because in that case all accessors will not be available. And then with mbonnins suggestion it worked because you also fixed the other problem. But that is just a wild guess as long as you do not provide a reproducible example.
You're not getting the accessors generated because subprojects do not use the 
plugins {}
 block
That's pretty much non-sense, sorry. The scope of accessors is a build script, not any type of project. The
plugins
block of a script is applied to an empty project, then this project is investigated for all supported things (tasks, extensions, ...), for those accessors generated and then added to the class path of the script where the
plugins
block resides for compilation of the remaining script. You can use it anywhere in that script, also in
subprojects
or
allprojects
closures, even with them being not the best practice anymore.
m

mbonnin

12/29/2020, 9:34 AM
You can use it anywhere in that script, also in 
subprojects
 or 
allprojects
 closures, even with them being not the best practice anymore.
That seems to contradict https://docs.gradle.org/current/userguide/plugins.html#sec:constrained_syntax
The plugins {} block must also be a top level statement in the buildscript. It cannot be nested inside another construct (e.g. an if-statement or for-loop)
v

Vampire

12/29/2020, 9:47 AM
No it does not. I did not say you can use the
plugins
block, that will not work. I said you can use the accessors.
m

mbonnin

12/29/2020, 9:48 AM
Ah, makes sense. But these accessors will configure the root project, right? Not sub-projects?
v

Vampire

12/29/2020, 9:48 AM
No
Ctrl+click one of them
They are just syntactic sugar for the verbose version you suggested
👍 1
m

mbonnin

12/29/2020, 9:49 AM
TIL
v

Vampire

12/29/2020, 9:52 AM
To say it again by example, this will not work:
allprojects {
    plugins {
        id("io.gitlab.arturbosch.detekt") version "1.15.0"
    }
    dependencies {
        detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.14.2")
    }
    detekt {
        buildUponDefaultConfig = true
    }
}
This will work:
plugins {
    id("io.gitlab.arturbosch.detekt") version "1.15.0"
}
allprojects {
    apply(plugin = "io.gitlab.arturbosch.detekt")
    dependencies {
        detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.14.2")
    }
    detekt {
        buildUponDefaultConfig = true
    }
}
This will also work:
plugins {
    id("io.gitlab.arturbosch.detekt") version "1.15.0"
}
subprojects {
    apply(plugin = "io.gitlab.arturbosch.detekt")
}
allprojects {
    dependencies {
        detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.14.2")
    }
    detekt {
        buildUponDefaultConfig = true
    }
}
And now the super-question, why will this not work? You can win a virtual cookie. :-)
plugins {
    id("io.gitlab.arturbosch.detekt") version "1.15.0" apply false
}
allprojects {
    apply(plugin = "io.gitlab.arturbosch.detekt")
    dependencies {
        detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.14.2")
    }
    detekt {
        buildUponDefaultConfig = true
    }
}
m

mbonnin

12/29/2020, 9:52 AM
Gosh, because it's not applied to the root project?
v

Vampire

12/29/2020, 9:53 AM
But
allprojects {
    apply(plugin = "io.gitlab.arturbosch.detekt")
does apply it, doesn't it?
m

mbonnin

12/29/2020, 9:53 AM
Yea but I guess that happens after accessors generation
🍪 1
v

Vampire

12/29/2020, 9:54 AM
Exactly. As I said, for accessor generation the plugins block is copied to an empty project, that is evaluated and then investigated for things to generate accessors for. If the plugins block does not apply the plugin, no accessors will be generated.
m

mbonnin

12/29/2020, 9:55 AM
Yup, this is what mislead me, since there's a need for the plugin to be applied, I was somehow assuming the accessors were "bound" to a project
Thanks for the deep dive!
v

Vampire

12/29/2020, 9:55 AM
yw