Understanding of finalizers and command line options

Hello everyone,
I’m new in gradle, I spent a lot of time to understand how to achieve my goal and it seems like I did it but still I have some doubts whether I’m doing it in a gradle way and not breaking key concepts. Here is what I want to achieve:
in my project a default task ‘test’ could be run with a system property set to different values (e.g. -Dbu=bu1, -Dbu=bu2 etc.) thus providing different results. Since bu can be set to a finite well-known values (e.g. bu1, bu2, etc) I want to create a list of dynamic tasks lets say ‘run_api_for_’ and a task which will be an entry point and become finalized by dynamic tasks I will provide in a command line option (lets say I name it runallapi). Another important note is that I want to be able to configure my dynamic test tasks by specifying test classes and debug mode. And I want to configure them via good looking gradle command line options (@Option). So here is my solution:

ext.apiTaskPrefix = 'run_api_for_'
ext.allowedBuNames = ['bu1', 'bu2', 'bu3']

allowedBuNames.collect { buName ->
    tasks.create(apiTaskPrefix + buName, Test) {
        group 'verification'
        maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
        ignoreFailures = true
        enabled = false
        testLogging {
            events = ["failed"]
            showStandardStreams = false


task runallapi(type: RunAllApiTask) {
    group 'verification'
    bus.each { finalizedBy project.properties.apiTaskPrefix + it }
    doFirst {
        bus.each { buName ->
            tasks.getByName(apiTaskPrefix + buName) {
                enabled = true
                debugOptions {
                    enabled = debugJvm
                filter {
                doFirst {
                    systemProperty('bu', buName)

class RunAllApiTaskextends DefaultTask {
    String includeTests = '*'
    boolean debugJvm = false
    List<String> bus = project.properties.allowedBuNames

    @Option(option = "bus", description = "Comma separated BUs.")
    void setBus(String bus) {
        this.bus = bus.split(",")
        assert project.properties.allowedBuNames.containsAll(this.bus) : 'Incorrect bu name was passed as a --bus argument'

    @Option(option = "tests", description = "Sets test class or method name to be included, '*' is supported.")
    void setIncludeTests(String includeTests) {
        this.includeTests = includeTests

    @Option(option = "debug-jvm", description = "Enable debugging for the test process. The process is started suspended and listening on port 5005.")
    void setDebugJvm(boolean debugJvm) {
        this.debugJvm = debugJvm

as you may see I’m configuring my dynamic tasks when the runallapi execution is started so I can access command line options.
So here are my questions:

  1. Is it a correct usage of gradle?
  2. If the answer to the first question is no, does my goal is achievable at all (without braking gradle conepts) or I should rethink of what I’m actually want to achieve?
  3. Why configuration blocks for any task is running strictly before setter for command line options are called? and is it possible to do it vice-versa?