I want to run a specific task after EVERY build of my subprojects. I can go into each of my subprojects build.gradle.kts file and add the following
tasks.build {
finalizedBy("afterbuildtask")
}
However, this should be possible to do in my root project build.gradle.kts file right? I tried it by doing the following:
subprojects {
this.tasks.findByName("build")?.dependsOn("afterbuildtask")
}
But nothing happens. How can I achieve this?
You can't programatically execute tasks from other tasks in newer versions of Gradle.
Instead, you are supposed to declare task dependencies and Gradle will ensure they get executed in the correct order. But I think it's not what you want
Alternatively, you could move your logic into the doLast block in the build task. eg:
build {
doLast {
println("Copying...")
copy {
from 'source'
into 'target'
include '*.war'
}
println("completed!")
}
}
good coding! ¯_(ツ)_/¯
So let's say I have the following settings.gradle:
include 'math-server'
project(':math-server').projectDir = file('math/server')
include 'math-client-gen'
project(':math-client-gen').projectDir = file('math/client')
include 'ai'
Now I'd like to not commit the any of the files in math-client-gen (including the build.gradle) since those are generated by a build job in math-server:
// math/server/build.gradle
task generateClient(type:Exec) {
workingDir '.'
inputs.dir('./app')
inputs.dir('.')
outputs.dir('../client')
commandLine './client-generator/generate.sh'
}
The generate.sh leverages the openapi client generator for kotlin.
Now the ai project relies on the math-client-gen:
// ai/build.gradle
dependencies {
compile project(':math-client-gen')
}
Now I have currently found two suboptimal ways to make this work.
Option 1 is to run ./gradlew :math-server:generateClient before I'm able to run ./gradlew :ai:build. This sucks, since you cannot build ai on its own anymore.
Option 2 is to commit the files, which of course also isn't the way it should be.
I'm sure there is a better way to do it with gradle, but I just didn't manage to find it yet. As a compromise, I'd be willing to commit the generated math-client-gen/build.gradle if it doesn't work without that.
What's the best solution to this problem?
Note: I also saw something like:
implementation files(layout.buildDirectory.dir('classes')) {
builtBy 'compile'
}
in the docs, that looks promising, but i'd like to have it for an entire subproject and not just some source files if possible.
// ai/build.gradle
afterEvaluate {
tasks.build.dependsOn(project(":math-client").tasks["generateClient"])
}
To automate your first option.
I ended up committing the build.gradle of the math-client-gen and have this line there:
// math/client/build.gradle
compileKotlin {
dependsOn ':math-server:buildMathClient'
}
This ensures that the client is always generated when this project is listed as a dependency somewhere.
Then you can simply add the math-client-gen as a dependency in other projects, no additional steps required:
// ai/build.gradle
dependencies {
compile project(':math-client-gen')
}
If I have a simple gradle java build, can I somehow swap out one of the jar dependencies, say jarX for jarY based on a flag?
e.g.:
if running ./gradlew build - then include jarX
but if running ./gradlew build -specialBuild - then include jarY instead of jarX
Yes, you can use conditional statements on the dependencies {} closure.
dependencies {
if (project.hasProperty("useX")) {
implementation 'x:x:x'
} else {
implementation 'y:y:y'
}
}
call as
gradle -PuseX=true
For a project, I have a custom configuration which should simply extend the default one, both in terms of java sources and in terms of dependencies.
This is what it looks like at the moment:
configurations {
// Tools inherits everything from default and adds on
toolsCompile.extendsFrom(compile)
}
sourceSets {
main {
java {
srcDirs = ['src']
}
}
tools {
java {
// Tools extends on the core sources
srcDirs = sourceSets.main.java.srcDirs + ['src-tools']
}
}
}
dependencies {
compile libs.a
compile libs.b
compile libs.c
// Tools adds on the dependencies of the default configuration
toolsCompile libs.d
toolsCompile libs.e
}
I know I could have also used sub-projects for this. I gave up on it, after trying, because I can't get it work properly together with the Eclipse integration plugin (it works fine when used from command line).
I have a couple of questions on the solution above:
Is the way I extend tools.java.srcDirs correct? Is there a more elegant way?
EDIT: Apparently it is not correct, as gradle eclipse generates a .classpath with a duplicate entry for src. Help please?
After I created my tools configuration, I know I can for example use it as a dependency from another project, as in compile project(path: ':myproject', configuration: 'tools'). What do I need to add if I instead want to get the output of the assemble task for my tools configuration? Do I have to make an explicit task for that? The task toolsClasses is created automatically, but not toolsAssemble or toolsBuild.
I have a custom compile task.
task compileSpeedTest(type: JavaCompile) {
classpath = files('build')
source = fileTree('src/test/java/speed')
destinationDir = file('bin')
}
Gradle doesn't try to download dependencies before its execution.
I cannot find anywhere a task name which does it to add it on list dependsOn.
Downloading java dependencies is possible, if you actually really need to download them into a folder.
Example:
apply plugin: 'java'
dependencies {
runtime group: 'com.netflix.exhibitor', name: 'exhibitor-standalone', version: '1.5.2'
runtime group: 'org.apache.zookeeper', name: 'zookeeper', version: '3.4.6'
}
repositories { mavenCentral() }
task getDeps(type: Copy) {
from sourceSets.main.runtimeClasspath
into 'runtime/'
}
Download the dependencies (and their dependencies) into the folder runtime when you execute gradle getDeps.
For Intellij go to View > Tool Windows > Gradle > Refresh All Projects (the blue circular arrows at the top of the Gradle window.
A slightly lighter task that doesn't unnecessarily copy files to a dir:
task downloadDependencies(type: Exec) {
configurations.testRuntime.files
commandLine 'echo', 'Downloaded all dependencies'
}
Updated for kotlin & gradle 6.2.0, with buildscript dependency resolution added:
fun Configuration.isDeprecated() = this is DeprecatableConfiguration && resolutionAlternatives != null
fun ConfigurationContainer.resolveAll() = this
.filter { it.isCanBeResolved && !it.isDeprecated() }
.forEach { it.resolve() }
tasks.register("downloadDependencies") {
doLast {
configurations.resolveAll()
buildscript.configurations.resolveAll()
}
}
I have found this answer https://stackoverflow.com/a/47107135/3067148 also very helpful:
gradle dependencies will list the dependencies and download them as a
side-effect.
This version builds on Robert Elliot's, but I'm not 100% sure of its efficacy.
// There are a few dependencies added by one of the Scala plugins that this cannot reach.
task downloadDependencies {
description "Pre-downloads *most* dependencies"
doLast {
configurations.getAsMap().each { name, config ->
println "Retrieving dependencies for $name"
try {
config.files
} catch (e) {
project.logger.info e.message // some cannot be resolved, silentlyish skip them
}
}
}
}
I tried putting it into configuration instead of action (by removing doLast) and it broke zinc. I worked around it, but the end result was the same with or without. So, I left it as an explicit state. It seems to work enough to reduce the dependencies that have to be downloaded later, but not eliminate them in my case. I think one of the Scala plugins adds dependencies later.
You should try this one :
task getDeps(type: Copy) {
from configurations.runtime
into 'runtime/'
}
I was was looking for it some time ago when working on a project in which we had to download all dependencies into current working directory at some point in our provisioning script. I guess you're trying to achieve something similar.
Building on top of Robert Elliot's answer. For whatever reason, if one is interested in downloading the dependencies to Gradle cache then copying to a local repository like maven's (by default ~/.m2/repository):
task downloadDependencies(type: Exec) {
configurations.implementation.files + configurations.runtimeOnly.files
finalizedBy "cacheToMavenLocal"
commandLine "echo", "Downloaded all dependencies and copied to mavenLocal"
}
task cacheToMavenLocal(type: Copy) {
from new File(gradle.gradleUserHomeDir, "caches/modules-2/files-2.1")
into repositories.mavenLocal().url
eachFile {
List<String> parts = it.path.split("/")
it.path = [parts[0].replace(".","/"), parts[1], parts[2], parts[4]].join("/")
}
includeEmptyDirs false
}
The task cacheToMavenLocal was copied and adapted from #Adrodoc55's answer on Gradle forum.
It is hard to figure out exactly what you are trying to do from the question. I'll take a guess and say that you want to add an extra compile task in addition to those provided out of the box by the java plugin.
The easiest way to do this is probably to specify a new sourceSet called 'speedTest'. This will generate a configuration called 'speedTest' which you can use to specify your dependencies within a dependencies block. It will also generate a task called compileSpeedTestJava for you.
For an example, take a look at defining new source sets in the Java plugin documentation
In general it seems that you have some incorrect assumptions about how dependency management works with Gradle. I would echo the advice of the others to read the 'Dependency Management' chapters of the user guide again :)
There is no task to download dependencies; they are downloaded on demand. To learn how to manage dependencies with Gradle, see "Chapter 8. Dependency Management Basics" in the Gradle User Guide.