Gradle, je t’aime: moi non plus.

7843bb075c05be6886a97b77e36758ff?s=47 David
April 19, 2019

Gradle, je t’aime: moi non plus.

Un outil de build de qualité est essentiel dans un projet IT. On attend de lui qu’il soit rapide, facile à configurer et qu’il se fasse oublier le reste du temps. Même si l’écosystème Java utilise encore fortement Maven, Gradle est une alternative à considérer, particulièrement avec les dernières fonctionnalités apportées.

Pourquoi avoir choisi Gradle ? Quelles sont les fonctionnalités de l’outil qui nous satisfont le plus ? Quelles sont nos bonnes pratiques ? Quelles sont les problèmes que nous avons rencontrés ? Comment nos builds sont maintenant organisés avec cet outil ?

Cette session répondra à ces questions et vous aidera à choisir votre prochain outil de build.

Devoxx France 2019 - 19 Avril 2019

7843bb075c05be6886a97b77e36758ff?s=128

David

April 19, 2019
Tweet

Transcript

  1. Gradle, je t’aime, 
 … moi non plus @JeremMartinez -

    @dwursteisen
  2. None
  3. David Wursteisen Jeremie Martinez

  4. Satisfait de votre banque ?

  5. Une banque pour entreprise

  6. Nous construisons notre propre CBS.

  7. Nous construisons notre propre Core Banking System.

  8. Data Payments Backend Core

  9. Data Payments Backend Core Created Deposited Withdraw Withdraw Closed WRITE

    Event store Reporting Accounting Regulators Data sciences GDPR Users Transfers Customers Collections Cards KYC Limit controller
  10. Un outil de build est comme une banque. On ne

    choisit pas le meilleur mais le moins pire. Un outil de build est comme une banque. On ne choisit pas le meilleur mais le moins pire.
  11. Choix de l’outil de build : 2017 Choix de l’outil

    de build : 2017
  12. Bazel Buck

  13. Construction incrementale DSL en Groovy Dynamisme du produit

  14. Système à base de tâche.

  15. Tâche Entrée Sortie

  16. Assemble

  17. Jar Assemble

  18. Compile Jar Assemble

  19. Compile Jar Assemble

  20. Compile Jar Assemble Compile [ Up-to-date ] [ Up-to-date ]

    [ Up-to-date ] Jar Assemble
  21. On ne construit que le nécessaire. On ne construit que

    le nécessaire.
  22. Développeur Mainteneur de scripts Build master 1 2 3

  23. Développeur Mainteneur de scripts Build master 1

  24. Support IDE.

  25. None
  26. None
  27. None
  28. None
  29. None
  30. Gradle Wrapper.

  31. None
  32. distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://services.gradle.org/distributions/gradle-5.3-bin.zip

  33. distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://services.gradle.org/distributions/gradle-5.3-bin.zip

  34. distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip

  35. distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc6

  36. distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc6

  37. distributionhttps://internal/gradle/gradle/gradle/5.3/gradle-5.3-bin.zip distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc6 Ne sont pas des variables d’environment valides !

  38. None
  39. 4 Go =

  40. Gestion des dépendances

  41. src main module kotlin test kotlin resources custom kotlin

  42. dependencies { }

  43. dependencies { compile("io.swagger:swagger-annotations:1.5.0") }

  44. dependencies { compile("io.swagger:swagger-annotations:1.5.0") compile(group = "io.swagger", name = "swagger-annotations", version

    = "1.5.0") }
  45. dependencies { compile("io.swagger:swagger-annotations:1.5.0") compile(group = "io.swagger", name = "swagger-annotations", version

    = "1.5.0") compile(project(":otherProject")) }
  46. dependencies { compile("io.swagger:swagger-annotations:1.5.0") compile(group = "io.swagger", name = "swagger-annotations", version

    = "1.5.0") compile(project(":otherProject")) testCompile("io.mockk:mockk:1.9.3") }
  47. dependencies { compile("io.swagger:swagger-annotations:1.5.0") compile(group = "io.swagger", name = "swagger-annotations", version

    = "1.5.0") compile(project(":otherProject")) testCompile("io.mockk:mockk:1.9.3") customCompile("org.codehaus.janino:janino:2.5.16") }
  48. customCompile("org.codehaus.janino:janino:2.5.16") sourceSet configuration

  49. compile("org.codehaus.janino:janino:2.5.16") compileOnly("org.codehaus.janino:janino:2.5.16") runtime("org.codehaus.janino:janino:2.5.16") annotationProcessor("org.codehaus.janino:janino:2.5.16")

  50. compile("org.codehaus.janino:janino:2.5.16") compileOnly("org.codehaus.janino:janino:2.5.16") runtime("org.codehaus.janino:janino:2.5.16") annotationProcessor("org.codehaus.janino:janino:2.5.16")

  51. compile("org.codehaus.janino:janino:2.5.16") compileOnly("org.codehaus.janino:janino:2.5.16") runtime("org.codehaus.janino:janino:2.5.16") annotationProcessor("org.codehaus.janino:janino:2.5.16") runtimeOnly("org.codehaus.janino:janino:2.5.16") api("org.codehaus.janino:janino:2.5.16") implementation("org.codehaus.janino:janino:2.5.16")

  52. runtimeOnly("org.codehaus.janino:janino:2.5.16") api("org.codehaus.janino:janino:2.5.16") implementation("org.codehaus.janino:janino:2.5.16")

  53. mailer-service mailer-api amazing-mail com.lib.mailer.api com.lib.mailer.impl MailerService MailerApi webapp fr.amazing.client ClientMail

  54. mailer-service mailer-api amazing-mail com.lib.mailer.api com.lib.mailer.impl MailerService MailerApi webapp fr.amazing.client ClientMail

    compilation compilation compilation est visible est visible implementation implementation api
  55. Repositories.

  56. repositories { }

  57. repositories { mavenCentral() }

  58. repositories { mavenCentral() jcenter() google() }

  59. repositories { mavenCentral() jcenter() google() maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/")

    } }
  60. repositories { mavenCentral() jcenter() google() maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/")

    } maven { url = uri("https://internal") content { includeGroupByRegex("com\\.mycompany.*") } } } Selection des dépendances
  61. repositories { mavenCentral() jcenter() google() maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/")

    } maven { url = uri("https://internal") content { includeGroupByRegex("com\\.mycompany.*") } } ivy { url = uri("https://oss.sonatype.org/content/repositories/releases/") } flatDir { dirs("libs") } }
  62. repositories { mavenCentral() jcenter() google() maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/")

    } maven { url = uri("https://internal") content { includeGroupByRegex("com\\.mycompany.*") } } ivy { url = uri("https://oss.sonatype.org/content/repositories/releases/") } flatDir { dirs("libs") } mavenLocal() } Devrait être inutile
  63. projectA projectB mavenLocal publishToMavenLocal Dépend de…

  64. Composite Build.

  65. projectA projectB compositeBuild includeBuild(…)

  66. projectA projectB dependencySource gitRepository(https://github.com/…) version = branch/tag

  67. mailer 1.0.0 Master dev/feature superProject otherProject projectZ

  68. mailer 1.0.0 Master dev/feature superProject OK otherProject OK projectZ OK

  69. mailer 1.0.0 master superProject OK OK otherProject OK OK projectZ

    OK KO Dependency sources
  70. mailer 1.0.0 master dev/feature superProject OK OK KO otherProject OK

    OK OK projectZ OK KO OK Dependency sources Dependency sources
  71. Performance.

  72. None
  73. org.gradle.caching=true org.gradle.configureondemand=true org.gradle.jvmargs=-Xmx2048M -Xms2048M org.gradle.parallel=true Réutilisation des résultats de build

    Execution des tâches en parallèle Utilisation d’un maximum de mémoire Configuration uniquement des tâches nécessaires
  74. None
  75. Daemon Gradle 5.1.1 Daemon Gradle 4.10

  76. None
  77. None
  78. Simplicité d’utilisation Performance Fonctionnalités

  79. Développeur Mainteneur de scripts Build master 2

  80. Data Payments Backend Core Created Deposited Withdraw Withdraw Closed WRITE

    Event store Reporting Accounting Regulators Data sciences GDPR Users Transfers Customers Collections Cards KYC Limit controller
  81. Data Payments Backend Reporting Accounting Regulators Data sciences GDPR Users

    Transfers Customers Collections Cards KYC Limit controller
  82. Backend GDPR Users Customers KYC Limit controller kotlin nexus release

    lint Configuration
  83. Plugin interne.

  84. apply(plugin = "com.your.company.commons")

  85. None
  86. Configurer une seule fois, Exécuter partout.

  87. buildSrc.

  88. None
  89. None
  90. None
  91. None
  92. src main buildSrc kotlin myProject

  93. open class MyExtension(var yourName: String = "not defined!")

  94. open class MyExtension(var yourName: String = "not defined!") class MyPlugin

    : Plugin<Project> { override fun apply(project: Project) { } }
  95. open class MyExtension(var yourName: String = "not defined!") class MyPlugin

    : Plugin<Project> { override fun apply(project: Project) { val exts = project.extensions.create("myPlugin", MyExtension::class) } }
  96. open class MyExtension(var yourName: String = "not defined!") class MyPlugin

    : Plugin<Project> { override fun apply(project: Project) { val exts = project.extensions.create("myPlugin", MyExtension::class) project.task("myTask") { doLast { println("hello ${exts.yourName}") } } } }
  97. apply<MyPlugin>() configure<MyExtension> { yourName = "Devoxx France" }

  98. None
  99. DSL.

  100. Groovy DSL.

  101. sourceSets { } Groovy

  102. sourceSets { integrationTest { } } DSL Dynamique Groovy

  103. None
  104. Type safety IDE Support Navigation Refactoring

  105. sourceSets { integrationTest { } } Groovy

  106. sourceSets.create("integrationTest") { … } Kotlin

  107. None
  108. None
  109. None
  110. idea { project { settings { runConfigurations { "Start Application"(Application)

    { // … } } } } } Groovy
  111. idea { project { this as ExtensionAware configure<ProjectSettings> { this

    as ExtensionAware configure<NamedDomainObjectContainer<RunConfiguration>> { // cast to PolymorphicDomainObjectContainer to access the create method used bellow. @Suppress("UnstableApiUsage") this as PolymorphicDomainObjectContainer<RunConfiguration> create("Start Application", Application::class) { // … } } } } } Kotlin
  112. « Un langage pour les gouverner tous. »

  113. Migration vers Kotlin DSL.

  114. object Versions { val assertj = "3.10.0" val junit =

    "4.12" val mockito = "2.19.1" val mockito_kotlin = "1.6.0" val postgres = "42.2.4" val prometheus = "0.6.0" val springboot = "2.1.3.RELEASE" val swagger = "1.5.20" }
  115. object TestDeps { val assertj = "org.assertj:assertj-core:${Versions.assertj}" val junit =

    "junit:junit:${Versions.junit}" val mockito = "org.mockito:mockito-core:${Versions.mockito}" }
  116. dependencies { testImplementation(TestDeps.assertj) testImplementation(TestDeps.junit) testImplementation(TestDeps.mockito) }

  117. 1. Doublez vos quotes.

  118. allprojects { group = 'com.margo.backend' version = '1.0' } Groovy

  119. allprojects { group = 'com.margo.backend' version = '1.0' } Groovy

  120. allprojects { group = "com.margo.backend" version = "1.0" } Kotlin

  121. 2. Explicitez vos assignations.

  122. repositories { maven { url 'https://plugins.gradle.org/m2/' } } Groovy

  123. repositories { maven { url = uri("https://plugins.gradle.org/m2/") } } Kotlin

  124. dependencies { compile project(":service") } Groovy

  125. dependencies { compile(project(":service")) } Kotlin

  126. val commit by extra { Git.commit() } Kotlin

  127. object Git { fun commit() = Runtime.getRuntime() .exec("git rev-parse --short

    HEAD") .inputStream.bufferedReader() .readText() } buildSrc
  128. 3. Fichier par fichier.

  129. web buildSrc src build.gradle settings.gradle build.gradle src build.gradle

  130. build.gradle.kts web buildSrc src settings.gradle build.gradle src build.gradle

  131. settings.gradle.kts build.gradle.kts web buildSrc src build.gradle src build.gradle

  132. build.gradle.kts settings.gradle.kts build.gradle.kts web buildSrc src src build.gradle

  133. web buildSrc src build.gradle.kts settings.gradle.kts build.gradle.kts src build.gradle.kts

  134. Quelques difficultés.

  135. 1. Documentation.

  136. None
  137. 2. Exemples.

  138. None
  139. None
  140. 3. Utilisation avancée.

  141. processResources { filesMatching('**/*.properties') { expand(project.properties) } } Groovy

  142. tasks .withType(ProcessResources::class) .named("processResources") .configure { filesMatching("**/*.properties") { expand(project.properties) } }

    Kotlin
  143. tasks .withType(ProcessResources::class) .named("processResources") .configure { filesMatching("**/*.properties") { expand(project.properties) } }

    Kotlin
  144. tasks .withType(ProcessResources::class) .named("processResources") .configure { filesMatching("**/*.properties") { expand(project.properties) } }

    Kotlin
  145. tasks .withType(ProcessResources::class) .named("processResources") .configure { filesMatching("**/*.properties") { expand(project.properties) } }

    Kotlin
  146. tasks .withType(ProcessResources::class) .named("processResources") .configure { filesMatching("**/*.properties") { expand(project.properties) } }

    Kotlin
  147. tasks .withType(ProcessResources::class) .named("processResources") .configure { filesMatching("**/*.properties") { expand(project.properties) } }

    Kotlin
  148. 4. Migration du plugin interne.

  149. Si c’était à refaire ?

  150. buildSrc Performance Plugin interne IDE Support

  151. Prochaines étapes. Consommation mémoire Build cache

  152. Questions ?