Orchestrating Gradle build invocations with custom tasks - groovy

I’m trying to define two new Gradle tasks, buildAll and pubLocal, to run other tasks in a specific order.
When gradle buildAll is invoked, I want Gradle to do the same thing as if I had executed gradle clean build writePom (see below for writePom).
When gradle pubLocal is executed, I want Gradle to do the same thing as if gradle buildAll install had been executed.
Here’s my best attempt thus far:
// build.gradle
task writePom << {
pom {
project {
groupId 'mygroup'
artifactId 'mylib'
version version
inceptionYear '2015'
licenses {
license {
name 'Blah'
url 'blah'
distribution 'blah'
}
}
}
}.writeTo("build/libs/pom.xml")
}
task buildAll(dependsOn: clean, build, writePom)
task pubLocal(dependsOn: buildAll, install)
When I run gradle buildAll on this, I get:
myuser#mymachine:~/tmp/myapp$./gradlew buildAll
FAILURE: Build failed with an exception.
* Where:
Build file '/Users/myuser/tmp/myapp/build.gradle' line: 67
* What went wrong:
A problem occurred evaluating root project 'myapp'.
> Could not find method buildAll() for arguments [{dependsOn=task ':clean'}, task ':build', task ':writePom'] on root project 'myapp'.
Any ideas as to where I’m going awry?

