SlideShare ist ein Scribd-Unternehmen logo
1 von 128
Downloaden Sie, um offline zu lesen
@YourTwitterHandle#YourSessionHashtag
Plugin Gradle, prenez le contrĂŽle du build !
Eyal LEZMY
http://eyal.fr
Cedric CHAMPEAU
@CedricChampeau
SLIDES
bit.ly/gradle-plugin-devoxx
DEFINITIONS01
A dependency management
engine
A dependency based execution
system
A plugin system
A set of plugins
DEFINITIONS
What is
Gradle?
by Luke Daley, Gradle core
developer
Build scripts
Your build.gradle file
Script plugins
The customization you start writing
Binary plugins
The code I want you to write
DEFINITIONS
Gradle
Plugins
Types
Is a piece of work for a build
Compiling a class, generating javadoc, ...
Can be manipulated
doFirst, doLast
Can inherit from another
type
Can depend on another task
dependsOn, finalizedBy
DEFINITIONS
The Gradle
Task
LET’S GET STARTED!02
Your unit
tests results,
you have to
version
THE SUBJECT
THE JOB
Copy and version this folder
task archiveTests (type: Copy) {
from "$reportsDir/reports"
into "$projectDir/reports/report-${currentTimeMillis()}"
}
tasks.test.finalizedBy archiveTests
THE CODE
End of build.gradle
task archiveTests (type: Copy) {
from "$reportsDir/reports"
into "$projectDir/reports/report-${currentTimeMillis()}"
}
tasks.test.finalizedBy archiveTests
THE CODE
We create the task
End of build.gradle
task archiveTests (type: Copy) {
from "$reportsDir/reports"
into "$projectDir/reports/report-${currentTimeMillis()}"
}
tasks.test.finalizedBy archiveTests
THE CODE
It inherits from Copy task
End of build.gradle
task archiveTests (type: Copy) {
from "$reportsDir/reports"
into "$projectDir/reports/report-${currentTimeMillis()}"
}
tasks.test.finalizedBy archiveTests
THE CODE
We define the copy parameters
End of build.gradle
task archiveTests (type: Copy) {
from "$reportsDir/reports"
into "$projectDir/reports/report-${currentTimeMillis()}"
}
tasks.test.finalizedBy archiveTests
THE CODE
We define the copy parameters
This is the versioningEnd of build.gradle
task archiveTests (type: Copy) {
from "$reportsDir/reports"
into "$projectDir/reports/report-${currentTimeMillis()}"
}
tasks.test.finalizedBy archiveTests
THE CODE
We ask to run it after test task
End of build.gradle
BUILD A PLUGIN03

 for real
