Execute GradleBuild task inside each loop


(Rodrigo Oliveira) #1

Hi all!

I have two GradleBuild tasks that run a series of other tasks to set up the database for the main and the othter tenants in a multitenancy environment:

task runDatabaseChangesForTenants(type: GradleBuild) {
dir = projectProperties.sfwDir
buildFile = "${projectProperties.sfwDir}/build.gradle"
tasks = [‘verificaGrants’, ‘printDatabaseInfo’, ‘atualizaDb’, ‘aplicarScriptsMd’, ‘aplicarMetadadosSfw’, ‘printDatabaseInvalidObjects’, ‘gravaDadosBannerAplicacaoSfw’]
startParameter.projectProperties = project.projectProperties
startParameter.projectProperties.runScript = project.projectProperties.runScriptsAutomaticallyQuestion
startParameter.projectProperties.rerunTasks = true
}

// Cópia do anterior mas sem a task ‘aplicarScriptsMd’ e com a alteração da task 'aplicarMetadadosSfwMainTenant’
task runDatabaseChangesMainTenant(type: GradleBuild) {
dir = projectProperties.sfwDir
buildFile = "${projectProperties.sfwDir}/build.gradle"
tasks = [‘verificaGrants’, ‘printDatabaseInfo’, ‘atualizaDb’, ‘aplicarMetadadosSfwMainTenant’, ‘printDatabaseInvalidObjects’, ‘gravaDadosBannerAplicacaoSfw’, ‘verificarClientemBanco’]
startParameter.projectProperties = project.projectProperties
startParameter.projectProperties.runScript = project.projectProperties.runScriptsAutomaticallyQuestion
}

I have a config file with the main and the other tenats configuration that I need to read to pass the data to the tasks above:

def runDatabaseChangesInstall(ehAmbienteCloud = false, configFile = ‘tenantConfig.groovy’) {

// se a propriedade ambienteCloud for true, a instalação deverá ser multi-tenancy,
// neste caso é necessário a existencia do arquivo tenantConfig.groovy.
if (ehAmbienteCloud) {
    menssageInstaller("INSTALACAO MULTI-TENANCY ATIVADA", true)

    File tenantConfigFile = file(configFile)
    if (!tenantConfigFile.exists()) {
        createTenantConfigFile()
    }

    ConfigSlurper tenantConfigSluper = new ConfigSlurper("tenancies")
    ConfigObject configOj = tenantConfigSluper.parse(tenantConfigFile.toURI().toURL())

    // se não contrar nenhum tenant configurado...
    if (configOj.keySet().isEmpty()) {
        throw new GradleException("ERRO: Nenhum Tenant configurado no arquivo tenantConfig.groovy, nao eh possivel continuar.")
    }
    // caso contrário, inicio a atualização dos tenants
    printMessage "Os seguintes tenants serão atualizados:"
    configOj.keySet().each { printMessage "  - $it" }
	
	def buildToExecuteMain = runDatabaseChangesMainTenant
	def buildToExecute2nd = runDatabaseChangesForTenants
	

    // para cada tenant do arquivo tenantConfig.groovy, executo o a task runDatabaseChanges
    configOj.each { tenantConfig ->
	
        menssageInstaller("ATUALIZANDO TENANT: $tenantConfig.key")            

        // Build do main tenant é diferente pois não aplica scripts do MD e a task de aplicar metadados é outra
        if (tenantConfig.key == 'mainTenant') {
		
            buildToExecuteMain.startParameter.projectProperties.databaseDir = 'install/db/main'
			buildToExecuteMain.execute()
			// Limpa a configuração pois senão as próximas execuções utilizarão o mesmo diretório erroneamente
			buildToExecuteMain.startParameter.projectProperties?.remove('databaseDir')
			
        } else {
		
			buildToExecute2nd.startParameter.projectProperties.tenantConfig = tenantConfig
			buildToExecute2nd.execute()
			// Limpa a configuração pois senão as próximas execuções utilizarão o mesmo diretório erroneamente
			buildToExecute2nd.startParameter.projectProperties?.remove('databaseDir')
			
		}

    }
}
// a instalação não é multi-tenancy, então executo a task antiga
else {
    tasks.runDatabaseChanges.execute()
}

}

Problem is the second time this loop runs the runDatabaseChangesForTenants tasks it does not run at all, it’s like since it has run a first time it will not run again. ever.

Is there a way to run a task multiple times inside a loop? I’m on gradle 4.0, Gradle 4.2 and Java 8. Thanks in advance!!


(Rodrigo Oliveira) #2

Hi all!

I could solve the problem based on this:

http://gradle.1045684.n5.nabble.com/calling-task-multiple-times-with-different-parameters-td3290970.html

What I did was create dynamic tasks inside the loop and them called each one:

def runDatabaseChangesInstall(ehAmbienteCloud = false, configFile = ‘tenantConfig.groovy’) {

// se a propriedade ambienteCloud for true, a instalação deverá ser multi-tenancy,
// neste caso é necessário a existencia do arquivo tenantConfig.groovy.
if (ehAmbienteCloud) {
    menssageInstaller("INSTALACAO MULTI-TENANCY ATIVADA", true)

    File tenantConfigFile = file(configFile)
    if (!tenantConfigFile.exists()) {
        createTenantConfigFile()
    }

    ConfigSlurper tenantConfigSluper = new ConfigSlurper("tenancies")
    ConfigObject configOj = tenantConfigSluper.parse(tenantConfigFile.toURI().toURL())

    // se não contrar nenhum tenant configurado...
    if (configOj.keySet().isEmpty()) {
        throw new GradleException("ERRO: Nenhum Tenant configurado no arquivo tenantConfig.groovy, nao eh possivel continuar.")
    }
    // caso contrário, inicio a atualização dos tenants
    printMessage "Os seguintes tenants serão atualizados:"
    configOj.keySet().each { printMessage "  - $it" }

    // para cada tenant do arquivo tenantConfig.groovy, executo o a task runDatabaseChanges
    configOj.each { tenantConfig ->

        // Build do main tenant é diferente pois não aplica scripts do MD e a task de aplicar metadados é outra
        if (tenantConfig.key == 'mainTenant') {

            menssageInstaller("CRIANDO TASK: runDatabaseChangesForTenantMain")

            tasks.create(name: "runDatabaseChangesForTenantMain", type: GradleBuild) {

                dir = projectProperties.sfwDir
                buildFile = "${projectProperties.sfwDir}/build.gradle"
                tasks = ['verificaGrants', 'printDatabaseInfo', 'atualizaDb', 'aplicarMetadadosSfwMainTenant', 'printDatabaseInvalidObjects', 'gravaDadosBannerAplicacaoSfw', 'verificarClientemBanco']

            }

        } else {

            menssageInstaller("CRIANDO TASK: runDatabaseChangesForTenant$tenantConfig.key")

            tasks.create(name: "runDatabaseChangesForTenant$tenantConfig.key", type: GradleBuild) {

                dir = projectProperties.sfwDir
                buildFile = "${projectProperties.sfwDir}/build.gradle"
                tasks = ['verificaGrants', 'printDatabaseInfo', 'atualizaDb', 'aplicarScriptsMd', 'aplicarMetadadosSfw', 'printDatabaseInvalidObjects', 'gravaDadosBannerAplicacaoSfw']

            }

        }

    }

    configOj.each { configTenant ->

        menssageInstaller("ATUALIZANDO TENANT: $configTenant.key")

        // Build do main tenant é diferente pois não aplica scripts do MD e a task de aplicar metadados é outra
        if (configTenant.key == 'mainTenant') {

            tasks.matching { Task task -> task.name.startsWith("runDatabaseChangesForTenantMain") }.each { taskMain ->

                menssageInstaller("EXECUTANDO TASK: $taskMain.name")
                taskMain.startParameter.projectProperties = project.projectProperties
                taskMain.startParameter.projectProperties.databaseDir = 'install/db/main'
                taskMain.startParameter.projectProperties.tenantConfig = configTenant
                taskMain.startParameter.projectProperties.runScript = project.projectProperties.runScriptsAutomaticallyQuestion
                taskMain.execute()
                taskMain.startParameter.projectProperties?.remove('databaseDir')
                taskMain.startParameter.projectProperties?.remove('tenantConfig')

            }

        } else {

            tasks.matching { Task task -> task.name.startsWith("runDatabaseChangesForTenant$configTenant.key") }.each { taskTenant ->

                menssageInstaller("EXECUTANDO TASK: $taskTenant.name")
                taskTenant.startParameter.projectProperties = project.projectProperties
                taskTenant.startParameter.projectProperties.runScript = project.projectProperties.runScriptsAutomaticallyQuestion
                taskTenant.startParameter.projectProperties.tenantConfig = configTenant
                taskTenant.execute()
                taskTenant.startParameter.projectProperties?.remove('databaseDir')
                taskTenant.startParameter.projectProperties?.remove('tenantConfig')

            }

        }

    }

}
// a instalação não é multi-tenancy, então executo a task antiga
else {
    tasks.runDatabaseChanges.execute()
}

}


(Sterling Greene) #3

Please don’t call Task.execute(). This is never the right answer because it by-passes all of Gradle’s infrastructure (up-to-date checks, parallelism, correctness checks, etc). You’re basically using Gradle as a glorified shell script at this point. Calling execute() is already going to give you a warning in 4.3 and will eventually be prevented entirely.

You should be able to do something like:

  1. Loop through your configuration and create all of the dynamic tasks that you want.
  2. Add a “doAllTheWork” task that depends on all of the tasks you created above.
  3. Run gradle doAllTheWork and have Gradle orchestrate each of the tasks/builds.

There’s a bit too much going on in your example, but I would also question the need to use separate GradleBuild tasks. You might be better off just using a shell script and calling Gradle multiple times with different parameters. I’m not sure what the 'verificaGrants', 'printDatabaseInfo', 'atualizaDb', 'aplicarScriptsMd', 'aplicarMetadadosSfw', 'printDatabaseInvalidObjects', 'gravaDadosBannerAplicacaoSfw' tasks are doing to make that call.