NormandyJUG
        20 octobre 2009
           Builders Battle
Maven / Ivy / Ant / Gradle / EasyAnt ...
Grégory Boissinot
• Committer Hudson depuis 2008

• Consultant Zenika
  – Spécialiste sur les outils de build et
    l'intégration continue
  – Formateur sur l'usine logicielle
  – A mis en place Gradle chez un grand
    acteur de l'industrie
Gradle en quelque mots
•   Système de build complet et flexible à la Ant
•   Utilisation des conventions de Maven à la demande
•   Une gestion multi projet avancée
•   Utilisation de Apache Ivy comme gestionnaire de
    dépendances
    – Utilisation par API
• Support et Insertion totale dans une infrastructure
  Maven et Ivy existante
• Chaîne de build en Groovy
• Modèle de description du build très riche
Architecture
                                                                     Gradle

   CORE            UI       WRAPPER           OPEN-API         DOCS
                                                                     api

   java       groovy     maven       osgi       code-quality
   war         jetty     scala      eclipse     project-reports
                                                                  plugins


    Ant           Ivy       Maven Ant Tasks          Groovy
                                                           build tools

 checkstyle   codeNarc     webdav       other dependencies

                                                     librairies tierces
Notion de tâche
 Un script de build Gradle est défini par un
  ensemble de tâches sur lesquelle est ajouté des
  actions qui sont des closures Groovy
<!-- build.gradle -->                       Tâche
 <!-- build.gradle -->                      simple
task distribution <<{
 task distribution <<{
 println "Distribution"
   println "Distribution"
}}                                        Accès à l'API
                                             Java
task release (dependsOn: 'distribution')<<{
 task release (dependsOn: 'distribution')<<{
 println "Release"
   println "Release"
}}

>> gradle distribution      >> gradle release
                                gradle release
    gradle distribution     Distribution
Distribution
 Distribution                Distribution
                            Release
                             Release
Les tâches ont une API
                                           Tâche
Copy myCopy == task(myCopy, type:Copy)    améliorée
 Copy myCopy    task(myCopy, type:Copy)
myCopy.from(file('resources'))
 myCopy.from(file('resources'))
myCopy.into(file('target'))
 myCopy.into(file('target'))                          CustomTask
myCopy.include('**/*.txt', '**/*.xml')
 myCopy.include('**/*.txt', '**/*.xml')
task mycopy (type:Copy)
 task mycopy (type:Copy)
mycopy{                                                 Copy
 mycopy{
 description ='Copies the resources dir'
  description ='Copies the resources dir'
 from(file('resources'))
  from(file('resources'))
 into(file('target'))
  into(file('target'))
 include('**/*.txt', '**/*.xml')
  include('**/*.txt', '**/*.xml')                      mycopy
}
 }

task mycopy (type:Copy){
 task mycopy (type:Copy){
 description ='Copies the resources dir'
  description ='Copies the resources dir'
 from(file('resources'))
  from(file('resources'))
 into(file('target'))
  into(file('target'))
 include('**/*.txt', '**/*.xml')
  include('**/*.txt', '**/*.xml')
}
 }
Une API très riche
task source(type:Jar){
 task source(type:Jar){                        CustomTask
 baseName='source'
   baseName='source'
 from sourceSets.main.java
   from sourceSets.main.java
}}
                                                        Abstract
                                     SourceTask         ArchiveTask
task distrib(type:Zip){
 task distrib(type:Zip){
 dependsOn(jar)
   dependsOn(jar)
 baseName='dist'
   baseName='dist'
 from sourceSets.main.java           Javadoc              Zip
   from sourceSets.main.java
 from jar.archivePath
   from jar.archivePath
}}
                                                  Jar        Tar
task javadoc(type: Javadoc) {{
 task javadoc(type: Javadoc)
   source sourceSets.main.allJava
}}
    source sourceSets.main.allJava                War
Plusieurs tâches par défaut
<!-- build.xml -->               <!-- build.gradle -->
                                  <!-- build.gradle -->
 <!-- build.xml -->              defaultTasks 'clean',
<project default="all">           defaultTasks 'clean',
 <project default="all">                      'jar'
                                               'jar'
<target name="clean">
 <target name="clean">
 <echo message="Cleaning"/>      task clean << {{
                                  task clean <<
  <echo message="Cleaning"/>      println "Cleaning"
</target>                           println "Cleaning"
 </target>                       }}
<target name="jar">
 <target name="jar">
  <echo message="Packaging"/>    task jar << {{
                                  task jar <<
   <echo message="Packaging"/>    println "Packaging"
</target>                           println "Packaging"
 </target>                       }}
<target name="all">                             >> gradle
                                                    gradle
 <target name="all">                            Cleaning
  <antcall target="clean"/>
   <antcall target="clean"/>                     Cleaning
  <antcall target="jar"/>                       Packaging
                                                 Packaging
   <antcall target="jar"/>
</target>
 </target>
</project>
 </project>        >> ant
                       ant
                   Cleaning
                    Cleaning
                   Packaging
                    Packaging
Exécution unique et ordonnée

compile                                     dist
             compileTest
                             test


  >> ant test dist
      ant test dist        >> gradle test dist
                               gradle test dist
  compile
   compile                 :compile
                            :compile
  compileTest
   compileTest             :compileTest
                            :compileTest
  test
   test                    :test
                            :test
  compile
   compile                 :dist
                            :dist
  compileTest
   compileTest
  test
   test
  dist
   dist
Pour un projet Java/JEE
                                                                     Gradle

   CORE            UI       WRAPPER           OPEN-API         DOCS
                                                                     api

   java       groovy     maven       osgi       code-quality
   war         jetty     scala      eclipse     project-reports
                                                                  plugins


    Ant           Ivy       Maven Ant Tasks          Groovy
                                                           build tools

 checkstyle   codeNarc     webdav       other dependencies

                                                     librairies tierces
Build d'une librairie
<!-- build.gradle -->                  Configuration
 <!-- build.gradle -->
usePlugin 'java'                        accessible
 usePlugin 'java'                       sous forme
                                       de propriétés
archivesBaseName == 'core'
 archivesBaseName    'core'                            Gradle
version == '3.5'
 version    '3.5'
manifest.mainAttributes(
 manifest.mainAttributes(
 'Implementation-Version': version
   'Implementation-Version': version
))