A PLUGIN?
Use it on different projects
Share it with others
Keep your build script clean
Keep your build script focused
Cause’ it’s so easy!
Why a
plugin?
Is a Gradle project
Basically, a Groovy project
It contains
A build.gradle
A plugin class
A descriptor
One or several tasks
An extension
Examples
Java, Groovy, Maven, Android plugin
A PLUGIN?
The Binary
Plugin
THE ARCHITECTURE
THE ARCHITECTURE
The plugin class
THE ARCHITECTURE
The plugin class
A task
THE ARCHITECTURE
The plugin class
A task
The extension
THE ARCHITECTURE
The plugin class
A task
The extension
The descriptor
THE ARCHITECTURE
The plugin class
A task
The extension
The descriptor
The build.gradle
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//TODO create the extension
//TODO create the tasks
//TODO link the tasks to the build chain
}
}
THE CODE
The Plugin class
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//TODO create the extension
//TODO create the tasks
//TODO link the tasks to the build chain
}
}
THE CODE
The Plugin class
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//TODO create the extension
//TODO create the tasks
//TODO link the tasks to the build chain
}
}
THE CODE
The Plugin class
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//TODO create the extension
//TODO create the tasks
//TODO link the tasks to the build chain
}
}
THE CODE
The Plugin class
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//create the extension
project.extensions.create(“achivetest”,ArchiveTestPluginExtension,
project)
//create the tasks
project.task(name:“achivetest”, type:ArchiveTask){}
//link the tasks to the build chain
Task task = project.tasks.getByName(project.archivetest.task)
task.finalizedBy “achivetest”
}
}
THE CODE
The Plugin class
class ArchiveTask extends Copy {
ArchiveTask(){
from project.archivetest.from
into project.archivetest.into
}
@TaskAction
def exec() {
println "Reports copied into ${project.archivetest.into}"
}
}
THE CODE
The Task class
class ArchiveTask extends Copy {
ArchiveTask(){
from project.archivetest.from
into project.archivetest.into
}
@TaskAction
def exec() {
println "Reports copied into ${project.archivetest.into}"
}
}
THE CODE
The Task class
class ArchiveTask extends Copy {
ArchiveTask(){
from project.archivetest.from
into project.archivetest.into
}
@TaskAction
def exec() {
println "Reports copied into ${project.archivetest.into}"
}
}
THE CODE
We want a Copy task.
Use DefaultTask to implement your ownThe Task class
class ArchiveTask extends Copy {
ArchiveTask(){
from project.archivetest.from
into project.archivetest.into
}
@TaskAction
def exec() {
println "Reports copied into ${project.archivetest.into}"
}
}
THE CODE
The Task class
class ArchiveTask extends Copy {
ArchiveTask(){
from project.archivetest.from
into project.archivetest.into
}
@TaskAction
def exec() {
println "Reports copied into ${project.archivetest.into}"
}
}
THE CODE
The Task class
class ArchiveTask extends Copy {
ArchiveTask(){
from project.archivetest.from
into project.archivetest.into
}
@TaskAction
def exec() {
println "Reports copied into ${project.archivetest.into}"
}
}
THE CODE
The Task class
Here we use the
extension’s content
archivetest {
from "origin/folder"
into "destination/folder"
task "taskToLaunchCopy"
}
THE CODE
The Extension: the syntax expected
archivetest {
from "origin/folder"
into "destination/folder"
task "taskToLaunchCopy"
}
THE CODE
The Extension: the syntax expected
THE CODE
The Extension class
class ArchiveTestPluginExtension {
def from
def into
def task
ArchiveTestPluginExtension(Project project) {
from = project. reportsDir
into = project.projectDir+"/reports/report-${currentTimeMillis()}"
task = "test"
}
}
THE CODE
The Extension class
class ArchiveTestPluginExtension {
def from
def into
def task
ArchiveTestPluginExtension(Project project) {
from = project. reportsDir
into = project.projectDir+"/reports/report-${currentTimeMillis()}"
task = "test"
}
}
This is a simple POGO
THE CODE
The Extension class
class ArchiveTestPluginExtension {
def from
def into
def task
ArchiveTestPluginExtension(Project project) {
from = project.reportsDir
into = project.projectDir+"/reports/report-${currentTimeMillis()}"
task = "test"
}
}
implementation-class= main.groovy.fr.eyal.ArchiveTestPlugin
THE CODE
The Descriptor: achivetest.properties
implementation-class=main.groovy.fr.eyal.ArchiveTestPlugin
THE CODE
The name of this file implies
apply plugin: “archivetest”
The Descriptor: achivetest.properties
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
...
THE CODE
The build.gradle (1/2)
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
...
THE CODE
The build.gradle (1/2) A plugin is a groovy project
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
...
THE CODE
The build.gradle (1/2)
Add a gradle API dependency corresponding
to the gradle version used to compile the
project
apply plugin: 'groovy'
dependencies {
compile gradleApi()
compile localGroovy()
}
...
THE CODE
The build.gradle (1/2)
Add a groovy dependency corresponding to
the gradle version used
...
apply plugin: 'maven-publish'
group = 'fr.eyal'
version = '0.1'
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
THE CODE
The build.gradle (2/2)
...
apply plugin: 'maven-publish'
group = 'fr.eyal'
version = '0.1'
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
THE CODE
The build.gradle (2/2)
...
apply plugin: 'maven-publish'
group = 'fr.eyal'
version = '0.1'
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}
THE CODE
The build.gradle (2/2)
USE THE PLUGIN04
USE THE PLUGIN
Add the repository
Add dependency
Apply the plugin
Configure the plugin if needed
How to use
our plugin?
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'fr.eyal:archivetest:0.1'
}
}
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task “connectedAndroidTest”
}
THE CODE
The user’s build.gradle
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'fr.eyal:archivetest:0.1'
}
}
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task “connectedAndroidTest”
}
THE CODE
The user’s build.gradle
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'fr.eyal:archivetest:0.1'
}
}
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task “connectedAndroidTest”
}
THE CODE
The user’s build.gradle The local repository folder
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath ' fr.eyal:archivetest:0.1'
}
}
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task “connectedAndroidTest”
}
THE CODE
The user’s build.gradle
pom.group pom.artifactId pom.version
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'fr.eyal:archivetest:0.1'
}
}
apply plugin: ' archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task “connectedAndroidTest”
}
THE CODE
The user’s build.gradle
archivetest.properties
buildscript {
repositories {
mavenLocal()
}
dependencies {
classpath 'fr.eyal:archivetest:0.1'
}
}
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task “connectedAndroidTest”
}
THE CODE
The user’s build.gradle
Our extension
RUN IT05
archivetest {
from "build/report"
into "/tmp/archives"
}
RUN IT
$ gradle test
archivetest {
from "build/report"
into "/tmp/archives"
}
RUN IT
$ gradle test
...
Reports copied into /home/user/project/reports/report-1422480068261
...
BUILD SUCCESSFUL
archivetest {
from "build/report"
into "/tmp/archives"
}
RUN IT
$ gradle test
...
Reports copied into /home/user/project/reports/report-1422480068261
...
BUILD SUCCESSFUL
Yay!
RUN IT
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
RUN IT
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
Copy after the hello task
RUN IT
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
Copy after the hello task
Create the hello task
$ gradle hello
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
RUN IT
RUN IT
$ gradle hello
...
BUILD SUCCESSFUL
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
No copy
RUN IT
$ gradle hello
...
BUILD SUCCESSFUL
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
Oh no...
To figure out
you have to
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
DEBUG IT
The user’s build.gradle
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
DEBUG IT
The user’s build.gradle
Call apply() on ArchiveTestPlugin
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
DEBUG IT
The user’s build.gradle
Call apply() on ArchiveTestPlugin
- Create the extension
- archivetest.task = "test"
- Create the copy task
- Finalize archivetest.task by achivetest task
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
DEBUG IT
The user’s build.gradle
Modify the extension content
- archivetest.task = "hello"
Call apply() on ArchiveTestPlugin
- Create the extension
- archivetest.task = "test"
- Create the copy task
- Finalize archivetest.task by achivetest task
apply plugin: 'archivetest'
archivetest {
from "build/report"
into "/tmp/archives"
task "hello"
}
task hello << {
println "Sample task"
}
DEBUG IT
The user’s build.gradle
Call apply() on ArchiveTestPlugin
Create the hello task
- Create the extension
- archivetest.task = "test"
- Create the copy task
- Finalize archivetest.task by achivetest task
Modify the extension content
- archivetest.task = "hello"
THE TASK GRAPH
THE TASK GRAPH
Created by Java/Groovy plugin
test
THE TASK GRAPH
Created by archivetest plugin
test test
archive
test
THE TASK GRAPH
‘test’ finalized by ‘archivetest’
test test
archive
test
THE TASK GRAPH
test test
archive
test
test
archive
test
Created by build.gradle
hello
THE TASK GRAPH
test
archive
test
hello Launch hello
THE TASK GRAPH
test
archive
test
hello Launch hello
THE TASK GRAPH
test
archive
test
hello Launch hello
THE TASK GRAPH
test
archive
test
hello Launch hello
No link to our copy task
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//create the extension
project.extensions.create(“achivetest”,ArchiveTestPluginExtension,
project)
//create the tasks
project.task(name:“achivetest”, type:ArchiveTask){}
//link the tasks to the build chain
Task task = project.tasks.getByName(project.archivetest.task)
task.finalizedBy “achivetest”
}
}
DEBUG IT
The Plugin class
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
//create the extension
project.extensions.create(“achivetest”,ArchiveTestPluginExtension,
project)
//create the tasks
project.task(name:“achivetest”, type:ArchiveTask){}
//link the tasks to the build chain
Task task = project.tasks.getByName(project.archivetest.task)
task.finalizedBy “achivetest”
}
}
DEBUG IT
The Plugin class
Executed too early
DEBUG IT
Initialization
Choose project(s) to build
Configuration
Execute build.gradle
Build task graph
Execution
Execute tasks chain
Gradle
build
lifecylcle
DEBUG IT
Project evaluation
beforeEvaluate
afterEvaluate
Task Graph
whenTaskAdded
whenReady
beforeTask
afterTask
The
lifecycle
events
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
...
//link the tasks to the build chain
Task task = project.tasks.getByName(project.archivetest.task)
task.finalizedBy “achivetest”
}
}
DEBUG IT
The Plugin class
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
...
//link the tasks to the build chain
project.afterEvaluate {
Task task = project.tasks.getByName(project.archivetest.task)
task.finalizedBy “achivetest”
}
}
}
DEBUG IT
The Plugin class
We add the task after the evaluation
THE TASK GRAPH
test
archive
test
hello
THE TASK GRAPH
test
archive
test
hello
Yay!
TEST IT06
Very simple
As simple as Groovy is
Groovy is your best friend
A language very easy to mock
Junit & co
As anybody knows
TEST IT
Gradle
project
testing
ProjectBuilder
To create a mock project
Evaluate
To execute your mocked build script
A few
specificities
TEST IT
TEST IT
TEST IT
Adding a test class
TEST IT
Adding a test class
Adding junit dependency
TEST IT
Our buid.gradle
...
repositories {
jcenter()
}
dependencies {
testCompile 'junit:junit:4.11'
}
...
TEST IT
Our buid.gradle
...
repositories {
jcenter()
}
dependencies {
testCompile 'junit:junit:4.11'
}
...
Adding maven central repository
TEST IT
Our buid.gradle
...
repositories {
jcenter()
}
dependencies {
testCompile 'junit:junit:4.11'
}
...
Adding junit as testing dependency
Now, test the
extension
TEST IT
Your first test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTestExtension() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.archivetest instanceof ArchiveTestPluginExtension
}
}
TEST IT
Your first test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTestExtension() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.archivetest instanceof ArchiveTestPluginExtension
}
}
Mock a Gradle project
TEST IT
Your first test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTestExtension() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.archivetest instanceof ArchiveTestPluginExtension
}
}
Apply Java plugin
To create ‘test’ task
TEST IT
Your first test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTestExtension() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.archivetest instanceof ArchiveTestPluginExtension
}
}
Apply our plugin
TEST IT
Your first test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTestExtension() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.archivetest instanceof ArchiveTestPluginExtension
}
}
Test our extension exists
Now, test
the task
TEST IT
Your second test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTask() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.tasks.archivetest instanceof ArchiveTask
}
}
We initialize our project
TEST IT
Your second test!
class ArchiveTestPluginTest {
@Test
public void canAddArchiveTask() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
assert project.tasks.archivetest instanceof ArchiveTask
}
}
We test the task
TEST IT
Run your second test
$ gradle test --stacktrace --debug
TEST IT
Run your second test
$ gradle test --stacktrace --debug
...
test.groovy.fr.eyal.ArchiveTestPluginTest > canAddArchiveTask FAILED
MissingPropertyException: Could not find property 'archivetest' on task set
...
BUILD FAILED
TEST IT
Run your second test
$ gradle test --stacktrace --debug
...
test.groovy.fr.eyal.ArchiveTestPluginTest > canAddArchiveTask FAILED
MissingPropertyException: Could not find property 'archivetest' on task set
...
BUILD FAILED
Our task is not created
class ArchiveTestsPlugin implements Plugin<Project> {
void apply(Project project) {
...
project.afterEvaluate {
//create the tasks
project.task(name:“achivetest”, type:ArchiveTask){}
//inject the task
Task task = project.tasks.getByName(project.archivetest.task)
task.finalizedBy “achivetest”
}
}
}
TEST IT
The Plugin class
Tasks are often created after project.
evaluate()
So, evaluate.
TEST IT
Your first test!
class ArchiveTestPluginTest {
@Test
void canAddArchiveTask() {
Project project = ProjectBuilder.builder().build()
project.apply plugin: 'java'
project.apply plugin: 'archivetest'
project.evaluate()
assert project.tasks.archivetest instanceof ArchiveTask
}
} We launch evaluate() on the project
TEST IT
Run your second test
$ gradle test --stacktrace --debug
TEST IT
Run your second test
$ gradle test --stacktrace --debug
...
BUILD SUCCESSFUL
TEST IT
Run your second test
$ gradle test --stacktrace --debug
...
BUILD SUCCESSFUL
Yay!
TEST IT
LUKE DALEY
Gradleware Principal Engineer
GRADLE FORUM
You don't see this in the API docs for Project
because it is an internal method and is therefore
potentially subject to change in future releases.
There will be a supported mechanism for doing this
kind of thing in the near future.
”
“
TEST IT
LUKE DALEY
Gradleware Principal Engineer
GRADLE FORUM
You don't see this in the API docs for Project
because it is an internal method and is therefore
potentially subject to change in future releases.
There will be a supported mechanism for doing this
kind of thing in the near future.
June 2011
”
“
IMPROVE IT07
Plugin Base Java
vs. Plugin Java
Defines what is a test task
tasks.withType(Test)
IMPROVE IT
Convention
over
Configuration
Avoid running useless tasks
UP-TO-DATE
Declare Inputs
@Input, @InputFile, @InputFiles, @InputDirectory
Declare outputs
@OutputFile, @OutputDirectory
IMPROVE IT
Incremental
builds
More flexibility of annotations
@InputFile String filePath
@InputDirectory String directoryPath
...
IMPROVE IT
Coming
soon
OnlyIf
Conditional task execution
IMPROVE IT
Tweaking
Execution
Graph
ArchiveTask() {
onlyIf {
!parent.state.skipped
}
}
IMPROVE IT
Gradle Plugin documentation
https://gradle.org/documentation
References
SLIDES
http://bit.ly/gradle-plugin-devoxx
Thank you!

