How to reference a subproject dir from a root gradle task when calling task from subproject - gradle

I have a root project gradle task defined below. I am
task createVersionTxtResourceFile {
doLast {
def webAppVersionFile = new File("$projectDir/src/main/resources/VERSION.txt")
def appVersion = project.ext.$full_version
println "writing VERSION.txt to " + webAppVersionFile + ", containing " + appVersion
webAppVersionFile.delete()
webAppVersionFile.write(appVersion)
}
}
In a few subprojects, I want to run this task and create the VERSION.txt file in the subproject's src/main/resources/VERSION.txt. My problem is that the root level task's $projectDir is the root project.
Is it possible to define a root level task that uses the sub-project directory when invoking it? Or perhaps there's a better approach all together.

You could do it slightly more controlled when you register an action to wait for the java plugin to be applied on the subproject. With this you can create the task only in subprojects who contain the desired compileJava task and configure everything from the root project.
subprojects { sub ->
//register an action which gets executed when the java plugins gets applied.
//if the project is already configured with the java plugin
//then this action gets executed right away.
sub.plugins.withId("java") {
//create the task and save it.
def createVersionTxtResourceFile = sub.tasks.create("createVersionTxtResourceFile") {
doLast {
def webAppVersionFile = new File("${sub.projectDir}/src/main/resources/VERSION.txt")
def appVersion = rootProject.full_version
println "writing VERSION.txt to " + webAppVersionFile + ", containing " + appVersion
webAppVersionFile.delete()
webAppVersionFile.write(appVersion)
}
}
// set the task dependency
sub.tasks.compileJava.dependsOn createVersionTxtResourceFile
}
}

I ended up just defining the task in each subproject, and setting a dependency on it in the appropriate subprojects:
subprojects {
task createVersionTxtResourceFile {
doLast {
def webAppVersionFile = new File("$projectDir/src/main/resources/VERSION.txt")
def appVersion = rootProject.full_version
println "writing VERSION.txt to " + webAppVersionFile + ", containing " + appVersion
webAppVersionFile.delete()
webAppVersionFile.write(appVersion)
}
}
}
then in a subproject build.gradle:
compileJava.dependsOn createVersionTxtResourceFile

Related

How to pass text parameters into a Gradle task from another gradle task (not command line)

