Customize gradle task properties when dependsOn - gradle

I created custom task which should process output of gradle dependencies task ( exactly ./gradlew dependencies --configuration myFlavorDebugRuntimeClasspath). I want to create my custom task for every buildVariant (PassportGenerateTask passportGen = project.tasks.create("pasportGenerate${variantName}", PassportGenerateTask)).
But i cant customize dependenciesReportTask properties for every passportGen. When i call passportGen for speciefic buildVariant it use dependenciesReportTask.setProperty("configurations", ...) of last build variant among all (project.android.applicationVariants.all).
For examlpe if I have following build variants (googleDebug googleRelease samsungDebug samsungRelease) and call passportGen task (./gradlew pasportGenerateGoogleDebug) it will use wrong properties for dependenciesReportTask (configuration will be samsungReleaseRuntimeClasspath configuration )
class AppPlugin implements Plugin<Project> {
void apply(Project project) {
project.afterEvaluate {
// Create tasks for each Build Variant
project.android.applicationVariants.all { ApplicationVariant variant ->
def variantName = variant.name.capitalize()
def variantOutput = variant.outputs.first()
//Generating configuration name for dependency report
def configurationName = ""
if (variant.productFlavors.size() > 0) {
configurationName += variant.productFlavors.get(0).name
configurationName += variant.getBuildType().name.capitalize()
} else {
configurationName += variant.getBuildType().name
}
configurationName += "RuntimeClasspath"
def configurations = project.configurations.collect()
configurations.removeAll {
!it.name.equals(configurationName)
}
//prepare file for output of "dependencies" tasks
def depReportFileName = "dependeciesReport${variantName}.txt"
def dependenciesReportOutputFile = new File(depReportFileName)
//Get "dependencies" task from all project tasks
def dependenciesReportTask = project.tasks["dependencies"]
dependenciesReportTask.setProperty("configurations", configurations)
dependenciesReportTask.setProperty("outputFile", dependenciesReportOutputFile)
//create cutom task for every buildVariant which depends on "dependencies" task
PassportGenerateTask passportGen = project.tasks.create("pasportGenerate${variantName}", PassportGenerateTask)
passportGen.variant = variant
passportGen.configuration = configurations.collect().get(0)
//add dependency on "dependencies"
passportGen.dependsOn dependenciesReportTask
}
}
}
}
The only way i can achieve what i want is call:
def dependenciesReportTask = project.tasks["dependencies"]
dependenciesReportTask.setProperty("configurations", configurations)
dependenciesReportTask.setProperty("outputFile", dependenciesReport)
dependenciesReportTask.execute()
inside my custom PassportGenerateTask task main action method (#TaskAction) but calling execute inside other task is deprecated feature and will be removed in gradle 5.0

It is not only deprecated, it is purely internal implementation detail that most probably does not do what you expect it does and almost always produces many more problems than it tries to solve and actually fails.
You most probably also shouldn't rape the dependencies task. If you need multiple such tasks with different configuration, simply create new tasks of type DependencyReportTask and configure them however you like.

Related

TaskInternal.execute Migration

In a spring boot application in the build.gradle
task loadDbConfigFromSpringProfile {
def activeProfileProperties = new Properties()
file("src/main/resources/application.properties").withInputStream {
activeProfileProperties.load(it)
}
def profileProperties = new Properties()
file("src/main/resources/application-" + activeProfileProperties.getProperty("spring.profiles.active") + ".properties").withInputStream {
profileProperties.load(it)
}
active_db_url = profileProperties.getProperty("spring.datasource.url")
}
loadDbConfigFromSpringProfile.execute()
When i run application with gradle 4.4, I get
The TaskInternal.execute() method has been deprecated and is scheduled
to be removed in Gradle 5.0.
I started to create a class who extends extends DefaultTask but I'm not sure if it's the easier way to fix issue.
If you remove the call to loadDbConfigFromSpringProfile.execute(), your code will have the same effect.
You do not even need the task definition, putting the following in your build file has the same effect:
def activeProfileProperties = new Properties()
file("src/main/resources/application.properties").withInputStream {
activeProfileProperties.load(it)
}
def profileProperties = new Properties()
file("src/main/resources/application-" + activeProfileProperties.getProperty("spring.profiles.active") + ".properties").withInputStream {
profileProperties.load(it)
}
active_db_url = profileProperties.getProperty("spring.datasource.url")
Here is why: The task you are defining has no actions. Actions can be added to a task by using doLast or doFirst as shown in the hello world example.
That also means that everything which is in the body of your task is executed at configuration time - since it is supposed to be configuring the task.
Therefore, loadDbConfigFromSpringProfile.execute() has no effect - the task is skipped since it has no actions.
you can replace by finalizedBy()
https://discuss.gradle.org/t/how-to-call-task-execution-from-outside-task/25971

Task of Type Copy not executed

I am facing an issue executing my task of type Copy,:
Skipping the task as it has no source files
I get if I run in the debug mode.
My Plugin.groovy class (where the call to the plugin task in made )
Task task = project.tasks.create("makeJarPlugin", MakeJarPluginTask.class)
task.dependsOn("clearDistPlugin", "build")
My MakeJarPluginTask.grrovy
class MakeJarPluginTask extends Copy {
#TaskAction
def makeJar(){
logger.lifecycle("creating a jar *********************")
delete('dist/')
from('build/intermediates/bundles/release')
into('dist/')
include('classes.jar')
def jarName = new VersionName().getNameWithVersion() + '.jar'
rename('classes.jar', jarName)
}
}
Now, I execute this task in my android studio project using
gradlew makeJarPlugin --info
It gives me the output:
Skipping task ':network:makeJar1' as it has no source files.
makeJar1 UP-TO-DATE
There is something wrong with the type Copy as in the same way I execute my delete task and it executes. Any pointers!
It seems that this answer may be helpful.
Hint: you need to configure the task. Otherwise it won't be executed since the whole configuration is done in makeJar which is too late since this is an action.
Instead of using copy you can also try:
class MakeJarPluginTask extends DefaultTask {
#TaskAction
def makeJar() {
logger.lifecycle("creating a jar *********************")
delete('dist/')
project.copy {
from('build/intermediates/bundles/release')
into('dist/')
include('classes.jar')
def jarName = new VersionName().getNameWithVersion() + '.jar'
rename('classes.jar', jarName)
}
}
}

How to create a dependency between a task and an extension?

I have an Android gradle script as follows:
preBuild.dependsOn "editManfest"
task editManfest(type: Copy) {
// copies and edits the AndroidManifest.xml
}
import com.android.builder.core.DefaultManifestParser
def extension = android {
def manifestParser = new DefaultManifestParser()
def manifestVersion = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
...
However the code in the extension is attempting to access the manifest file before the editManifest task has completed.
What can I do to ensure the task is completed before the extension's code attempts to access the manifest?
Your running into execution vs configuration time issue. The editManfest task will always execute after configuration configuring the android extension .
Can you add a
doLast {
def manifestParser = new DefaultManifestParser()
def manifestVersion = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
}
to your editManfest task?

How to use gradle extension correctly in plugins using GradleBuild task?

EDIT : I rephrased my question in taken the propositon of David M. Karr into account.
I am writing a gradle plugin. This plugin is launching a task extending GradleBuild. The external gradle build file needs some info as parameters. These parameters are given in project extension.
Plugin code
class MyPlugin implements Plugin<Project> {
def mExt
void apply(Project project) {
mExt = project.extensions.create('myext',MyExt)
project.task('myTask', type:GradleBuild){
def param = new StartParameter()
param.setProjectProperties([target:getTarget()])
// Problem here
startParameter = param
buildFile = getMyBuildPath()
tasks = [
'build',
'generateDebugJavadocJar'
]
}
}
def getMyBuildPath(){
...
}
// Problem here
def getTarget(){
return {mExt.target}
}
}
class MyExt {
def String target = "uninitialised"
}
Gradle build file :
apply plugin : 'com.example.myplugin'
ext{
target = "myTarget"
}
External Gradle build file :
task build(){
println project.target
}
If I put a closure in getTarget(), println project.target shows the closure and not the string.
If I don't put the closure :
// Problem here
def getTarget(){
return mExt.target
}
Then I got "uninitialised" instead of "myTarget".
How can I get the value of myext.target here ?
I am using gradle 2.3
Try this:
Define an instance variable called "myext", of type "MyExt".
In the "apply" method, do this:
myext = project.extensions.create('myext',MyExt)
In the "getTarget" method, return "myext.target".
I have succeeded in getting what I wanted to in using project.afterEvaluate method. Thanks to this question
1) In gradle build task, startParameter.projectProperties is waiting for a map, not a closure. So the idea to put a closure for a lazy definition cannot work.
2) If I put directly in my plugin a reference to mExt.target or project.myext.target, then the initial value is set. The value put in my build.gradle file is not used because the plugin is already evaluated.
3) project.afterEvaluate() solve my problem. The closure ends configuring myTask in using the project's extension.
void apply(Project project) {
project.extensions.create('myext',MyExt)
project.task('myTask', type:GradleBuild){
buildFile = getMyBuildPath()
tasks = [
'build',
'generateDebugJavadocJar'
]
}
project.afterEvaluate { proj ->
proj.myTask.startParameter.projectProperties = [target:proj.myext.target]
}
}

