Introdução ao Gradle

Introdução ao Gradle

*1. Visão geral *

Gradle é um sistema de gerenciamento de construção baseado em Groovy, projetado especificamente para criar projetos baseados em Java.

As instruções de instalação podem ser encontradas em here.

===* 2. Blocos de construção - Projetos e tarefas *

*No Gradle, os Builds consistem em um ou mais projetos e cada projeto consiste em uma ou mais tarefas.*

Um projeto no Gradle pode estar montando um arquivo jar, war ou mesmo um zip.

*Uma tarefa é uma única peça de trabalho.* Isso pode incluir a compilação de classes ou a criação e publicação de arquivos Java/web.

Uma tarefa simples pode ser definida como:

task hello {
    doLast {
        println 'Baeldung'
    }
}

Se executarmos a tarefa acima usando o comando gradle -q hello do mesmo local em que build.gradle reside, devemos ver a saída no console.

2.1 Tarefas

Os scripts de construção de Gradle nada mais são do que Groovy:

task toLower {
    doLast {
        String someString = 'HELLO FROM BAELDUNG'
        println "Original: "+ someString
        println "Lower case: " + someString.toLowerCase()
    }
}

Podemos definir tarefas que dependem de outras tarefas. A dependência da tarefa pode ser definida passando o argumento dependsOn: taskName em uma definição de tarefa:

task helloGradle {
    doLast {
        println 'Hello Gradle!'
    }
}

task fromBaeldung(dependsOn: helloGradle) {
    doLast {
        println "I'm from Baeldung"
    }
}

2.2 Adicionando comportamento a uma tarefa

Podemos definir uma tarefa e aprimorá-la com algum comportamento adicional:

task helloBaeldung {
    doLast {
        println 'I will be executed second'
    }
}

helloBaeldung.doFirst {
    println 'I will be executed first'
}

helloBaeldung.doLast {
    println 'I will be executed third'
}

helloBaeldung {
    doLast {
        println 'I will be executed fourth'
    }
}

doFirst e doLast adicionam ações na parte superior e inferior da lista de ações, respectivamente, e pode ser definido várias vezes em uma única tarefa .

2.3 Adicionando propriedades da tarefa

Também podemos definir propriedades:

task ourTask {
    ext.theProperty = "theValue"
}

Aqui, estamos definindo _ "theValue" _ como theProperty da tarefa ourTask.

*3. Gerenciando plugins *

Existem dois tipos de plugins no Gradle - script, _ e _binary.

Para se beneficiar de uma funcionalidade adicional, todo plug-in precisa passar por duas fases: resolving e applying.

*_Resolving_ significa encontrar a versão correta do jar do plugin e adicioná-la ao _classpath_ do projeto.*
*_Aplicando_ plugins está executando*  *_Plugin.apply (T) _*  *no projeto* .

3.1 Aplicando plugins de script

No _aplugin.gradle, _ podemos definir uma tarefa:

task fromPlugin {
    doLast {
        println "I'm from plugin"
    }
}

Se quisermos aplicar esse plug-in ao nosso arquivo build.gradle do projeto, basta adicionar esta linha ao nosso build.gradle:

apply from: 'aplugin.gradle'

Agora, a execução do comando gradle tasks deve exibir a tarefa fromPlugin na lista de tarefas.

3.2 Aplicando plug-ins binários usando plug-ins DSL

No caso de adicionar um plug-in binário principal, podemos adicionar nomes curtos ou um ID de plug-in:

plugins {
    id 'application'
}

Agora a tarefa run do plugin application deve estar disponível em um projeto para executar qualquer jar runnable. Para aplicar um plug-in da comunidade, precisamos mencionar um ID de plug-in totalmente qualificado:

plugins {
    id "org.shipkit.bintray" version "0.9.116"
}

Agora, as tarefas Shipkit devem estar disponíveis na lista gradle tasks.

As limitações dos plug-ins DSL são:

  • Ele não suporta código Groovy dentro do bloco plugins

  • O bloco plugins precisa ser a instrução de nível superior nos scripts de construção do projeto (apenas o bloco buildscripts \ {} _ é permitido antes dele) *Os plug-ins DSL não podem ser gravados no plug-in scripts, no arquivo _settings.gradle ou nos scripts init

Plug-ins DSL ainda está incubando. O DSL e outras configurações podem mudar nas versões posteriores do Gradle.

====* 3.3 Procedimento herdado para aplicar plug-ins *

Também podemos aplicar plugins usando o _ “aplicar plugin” _:

apply plugin: 'war'

Se precisarmos adicionar um plugin da comunidade, precisamos adicionar o jar externo ao caminho de classe da compilação usando o bloco _buildscript \ {} _.

Em seguida,* podemos aplicar o plug-in nos scripts de construção, mas * somente após qualquer bloco existente de _plugins \ {} _ :

buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "org.shipkit:shipkit:0.9.117"
    }
}
apply plugin: "org.shipkit.bintray-release"

*4. Gerenciamento de Dependências *

Gradle suporta um sistema de gerenciamento de dependências muito flexível, é compatível com a ampla variedade de abordagens disponíveis.

As práticas recomendadas para gerenciamento de dependências em Gradle são controle de versão, controle de versão dinâmico, resolução de conflitos de versão e gerenciamento de dependências transitivas.

====* 4.1 Configuração de Dependência *

As dependências são agrupadas em diferentes configurações.* Uma configuração tem um nome e eles podem se estender *.