Weitere Àhnliche Inhalte

Was ist angesagt?

An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersKostas Saidis
 
Gradle 3.0: Unleash the Daemon!
Gradle 3.0: Unleash the Daemon!Gradle 3.0: Unleash the Daemon!
Gradle 3.0: Unleash the Daemon!Eric Wendelin
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingSchalk Cronjé
 
Gradle by Example
Gradle by ExampleGradle by Example
Gradle by ExampleEric Wendelin
 
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
Gradle build tool that rocks with DSL JavaOne India 4th May 2012Gradle build tool that rocks with DSL JavaOne India 4th May 2012
Gradle build tool that rocks with DSL JavaOne India 4th May 2012Rajmahendra Hegde
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingSchalk Cronjé
 
Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Joachim Baumann
 
Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!Corneil du Plessis
 
Gradle,the new build system for android
Gradle,the new build system for androidGradle,the new build system for android
Gradle,the new build system for androidzhang ghui
 
Gradle - time for another build
Gradle - time for another buildGradle - time for another build
Gradle - time for another buildIgor Khotin
 
うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-
うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-
うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-kyon mm
 
Building Grails Plugins - Tips And Tricks
Building Grails Plugins - Tips And TricksBuilding Grails Plugins - Tips And Tricks
Building Grails Plugins - Tips And TricksMike Hugo
 