repositories {{
 repositories
    mavenCentral()
     mavenCentral()
}}                                               core-3.5.jar
dependencies {{
 dependencies
    compile group: 'commons-collections',
     compile group: 'commons-collections',
            name: 'commons-collections',
              name: 'commons-collections',
            version: '3.2'
              version: '3.2'
    testCompile group: 'junit',
     testCompile group: 'junit',
                 name: 'junit',
                  name: 'junit',
                 version: '4.+'
                  version: '4.+'
}}                         >> gradle compileJava
                               gradle compileJava
                           >> gradle jar
                               gradle jar
Build d'une webapp
                                      WEB-INF
<!-- build.gradle -->
 <!-- build.gradle -->                optionel
usePlugin 'war'
 usePlugin 'war'
usePlugin 'jetty'
 usePlugin 'jetty'                                 Gradle
archivesBaseName == 'web'              JEE6
 archivesBaseName    'web'           compatible
version == '1.0'
 version    '1.0'
repositories {{
 repositories
    mavenCentral()
     mavenCentral()
}}

dependencies {{
 dependencies                                     web-2.4.war
    compile "commons-io:commons-io:1.4"
     compile "commons-io:commons-io:1.4"
    compile ("log4j:log4j:1.2.15"){
     compile ("log4j:log4j:1.2.15"){
     exclude(group:'javax.jms')
       exclude(group:'javax.jms')
     exclude(group:'com.sun.jdmk')
       exclude(group:'com.sun.jdmk')
     exclude(module:'jmxri')
       exclude(module:'jmxri')
    }}
}}
                           >> gradle war
                               gradle war
                           >> gradle jettyRun
                               gradle jettyRun
Phases de build
Gradle fournit 3 phases distinctes de build
• Initialisation
   – Détermine l'ensemble des projets à builder
   – Création d'un objet Projet pour chaque module
• Configuration
   – Configuration des objets Project
• Exécution
   – Exécution des tâches crées et configurés précédemment
 gradle.taskGraph.whenReady {taskGraph ->
  gradle.taskGraph.whenReady {taskGraph ->
  if (taskGraph.hasTask(':release')) {{
    if (taskGraph.hasTask(':release')) Nombreux
    version == '1.0'
     version    '1.0'
  }} else {{                             hooks
      else                             disponibles
    version == '1.0-SNAPSHOT'
     version    '1.0-SNAPSHOT'
  }}
 }}
Gradle fournit des cycles de vies (1/2)
Ensemble de tâches prédéfinies




              Exemple
            du plugin 'java'
Des conventions de répertoires
                                                             Très
                                     <!-- build.gradle -->
Gradle utilise par défaut                                 configurable
                                      <!-- build.gradle -->
                                     sourceSets{
                                      sourceSets{
 les mêmes conventions de             main{
                                        main{
                                         java {{
 répertoires que Maven                     java
                                            srcDir 'src/java'
                                             srcDir 'src/java'
                        Séparation       }}
<!-- répertoires -->
 <!-- répertoires -->     propre         resources {{
+build.gradle                              resources
 +build.gradle                              srcDir 'src/resources'
                                             srcDir 'src/resources'
+src/main/java
 +src/main/java                          }}
+src/main/resources
 +src/main/resources                    }}
+src/main/webapp
 +src/main/webapp                     main{
+src/test/java                          main{
 +src/test/java                          java {{
                                           java
+src/test/resources
 +src/test/resources                        srcDir 'src2/java'
                                             srcDir 'src2/java'
                                         }}
+build/classes
 +build/classes                          resources {{
+build/libs                                resources
 +build/libs                                srcDir 'src2/resources'
                                             srcDir 'src2/resources'
+build/reports
 +build/reports                          }}
+build/test-results
 +build/test-results                    }}
                                     }}
Gestion des dépendances avec Ivy
                                                                     Gradle

   CORE            UI       WRAPPER           OPEN-API         DOCS
                                                                     api

   java       groovy     maven       osgi       code-quality
   war         jetty     scala      eclipse     project-reports
                                                                  plugins


    Ant           Ivy       Maven Ant Tasks          Groovy
                                                           build tools

 checkstyle   codeNarc     webdav       other dependencies

                                                     librairies tierces
Gestion des dépendances

                Repository
                                                • Support complet de
                 Maven
                local/distant Artifacts +
                                                   repository Maven ou
          Ivy
                                méta Maven
                                (pom.xml)          Ivy existant
Gradle
                                                • Interaction possible
                Repository
                   Ivy                            avec un gestionnaire
                local/distant
                                  Artifacts +
                                   méta Ivy       de configuration
                                  (ivy.xml)
                                                • Gestion des
                                                  dépendances
                   VCS                            transitives
                                Artifacts +
                                méta gradle       (client module)
Définition des repositories
repositories {{
 repositories
    mavenCentral()
     mavenCentral()
    mavenRepo urls:"http://serveur/archiva/repo-group"
     mavenRepo urls:"http://serveur/archiva/repo-group"
}}

repositories {{
 repositories
      flatDir name: 'localRepository', dirs: 'lib'
       flatDir name: 'localRepository', dirs: 'lib'
}}

repositories {{
 repositories
add(
 add(
 new org.apache.ivy.plugins.resolver.FileSystemResolver()){
   new org.apache.ivy.plugins.resolver.FileSystemResolver()){
 name == 'repo'
   name   'repo'
 addArtifactPattern
   addArtifactPattern
           "$projectDir/lib/[module]_[revision].[ext]"
            "$projectDir/lib/[module]_[revision].[ext]"
   descriptor == 'optional'
    descriptor    'optional'
   checkmodified == true
    checkmodified    true
 }}
}}
Déclaration des dépendances
• Dépendances vers des modules (+deps)
  dependencies {{
   dependencies
     compile "log4j:log4j:1.2.14"
      compile "log4j:log4j:1.2.14"
     testCompile "junit:junit:4.7"
      testCompile "junit:junit:4.7"
  }}

• Dépendances vers des artefacts (-deps)
  dependencies {{
   dependencies
     runtime "org.groovy:groovy:1.5.6@jar"
      runtime "org.groovy:groovy:1.5.6@jar"
  }}

• Client modules
  dependencies {{
   dependencies
   runtime module("commons-lang:commons-lang:2.4") {{
     runtime module("commons-lang:commons-lang:2.4")
     dependency("commons-io:commons-io:1.2")
      dependency("commons-io:commons-io:1.2")     Dépendances
   }}                                         transitives sans XML
  }}