This may be a left-over from copy-pasting, but your strings are not quoted consistently using standard single- or double-quotes. Example:
}.writeTo(“build/libs/pom.xml")
does not quote the string properly, as it opens with the “ character instead of ". Same with the single-quotes above it.
You can see from the way your code is highlighted, that everything in red is interpreted as a string. If this is the case in your actual code, the buildAll and pubLocal tasks will not be recognized, as they are part of a string rather than code.
UPDATE:
Since the above answer is irrelevant now, here is another possibility. The error message shows that only the "clean" task is listed in the dependsOn parameter. The buildAll task dependencies should be declared like this:
task buildAll(dependsOn: [clean, build, writePom])
Similar with the pubLocal task.

I'm using Gradle 2.4. The following file includes the Maven plugin, uses a list [] in the dependsOn, and ensures that clean must be executed before build:
apply plugin: 'maven'
task writePom << {
pom {
project {
groupId 'mygroup'
artifactId 'mylib'
version version
inceptionYear '2015'
licenses {
license {
name 'Blah'
url 'blah'
distribution 'blah'
}
}
}
}.writeTo("build/libs/pom.xml")
println "TRACER writePom"
}
task clean << { println "TRACER clean" }
task build << { println "TRACER build" }
build.mustRunAfter clean
task install << { println "TRACER install" }
task buildAll(dependsOn: [clean, build, writePom])
task pubLocal(dependsOn: [buildAll, install])
I get this output (minus Gradle 3 warnings):
bash-3.2$ gradle buildAll
:clean
TRACER clean
:build
TRACER build
:writePom
TRACER writePom
:buildAll
BUILD SUCCESSFUL
and this:
bash-3.2$ gradle pubLocal
:clean
TRACER clean
:build
TRACER build
:writePom
TRACER writePom
:buildAll
:install
TRACER install
:pubLocal
BUILD SUCCESSFUL

Related

Why Gradle is not running dependent tasks

I have the following build.gradle in an angular project:
plugins {
id 'war'
}
task npmInstall(type:Exec)
commandLine "npm.cmd", "install", "#angular/cli"
}
task npmBuild(type: Exec) {
commandLine "npm.cmd", "run", "build"
}
task war.dependsOn(npmInstall, npmBuild)
but when I run the war task the npmBuild and npmInstall are not ran
As of Gradle 7.5, your build script doesn't compile anymore and raises the following error
> Could not create task ':task ':war''.
> The task name 'task ':war'' must not contain any of the following characters: [/, \, :, <, >, ", ?, *, |].
The problem is with the task keyword in statement task war.dependsOn(npmInstall, npmBuild). To instruct Gradle to execute npmInstall and npmBuild before executing the war task do this:
war.configure {
dependsOn npmInstall, npmBuild
}
You may also use war.dependsOn npmInstall, npmBuild to configure the dependency.

Why is Gradle failing on :linkDebugTestLinux in my Kotlin multiplatform project?

I'm porting a C# library to Kotlin to take advantage of multiplatform. When running the build task, it fails in the subtask linkDebugTestLinux.
For context, I'm using IDEA Ultimate on Manjaro. I'm certain there's nothing wrong with my code as compileKotlinLinux finishes without error.
There are zero DDG results for "linkDebugTestLinux" and nothing helpful for "konan could not find home" or "kotlin native ...". After hours of stitching together incomplete and outdated examples from the official docs, I've given up.
My build.gradle.kts:
plugins {
kotlin("multiplatform") version "1.3.40"
}
repositories {
mavenCentral()
}
dependencies {
commonMainImplementation("org.jetbrains.kotlin:kotlin-stdlib")
commonTestImplementation("org.jetbrains.kotlin:kotlin-test-common")
commonTestImplementation("org.jetbrains.kotlin:kotlin-test-annotations-common")
}
kotlin {
// js() // wasn't the issue
linuxX64("linux")
}
Output of task build without args:
> Configure project :
Kotlin Multiplatform Projects are an experimental feature.
> Task :compileKotlinLinux
[...unused param warnings...]
> Task :compileKotlinMetadata
[...unused param warnings...]
> Task :metadataMainClasses
> Task :metadataJar
> Task :assemble
> Task :linuxProcessResources NO-SOURCE
> Task :linuxMainKlibrary
> Task :linkDebugTestLinux FAILED
e: Could not find "/home/username/" in [/home/username/path/to/the/repo, /home/username/.konan/klib, /home/username/.konan/kotlin-native-linux-1.3/klib/common, /home/username/.konan/kotlin-native-linux-1.3/klib/platform/linux_x64].
[...snip...]
BUILD FAILED in 16s
4 actionable tasks: 4 executed
Process 'command '/usr/lib/jvm/java-8-openjdk/bin/java'' finished with non-zero exit value 1
In the boilerplate I omitted it suggests to use --debug, so I've uploaded that here.
After some investigation, it was assumed that the problem is in the path. In the debug log, you got the /home/yoshi/,/ fragment. As far as this directory name was unexpected, the compiler interpreted this , as a delimiter between lib names. So, it tried to find library /home/yoshi/, that was obviously unavailable.
For now, I would recommend you to change the directory name to be something trivial.

How to clear specific gradle cache files when running the "Clean project" command?

I have added the following task in my project's build.gradle file:
task('clearLibCache', type: Delete, group: 'MyGroup',
description: "Deletes any cached artifacts with the domain of com.test in the Gradle or Maven2 cache directories.") << {
def props = project.properties
def userHome = System.getProperty('user.home')
def domain = props['domain'] ?: 'com.test'
def slashyDomain = domain.replaceAll(/\./, '/')
file("${userHome}/.gradle/caches").eachFile { cacheFile ->
if (cacheFile.name =~ "^$domain|^resolved-$domain") delete cacheFile.path
}
delete "${userHome}/.m2/repository/$slashyDomain"
}
I'd like this task to be executed when I hit the "Clean project" menu, and only in this case.
How to do that ?
That "Clean project" menu item under the hood appears to do a couple of things (based on the output of the Gradle Console window when you click it):
A gradle clean, the equivalent of calling ./gradlew clean
Generate sources and dependencies for a debug build, including a mockable Android sources jar if needed.
I would make your task a dependency for the Gradle clean task, so that whenever the project is cleaned, this task is also invoked. This can be achieved by adding the line clean.dependsOn clearLibCache in your build.gradle after you declare the task.

How to make Android Studio build fail on lint errors

Is it possible to make Android Studio build fail on lint check errors ?
I have problems with ImageViews when I convert icon from .png to vector drawable .xml
Sometimes I forgot to change
android:src="#drawable/ic_minus"
to
app:srcCompat="#drawable/ic_minus"
and the app crashes on older OS devices.
?
If there's a lint check for that you can change the severity to FATAL and then when building the release version of your APK it should fail.
android {
lintOptions {
fatal 'MY_LINT_CHECK_ID'
}
}
Also you can execute the Gradle lint task which will fail. If you also want warnings to let your build fail you can use this.
android {
lintOptions {
warningsAsErrors true
}
}
You can also use the below code inside android block in module/app level build.gradle file
For build.gradle
android {
applicationVariants.all {
// Example lint task, your verification task can be anything
def lintTask = tasks["lint${name.capitalize()}"]
assembleProvider.get().dependsOn(lintTask/*, detekt*/) // add list of all the tasks which should fail the build
}
}
For build.gradle.kts(Kotlin DSL)
android {
applicationVariants.all {
// Example lint task, your verification task can be anything
val lintTask = tasks["lint${name.capitalize()}"]
assembleProvider.get().dependsOn.addAll(listOf(lintTask/*, tasks["detekt"]*/)) // add list of all the tasks which should fail the build
}
}
Above code makes the build assemble task which run when we run build app or run app, depends on the listed verification tasks and hence fails it when those tasks fails
Make sure your verification tasks(in our case lint task) are set to fail the build when they are run and there are some issues found in them. All verification tasks has their own flags to enable this behaviour.
For lint you can enable the build failure on warning as below(build.gradle.kts for Kotlin DSL)
android {
lint {
isWarningsAsErrors = true
}
}

How can a custom gradle task be ran from the body of a build

I have the following custom plugin:
class GenPlugin implements Plugin<Project> {
void apply(Project project) {
project.task("gen", type:GenTask)
}
}
That adds the following task to the project:
class GenTask extends DefaultTask {
#TaskAction
def gen() {
println "hello"
}
}
The groovy code is packaged and deployed to a local maven repository, I then reference the dependency in a build with:
apply plugin: 'gen'
I can run the task successfully by using gradle gen, how can I run this task in my build.gradle without specifying it as an argument?
You can use defaultTasks, have a look at the docs.
Running the task from gradle itself is highly discouraged. You can do it with:
project.tasks.gen.execute()
however I don't recommend you to go that way. Instead you can define a dependency on the task you run from command line. If this task is called e.g. afterGen, then use:
afterGen.dependsOn gen

Resources