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.