I have gradle project with 4 subprojects. I have current root gradle.build with checkstyle:
allprojects {
apply plugin: "checkstyle"
checkstyle {
...
}
}
so when I run ./gradlew build in the main folder, I get next:
checkstyle for 1st subproject, then tests. Then it runs checkstyle for 2nd subproject and then tests for 2nd, etc.
The problem is: if I have long tests in 1st subproject, I can wait a lot of time, and then discover that I have 2 spaces in the 4th project, so checkstyle fails, but I was waiting so much time for it.
What I really want:
run all checks (checkstyle, and I have pmd too) for all subprojects, and then run all tests in all subprojects. It will save a lot of time for everybody in the team.
Can I do it except, make 2 different pipelines, and run them separately? like: ./gradlew allMyCheckstyles && ./gradlew build.
I would love to use just ./gradlew build
Thanks!
I tried many dependsOn, runAfter, but it didn't work out.
Apologies, a previous version of this answer misinterpreted the requirements of this question.
Here's a solution that should do what you want:
// Create a lifecycle task in the root project.
// We'll make this depend on all checkstyle tasks from subprojects (see below)
def checkstyleAllTask = task("checkstyleAll")
// Make 'check' task depend on our new lifecycle task
check.dependsOn(checkstyleAllTask)
allProjects {
// Ensure all checkstyle tasks are a dependency of the "checkstyleAll" task
checkstyleAllTask.dependsOn(tasks.withType(Checkstyle))
tasks.withType(Test) {
// Indicate that testing tasks should run after the "checkstyleAll" task
shouldRunAfter(checkstyleAllTask)
// Indicate that testing tasks should run after any checksytle tasks.
// This is useful for when you only want to run an individual
// subproject's checks (e.g. ./gradlew ::subprojA::check)
shouldRunAfter(tasks.withType(Checkstyle))
}
}
Documentation here and here
Related
I am starting to use Gradle for an Android application. I would like the build to fail if the developer fails to create a file at a specific location such as ./src/res/values/specialfile.xml
A bit of searching led me to believe that a .doFirst would work
android.doFirst {
assert file("./src/res/values/specialfile.txt").exists()
}
However, Gradle says "unsupported Gradle DSL method found: 'doFirst()'!"
What can I do to assert a file's existence?
doFirst only exists on tasks object. android is not a task.
If would want this test to always be done even if the developer doesn't try to build (for example when running the tasks task), you should simply put in your build.gradle
assert file("./src/res/values/specialfile.txt").exists()
However this is really not recommended as this would be executed even for non build tasks, or even when the model is built for IDE integration.
There is a task called preBuild that is executed before anything in the android build, so you can hook your test to it, either through another task or through doFirst:
preBuild.doFirst {
assert file("./src/res/values/specialfile.txt").exists()
}
One may want to check in a module build.gradle ...
below the plugins configuration block
above the android configuration block
eg. in order to determine which Gradle plugins to apply:
plugins {
id "com.android.application"
}
def json_google = "src/google-services.json";
if (project.file(json_google).exists()) {
println "found: ${project.file(json_google)}"
apply plugin: "com.google.gms.google-services"
apply plugin: "com.google.firebase.crashlytics"
...
} else {
def message = "missing: ${project.file(json_google)}"
// throw new GradleException(message)
println message
}
android { ... }
rootProject.file() and project.file() might be more convenient than file() (it depends). Using assert seems a bit harsh - but then one has to take care that it will not crash elsewhere.
My projects usually have a few optional config files, which the environment may or may not provide, because not every product flavor may require the same set of plugins & config files.
I am using some static analysis plugins (spotbugs, pmd) attached to my gradle build. They run automatically when you run gradlew check or something that depends on check.
I am trying to find a way to run JUST the parts of check, but exclude unit tests, in a command. Since check depends on test, I am not sure how to do this, if it's possible.
I have a large number of java / android modules and it takes a long time to do a full build with tests and static analysis, so I want to break them up as separate tasks on separate CI systems.
You should be able to do:
./gradlew check --exclude-task test
See the docs here
Instead of calling the task check with excluded task test as proposed by Dave, you can simply create a new task and add dependencies on all tasks that perform static analysis:
task staticAnalysis {
dependsOn 'spotbugsMain'
dependsOn 'pmdMain'
}
You may then call ./gradle staticAnalysis.
INTRODUCTION
The project is in Kotlin and builds using Gradle. I'm trying to generate a basic data class with some build info, let's say for now that I need it [re]generated every time before running.
Here's the Gradle task I have now:
def generatedDir = "$buildDir/generated"
// noinspection GroovyAssignabilityCheck
task generateBuildInfo {
inputs.property "version", rootProject.version.toString()
inputs.property "name", rootProject.name.toString()
outputs.dir generatedDir
outputs.upToDateWhen { false }
doFirst {
def buildInfoFile = file("$generatedDir/BuildInfo.kt")
buildInfoFile.parentFile.mkdirs()
buildInfoFile.text = """
internal data class BuildInfo(
val version: String = "${project.version.toString() ?: "unspecified"}",
val name: String = "${project.name.toString() ?: "unspecified"}"
)
""".replace(" ", "").trim()
}
}
To be able to resolve this from IntelliJ IDEA, I added my new folder to project sources, and obviously wired up the dependencies, like so:
sourceSets.main.kotlin.srcDirs += generatedDir
project.afterEvaluate {
compileJava.dependsOn generateBuildInfo
compileKotlin.dependsOn generateBuildInfo
}
This is all done in a separate file (to avoid polluting my main scripts). Due to this organization, after applying plugins, I just include the generator in my main script, like this:
apply from: "gradle/scripts/build-info-generator.gradle"
THE PROBLEM
It looks like the generator code is executed only once, after running assemble when I first ran clean on this module. This is not what I want, because when I change some of the project properties (like version), the source does not get updated... as if compileJava/compileKotlin and my custom task are not executed.
They do not appear in build logs as executed.
Is there any way I can run this task every time I want to run my module's launcher? Sure, I can do some smart file comparison to see if generation is needed, but for now I just want it done each time. Am I missing something?
IDEA has its own build system, indepenant from Gradle.
You can configure it to run a Gradle task before its own build task.
You can also configure it to delegate all the build/run tasks to Gradle. But that's not the default.
i would like to run the build-task from the gradle war plugin inside one of my own defined tasks. I tried various things, but nothing worked.
This is how my task looks at the moment:
task deploy << {
build.execute()
copy {
from '/build/libs/app.war'
into tomcat_webapps
}
}
When i run
gradle deploy
the build task will not be executed. Does anyone of you know how i can do this?
Thank you!
Calling tasks manually should be your very last resort. The gradle way would be to define a dependency between your task and the build task. This way gradle can determine a proper order for the tasks that need to be executed.
Setting up the dependency can be done in several ways. One way would be this:
task deploy(type: Copy) {
dependsOn build
from '/build/libs/app.war'
into tomcat_webapps
}
I have a multi-project dependency in my gradle build, but there's a feature that's somewhat in my way. Whenever I call a task name that exists in both projects, it calls them both. I don't like that.
My directory structure is as follows:
[Root]
---->[projA]
----------->build.gradle
---->[projB]
----------->build.gradle
So I have projB dependent on projA in my code.
Say I have a task run in projB:
task run << {
println 'projB running'
}
And I also have a task run in projA:
task run << {
println 'projA running'
}
By calling gradle run, I would get
:run
projB running
:projA:run
projA running
Is there any way to prevent some of the tasks from having this dependency? Some of them, say clean is fine, but I'd prefer to have specific tasks separate (without having to change the naming scheme).
The equivalent of what I want can be achieved by doing either:
gradle run -x :projA:run
or
gradle :run
I want a solution that is within the build file, though.
Thanks!
That fact that projB declares a project dependency on projA is irrelevant for the behavior you are seeing. If you execute a task from the root project of a multi-project build Gradle will try to find the task in any of its subprojects with the requested name and execute it. This feature is called task execution matching. Given this default behavior there's no way Gradle could know which run task you mean when executing gradle run from the root project. I'd suggest you define what you want to execute on the command line as mentioned in my previous comment.
If you really wanted to add logic to your build script, then you could achieve it with the following code:
def taskRequests = gradle.startParameter.taskRequests
def runTaskRequest = taskRequests.find { it.args.contains('run') }
if (runTaskRequest) {
gradle.startParameter.excludedTaskNames = [':projA:run']
}
The code provided would prevent the execution of the run task for the subproject projA if you execute the command gradle run. Keep in mind that it would also exclude :projA:run if you navigate to the projA subdirectory and run the same command. If you still want to be able to execute the run task from the subdirectory, then you'll have to build in additional logic.