Vlastimil Brecka
10/18/2026, 12:30 AMtony
10/18/2026, 6:56 PMVlastimil Brecka
10/18/2026, 7:04 PMtony
10/18/2026, 7:37 PMVlastimil Brecka
10/18/2026, 7:40 PMtony
10/18/2026, 7:43 PMVlastimil Brecka
10/18/2026, 7:44 PMtony
10/18/2026, 7:46 PMi only allow certain stuff anyways as you probably do too👍
tony
10/18/2026, 7:47 PM..declarative gradle cant come soon enoughprobably years before it's "production-ready." I get there with strict linting. My most recent project basically only has
plugins, dependencies, and a custom DSL block in each script, as well as all deps through the version catalog, and some other requirementsVlastimil Brecka
10/18/2026, 7:48 PMtony
10/18/2026, 7:49 PM"Vlastimil Brecka
10/18/2026, 7:50 PMtony
10/18/2026, 7:51 PMVlastimil Brecka
10/18/2026, 7:52 PM” is what i enforce, hate ' 😁tony
10/18/2026, 7:52 PMtony
10/18/2026, 7:53 PM' because I've been burned by GStringImpl in the past 🪦Vlastimil Brecka
10/18/2026, 7:53 PMVlastimil Brecka
10/18/2026, 7:53 PMtony
10/18/2026, 7:54 PMtony
10/18/2026, 7:55 PMtony
10/18/2026, 7:55 PMVlastimil Brecka
10/18/2026, 7:56 PMtony
10/18/2026, 7:57 PMtony
10/18/2026, 7:57 PMVlastimil Brecka
10/18/2026, 7:58 PMVlastimil Brecka
10/18/2026, 7:59 PMVampire
10/18/2026, 10:18 PMwont work with groovy?If you use Groovy DSL, you should be able to simply use CodeNarc to lint the build scripts. You can also create custom rules for it that check exactly what you want to have or not to have.
Vlastimil Brecka
10/18/2026, 11:14 PMVlastimil Brecka
10/19/2026, 3:06 AMVampire
10/19/2026, 7:37 AMysb33r
10/19/2026, 2:06 PMVampire
10/19/2026, 2:10 PMVampire
10/19/2026, 2:10 PMysb33r
10/19/2026, 2:18 PMtony
10/19/2026, 4:30 PMJohn
10/19/2026, 11:05 PMephemient
10/19/2026, 11:23 PMVlastimil Brecka
10/19/2026, 11:24 PM.gradle files from the build - worked correctly, but was slow as that is single threaded and not cachable etc
v2 im trying right now is the more standard design, of a plugin applied to every projects, and the task then runs per project, which is parallel and cacheable
however now I need to whitelist where im looking for .gradle files
val buildFilesInThisProject = target.fileTree(target.projectDir) {
it.include("*.gradle", "gradle/**/*.gradle")
}
as to avoid root project then looking basically everywhere
but now foo/whatever.gradle is not linted
it cant even be depth based as app/build.gradle would be picked up by the root project one
any ideas?Vampire
10/20/2026, 6:55 AM--configuration-cache or --parallel.Vlastimil Brecka
10/20/2026, 10:40 AMVampire
10/20/2026, 10:42 AMVlastimil Brecka
10/20/2026, 11:57 AMtarget.tasks.register("lintBuildFiles", LintBuildFilesTask::class.java) {
it.rootDirectory.set(target.layout.projectDirectory)
it.buildFiles.from(target.fileTree(target.rootDir) { tree -> tree.include("**/*.gradle") })
}
@DisableCachingByDefault(because = "Reports violations to the console and has no output files.")
abstract class LintBuildFilesTask : DefaultTask() {
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val buildFiles: ConfigurableFileCollection
@get:Internal
abstract val rootDirectory: DirectoryProperty
@TaskAction
fun lintBuildFiles() {
val root = rootDirectory.get().asFile
val sortedBuildFiles = buildFiles.files.sortedBy { it.relativeTo(root).invariantSeparatorsPath }
for (buildFile in sortedBuildFiles) {
...
}
}
}
the trouble is, I have specific additional rules for jvm library, android library etc, so I need to know what type it is, so v1
class LintBuildFilesPlugin : Plugin<Project> {
override fun apply(target: Project) {
require(target == target.rootProject) { "Apply sk.ursus.gradle-lint to the root project." }
val lintTask = target.tasks.register("lintBuildFiles", LintBuildFilesTask::class.java) {
it.rootDirectory.set(target.layout.projectDirectory)
it.buildFiles.from(target.fileTree(target.rootDir) { tree -> tree.include("**/*.gradle") })
}
target.allprojects { module ->
if (module == target) return@allprojects
val buildFile = module.buildFile
val path = buildFile.relativeTo(target.rootDir).invariantSeparatorsPath
module.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
if (!module.pluginManager.hasPlugin("com.android.application")) {
lintTask.registerPolicy(policy = ModulePolicy.LIBRARY, buildFile = buildFile, path = path)
}
}
module.pluginManager.withPlugin("com.android.librar") {
if (!module.pluginManager.hasPlugin("com.android.application")) {
lintTask.registerPolicy(policy = ModulePolicy.LIBRARY, buildFile = buildFile, path = path)
}
}
module.pluginManager.withPlugin("com.android.application") {
lintTask.registerPolicy(policy = ModulePolicy.APPLICATION, buildFile = buildFile, path = path)
}
}
}
}
does this, it needs allprojectsVlastimil Brecka
10/20/2026, 11:57 AMVampire
10/20/2026, 12:11 PMpluginManager.withPlugin can configure the project-own analysis task depending on which plugins get applied.
Besides that the approach you just posted does double-cross-project-configuration, configuring the other projects to later configure the root project.
Also your approach is plugin application order-sensitive which is bad.
If a project first applies K/JVM and later Android Application, then you do two registerPolicy calls, if they are applied the other way around, you only do one call.
And the Android library ID has a typo.
Also, requiring root project application might be problematic unless you control all usages iirc, because if you apply that plugin in a precompiled Kotlin DSL script plugin, the accessor-generation might make problems.
Also, the @DisableCachingByDefault is not really appropriate.
Instead you would do init { _outputs_.upToDateWhen *{* true *}* }, then the task is cacheable.
Because if it fails, it is anyway rerun next time, but as you say "the outputs are up to date" explicitly, the task can be up-to-date and also cached if the inputs are the same.
An alternative if the violation calculation is resource-intense is, to have one task that does not fail the build but writes the violations to a file and another task that consumes that file output and fails the build with the console output from the file. Then the analysis task can be up-to-date or coming from cache, and the failing is more or less instantly if the inputs are the same and thus the violations are the same.Vlastimil Brecka
10/20/2026, 1:53 PMVampire
10/20/2026, 2:44 PMtarget.buildFile and that's it.Vampire
10/20/2026, 2:45 PMVlastimil Brecka
10/20/2026, 2:50 PMVlastimil Brecka
10/20/2026, 2:51 PMVampire
10/20/2026, 2:52 PMVampire
10/20/2026, 2:52 PMVampire
10/20/2026, 2:52 PMtarget.buildFileVampire
10/20/2026, 2:53 PMVlastimil Brecka
10/20/2026, 2:53 PMarbitrary.gradle right?Vampire
10/20/2026, 2:54 PMarbitrary.gradle is just a file that ends in .gradle you can also store an image in it if you like.John
10/20/2026, 2:55 PMVlastimil Brecka
10/20/2026, 2:55 PMarbitrary.gradle use that to share utilities and stuffJohn
10/20/2026, 2:56 PMVampire
10/20/2026, 2:56 PMVlastimil Brecka
10/20/2026, 2:57 PMVampire
10/20/2026, 2:57 PMVampire
10/20/2026, 2:57 PMVlastimil Brecka
10/20/2026, 2:58 PMVampire
10/20/2026, 2:58 PMVampire
10/20/2026, 2:59 PMVlastimil Brecka
10/20/2026, 2:59 PMVampire
10/20/2026, 2:59 PMVampire
10/20/2026, 2:59 PMVampire
10/20/2026, 3:00 PMVlastimil Brecka
10/20/2026, 3:00 PMVampire
10/20/2026, 3:00 PMVampire
10/20/2026, 3:01 PM.gradle file that is not one of the actual build scripts or something like that.Vlastimil Brecka
10/20/2026, 3:02 PMgradle/ via CI means?Vampire
10/20/2026, 3:02 PMVampire
10/20/2026, 3:02 PMmaybe just ban arbitrary .gradle placement and force the legacy scripts intoWhatever works for you 🤷♂️via CI means?gradle/
Vampire
10/20/2026, 3:03 PMVlastimil Brecka
10/20/2026, 3:04 PMVampire
10/20/2026, 3:04 PM.gradle files of only that project and not subprojects and you maybe get the setup you envision?Vlastimil Brecka
10/20/2026, 3:04 PM../ ?Vampire
10/20/2026, 3:18 PM*.gradle files that are not part of the project directory of another project.
And in the linting forbid to contain any .. or absolute path or file object, but restrict it to applying from by String literal that must contain a relative path that does not contain any .., or something like that.Vlastimil Brecka
10/20/2026, 3:34 PM