Exploring the power of Gradle in android studio - Basics & Beyond
Exploring the power of Gradle in android studio - Basics & BeyondExploring the power of Gradle in android studio - Basics & Beyond
Exploring the power of Gradle in android studio - Basics & BeyondKaushal Dhruw
 
0900 learning-react
0900 learning-react0900 learning-react
0900 learning-reactRohitYadav696
 
react.pdf
react.pdfreact.pdf
react.pdfyihunie2
 

Was ist angesagt? (20)

An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java Developers
 
Gradle presentation
Gradle presentationGradle presentation
Gradle presentation
 
Gradle : An introduction
Gradle : An introduction Gradle : An introduction
Gradle : An introduction
 
Gradle 3.0: Unleash the Daemon!
Gradle 3.0: Unleash the Daemon!Gradle 3.0: Unleash the Daemon!
Gradle 3.0: Unleash the Daemon!
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Gradle by Example
Gradle by ExampleGradle by Example
Gradle by Example
 
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
Gradle build tool that rocks with DSL JavaOne India 4th May 2012Gradle build tool that rocks with DSL JavaOne India 4th May 2012
Gradle build tool that rocks with DSL JavaOne India 4th May 2012
 
Building with Gradle
Building with GradleBuilding with Gradle
Building with Gradle
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)Gradle For Beginners (Serbian Developer Conference 2013 english)
Gradle For Beginners (Serbian Developer Conference 2013 english)
 
Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!Gradle: The Build System you have been waiting for!
Gradle: The Build System you have been waiting for!
 
Gradle,the new build system for android
Gradle,the new build system for androidGradle,the new build system for android
Gradle,the new build system for android
 
Android presentation - Gradle ++
Android presentation - Gradle ++Android presentation - Gradle ++
Android presentation - Gradle ++
 
Gradle - time for another build
Gradle - time for another buildGradle - time for another build
Gradle - time for another build
 
Hands on the Gradle
Hands on the GradleHands on the Gradle
Hands on the Gradle
 
うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-
うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-
うさぎ甄 in G* WorkShop -ă†ă•ăżăżăźæ—„ćžž-
 
Building Grails Plugins - Tips And Tricks
Building Grails Plugins - Tips And TricksBuilding Grails Plugins - Tips And Tricks
Building Grails Plugins - Tips And Tricks
 
Exploring the power of Gradle in android studio - Basics & Beyond
Exploring the power of Gradle in android studio - Basics & BeyondExploring the power of Gradle in android studio - Basics & Beyond
Exploring the power of Gradle in android studio - Basics & Beyond
 
0900 learning-react
0900 learning-react0900 learning-react
0900 learning-react
 
react.pdf
react.pdfreact.pdf
react.pdf
 

Andere mochten auch

Secure your Android app- fight the leaks!
Secure your Android app- fight the leaks!Secure your Android app- fight the leaks!
Secure your Android app- fight the leaks!Eyal Lezmy
 
PlayStore bashing: learn from the biggest fails on the Google Play Store
PlayStore bashing: learn from the biggest fails on the Google Play StorePlayStore bashing: learn from the biggest fails on the Google Play Store
PlayStore bashing: learn from the biggest fails on the Google Play StoreEyal Lezmy
 
Android, the life of your app
Android, the life of your appAndroid, the life of your app
Android, the life of your appEyal Lezmy
 
Build a user experience on Android
Build a user experience on AndroidBuild a user experience on Android
Build a user experience on AndroidEyal Lezmy
 
Android mit Google Befreiung, PlayStore Apps im eigenen Repo
Android mit Google Befreiung, PlayStore Apps im eigenen RepoAndroid mit Google Befreiung, PlayStore Apps im eigenen Repo
Android mit Google Befreiung, PlayStore Apps im eigenen RepoB1 Systems GmbH
 
Hype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerHype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerLuminary Labs
 

Andere mochten auch (6)

Secure your Android app- fight the leaks!
Secure your Android app- fight the leaks!Secure your Android app- fight the leaks!
Secure your Android app- fight the leaks!
 
PlayStore bashing: learn from the biggest fails on the Google Play Store
PlayStore bashing: learn from the biggest fails on the Google Play StorePlayStore bashing: learn from the biggest fails on the Google Play Store
PlayStore bashing: learn from the biggest fails on the Google Play Store
 