Se aplicarmos o plug-in Java, teremos as configurações compile, testCompile, runtime disponíveis para agrupar nossas dependências. A configuração default c estende "runtime" .

4.2 Declarando dependências

Vejamos um exemplo de adição de algumas dependências (Spring e Hibernate) usando várias maneiras diferentes:

dependencies {
    compile group:
      'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'
    compile 'org.springframework:spring-core:4.3.5.RELEASE',
            'org.springframework:spring-aop:4.3.5.RELEASE'
    compile(
        [group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'],
        [group: 'org.springframework', name: 'spring-aop', version: '4.3.5.RELEASE']
    )
    testCompile('org.hibernate:hibernate-core:5.2.12.Final') {
        transitive = true
    }
    runtime(group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final') {
        transitive = false
    }
}

Estamos declarando dependências em várias configurações: compile, testCompile e runtime em vários formatos.

Às vezes, precisamos de dependências que tenham vários artefatos. Nesses casos, podemos adicionar notações somente de artefato _ @ extensionName_ (ou ext no formulário expandido) para fazer o download do artefato desejado:

runtime "org.codehaus.groovy:groovy-all:[email protected]"
runtime group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.11', ext: 'jar'

Aqui, adicionamos a notação _ @ jar_ para baixar apenas o artefato jar sem as dependências.

Para adicionar dependências a qualquer arquivo local, podemos usar algo como isto:

compile files('libs/joda-time-2.2.jar', 'libs/junit-4.12.jar')
compile fileTree(dir: 'libs', include: '*.jar')
*Quando queremos evitar dependências transitivas,*  *podemos fazê-lo no nível de configuração ou no nível de dependência* :
configurations {
    testCompile.exclude module: 'junit'
}

testCompile("org.springframework.batch:spring-batch-test:3.0.7.RELEASE"){
    exclude module: 'junit'
}

*5. Construções para vários projetos *

====* 5.1. Criar ciclo de vida *

*Na fase de inicialização, Gradle determina quais projetos participarão de uma compilação de vários projetos.*

Isso geralmente é mencionado no arquivo settings.gradle, localizado na raiz do projeto. Gradle também cria instâncias dos projetos participantes.

*Na fase de configuração, todas as instâncias de projetos criadas são configuradas com base na configuração do recurso Gradle sob demanda.*

Nesse recurso, apenas os projetos necessários são configurados para uma execução de tarefa específica. Dessa forma, o tempo de configuração é altamente reduzido para uma compilação grande de vários projetos. Esse recurso ainda está em incubação.

Finalmente, na fase de execução, é executado um subconjunto de tarefas, criadas e configuradas. Podemos incluir código nos arquivos settings.gradle e build.gradle para perceber essas três fases.

Em settings.gradle:

println 'At initialization phase.'

Em build.gradle:

println 'At configuration phase.'

task configured { println 'Also at the configuration phase.' }

task execFirstTest { doLast { println 'During the execution phase.' } }

task execSecondTest {
    doFirst { println 'At first during the execution phase.' }
    doLast { println 'At last during the execution phase.' }
    println 'At configuration phase.'
}

5.2 Criando a criação de vários projetos

Podemos executar o comando gradle init na pasta raiz para criar um esqueleto para os arquivos settings.gradle e build.gradle.

Toda a configuração comum será mantida no script de construção raiz:

allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    version = '1.0'
}

O arquivo de configuração precisa incluir o nome do projeto raiz e o nome do subprojeto:

rootProject.name = 'multi-project-builds'
include 'greeting-library','greeter'

Agora precisamos ter algumas pastas de subprojetos denominadas greeting-library e greeter para ter uma demonstração de uma compilação de vários projetos. Cada subprojeto precisa ter um script de construção individual para configurar suas dependências individuais e outras configurações necessárias.

Se gostaríamos de ter nosso projeto greeter dependente da greeting-library, precisamos incluir a dependência no script de construção de greeter:

dependencies {
    compile project(':greeting-library')
}

*6. Usando o Gradle Wrapper *

Se um projeto Gradle tiver arquivos gradlew para Linux e gradlew.bat para Windows, não precisamos instalar o Gradle para compilar o projeto.

Se executarmos gradlew build no Windows e ./gradlew build no Linux, uma distribuição Gradle especificada no arquivo gradlew será baixada automaticamente.

Se quisermos adicionar o wrapper Gradle ao nosso projeto:

gradle wrapper --gradle-version 4.2.1

O comando precisa ser executado a partir da raiz do projeto. Isso criará todos os arquivos e pastas necessários para vincular o wrapper Gradle ao projeto. A outra maneira de fazer o mesmo é adicionar a tarefa do wrapper ao script de construção:

task wrapper(type: Wrapper) {
    gradleVersion = '4.2.1'
}

Agora precisamos executar a tarefa wrapper e a tarefa amarrará nosso projeto ao wrapper. Além dos arquivos gradlew, uma pasta wrapper é gerada dentro da pasta gradle que contém um jar e um arquivo de propriedades.

Se queremos mudar para uma nova versão do Gradle, precisamos apenas alterar uma entrada em gradle-wrapper.properties.

===* 7. Conclusão*

Neste artigo, vimos Gradle e vimos que ele tem maior flexibilidade sobre outras ferramentas de compilação existentes em termos de resolução de conflitos de versão e gerenciamento de dependências transitivas.

O código fonte deste artigo está disponível over no GitHub.