How to get property of Gradle task from an included build? - gradle

I have a composite Gradle build and in the root build I would like to reference a property of a task in one of the included builds, is this possible?
E.g. if I have this structure:
rootBuild
+ includedBuild1
+ project1
+ project2
+ includedBuild2
I know that in the build.gradle of "project1" I can use this statement to output the property I am interested in:
println shadowJar.archiveFile.get()
For some reason I don't understand, from this project's parent build.gradle ("includedBuild1") I can't reference the 'shadowJar' plugin task directly, but I am able to get the property I'm interested in like this:
println tasks.getByPath(':project1:jar').archiveFile.get()
Now I would like to reference this same property in the root build. However, trying something like this indicates that property 'archiveFile' is not set on the refenced task (i.e. outputs "null"):
println gradle.includedBuild('includedBuild1').task(':project1:jar').properties['archiveFile']
Is there a way to reference the property I'm interested in from the root of the composite build?

Related

Gradle equivalent for maven properties

How can I add properties in Gradle which are similar to Maven's properties?
The use case is this: I want to have a file which declares all versions for repo dependencies so they are unified in a single place for a multi module project
compile group: 'javax.servlet.jsp.jstl', name: 'jstl', version: '1.2'
In Maven you can have properties like this:
<properties>
<jstlVersion>1.2</jstlVersion>
</properties>
Is it ok to use Gradle's external properties? Or just add them to the gradle.properties file?
Project properties defined in the root build file are available to subprojects. So if you have this in your root build.gradle file:
ext.commonsLangVersion = "2.4"
then you can use that in the dependencies {} block of a subproject like so:
dependencies {
implementation "commons-lang:commons-lang:${commonsLangVersion}"
}
You can also define such properties in the root gradle.properties file instead of the root build file. You use them in the same way.
If you really feel the need to put the versions in a separate file, you can do so. Simply add the following line to the root build file:
apply from: "dependencies.gradle"
Within the dependencies.gradle file, you can define the extra project properties as if they were in the root build file directly:
ext.commonsLangVersion = "2.4"
Note Normally, the values set in the build script take precedence over the values in gradle.properties. But if you set a value in the root build script as above, then any matching value in gradle.properties will override it in subprojects.
This behaviour is somewhat confusing and unique. For behaviour that is consistent with Gradle single-project builds you would need to use the following in the root build script:
allprojects {
apply from: "dependencies.gradle"
}
As a general rule of thumb, any given property should be declared/defined in either the build script or gradle.properties. If users want to override a particular property value, they can do so in $USER_HOME/.gradle/gradle.properties.
[EDIT I have updated the above note to clarify the actual behaviour]
One final thing: Gradle also allows you to control the versions of transitive dependencies via dependency constraints. You can also import Maven BOMs if you're using Gradle 4.6 or newer.
Found this as a possible solution, though I don't really like that uses relative path to the properties file.
Point 7 from here:
https://proandroiddev.com/make-your-build-gradle-great-again-c84cc172a654#8029

Understanding gradle multi project build.gradle execution order

I'm doing some experiments on below gradle multi project structure
I have added println in all the build.gradle & settings.gradle files to see in what order they execute. I'm seeing that projectA -> build.gradle file is executing after its subproject pA1->build.gradle as seen in the output below
I'm not understanding why projectA->build.gradle is executing after its sub projects ? Should it not execute before its subproject, just like the build.gradle file on root.
location on project Multi project sample
First off, putting a naked println line in your build.gradle files does not give you execution order. The println will be invoked in the configuration phase, so if anything you're looking at the configuration order.
If you want to investigate execution order add a task with the same name to all your build.gradle files, maybe something like this:
task action << {
println("In project: ${project.name}")
}
and then run gradle action from the root folder.

Reading Gradle build parameters

I have a Gradle project with subprojects that I can issue separate build commands if I don't want to build all the subprojects at once. For example,
parent
subprojectA
subprojectB
subprojectC
I can then issue commands like ./gradlew :subprojectA:assemble :subprojectC:assemble. What I like to do is construct a meaning git tag from each subproject group and version values for those subprojects that are being built, i.e., group and version for only subprojectA and subprojectC in this case. I am thinking of writing a standalone plugin to do this but unsure where / how to get this information at build time. Any suggestions would be much appreciated.
Both group and version (as well as any other project property) is available globally in your build script.
task myTask << {
println group + "-" + version
}
If you are writing a binary plugin you can also access properties off the Project object itself via the property() method.
def group = project.property('group')
Edit
If you want to determine if a particular project is being built you can inspect the TaskExecutionGraph.
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(':subprojectA:assemble')) {
println 'Will build subprojectA'
}
}

