Gradle plugin to read build command parameters

Ensure you apply your plugin after the ‘java’ plugin. Additionally, you could have your plugin apply the ‘java’ plugin, if it required it, or you could use some of Gradle’s live collection capabilities to configure the assemble task, regardless of when it was created.

project.tasks.matching { it.name == ‘assemble’ }.all {

finalizedBy ‘:buildManifest’

}

Again, it works. Dude, you are amazing! I am using your suggestion of Gradle’s live collection feature because I prefer to 'apply plugin: ‘org.samples.greeting’ at the top level ‘build.gradle’ and not at each subproject ‘build.gradle’. That said, ‘assemble’ now works but it doesn’t seem to trigger ‘buildManifest’

For completeness, here’s the plugin code

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello', type: GreetingTask)
        project.tasks.create('buildManifest', BuildManifestTask)
        project.tasks.matching { it.name == 'assemble' }.all {
            finalizedBy ':buildManifest'
        }
    }
  }
  class BuildManifestTask extends DefaultTask {
    @TaskAction
    def buildManifest() {
        println "buildManifest"
        Set projects = []
        gradle.taskGraph.afterTask { task ->
            if (task.didWork) projects += task.project
        }
          doLast {
            println projects +", " + versions
        }
          mustRunAfter subprojects.collectNested { it.tasks }
    }
}

In the multiproject top level build.gradle, I have

dependencies {
        classpath 'com.android.tools.build:gradle:1.0.0'
}
  apply plugin: 'org.samples.greeting'

This is because you are only adding the ‘finalizedBy’ dependency to the root project’s ‘assemble’ task. This needs to be done to all sub-projects. Make the following modification to your plugin.

project.subprojects {

tasks.matching { it.name == ‘assemble’ }.all {

finalizedBy ‘:buildManifest’

}

}

Sweet, works! Now I am getting this error

Execution failed for task ':buildManifest'.
> Cannot call Task.doLast(Closure) on task ':buildManifest' after task has started execution.

Incidentally, how do I also get the ‘version’ for the ‘project’

You can’t call ‘doLast()’ inside of a method annotated with ‘@TaskAction’. Additionally you’ll want to do the task setup outside of the task action as well, like in a constructor. Try structuring your task class like so.

class BuildManifestTask extends DefaultTask {

Set projects = []

BuildManifestTask() {

this.project.gradle.taskGraph.afterTask { task ->

if (task.didWork) projects += task.project

}

this.mustRunAfter this.project.subprojects.collectNested { it.tasks }

}

@TaskAction

def buildManifest() {

println projects +", " + versions

}

}

Ok, that mostly worked except it couldn’t find ‘versions’

Execution failed for task ':buildManifest'.
> Could not find property 'versions' on task ':buildManifest'.

After I removed ‘versions’, it built but only listed one of the subproject, not both, I ran ‘gradlew assemble’

Where is ‘versions’ supposed to be defined? That’s not an implicit project property. Was the other project already up-to-date? Can you post the build output? What if you do ‘gradlew clean assemble’?

Oh my bad, that was copied from my earlier attempt to print ‘versions’, so I guess back to my question, how do I get the corresponding ‘version’ for each of the subproject?

Never mind, you called it, running it with ‘clean’ work and it listed both subprojects. So that just leaves the ‘version’ question.

UPDATE Figured it out :slight_smile:

if (task.didWork) projects += (task.project.name + "-" + task.project.version)

Mark, I want to thank you for all your help, you have been super helpful and patient working with me through all my trials and tribulations. I hope this thread serves as a mini-tutorial for other newbies trying to do something similar. If you are in the Bay Area or ever in town, please let me know and I’ll be happy to buy you a pint or two :slight_smile:

Happy New Year!

No worries, glad I could help. Enjoy the New Year.

Hi Mark,

In this snippet of code in the constructor, what’s the best way to get the task name?

class BuildManifestTask extends DefaultTask {
      Set projects = []
      BuildManifestTask() {
          this.project.gradle.taskGraph.afterTask { task ->
              if (task.didWork) projects += task.project
          }
          this.mustRunAfter this.project.subprojects.collectNested { it.tasks }
      }
      @TaskAction
      def buildManifest() {
          println projects +", " + versions
      }
  }

The ‘BuildManifestTask’ itself? Just use ‘this.name’. Although depending on where you reference that it may not be set yet. In the context of the constructor itself I would imagine that value would still be ‘null’, however it should be fine to reference it inside the ‘afterTask {}’ block.

So I tried that before and it returns ‘buildManifest’ and I am expecting it to be something like ‘assemble’, etc. I am referencing it inside ‘afterTask {}’.

Then what task exactly are you trying to get the name of? The ‘afterTask {}’ block is being evaluated for every task that executes. If you want that task name then simply reference the ‘task’ argument being passed to that closure. In that case it was be ‘task.name’.

I swore I tried that before and it didn’t work, it works now, thanks again!