Intégration native avec Ant
                                                                     Gradle

   CORE            UI       WRAPPER           OPEN-API         DOCS
                                                                     api

   java       groovy     maven       osgi       code-quality
   war         jetty     scala      eclipse     project-reports
                                                                  plugins


    Ant           Ivy       Maven Ant Tasks          Groovy
                                                           build tools

 checkstyle   codeNarc     webdav       other dependencies

                                                     librairies tierces
Utilisation possible des tâches Ant
<!-- build.gradle -->                       Utilisation de l'objet
 <!-- build.gradle -->                      Groovy AntBuilder
task generateStub << {{
 task generateStub <<
 ant {{
  ant
  def wsdl2java_classpath == path {{
   def wsdl2java_classpath     path
   fileset(dir: 'lib') {{
     fileset(dir: 'lib')
       include(name: '*.jar')
        include(name: '*.jar')
   }}
  }}

  taskdef( name: 'axisWsdl2java',
   taskdef( name: 'axisWsdl2java',
           classname:
            classname:
      'org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask',
       'org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask',
           classpath: wsdl2java_classpath
            classpath: wsdl2java_classpath
  ))

  axisWsdl2java( output:"generated",
   axisWsdl2java( output:"generated",
                verbose:"true" ,, url:"Exemple.wsdl")
                 verbose:"true"    url:"Exemple.wsdl")
 }}
}}
Gradle et Ant: dans les deux sens (1/2)

                <!-- build.xml -->
                 <!-- build.xml -->
                <property name="src.dir" value="src">
                 <property name="src.dir" value="src">
                <target name="compile">
                 <target name="compile">
                 <echo message="Compile,from Ant"/>
                  <echo message="Compile,from Ant"/>
                </target>
                 </target>
<!-- build.gradle -->
 <!-- build.gradle -->
ant.importBuild 'build.xml'
 ant.importBuild 'build.xml'
//Complément de la tâche compile
 //Complément de la tâche compile
compile << {{
 compile <<
 println "Added compiling from Gradle"
   println "Added compiling from Gradle"
 println "SourceDir: ${ant.properties['src.dir']}"
   println "SourceDir: ${ant.properties['src.dir']}"
}}
>> gradle compile
    gradle compile
:compile
 :compile
[ant:echo] Compile, from Ant
 [ant:echo] Compile, from Ant
Added compiling from Gradle
 Added compiling from Gradle
SourceDir: src
 SourceDir: src
Gradle et Ant: dans les deux sens (2/2)

<!-- build.gradle -->
 <!-- build.gradle -->
task assemble (dependsOn: 'compile') << {{
 task assemble (dependsOn: 'compile') <<
 println 'Assemble, from Gradle'
   println 'Assemble, from Gradle'
}}

               <!-- build.xml -->
                <!-- build.xml -->
               <target name="deploy" depends="assemble">
                <target name="deploy" depends="assemble">
                  <echo message="Deploy, from Ant"/>
                   <echo message="Deploy, from Ant"/>
               </target>
                </target>
>> gradle deploy
    gradle deploy
:compile
 :compile
[ant:echo] Compile, from Ant
 [ant:echo] Compile, from Ant
Added compiling from Gradle
 Added compiling from Gradle
:assemble
 :assemble
Assemble, from Gradle
 Assemble, from Gradle
:deploy
 :deploy
[ant:echo] Deploy, from Ant
 [ant:echo] Deploy, from Ant
Gestion multi projet très avancée
                                                                     Gradle

   CORE            UI       WRAPPER           OPEN-API         DOCS
                                                                     api

   java       groovy     maven       osgi       code-quality
   war         jetty     scala      eclipse     project-reports
                                                                  plugins


    Ant           Ivy       Maven Ant Tasks          Groovy
                                                           build tools

 checkstyle   codeNarc     webdav       other dependencies

                                                     librairies tierces
Gestion multi projet (1/3)
• Les descripteurs dans les sous
                                              common jar
  modules sont optionnels
• Injection de configuration            depends     depends


• Possibilité de mettre toute la      biz-auth        pz
                                             war              war
  logique de build dans le parent

<!-- Structure de répertoires -->
 <!-- Structure de répertoires -->   <!-- settings.gradle -->
                                      <!-- settings.gradle -->
+build.gradle
 +build.gradle                       include
                                      include
+settings.gradle
 +settings.gradle                    "common",
                                      "common",
+common/
 +common/                            "pz",
                                      "pz",
+pz/
 +pz/                                "biz:auth"
                                      "biz:auth"
  +build.gradle
   +build.gradle
-biz/
 -biz/
  -- biz-auth/
      biz-auth/
Gestion multi projet (2/3)
<!-- master build.gradle -->
 <!-- master build.gradle -->                <!-- pz/build.gradle -->
                                              <!-- pz/build.gradle -->
subprojects{
 subprojects{                                usePlugin 'war'
                                              usePlugin 'war'
 usePlugin('java')
  usePlugin('java')
 group='org.jug.normandyjug'
  group='org.jug.normandyjug'                dependencies{
                                              dependencies{
 version='1.0'
  version='1.0'                               compile
                                                compile
                                                    project(':common')
                                                     project(':common')
 repositories{
  repositories{                              }}
  mavenCentral()
    mavenCentral()
 }}
 dependencies {{
  dependencies
  testCompile 'junit:junit:4.7'
    testCompile 'junit:junit:4.7'
 }}
               cross project configuration
}}
project(':biz:biz-auth'){
 project(':biz:biz-auth'){
 dependencies{
   dependencies{
   compile project(':common')
    compile project(':common')
 }}
 usePlugin 'war'
   usePlugin 'war'
}}
Gestion multi projet (3/3)
/web> gradle compileJava
 /web> gradle compileJava
:common:compileJava
 :common:compileJava
:common:processResources
 :common:processResources
:common:classes
 :common:classes
:common:jar
 :common:jar
:common:uploadDefaultInternal
 :common:uploadDefaultInternal
:pz:compileJava
 :pz:compileJava
:biz:biz-auth:compileJava
 :biz:biz-auth:compileJava

/web/biz/biz-auth> gradle compileJava
 /web/biz/biz-auth> gradle compileJava
:common:compileJava
 :common:compileJava
:common:processResources            Compilation
 :common:processResources            des projets
:common:classes
 :common:classes
:common:jar                          dépendants
 :common:jar