Android, the life of your app
Android, the life of your appAndroid, the life of your app
Android, the life of your app
 
Build a user experience on Android
Build a user experience on AndroidBuild a user experience on Android
Build a user experience on Android
 
Android mit Google Befreiung, PlayStore Apps im eigenen Repo
Android mit Google Befreiung, PlayStore Apps im eigenen RepoAndroid mit Google Befreiung, PlayStore Apps im eigenen Repo
Android mit Google Befreiung, PlayStore Apps im eigenen Repo
 
Hype vs. Reality: The AI Explainer
Hype vs. Reality: The AI ExplainerHype vs. Reality: The AI Explainer
Hype vs. Reality: The AI Explainer
 

Ähnlich wie Gradle plugin, take control of the build

Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writingSchalk Cronjé
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingSchalk Cronjé
 
Basic Gradle Plugin Writing
Basic Gradle Plugin WritingBasic Gradle Plugin Writing
Basic Gradle Plugin WritingSchalk Cronjé
 
Apache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolboxApache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolboxAntoine Sabot-Durand
 
Improving your Gradle builds
Improving your Gradle buildsImproving your Gradle builds
Improving your Gradle buildsPeter Ledbrook
 
How to setup unit testing in Android Studio
How to setup unit testing in Android StudioHow to setup unit testing in Android Studio
How to setup unit testing in Android Studiotobiaspreuss
 
Szczepan.faber.gradle
Szczepan.faber.gradleSzczepan.faber.gradle
Szczepan.faber.gradlemagda3695
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using SwiftDiego Freniche Brito
 
Anatomy of a Gradle plugin
Anatomy of a Gradle pluginAnatomy of a Gradle plugin
Anatomy of a Gradle pluginDmytro Zaitsev
 
Idiomatic Gradle Plugin Writing - GradleSummit 2016
Idiomatic Gradle Plugin Writing - GradleSummit 2016Idiomatic Gradle Plugin Writing - GradleSummit 2016
Idiomatic Gradle Plugin Writing - GradleSummit 2016Schalk Cronjé
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with GradleRyan Cuprak
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with GradleRyan Cuprak
 
Gradle - Build system evolved
Gradle - Build system evolvedGradle - Build system evolved
Gradle - Build system evolvedBhagwat Kumar
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle BuildAndres Almiray
 
Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestSeb Rose
 
Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Mastering the NDK with Android Studio 2.0 and the gradle-experimental pluginMastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Mastering the NDK with Android Studio 2.0 and the gradle-experimental pluginXavier Hallade
 
BMO - Intelligent Projects with Maven
BMO - Intelligent Projects with MavenBMO - Intelligent Projects with Maven
BMO - Intelligent Projects with MavenMert ÇalÄ±ĆŸkan
 
An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbtFabio Fumarola
 

Ähnlich wie Gradle plugin, take control of the build (20)

Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writing
 
Idiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin WritingIdiomatic Gradle Plugin Writing
Idiomatic Gradle Plugin Writing
 
GradleFX
GradleFXGradleFX
GradleFX
 
Basic Gradle Plugin Writing
Basic Gradle Plugin WritingBasic Gradle Plugin Writing
Basic Gradle Plugin Writing
 
Apache DeltaSpike: The CDI Toolbox
Apache DeltaSpike: The CDI ToolboxApache DeltaSpike: The CDI Toolbox
Apache DeltaSpike: The CDI Toolbox
 
Apache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolboxApache DeltaSpike the CDI toolbox
Apache DeltaSpike the CDI toolbox
 
Improving your Gradle builds
Improving your Gradle buildsImproving your Gradle builds
Improving your Gradle builds
 
How to setup unit testing in Android Studio
How to setup unit testing in Android StudioHow to setup unit testing in Android Studio
How to setup unit testing in Android Studio
 
Szczepan.faber.gradle
Szczepan.faber.gradleSzczepan.faber.gradle
Szczepan.faber.gradle
 
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides:  Let's build macOS CLI Utilities using SwiftMobileConf 2021 Slides:  Let's build macOS CLI Utilities using Swift
MobileConf 2021 Slides: Let's build macOS CLI Utilities using Swift
 
Anatomy of a Gradle plugin
Anatomy of a Gradle pluginAnatomy of a Gradle plugin
Anatomy of a Gradle plugin
 
Idiomatic Gradle Plugin Writing - GradleSummit 2016
Idiomatic Gradle Plugin Writing - GradleSummit 2016Idiomatic Gradle Plugin Writing - GradleSummit 2016
Idiomatic Gradle Plugin Writing - GradleSummit 2016
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with Gradle
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with Gradle
 
Gradle - Build system evolved
Gradle - Build system evolvedGradle - Build system evolved
Gradle - Build system evolved
 
Making the Most of Your Gradle Build
Making the Most of Your Gradle BuildMaking the Most of Your Gradle Build
Making the Most of Your Gradle Build
 
Stopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under TestStopping the Rot - Putting Legacy C++ Under Test
Stopping the Rot - Putting Legacy C++ Under Test
 
Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Mastering the NDK with Android Studio 2.0 and the gradle-experimental pluginMastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
 
BMO - Intelligent Projects with Maven
BMO - Intelligent Projects with MavenBMO - Intelligent Projects with Maven
BMO - Intelligent Projects with Maven
 
An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbt
 

KĂŒrzlich hochgeladen

Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfryanfarris8
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ
 
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïžcall girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïžDelhi Call girls
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024Mind IT Systems
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is insideshinachiaurasa2
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïžcall girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïžDelhi Call girls
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedDelhi Call girls
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456KiaraTiradoMicha
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto GonzĂĄlez Trastoy
 

KĂŒrzlich hochgeladen (20)

Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïžcall girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïžcall girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
call girls in Vaishali (Ghaziabad) 🔝 >àŒ’8448380779 🔝 genuine Escort Service đŸ”âœ”ïžâœ”ïž
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 