Make The Sonar Runner Gradle Task Depend On One Of My Tasks

I am trying out the new Sonar Runner task recently released in gradle 1.5. What I would like to do is be able to make the sonar runner task dependent on another task so that I can set the Sonar properties correctly for this project (i.e. sonar.sources, sonar.binaries, sonar.libraries, sonar.java.source, sonar.java.target).
Specifically I am using an osgi build tool called bnd which will provide these values when an ant init task is executed (note that whilst I include the default bnd build.xml file, my complete build is really being done using gradle).
I thought I would be able to customize the sonar runner task by doing this (this is a multi-module build):
subprojects {
sonarRunner.dependsOn init
}
Eventually adding something like this (from what I understand of the bnd ant variables):
subprojects {
sonarRunner {
sonarProperties {
property "sonar.java.source", ant.property["project.sourcepath"]
property "sonar.java.target", ant.property["project.output"]
property "sonar.sources", ant.property["project.allsourcepath"]
property "sonar.libraries", ant.property["project.buildpath"]
}
}
sonarRunner.dependsOn init
}
Unfortunately when I try to add the dependsOn I get the error:
* What went wrong:
A problem occurred evaluating root project 'myproject'.
> Could not find property 'init' on project ':com.company.myproject.mymodule'.
If I try to make sonarRunner depend on a gradle task I get the following error:
* What went wrong:
A problem occurred evaluating root project 'myproject'.
> Could not find method dependsOn() for arguments [task ':gradletask'] on org.gradle.api.sonar.runner.SonarRunnerExtension_Decorated#c4d7c0c.
Am I missing something obvious here? If someone could point me in the right direction it would be a big help.
Your problem with not being able to call dependsOn() on sonarRunner task comes from the fact that the plugin defines both both sonarRunner extension and a sonarRunner task. It looks like extensions take precedence over tasks when objects are resolved by name in a gradle build file, hence your stacktrace points out that you are trying to call dependsOn() on an instance of org.gradle.api.sonar.runner.SonarRunnerExtension_Decorated instead of caling it on a SonarRunner task instance.
I think that if you retrieved the task from the task container explicitly you should be ok:
tasks.sonarRunner.dependsOn init
The root project gradle file is evaluated before the child project gradle files, that means init does not exist on the location you try to address it.
A workaround if you want to declare dependencies in the root project is to use afterEvaluate as described in http://www.gradle.org/docs/current/userguide/build_lifecycle.html, try:
subprojects {
afterEvaluate{
sonarRunner.dependsOn init
}
}
Another solution would be to add the dependency in the sub projects, directly or by applying another root gradle file.
apply from: '../sonardependency.gradle'
If anyone is interested, this is one way of getting the bnd information to be set correctly in Sonar for each subproject (I am sure there are better ways):
subprojects {
afterEvaluate {
sonarRunner {
sonarProperties {
ant.taskdef(resource:"aQute/bnd/ant/taskdef.properties",
classpath: "../cnf/plugins/biz.aQute.bnd/biz.aQute.bnd-2.0.0.jar");
def projectDir = project.rootDir.toString() + "/" + project.name;
ant.bndprepare(basedir:projectDir,print:"false",top:null);
def binaries = ant.properties['project.buildpath'].split(':') as ArrayList;
binaries.remove(0);
def binariesString = binaries.join(',');
properties["sonar.java.source"] = ant.properties['javac.source'];
properties["sonar.java.target"] = ant.properties['javac.target'];
properties["sonar.binaries"] = ant.properties['project.output'].replace(':',',');
properties["sonar.sources"] = ant.properties['project.sourcepath'].replace(':',',');
properties["sonar.libraries"] = binariesString;
}
}
}
}

How to copy properties from a parent project in gradle

I'm trying to share one messages.properties (of each language) among multiple subprojects in gradle, one of which is a war and the rest are jars. My directory structure looks like this:
Top Level Project
+ Project War/
+ Project Jar/
+ Project Jar/
...
+ common/resources/properties files
+ build.gradle
I am trying to do something like this in the main project level build.gradle (which doesn't look to be working for me):
task copyProperties(type: Copy) {
description = 'Copies the messages.properties to individual projects.'
from relativePath('./common/resources')
into output.resourceDir
include '*.properties'
}
I'm calling this from a subproject's compileJava.dependsOn and I don't see any errors, but the copy doesn't happen.
You can inject a copy task like this into each sub-project. Instead of specifying the 'from' as a relative path, base it on $rootDir.
Each copy task should then be called as needed when building each sub-project.

Resources