How to make Gradle run tasks in certain order?

Let's say that I have created separate tasks for running integration and acceptance tests in my gradle build script. When I run the build task I want to run testing tasks before in this order: unit tests(test task), integration tests (intergationTest task) and acceptance tests (acceptanceTest task). Is this possible and how?
You are looking for "should run after" described in Gradle documentation - http://www.gradle.org/docs/current/userguide/more_about_tasks.html
Here's how you can do it without creating artificial dependencies:
https://caffeineinduced.wordpress.com/2015/01/25/run-a-list-of-gradle-tasks-in-specific-order/
TLDR; version:
//--- build aliases : define a synonym here if you want a shortcut to run multiple targets
def buildAliases = [
'all' : ['clean', 'assemble', 'runProvisioner', 'stopTomcat', 'installTomcat', 'deployToTomcat', 'startTomcat'],
'rebuild' : ['clean', 'assemble']
]
def expandedTaskList = []
gradle.startParameter.taskNames.each {
expandedTaskList << (buildAliases[it] ? buildAliases[it] : it)
}
gradle.startParameter.taskNames = expandedTaskList.flatten()
println "\n\n\texpanded task list: ${gradle.startParameter.taskNames }\n\n"
This is what I did on my projects.
check.dependsOn integTest
integTest.mustRunAfter test
tasks.withType(Pmd) {
mustRunAfter integTest // Pointing to a task
}
tasks.withType(FindBugs) {
mustRunAfter tasks.withType(Pmd) // Pointing to a group of tasks under Pmd
}
tasks.withType(Checkstyle) {
mustRunAfter tasks.withType(FindBugs)
}
It helped me to order tasks by group.
I created this helper method based on a solution that I found on Gradle forum.
Task.metaClass.runFirst = { Task... others ->
delegate.dependsOn(others)
delegate.mustRunAfter(others[0])
for (def i=0; i < others.size() - 1; i++) {
def before = others[i]
def after = others[i+1]
after.mustRunAfter(before)
}
}
Then you can create tasks X, A, B and C and use like this:
X.runFirst A, B, C
The first answer in the list turned out to be great for me. I used
X.shouldRunAfter Y
UPDATE: While using this "solution" for a short while i found out, that it does not work 100% as intended. I don't know why though. Any help to make it work would be appreciated. Maybe it does not work properly when there is more than one task in the Set?! While testing i did add some dummy-Tasks which only printed a text inbetween each of the other tasks and all seemed to be ok.
After some attempts with other solutions i came up with this solution:
It uses the mustRunAfter command to chain Sets of Tasks into the required order.
I'm working with Sets instead of individual Tasks, because i got circular dependency issues otherwise, since some tasks already depended on each other.
Also important to note: the isNotEmpty() check was essential, as it would otherwise break the enforced ordering if an ampty set was passed to the method.
tasks.register("cleanAndGenerate") {
var lastTasks: Set<Task> = setOf()
fun findTasks(taskName: String): Set<Task> {
return if (taskName.startsWith(":")) { // task in specific sub-project
setOf(tasks.findByPath(taskName)!!)
} else { // tasks in all (sub-)projects
getTasksByName(taskName, true)
}
}
fun dependsOnSequential(taskName: String) {
val tasks = findTasks(taskName)
tasks.forEach { task -> task.mustRunAfter(lastTasks) }
dependsOn(tasks)
if (tasks.isNotEmpty()) {
lastTasks = tasks
}
}
dependsOnSequential(":project1:clean") // task in specific sub-project
dependsOnSequential(":project2:clean")
dependsOnSequential("task1") // tasks in all (sub-)projects
dependsOnSequential("task2")
// add more as needed
}

Resources