:common:uploadDefaultInternal
 :common:uploadDefaultInternal
:biz:biz-auth:compileJava
 :biz:biz-auth:compileJava
/web/biz/biz-auth> gradle compileJava -a
 /web/biz/biz-auth> gradle compileJava -a     Utilisation
:biz:biz-auth:compileJava
 :biz:biz-auth:compileJava                     des jars
                                             dans le cache
Gradle GUI
             • Lancé par
               > gradle –gui

             • Exécution de
               tâches

             • Paramétrage du
               niveau de log
Publie dans une infra Maven et Ivy
                                                                     Gradle

   CORE            UI       WRAPPER           OPEN-API         DOCS
                                                                     api

   java       groovy     maven       osgi       code-quality
   war         jetty     scala      eclipse     project-reports
                                                                  plugins


    Ant           Ivy       Maven Ant Tasks          Groovy
                                                           build tools

 checkstyle   codeNarc     webdav       other dependencies

                                                     librairies tierces
Publication dans des repo Ivy
 Gradle        IVY API             Repository
                                      Ivy
                                                Artifacts +
                                                 meta Ivy
usePlugin 'java'
 usePlugin 'java'
version='1.0'
 version='1.0'
uploadArchives{
 uploadArchives{
 repositories{
   repositories{
   flatDir(dirs:'destRepo')
    flatDir(dirs:'destRepo')
 }}
}}
             >> gradle uploadArchives
                 gradle uploadArchives
Publication dans des repo Maven
              Maven                                     Repository
Gradle        Ant                                      Maven distant
              Tasks        Repository                            Artifacts +
                           Maven local   Artifacts +
                                                                 meta Maven
                                         meta Maven

usePlugin 'java'
 usePlugin 'java'
usePlugin 'maven'
 usePlugin 'maven'
group='org.jug.normandyjug'
 group='org.jug.normandyjug'
archivesBaseName='artefact-ex'
 archivesBaseName='artefact-ex'
version='1.0-SNAPSHOT'
 version='1.0-SNAPSHOT'