Gradle plugin, take control of the build

  • 5. A dependency management engine A dependency based execution system A plugin system A set of plugins DEFINITIONS What is Gradle? by Luke Daley, Gradle core developer
  • 6. Build scripts Your build.gradle file Script plugins The customization you start writing Binary plugins The code I want you to write DEFINITIONS Gradle Plugins Types
  • 7. Is a piece of work for a build Compiling a class, generating javadoc, ... Can be manipulated doFirst, doLast Can inherit from another type Can depend on another task dependsOn, finalizedBy DEFINITIONS The Gradle Task
  • 9. Your unit tests results, you have to version THE SUBJECT
  • 10. THE JOB Copy and version this folder
  • 11. task archiveTests (type: Copy) { from "$reportsDir/reports" into "$projectDir/reports/report-${currentTimeMillis()}" } tasks.test.finalizedBy archiveTests THE CODE End of build.gradle
  • 12. task archiveTests (type: Copy) { from "$reportsDir/reports" into "$projectDir/reports/report-${currentTimeMillis()}" } tasks.test.finalizedBy archiveTests THE CODE We create the task End of build.gradle
  • 13. task archiveTests (type: Copy) { from "$reportsDir/reports" into "$projectDir/reports/report-${currentTimeMillis()}" } tasks.test.finalizedBy archiveTests THE CODE It inherits from Copy task End of build.gradle
  • 14. task archiveTests (type: Copy) { from "$reportsDir/reports" into "$projectDir/reports/report-${currentTimeMillis()}" } tasks.test.finalizedBy archiveTests THE CODE We define the copy parameters End of build.gradle
  • 15. task archiveTests (type: Copy) { from "$reportsDir/reports" into "$projectDir/reports/report-${currentTimeMillis()}" } tasks.test.finalizedBy archiveTests THE CODE We define the copy parameters This is the versioningEnd of build.gradle
  • 16. task archiveTests (type: Copy) { from "$reportsDir/reports" into "$projectDir/reports/report-${currentTimeMillis()}" } tasks.test.finalizedBy archiveTests THE CODE We ask to run it after test task End of build.gradle
  • 18. A PLUGIN? Use it on different projects Share it with others Keep your build script clean Keep your build script focused Cause’ it’s so easy! Why a plugin?
  • 19. Is a Gradle project Basically, a Groovy project It contains A build.gradle A plugin class A descriptor One or several tasks An extension Examples Java, Groovy, Maven, Android plugin A PLUGIN? The Binary Plugin
  • 23. THE ARCHITECTURE The plugin class A task The extension
  • 24. THE ARCHITECTURE The plugin class A task The extension The descriptor
  • 25. THE ARCHITECTURE The plugin class A task The extension The descriptor The build.gradle
  • 26. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //TODO create the extension //TODO create the tasks //TODO link the tasks to the build chain } } THE CODE The Plugin class
  • 27. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //TODO create the extension //TODO create the tasks //TODO link the tasks to the build chain } } THE CODE The Plugin class
  • 28. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //TODO create the extension //TODO create the tasks //TODO link the tasks to the build chain } } THE CODE The Plugin class
  • 29. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //TODO create the extension //TODO create the tasks //TODO link the tasks to the build chain } } THE CODE The Plugin class
  • 30. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //create the extension project.extensions.create(“achivetest”,ArchiveTestPluginExtension, project) //create the tasks project.task(name:“achivetest”, type:ArchiveTask){} //link the tasks to the build chain Task task = project.tasks.getByName(project.archivetest.task) task.finalizedBy “achivetest” } } THE CODE The Plugin class
  • 31. class ArchiveTask extends Copy { ArchiveTask(){ from project.archivetest.from into project.archivetest.into } @TaskAction def exec() { println "Reports copied into ${project.archivetest.into}" } } THE CODE The Task class
  • 32. class ArchiveTask extends Copy { ArchiveTask(){ from project.archivetest.from into project.archivetest.into } @TaskAction def exec() { println "Reports copied into ${project.archivetest.into}" } } THE CODE The Task class
  • 33. class ArchiveTask extends Copy { ArchiveTask(){ from project.archivetest.from into project.archivetest.into } @TaskAction def exec() { println "Reports copied into ${project.archivetest.into}" } } THE CODE We want a Copy task. Use DefaultTask to implement your ownThe Task class
  • 34. class ArchiveTask extends Copy { ArchiveTask(){ from project.archivetest.from into project.archivetest.into } @TaskAction def exec() { println "Reports copied into ${project.archivetest.into}" } } THE CODE The Task class
  • 35. class ArchiveTask extends Copy { ArchiveTask(){ from project.archivetest.from into project.archivetest.into } @TaskAction def exec() { println "Reports copied into ${project.archivetest.into}" } } THE CODE The Task class
  • 36. class ArchiveTask extends Copy { ArchiveTask(){ from project.archivetest.from into project.archivetest.into } @TaskAction def exec() { println "Reports copied into ${project.archivetest.into}" } } THE CODE The Task class Here we use the extension’s content
  • 37. archivetest { from "origin/folder" into "destination/folder" task "taskToLaunchCopy" } THE CODE The Extension: the syntax expected
  • 38. archivetest { from "origin/folder" into "destination/folder" task "taskToLaunchCopy" } THE CODE The Extension: the syntax expected
  • 39. THE CODE The Extension class class ArchiveTestPluginExtension { def from def into def task ArchiveTestPluginExtension(Project project) { from = project. reportsDir into = project.projectDir+"/reports/report-${currentTimeMillis()}" task = "test" } }
  • 40. THE CODE The Extension class class ArchiveTestPluginExtension { def from def into def task ArchiveTestPluginExtension(Project project) { from = project. reportsDir into = project.projectDir+"/reports/report-${currentTimeMillis()}" task = "test" } } This is a simple POGO
  • 41. THE CODE The Extension class class ArchiveTestPluginExtension { def from def into def task ArchiveTestPluginExtension(Project project) { from = project.reportsDir into = project.projectDir+"/reports/report-${currentTimeMillis()}" task = "test" } }
  • 43. implementation-class=main.groovy.fr.eyal.ArchiveTestPlugin THE CODE The name of this file implies apply plugin: “archivetest” The Descriptor: achivetest.properties
  • 44. apply plugin: 'groovy' dependencies { compile gradleApi() compile localGroovy() } ... THE CODE The build.gradle (1/2)
  • 45. apply plugin: 'groovy' dependencies { compile gradleApi() compile localGroovy() } ... THE CODE The build.gradle (1/2) A plugin is a groovy project
  • 46. apply plugin: 'groovy' dependencies { compile gradleApi() compile localGroovy() } ... THE CODE The build.gradle (1/2) Add a gradle API dependency corresponding to the gradle version used to compile the project
  • 47. apply plugin: 'groovy' dependencies { compile gradleApi() compile localGroovy() } ... THE CODE The build.gradle (1/2) Add a groovy dependency corresponding to the gradle version used
  • 48. ... apply plugin: 'maven-publish' group = 'fr.eyal' version = '0.1' publishing { publications { mavenJava(MavenPublication) { from components.java } } } THE CODE The build.gradle (2/2)
  • 49. ... apply plugin: 'maven-publish' group = 'fr.eyal' version = '0.1' publishing { publications { mavenJava(MavenPublication) { from components.java } } } THE CODE The build.gradle (2/2)
  • 50. ... apply plugin: 'maven-publish' group = 'fr.eyal' version = '0.1' publishing { publications { mavenJava(MavenPublication) { from components.java } } } THE CODE The build.gradle (2/2)
  • 52. USE THE PLUGIN Add the repository Add dependency Apply the plugin Configure the plugin if needed How to use our plugin?
  • 53. buildscript { repositories { mavenLocal() } dependencies { classpath 'fr.eyal:archivetest:0.1' } } apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task “connectedAndroidTest” } THE CODE The user’s build.gradle
  • 54. buildscript { repositories { mavenLocal() } dependencies { classpath 'fr.eyal:archivetest:0.1' } } apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task “connectedAndroidTest” } THE CODE The user’s build.gradle
  • 55. buildscript { repositories { mavenLocal() } dependencies { classpath 'fr.eyal:archivetest:0.1' } } apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task “connectedAndroidTest” } THE CODE The user’s build.gradle The local repository folder
  • 56. buildscript { repositories { mavenLocal() } dependencies { classpath ' fr.eyal:archivetest:0.1' } } apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task “connectedAndroidTest” } THE CODE The user’s build.gradle pom.group pom.artifactId pom.version
  • 57. buildscript { repositories { mavenLocal() } dependencies { classpath 'fr.eyal:archivetest:0.1' } } apply plugin: ' archivetest' archivetest { from "build/report" into "/tmp/archives" task “connectedAndroidTest” } THE CODE The user’s build.gradle archivetest.properties
  • 58. buildscript { repositories { mavenLocal() } dependencies { classpath 'fr.eyal:archivetest:0.1' } } apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task “connectedAndroidTest” } THE CODE The user’s build.gradle Our extension
  • 60. archivetest { from "build/report" into "/tmp/archives" } RUN IT $ gradle test
  • 61. archivetest { from "build/report" into "/tmp/archives" } RUN IT $ gradle test ... Reports copied into /home/user/project/reports/report-1422480068261 ... BUILD SUCCESSFUL
  • 62. archivetest { from "build/report" into "/tmp/archives" } RUN IT $ gradle test ... Reports copied into /home/user/project/reports/report-1422480068261 ... BUILD SUCCESSFUL Yay!
  • 63. RUN IT archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" }
  • 64. RUN IT archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } Copy after the hello task
  • 65. RUN IT archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } Copy after the hello task Create the hello task
  • 66. $ gradle hello archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } RUN IT
  • 67. RUN IT $ gradle hello ... BUILD SUCCESSFUL archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } No copy
  • 68. RUN IT $ gradle hello ... BUILD SUCCESSFUL archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } Oh no...
  • 69. To figure out you have to
  • 70. apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } DEBUG IT The user’s build.gradle
  • 71. apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } DEBUG IT The user’s build.gradle Call apply() on ArchiveTestPlugin
  • 72. apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } DEBUG IT The user’s build.gradle Call apply() on ArchiveTestPlugin - Create the extension - archivetest.task = "test" - Create the copy task - Finalize archivetest.task by achivetest task
  • 73. apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } DEBUG IT The user’s build.gradle Modify the extension content - archivetest.task = "hello" Call apply() on ArchiveTestPlugin - Create the extension - archivetest.task = "test" - Create the copy task - Finalize archivetest.task by achivetest task
  • 74. apply plugin: 'archivetest' archivetest { from "build/report" into "/tmp/archives" task "hello" } task hello << { println "Sample task" } DEBUG IT The user’s build.gradle Call apply() on ArchiveTestPlugin Create the hello task - Create the extension - archivetest.task = "test" - Create the copy task - Finalize archivetest.task by achivetest task Modify the extension content - archivetest.task = "hello"
  • 76. THE TASK GRAPH Created by Java/Groovy plugin test
  • 77. THE TASK GRAPH Created by archivetest plugin test test archive test
  • 78. THE TASK GRAPH ‘test’ finalized by ‘archivetest’ test test archive test
  • 79. THE TASK GRAPH test test archive test test archive test Created by build.gradle hello
  • 83. THE TASK GRAPH test archive test hello Launch hello No link to our copy task
  • 84. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //create the extension project.extensions.create(“achivetest”,ArchiveTestPluginExtension, project) //create the tasks project.task(name:“achivetest”, type:ArchiveTask){} //link the tasks to the build chain Task task = project.tasks.getByName(project.archivetest.task) task.finalizedBy “achivetest” } } DEBUG IT The Plugin class
  • 85. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { //create the extension project.extensions.create(“achivetest”,ArchiveTestPluginExtension, project) //create the tasks project.task(name:“achivetest”, type:ArchiveTask){} //link the tasks to the build chain Task task = project.tasks.getByName(project.archivetest.task) task.finalizedBy “achivetest” } } DEBUG IT The Plugin class Executed too early
  • 86. DEBUG IT Initialization Choose project(s) to build Configuration Execute build.gradle Build task graph Execution Execute tasks chain Gradle build lifecylcle
  • 87. DEBUG IT Project evaluation beforeEvaluate afterEvaluate Task Graph whenTaskAdded whenReady beforeTask afterTask The lifecycle events
  • 88. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { ... //link the tasks to the build chain Task task = project.tasks.getByName(project.archivetest.task) task.finalizedBy “achivetest” } } DEBUG IT The Plugin class
  • 89. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { ... //link the tasks to the build chain project.afterEvaluate { Task task = project.tasks.getByName(project.archivetest.task) task.finalizedBy “achivetest” } } } DEBUG IT The Plugin class We add the task after the evaluation
  • 93. Very simple As simple as Groovy is Groovy is your best friend A language very easy to mock Junit & co As anybody knows TEST IT Gradle project testing
  • 94. ProjectBuilder To create a mock project Evaluate To execute your mocked build script A few specificities TEST IT
  • 96. TEST IT Adding a test class
  • 97. TEST IT Adding a test class Adding junit dependency
  • 98. TEST IT Our buid.gradle ... repositories { jcenter() } dependencies { testCompile 'junit:junit:4.11' } ...
  • 99. TEST IT Our buid.gradle ... repositories { jcenter() } dependencies { testCompile 'junit:junit:4.11' } ... Adding maven central repository
  • 100. TEST IT Our buid.gradle ... repositories { jcenter() } dependencies { testCompile 'junit:junit:4.11' } ... Adding junit as testing dependency
  • 102. TEST IT Your first test! class ArchiveTestPluginTest { @Test public void canAddArchiveTestExtension() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.archivetest instanceof ArchiveTestPluginExtension } }
  • 103. TEST IT Your first test! class ArchiveTestPluginTest { @Test public void canAddArchiveTestExtension() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.archivetest instanceof ArchiveTestPluginExtension } } Mock a Gradle project
  • 104. TEST IT Your first test! class ArchiveTestPluginTest { @Test public void canAddArchiveTestExtension() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.archivetest instanceof ArchiveTestPluginExtension } } Apply Java plugin To create ‘test’ task
  • 105. TEST IT Your first test! class ArchiveTestPluginTest { @Test public void canAddArchiveTestExtension() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.archivetest instanceof ArchiveTestPluginExtension } } Apply our plugin
  • 106. TEST IT Your first test! class ArchiveTestPluginTest { @Test public void canAddArchiveTestExtension() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.archivetest instanceof ArchiveTestPluginExtension } } Test our extension exists
  • 108. TEST IT Your second test! class ArchiveTestPluginTest { @Test public void canAddArchiveTask() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.tasks.archivetest instanceof ArchiveTask } } We initialize our project
  • 109. TEST IT Your second test! class ArchiveTestPluginTest { @Test public void canAddArchiveTask() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' assert project.tasks.archivetest instanceof ArchiveTask } } We test the task
  • 110. TEST IT Run your second test $ gradle test --stacktrace --debug
  • 111. TEST IT Run your second test $ gradle test --stacktrace --debug ... test.groovy.fr.eyal.ArchiveTestPluginTest > canAddArchiveTask FAILED MissingPropertyException: Could not find property 'archivetest' on task set ... BUILD FAILED
  • 112. TEST IT Run your second test $ gradle test --stacktrace --debug ... test.groovy.fr.eyal.ArchiveTestPluginTest > canAddArchiveTask FAILED MissingPropertyException: Could not find property 'archivetest' on task set ... BUILD FAILED Our task is not created
  • 113. class ArchiveTestsPlugin implements Plugin<Project> { void apply(Project project) { ... project.afterEvaluate { //create the tasks project.task(name:“achivetest”, type:ArchiveTask){} //inject the task Task task = project.tasks.getByName(project.archivetest.task) task.finalizedBy “achivetest” } } } TEST IT The Plugin class Tasks are often created after project. evaluate()
  • 115. TEST IT Your first test! class ArchiveTestPluginTest { @Test void canAddArchiveTask() { Project project = ProjectBuilder.builder().build() project.apply plugin: 'java' project.apply plugin: 'archivetest' project.evaluate() assert project.tasks.archivetest instanceof ArchiveTask } } We launch evaluate() on the project
  • 116. TEST IT Run your second test $ gradle test --stacktrace --debug
  • 117. TEST IT Run your second test $ gradle test --stacktrace --debug ... BUILD SUCCESSFUL
  • 118. TEST IT Run your second test $ gradle test --stacktrace --debug ... BUILD SUCCESSFUL Yay!
  • 119. TEST IT LUKE DALEY Gradleware Principal Engineer GRADLE FORUM You don't see this in the API docs for Project because it is an internal method and is therefore potentially subject to change in future releases. There will be a supported mechanism for doing this kind of thing in the near future. ” “
  • 120. TEST IT LUKE DALEY Gradleware Principal Engineer GRADLE FORUM You don't see this in the API docs for Project because it is an internal method and is therefore potentially subject to change in future releases. There will be a supported mechanism for doing this kind of thing in the near future. June 2011 ” “
  • 122. Plugin Base Java vs. Plugin Java Defines what is a test task tasks.withType(Test) IMPROVE IT Convention over Configuration
  • 123. Avoid running useless tasks UP-TO-DATE Declare Inputs @Input, @InputFile, @InputFiles, @InputDirectory Declare outputs @OutputFile, @OutputDirectory IMPROVE IT Incremental builds
  • 124. More flexibility of annotations @InputFile String filePath @InputDirectory String directoryPath ... IMPROVE IT Coming soon
  • 125. OnlyIf Conditional task execution IMPROVE IT Tweaking Execution Graph