I'm wondering how I can pass a parameter (PARAM) to a Gradle task from another Gradle task that depends on it.
For example something along these lines
task buildDist(PARAM) {
copy {
from "$projectDir/src/{PARAM}/ClientBanner.json"
into "$buildDir/${project.name}/"
}
and call this Gradle task from another one like:
task dist(type: Zip) {
from "$buildDir"
include "${project.name}/**/*"
archiveFileName = project.name + '.zip'
destinationDirectory = layout.buildDir.dir('dist')
dependsOn('buildDist(PARAM)')
}
#Shapebuster
The Gradle build script is Groovy (or Kotlin) based and can be extended using the supported syntax of that language. So, in your example, you should be able to use the PARAM like so:
task buildDist(String param1) {
copy {
from "$projectDir/src/$param1/ClientBanner.json"
into "$buildDir/${project.name}/"
}
}
and then:
task dist(type: Zip) {
from "$buildDir"
include "${project.name}/**/*"
archiveFileName = project.name + '.zip'
destinationDirectory = layout.buildDir.dir('dist')
dependsOn buildDist("$param1")
}

Gradle project, sub projects executed repeatedly

I have a project with sub projects. The layout:
rootproj
--subproj1
----mybuild.number
--subproj2
--build.gradle
--gradle.properties
--settings.gradle
mybuild.number
#Build Number for ANT. Do not edit!
#Wed Nov 210 2121:210:2121 PST 2102121
build.number=1
settings.gradle
include ('subproj1', 'subproj2')
build.gradle
allprojects {
repositories {
mavenLocal()
maven {url "http://repo1.maven.org/maven2"}
}
}
subprojects {
project (':subproj1') {
def oldN = new File("D:/rootproj/subproj1/mybuild.number").text.split("=")[1]
def newN = (oldN.toInteger() + 1).toString()
ant.replace(
file: "mybuild.number",
token: "${oldN}",
value: "${newN}"
)
println "From subproj1 : ${newN}"
task hello(overwrite: true){
doLast{
println "hello from subproject 1"
}
}
}
project (':subproj2'){
println "the build Dir: $buildDir"
task hello(overwrite: true){
doLast{
println "hello from subproject 2"
}
}
}
}
when I run
gradle -q subproj1:hello
or
gradle -q subproj2:hello
or
gradle
from the rootproj, I always get e.g.
....
From subproj1 : 24
the build Dir: D:\rootproj\subproj2\build
From subproj1 : 25
the build Dir: D:\rootproj\subproj2\build
1. Why the two sub projects always get executed twice, therefore the build number is incremented twice, instead of once?
2. why all sub projects get executed even though I explicitly specified the project:task in the command line?
I have searched the Internet, could not find useful information.
Thanks for your help in advance.
EDIT:
Change build.gradle as #JB Nizet suggested:
move the ant.replace to task incr
comment out subprojects
It works exactly as I expected.
allprojects {
repositories {
mavenLocal()
maven {url "http://repo1.maven.org/maven2"}
}
}
//subprojects {
def oldN = new File("E:/hqin/build/gradle/rootproj/subproj1/mybuild.number").text.split("=")[1]
def newN = (oldN.toInteger() + 1).toString()
project (':subproj1') {
task incr {
doLast{
ant.replace(
file: "mybuild.number",
token: "${oldN}",
value: "${newN}"
)
}
println "From subproj1 : ${newN}"
}
task hello(overwrite: true, dependsOn: 'incr'){
doLast{
println "hello from subproject 1"
}
}
}
project (':subproj2'){
task hello(overwrite: true){
doLast{
println "the build Dir: $buildDir"
println "hello from subproject 2"
}
}
}
//}
Regarding the second point: because your code is run as part of the project configuration, which is always run, whatever the task being executed. If you want code being executed when a task is executed, then it should be inside the doLast closure of a task definition:
task someTask {
doLast {
...
}
}
Regarding the first point: the closure passed to subprojects is executed for every subproject. So, it's called once for the subproject 1, and configures subproject 1 and subproject 2, then it's called again for subproject 2, and reconfigures subproject 1 and subproject 2 again. You shouldn't have subprojects at all.

How to get the path in build.gradle

I am working on build.gradle in a project directory. i want to know how can I get the path of the directory with one folder back in gradle task
task myTask << {
println file('.')
println projectDir}
This would return me the path which say is c:\a\b\c which is current directory
but i want to go to the path c:\a\b
task currentDir << {
println file('.')
println projectDir
}
task previousDir << {
println file('..')
println file("$projectDir/..")
}

variable is read-only when it shouldn't be

When i execute this in my script
artifacts = ['abc123-com', 'abc123-ejb', 'abc123-spec', 'abc123-war', 'abc123-war2']
task clone_workspace() << {
for (item in artifacts) {
println item
}
}
i get
> Cannot set the value of read-only property 'artifacts' on root project 'abc123'.
I have tried scoping to project with project.artifacts, and to ext with project.ext.artifacts.
what am I doing wrong here?
The following minimalist Gradle file illustrates that project already has a property for artifacts (documented here):
println "TRACER : " + project.artifacts.class
output:
bash$ gradle
TRACER : class org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated
By contrast, this version of the original is happier:
def myArtifacts = ['abc123-com', 'abc123-ejb', 'abc123-spec', 'abc123-war', 'abc123-war2']
task clone_workspace() << {
for (item in myArtifacts) {
println item
}
}

Upload all productFlavors with crashlytics

My problem is simple but I don't find the solution. In my app, I have added crashlytics and I want to use beta to upload builds.
For one productFlavor I use the task called crashlyticsUploadDistribution<ProductFlavor>Release and before I have to assemble build with assemble<ProductFlavor>Release otherwise it can upload a wrong apk.
Now I want to merge this two tasks in only one so in my gradle.file
task prepareFabric(group: 'aat') {
println 'HereSTART'
dependsOn 'assemble<ProductFlavor>Release'
}
task publishRealeaseOnFabric(group: 'aat') {
mustRunAfter prepareFabric
println 'HereFINAL'
dependsOn 'crashlyticsUploadDistribution<ProductFlavor>Release'
}
Now when I execute my task (publishRealeaseOnFabric), print appears but the following line is not executed
dependsOn 'assemble<ProductFlavor>Release'
My question is : How can I make two tasks assemble<ProductFlavor>Release and then crashlyticsUploadDistribution<ProductFlavor>Release in one task ?
I use that it create all the flavors
//Creates the app for all the productFlavors
File crashlyticsProperties = new File("${project.projectDir.absolutePath}/fabric.properties")
applicationVariants.all { variant ->
variant.productFlavors.each { flavor ->
println("flavor : " + variant.name)
def variantSuffix = variant.name.capitalize()
def generatePropertiesTask = task("fabricGenerateProperties${variantSuffix}") << {
Properties properties = new Properties()
properties.put("apiKey", flavor.fabricApiKey)
properties.put("apiSecret", flavor.fabricApiSecret)
properties.store(new FileWriter(crashlyticsProperties), "")
}
def generateResourcesTask = project.tasks.getByName("fabricGenerateResources${variantSuffix}")
generateResourcesTask.dependsOn generatePropertiesTask
generateResourcesTask.doLast {
println "Removing fabric.properties"
crashlyticsProperties.delete()
}
}
}

Resources