uploadArchives {{
 uploadArchives
 repositories.mavenDeployer {{
   repositories.mavenDeployer
    snapshotRepository(url:
     snapshotRepository(url:
   "http://serveur/archiva/repository/snapshots")
    "http://serveur/archiva/repository/snapshots")
}}
                                    >> gradle install
                                        gradle install
                                    >> gradle uploadArchives
                                        gradle uploadArchives
Production de plusieurs artefacts
   Une librairie/module peut avoir plusieurs artefacts
<!-- sample/build.xml -->
 <!-- sample/build.xml -->
usePlugin 'java'
 usePlugin 'java'                                           Gradle
task sourceJar(type: Jar)
 task sourceJar(type: Jar)
task distrib(type: Zip)
 task distrib(type: Zip)
artifacts{
 artifacts{
 archives sourceJar, distrib
   archives sourceJar, distrib
}}
                                                          Repository
repositories{
 repositories{                                               Ivy
 flatDir name:'repo', dirs:'repo'
   flatDir name:'repo', dirs:'repo'
}}                                        sample source       dist
                                                                     ivy.xml
uploadArchives {{                         -1.0.jar -1.0.jar -1.0.zip
 uploadArchives
 repositories {{
   repositories
     add project.repositories.repo
      add project.repositories.repo
 }}
}}
                >> gradle uploadArchives
                    gradle uploadArchives
Gestion simplifié des configurations
usePlugin 'java'
 usePlugin 'java'                          Ajout automatique
configurations{
 configurations{                                   de
 sources
   sources                             build[ConfigurationName]
 master {{                                         et
   master
   extendsFrom archives, sources      upload[ConfigurationName]
    extendsFrom archives, sources
 }}
}}
artifacts{
 artifacts{
 sources sourceJar
   sources sourceJar
 master distrib
   master distrib
}}
uploadArchives{
 uploadArchives{
 repositories{
   repositories{
    flatDir(dirs: file('repos'), name:'destRepo')
     flatDir(dirs: file('repos'), name:'destRepo')
 }}
}}
uploadSources{
 uploadSources{
 repositories{
   repositories{
   add project.uploadArchives.repositories.destRepo
    add project.uploadArchives.repositories.destRepo
 }}
}}
uploadMaster.repositories=uploadSources.repositories
 uploadMaster.repositories=uploadSources.repositories
Agir simplement sur le cycle de vie
• Un cycle de vie Gradle est composé d'un ensemble
  de tâches
  – Chaque tâche est une propriété du projet
  – Chaque tâche possède une propriété « enabled »
   compileTestJava.enabled=false
    compileTestJava.enabled=false
   processTestResources.enabled=false
    processTestResources.enabled=false
   testClasses.enabled=false
    testClasses.enabled=false
   test.enabled=false
    test.enabled=false
Portée des dépendances                   (1/2)

<dependency>
 <dependency>
  <groupId>log4j</groupId>
   <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
   <artifactId>log4j</artifactId>                    commons-
  <version>1.2;14</version>
   <version>1.2;14</version>                         codec
</dependency>
 </dependency>
<dependency>
 <dependency>
  <groupId>commons-httpclient</groupId>
   <groupId>commons-httpclient</groupId>
  <artifactId>commons-httpclient</artifactId>
   <artifactId>commons-httpclient</artifactId>
  <version>3.0</version>
   <version>3.0</version>
  <scope>provided</scope>                            commons-
   <scope>provided</scope>                           httpclient
</dependency>
 </dependency>
<dependency>
 <dependency>
  <groupId>commons-codec</groupId>
   <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
   <artifactId>commons-codec</artifactId>
  <version>1.2</version>
   <version>1.2</version>
</dependency>
 </dependency>
                             <!-- Contenu de l'archive -->
                              <!-- Contenu de l'archive -->
                             WEB-INF/lib
                              WEB-INF/lib
                             -- log4j-1.2.14.jar
                                 log4j-1.2.14.jar
                             -- commons-codec-1.2jar
                                 commons-codec-1.2jar
Portée des dépendances (2/2)
Le plugin 'war' fournit les scopes
  'providedCompile' et 'providedRuntime'
<build.gradle -->
 <build.gradle -->
dependencies {{
 dependencies
 compile "log4j:log4j:1.2.14"
   compile "log4j:log4j:1.2.14"
 providedCompile "commons-httpclient:commons-
   providedCompile "commons-httpclient:commons-
httpclient:3.0"
 httpclient:3.0"
 compile "commons-codec:commons-codec:1.2"
   compile "commons-codec:commons-codec:1.2"
}}
                            <!-- Contenu de l'archive -->
                             <!-- Contenu de l'archive -->
                            WEB-INF/lib
                             WEB-INF/lib
                            -- log4j-1.2.14.jar
                                log4j-1.2.14.jar
Gradle

LES INTÉRÊTS POUR UNE
ENTREPRISE
Gradle, un choix pertinent en
  Entreprise
• Utiliser Gradle en lieu et place de vos scripts Ant
  – Réutilisation (Import) de scripts Ant existant
  – Utilisation de toute tâche native
• Utiliser Gradle avec votre infrastructure Ivy
  – Intégration plus profonde et plus riche
• Utiliser Gradle avec votre infrastructure Maven
  existante
  – Les même conventions que Maven
  – Simplicité de gestion des dépendances Maven
  – Flexibilité au besoin
Gradle

LES PROBLEMES
Les problèmes
• Ce qui manque
  – Gestion d'un ear pour JEE
  – Génération de la configuration IDEA et NetBeans
  – Intégration avec les outils de couvertures de code ou
    d'autres outils de métriques (Findbugs, …)
     • Délégation à des tâches Ant aujourd'hui

• Un manque de maturité
  – Changement de la DSL entre chaque release
Gradle

LES DOCUMENTATIONS
          DOCUMENTATIONS
          ?
Quelques liens
• Le site web :
  – http://www.gradle.org/
• Un user guide
  – http://www.gradle.org/0.8/docs/userguide/userguide.html
  – http://www.gradle.org/0.8/docs/userguide/userguide.pdf
• Un cookbook
  – http://docs.codehaus.org/display/GRADLE/Cookbook
• Le wiki projet :
  – http://docs.codehaus.org/display/GRADLE/Home
Gradle

OÙ TROUVER DU SUPPORT ?
Support
• Liste de diffusion
  – http://www.gradle.org/lists.html
• Support commercial
  – http://www.gradle.biz/
Gradle

LA COMMUNAUTÉ
La communauté des utilisateurs
• Les utilisateurs Groovy
L'équipe projet
• 6 committeurs enregistrés
• L'entreprise « Gradle inc » soutient le projet
• De nouvelles contributions arrivent
Convaincu?

Gradle_NormandyJUG

  • 1.
    NormandyJUG 20 octobre 2009 Builders Battle Maven / Ivy / Ant / Gradle / EasyAnt ...
  • 2.
    Grégory Boissinot • CommitterHudson depuis 2008 • Consultant Zenika – Spécialiste sur les outils de build et l'intégration continue – Formateur sur l'usine logicielle – A mis en place Gradle chez un grand acteur de l'industrie
  • 3.
    Gradle en quelquemots • Système de build complet et flexible à la Ant • Utilisation des conventions de Maven à la demande • Une gestion multi projet avancée • Utilisation de Apache Ivy comme gestionnaire de dépendances – Utilisation par API • Support et Insertion totale dans une infrastructure Maven et Ivy existante • Chaîne de build en Groovy • Modèle de description du build très riche
  • 4.
    Architecture Gradle CORE UI WRAPPER OPEN-API DOCS api java groovy maven osgi code-quality war jetty scala eclipse project-reports plugins Ant Ivy Maven Ant Tasks Groovy build tools checkstyle codeNarc webdav other dependencies librairies tierces
  • 5.
    Notion de tâche Un script de build Gradle est défini par un ensemble de tâches sur lesquelle est ajouté des actions qui sont des closures Groovy <!-- build.gradle --> Tâche <!-- build.gradle --> simple task distribution <<{ task distribution <<{ println "Distribution" println "Distribution" }} Accès à l'API Java task release (dependsOn: 'distribution')<<{ task release (dependsOn: 'distribution')<<{ println "Release" println "Release" }} >> gradle distribution >> gradle release gradle release gradle distribution Distribution Distribution Distribution Distribution Release Release
  • 6.
    Les tâches ontune API Tâche Copy myCopy == task(myCopy, type:Copy) améliorée Copy myCopy task(myCopy, type:Copy) myCopy.from(file('resources')) myCopy.from(file('resources')) myCopy.into(file('target')) myCopy.into(file('target')) CustomTask myCopy.include('**/*.txt', '**/*.xml') myCopy.include('**/*.txt', '**/*.xml') task mycopy (type:Copy) task mycopy (type:Copy) mycopy{ Copy mycopy{ description ='Copies the resources dir' description ='Copies the resources dir' from(file('resources')) from(file('resources')) into(file('target')) into(file('target')) include('**/*.txt', '**/*.xml') include('**/*.txt', '**/*.xml') mycopy } } task mycopy (type:Copy){ task mycopy (type:Copy){ description ='Copies the resources dir' description ='Copies the resources dir' from(file('resources')) from(file('resources')) into(file('target')) into(file('target')) include('**/*.txt', '**/*.xml') include('**/*.txt', '**/*.xml') } }
  • 7.
    Une API trèsriche task source(type:Jar){ task source(type:Jar){ CustomTask baseName='source' baseName='source' from sourceSets.main.java from sourceSets.main.java }} Abstract SourceTask ArchiveTask task distrib(type:Zip){ task distrib(type:Zip){ dependsOn(jar) dependsOn(jar) baseName='dist' baseName='dist' from sourceSets.main.java Javadoc Zip from sourceSets.main.java from jar.archivePath from jar.archivePath }} Jar Tar task javadoc(type: Javadoc) {{ task javadoc(type: Javadoc) source sourceSets.main.allJava }} source sourceSets.main.allJava War
  • 8.
    Plusieurs tâches pardéfaut <!-- build.xml --> <!-- build.gradle --> <!-- build.gradle --> <!-- build.xml --> defaultTasks 'clean', <project default="all"> defaultTasks 'clean', <project default="all"> 'jar' 'jar' <target name="clean"> <target name="clean"> <echo message="Cleaning"/> task clean << {{ task clean << <echo message="Cleaning"/> println "Cleaning" </target> println "Cleaning" </target> }} <target name="jar"> <target name="jar"> <echo message="Packaging"/> task jar << {{ task jar << <echo message="Packaging"/> println "Packaging" </target> println "Packaging" </target> }} <target name="all"> >> gradle gradle <target name="all"> Cleaning <antcall target="clean"/> <antcall target="clean"/> Cleaning <antcall target="jar"/> Packaging Packaging <antcall target="jar"/> </target> </target> </project> </project> >> ant ant Cleaning Cleaning Packaging Packaging
  • 9.
    Exécution unique etordonnée compile dist compileTest test >> ant test dist ant test dist >> gradle test dist gradle test dist compile compile :compile :compile compileTest compileTest :compileTest :compileTest test test :test :test compile compile :dist :dist compileTest compileTest test test dist dist
  • 10.
    Pour un projetJava/JEE Gradle CORE UI WRAPPER OPEN-API DOCS api java groovy maven osgi code-quality war jetty scala eclipse project-reports plugins Ant Ivy Maven Ant Tasks Groovy build tools checkstyle codeNarc webdav other dependencies librairies tierces
  • 11.
    Build d'une librairie <!--build.gradle --> Configuration <!-- build.gradle --> usePlugin 'java' accessible usePlugin 'java' sous forme de propriétés archivesBaseName == 'core' archivesBaseName 'core' Gradle version == '3.5' version '3.5' manifest.mainAttributes( manifest.mainAttributes( 'Implementation-Version': version 'Implementation-Version': version )) repositories {{ repositories mavenCentral() mavenCentral() }} core-3.5.jar dependencies {{ dependencies compile group: 'commons-collections', compile group: 'commons-collections', name: 'commons-collections', name: 'commons-collections', version: '3.2' version: '3.2' testCompile group: 'junit', testCompile group: 'junit', name: 'junit', name: 'junit', version: '4.+' version: '4.+' }} >> gradle compileJava gradle compileJava >> gradle jar gradle jar
  • 12.
    Build d'une webapp WEB-INF <!-- build.gradle --> <!-- build.gradle --> optionel usePlugin 'war' usePlugin 'war' usePlugin 'jetty' usePlugin 'jetty' Gradle archivesBaseName == 'web' JEE6 archivesBaseName 'web' compatible version == '1.0' version '1.0' repositories {{ repositories mavenCentral() mavenCentral() }} dependencies {{ dependencies web-2.4.war compile "commons-io:commons-io:1.4" compile "commons-io:commons-io:1.4" compile ("log4j:log4j:1.2.15"){ compile ("log4j:log4j:1.2.15"){ exclude(group:'javax.jms') exclude(group:'javax.jms') exclude(group:'com.sun.jdmk') exclude(group:'com.sun.jdmk') exclude(module:'jmxri') exclude(module:'jmxri') }} }} >> gradle war gradle war >> gradle jettyRun gradle jettyRun
  • 13.
    Phases de build Gradlefournit 3 phases distinctes de build • Initialisation – Détermine l'ensemble des projets à builder – Création d'un objet Projet pour chaque module • Configuration – Configuration des objets Project • Exécution – Exécution des tâches crées et configurés précédemment gradle.taskGraph.whenReady {taskGraph -> gradle.taskGraph.whenReady {taskGraph -> if (taskGraph.hasTask(':release')) {{ if (taskGraph.hasTask(':release')) Nombreux version == '1.0' version '1.0' }} else {{ hooks else disponibles version == '1.0-SNAPSHOT' version '1.0-SNAPSHOT' }} }}
  • 14.
    Gradle fournit descycles de vies (1/2) Ensemble de tâches prédéfinies Exemple du plugin 'java'
  • 15.
    Des conventions derépertoires Très <!-- build.gradle --> Gradle utilise par défaut configurable <!-- build.gradle --> sourceSets{ sourceSets{ les mêmes conventions de main{ main{ java {{ répertoires que Maven java srcDir 'src/java' srcDir 'src/java' Séparation }} <!-- répertoires --> <!-- répertoires --> propre resources {{ +build.gradle resources +build.gradle srcDir 'src/resources' srcDir 'src/resources' +src/main/java +src/main/java }} +src/main/resources +src/main/resources }} +src/main/webapp +src/main/webapp main{ +src/test/java main{ +src/test/java java {{ java +src/test/resources +src/test/resources srcDir 'src2/java' srcDir 'src2/java' }} +build/classes +build/classes resources {{ +build/libs resources +build/libs srcDir 'src2/resources' srcDir 'src2/resources' +build/reports +build/reports }} +build/test-results +build/test-results }} }}
  • 16.
    Gestion des dépendancesavec Ivy Gradle CORE UI WRAPPER OPEN-API DOCS api java groovy maven osgi code-quality war jetty scala eclipse project-reports plugins Ant Ivy Maven Ant Tasks Groovy build tools checkstyle codeNarc webdav other dependencies librairies tierces
  • 17.
    Gestion des dépendances Repository • Support complet de Maven local/distant Artifacts + repository Maven ou Ivy méta Maven (pom.xml) Ivy existant Gradle • Interaction possible Repository Ivy avec un gestionnaire local/distant Artifacts + méta Ivy de configuration (ivy.xml) • Gestion des dépendances VCS transitives Artifacts + méta gradle (client module)
  • 18.
    Définition des repositories repositories{{ repositories mavenCentral() mavenCentral() mavenRepo urls:"http://serveur/archiva/repo-group" mavenRepo urls:"http://serveur/archiva/repo-group" }} repositories {{ repositories flatDir name: 'localRepository', dirs: 'lib' flatDir name: 'localRepository', dirs: 'lib' }} repositories {{ repositories add( add( new org.apache.ivy.plugins.resolver.FileSystemResolver()){ new org.apache.ivy.plugins.resolver.FileSystemResolver()){ name == 'repo' name 'repo' addArtifactPattern addArtifactPattern "$projectDir/lib/[module]_[revision].[ext]" "$projectDir/lib/[module]_[revision].[ext]" descriptor == 'optional' descriptor 'optional' checkmodified == true checkmodified true }} }}
  • 19.
    Déclaration des dépendances •Dépendances vers des modules (+deps) dependencies {{ dependencies compile "log4j:log4j:1.2.14" compile "log4j:log4j:1.2.14" testCompile "junit:junit:4.7" testCompile "junit:junit:4.7" }} • Dépendances vers des artefacts (-deps) dependencies {{ dependencies runtime "org.groovy:groovy:1.5.6@jar" runtime "org.groovy:groovy:1.5.6@jar" }} • Client modules dependencies {{ dependencies runtime module("commons-lang:commons-lang:2.4") {{ runtime module("commons-lang:commons-lang:2.4") dependency("commons-io:commons-io:1.2") dependency("commons-io:commons-io:1.2") Dépendances }} transitives sans XML }}
  • 20.
    Intégration native avecAnt Gradle CORE UI WRAPPER OPEN-API DOCS api java groovy maven osgi code-quality war jetty scala eclipse project-reports plugins Ant Ivy Maven Ant Tasks Groovy build tools checkstyle codeNarc webdav other dependencies librairies tierces
  • 21.
    Utilisation possible destâches Ant <!-- build.gradle --> Utilisation de l'objet <!-- build.gradle --> Groovy AntBuilder task generateStub << {{ task generateStub << ant {{ ant def wsdl2java_classpath == path {{ def wsdl2java_classpath path fileset(dir: 'lib') {{ fileset(dir: 'lib') include(name: '*.jar') include(name: '*.jar') }} }} taskdef( name: 'axisWsdl2java', taskdef( name: 'axisWsdl2java', classname: classname: 'org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask', 'org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask', classpath: wsdl2java_classpath classpath: wsdl2java_classpath )) axisWsdl2java( output:"generated", axisWsdl2java( output:"generated", verbose:"true" ,, url:"Exemple.wsdl") verbose:"true" url:"Exemple.wsdl") }} }}
  • 22.
    Gradle et Ant:dans les deux sens (1/2) <!-- build.xml --> <!-- build.xml --> <property name="src.dir" value="src"> <property name="src.dir" value="src"> <target name="compile"> <target name="compile"> <echo message="Compile,from Ant"/> <echo message="Compile,from Ant"/> </target> </target> <!-- build.gradle --> <!-- build.gradle --> ant.importBuild 'build.xml' ant.importBuild 'build.xml' //Complément de la tâche compile //Complément de la tâche compile compile << {{ compile << println "Added compiling from Gradle" println "Added compiling from Gradle" println "SourceDir: ${ant.properties['src.dir']}" println "SourceDir: ${ant.properties['src.dir']}" }} >> gradle compile gradle compile :compile :compile [ant:echo] Compile, from Ant [ant:echo] Compile, from Ant Added compiling from Gradle Added compiling from Gradle SourceDir: src SourceDir: src
  • 23.
    Gradle et Ant:dans les deux sens (2/2) <!-- build.gradle --> <!-- build.gradle --> task assemble (dependsOn: 'compile') << {{ task assemble (dependsOn: 'compile') << println 'Assemble, from Gradle' println 'Assemble, from Gradle' }} <!-- build.xml --> <!-- build.xml --> <target name="deploy" depends="assemble"> <target name="deploy" depends="assemble"> <echo message="Deploy, from Ant"/> <echo message="Deploy, from Ant"/> </target> </target> >> gradle deploy gradle deploy :compile :compile [ant:echo] Compile, from Ant [ant:echo] Compile, from Ant Added compiling from Gradle Added compiling from Gradle :assemble :assemble Assemble, from Gradle Assemble, from Gradle :deploy :deploy [ant:echo] Deploy, from Ant [ant:echo] Deploy, from Ant
  • 24.
    Gestion multi projettrès avancée Gradle CORE UI WRAPPER OPEN-API DOCS api java groovy maven osgi code-quality war jetty scala eclipse project-reports plugins Ant Ivy Maven Ant Tasks Groovy build tools checkstyle codeNarc webdav other dependencies librairies tierces
  • 25.
    Gestion multi projet(1/3) • Les descripteurs dans les sous common jar modules sont optionnels • Injection de configuration depends depends • Possibilité de mettre toute la biz-auth pz war war logique de build dans le parent <!-- Structure de répertoires --> <!-- Structure de répertoires --> <!-- settings.gradle --> <!-- settings.gradle --> +build.gradle +build.gradle include include +settings.gradle +settings.gradle "common", "common", +common/ +common/ "pz", "pz", +pz/ +pz/ "biz:auth" "biz:auth" +build.gradle +build.gradle -biz/ -biz/ -- biz-auth/ biz-auth/
  • 26.
    Gestion multi projet(2/3) <!-- master build.gradle --> <!-- master build.gradle --> <!-- pz/build.gradle --> <!-- pz/build.gradle --> subprojects{ subprojects{ usePlugin 'war' usePlugin 'war' usePlugin('java') usePlugin('java') group='org.jug.normandyjug' group='org.jug.normandyjug' dependencies{ dependencies{ version='1.0' version='1.0' compile compile project(':common') project(':common') repositories{ repositories{ }} mavenCentral() mavenCentral() }} dependencies {{ dependencies testCompile 'junit:junit:4.7' testCompile 'junit:junit:4.7' }} cross project configuration }} project(':biz:biz-auth'){ project(':biz:biz-auth'){ dependencies{ dependencies{ compile project(':common') compile project(':common') }} usePlugin 'war' usePlugin 'war' }}
  • 27.
    Gestion multi projet(3/3) /web> gradle compileJava /web> gradle compileJava :common:compileJava :common:compileJava :common:processResources :common:processResources :common:classes :common:classes :common:jar :common:jar :common:uploadDefaultInternal :common:uploadDefaultInternal :pz:compileJava :pz:compileJava :biz:biz-auth:compileJava :biz:biz-auth:compileJava /web/biz/biz-auth> gradle compileJava /web/biz/biz-auth> gradle compileJava :common:compileJava :common:compileJava :common:processResources Compilation :common:processResources des projets :common:classes :common:classes :common:jar dépendants :common:jar :common:uploadDefaultInternal :common:uploadDefaultInternal :biz:biz-auth:compileJava :biz:biz-auth:compileJava /web/biz/biz-auth> gradle compileJava -a /web/biz/biz-auth> gradle compileJava -a Utilisation :biz:biz-auth:compileJava :biz:biz-auth:compileJava des jars dans le cache
  • 28.
    Gradle GUI • Lancé par > gradle –gui • Exécution de tâches • Paramétrage du niveau de log
  • 29.
    Publie dans uneinfra Maven et Ivy Gradle CORE UI WRAPPER OPEN-API DOCS api java groovy maven osgi code-quality war jetty scala eclipse project-reports plugins Ant Ivy Maven Ant Tasks Groovy build tools checkstyle codeNarc webdav other dependencies librairies tierces
  • 30.
    Publication dans desrepo Ivy Gradle IVY API Repository Ivy Artifacts + meta Ivy usePlugin 'java' usePlugin 'java' version='1.0' version='1.0' uploadArchives{ uploadArchives{ repositories{ repositories{ flatDir(dirs:'destRepo') flatDir(dirs:'destRepo') }} }} >> gradle uploadArchives gradle uploadArchives
  • 31.
    Publication dans desrepo Maven Maven Repository Gradle Ant Maven distant Tasks Repository Artifacts + Maven local Artifacts + meta Maven meta Maven usePlugin 'java' usePlugin 'java' usePlugin 'maven' usePlugin 'maven' group='org.jug.normandyjug' group='org.jug.normandyjug' archivesBaseName='artefact-ex' archivesBaseName='artefact-ex' version='1.0-SNAPSHOT' version='1.0-SNAPSHOT' uploadArchives {{ uploadArchives repositories.mavenDeployer {{ repositories.mavenDeployer snapshotRepository(url: snapshotRepository(url: "http://serveur/archiva/repository/snapshots") "http://serveur/archiva/repository/snapshots") }} >> gradle install gradle install >> gradle uploadArchives gradle uploadArchives
  • 32.
    Production de plusieursartefacts Une librairie/module peut avoir plusieurs artefacts <!-- sample/build.xml --> <!-- sample/build.xml --> usePlugin 'java' usePlugin 'java' Gradle task sourceJar(type: Jar) task sourceJar(type: Jar) task distrib(type: Zip) task distrib(type: Zip) artifacts{ artifacts{ archives sourceJar, distrib archives sourceJar, distrib }} Repository repositories{ repositories{ Ivy flatDir name:'repo', dirs:'repo' flatDir name:'repo', dirs:'repo' }} sample source dist ivy.xml uploadArchives {{ -1.0.jar -1.0.jar -1.0.zip uploadArchives repositories {{ repositories add project.repositories.repo add project.repositories.repo }} }} >> gradle uploadArchives gradle uploadArchives
  • 33.
    Gestion simplifié desconfigurations usePlugin 'java' usePlugin 'java' Ajout automatique configurations{ configurations{ de sources sources build[ConfigurationName] master {{ et master extendsFrom archives, sources upload[ConfigurationName] extendsFrom archives, sources }} }} artifacts{ artifacts{ sources sourceJar sources sourceJar master distrib master distrib }} uploadArchives{ uploadArchives{ repositories{ repositories{ flatDir(dirs: file('repos'), name:'destRepo') flatDir(dirs: file('repos'), name:'destRepo') }} }} uploadSources{ uploadSources{ repositories{ repositories{ add project.uploadArchives.repositories.destRepo add project.uploadArchives.repositories.destRepo }} }} uploadMaster.repositories=uploadSources.repositories uploadMaster.repositories=uploadSources.repositories
  • 34.
    Agir simplement surle cycle de vie • Un cycle de vie Gradle est composé d'un ensemble de tâches – Chaque tâche est une propriété du projet – Chaque tâche possède une propriété « enabled » compileTestJava.enabled=false compileTestJava.enabled=false processTestResources.enabled=false processTestResources.enabled=false testClasses.enabled=false testClasses.enabled=false test.enabled=false test.enabled=false
  • 35.
    Portée des dépendances (1/2) <dependency> <dependency> <groupId>log4j</groupId> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <artifactId>log4j</artifactId> commons- <version>1.2;14</version> <version>1.2;14</version> codec </dependency> </dependency> <dependency> <dependency> <groupId>commons-httpclient</groupId> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <artifactId>commons-httpclient</artifactId> <version>3.0</version> <version>3.0</version> <scope>provided</scope> commons- <scope>provided</scope> httpclient </dependency> </dependency> <dependency> <dependency> <groupId>commons-codec</groupId> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <artifactId>commons-codec</artifactId> <version>1.2</version> <version>1.2</version> </dependency> </dependency> <!-- Contenu de l'archive --> <!-- Contenu de l'archive --> WEB-INF/lib WEB-INF/lib -- log4j-1.2.14.jar log4j-1.2.14.jar -- commons-codec-1.2jar commons-codec-1.2jar
  • 36.
    Portée des dépendances(2/2) Le plugin 'war' fournit les scopes 'providedCompile' et 'providedRuntime' <build.gradle --> <build.gradle --> dependencies {{ dependencies compile "log4j:log4j:1.2.14" compile "log4j:log4j:1.2.14" providedCompile "commons-httpclient:commons- providedCompile "commons-httpclient:commons- httpclient:3.0" httpclient:3.0" compile "commons-codec:commons-codec:1.2" compile "commons-codec:commons-codec:1.2" }} <!-- Contenu de l'archive --> <!-- Contenu de l'archive --> WEB-INF/lib WEB-INF/lib -- log4j-1.2.14.jar log4j-1.2.14.jar
  • 37.
  • 38.
    Gradle, un choixpertinent en Entreprise • Utiliser Gradle en lieu et place de vos scripts Ant – Réutilisation (Import) de scripts Ant existant – Utilisation de toute tâche native • Utiliser Gradle avec votre infrastructure Ivy – Intégration plus profonde et plus riche • Utiliser Gradle avec votre infrastructure Maven existante – Les même conventions que Maven – Simplicité de gestion des dépendances Maven – Flexibilité au besoin
  • 39.
  • 40.
    Les problèmes • Cequi manque – Gestion d'un ear pour JEE – Génération de la configuration IDEA et NetBeans – Intégration avec les outils de couvertures de code ou d'autres outils de métriques (Findbugs, …) • Délégation à des tâches Ant aujourd'hui • Un manque de maturité – Changement de la DSL entre chaque release
  • 41.
  • 42.
    Quelques liens • Lesite web : – http://www.gradle.org/ • Un user guide – http://www.gradle.org/0.8/docs/userguide/userguide.html – http://www.gradle.org/0.8/docs/userguide/userguide.pdf • Un cookbook – http://docs.codehaus.org/display/GRADLE/Cookbook • Le wiki projet : – http://docs.codehaus.org/display/GRADLE/Home
  • 43.
  • 44.
    Support • Liste dediffusion – http://www.gradle.org/lists.html • Support commercial – http://www.gradle.biz/
  • 45.
  • 46.
    La communauté desutilisateurs • Les utilisateurs Groovy
  • 47.
    L'équipe projet • 6committeurs enregistrés • L'entreprise « Gradle inc » soutient le projet • De nouvelles contributions arrivent
  • 48.