Pages

vendredi 6 janvier 2017

Ecrire ses scripts Gradle en Kotlin aux dépens de Groovy

En mai 2016 Gradle annonçait qu’il était maintenant possible d’écrire des scripts (build.gradle) et des plugins en Kotlin. Ce choix pouvait paraître étonnant alors que Gradle avait depuis ces débuts beaucoup investi sur le langage Groovy.



Mais le langage Kotlin à l’avantage d’être statique et typé et son utilisation permet de considérablement enrichir l’expérience des développeurs dans les IDE
  • Auto-complétion et aide contextuel
  • Navigation à la source
  • Refactoring 
  • ...
Je vous conseille de lire le très bon article de blog de Cédric Champeau (ancien de la core team Groovy embauché par Gradle) qui explique beaucoup mieux que moi les avantages.

Ce qui m’intéresse dans cet article c’est plutôt vous montrer comment paramétrer un cas concret. Je vous conseille pour cela d’utiliser la dernière version de Gradle (3.3). Le repo Github contenant les sources du projet “Gradle Script Kotlin” comprend plusieurs exemples.

Dans cet article je me base sur le script de construction build.gradle.kts du site Mix-IT 2017. Dans ce script nous utilisons une application Spring Boot écrit en Kotlin et ce qui est plutôt sympa c’est que Kotlin est du coup utilisé sur toute la chaîne. Vous pouvez comparer ce script avec celui utilisé dans l’ancienne version du site.

Dans cet article je vais vous montrer les différences entre un script Groovy et Kotlin en essayant de paramétrer le plugin gradle-node-plugin. Ce plugin permet de piloter Gulp (appli node.js) via Gradle pour avoir une seule manière de construire notre application Java ou Kotlin. A noter que ce plugin permet l'utilisation de npm ou yarn pour gérer vos dépendances JavaScript. Dans notre cas nous avons opté pour yarn.

Dans un script Gradle nous avons une partie utilisée pour paramétrer le build lui même. En Groovy on écrit

buildscript {
    ext {
        nodePluginVersion = '1.0.1'
    }
    repositories {
        mavenCentral()
        jcenter()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "com.moowork.gradle:gradle-node-plugin:${nodePluginVersion}"
    }
}

En Kotlin

buildscript {
    val kotlinVersion = "1.0.6"
    val nodePluginVersion = "1.0.1"    extra["kotlinVersion"] = kotlinVersion

    repositories {
        mavenCentral()
        jcenter()
        maven{
            setUrl("https://plugins.gradle.org/m2/")
        }
    }
    dependencies {
        classpath("com.moowork.gradle:gradle-node-plugin:$nodePluginVersion")
    }
}

Vous me direz jusque là pas beaucoup de changement. Déclarons maintenant les plugins utilisés par notre projet

En Groovy

apply plugin: 'idea'
apply plugin: 'com.moowork.node'
apply plugin: 'com.moowork.gulp'

En Kotlin

apply {
    plugin("idea")
    plugin("kotlin")
    plugin("kotlin-noarg")
    plugin("com.moowork.node")
    plugin("com.moowork.gulp")
}

Les plugins (c’est le cas de gradle-gulp-plugin) peuvent avoir une partie configuration (les points d’extensions)

En Groovy

node {
    version = '6.9.2'
    download = true
}

En Kotlin

import com.moowork.gradle.node.NodeExtension

configure<NodeExtension> {
    version = "6.9.2"
    download = true
}

Notez que vous devez importer le point d’extension pour être capable de surcharger les paramètres par défaut d’un plugin. Ceci demande de connaître un peu le fonctionnement de Gradle et de ces plugins (voir mon article ou encore mieux la doc :-) ).

Regardons maintenant comment configurer une tâche et l’intégrer dans le cycle de vie Gradle

En Groovy

task gulpBuild(type: GulpTask, dependsOn: yarnInstall) {
  inputs.dir 'src/main/sass'  inputs.files(npmInstall.outputs)
  outputs.dir "src/main/static/css"  args = ["default"]
}

processResources {
  dependsOn gulpBuild
}

En Kotlin

import com.moowork.gradle.gulp.GulpTask
import com.moowork.gradle.node.yarn.YarnInstallTask

task<GulpTask>("gulpBuild") {
  dependsOn(YarnInstallTask.NAME)
  inputs.dir("src/main/sass")
  inputs.dir("build/.tmp")
  outputs.dir("src/main/static/css")
  args = listOf("default")
}

tasks.getByName("processResources").dependsOn("gulpBuild")

Je n’ai exposé ici que les cas les plus courants utilisés dans Gradle. Vous pouvez toujours programmer vos tâches en Groovy ou Kotlin dans vos scripts. Pour plus d’info je vous réoriente vers les exemples officiels et la page Stackoverflow (qui n’est pas encore très riche sur le sujet).

Nous verrons dans les mois qui viennent si Kotlin prend la main sur Groovy dans les scripts de configuration Gradle. Pour le moment le manque de documentation sur Gradle Script Kotlin est vraiment problématique.

2 commentaires:

  1. Merci Guillaume pour cet article.
    Pourquoi faut-il déclarer la tâche yarnInstall en Kotlin, alors que tu ne le fais pas en groovy?
    La tâche gulpBuild ne pourrait-elle pas simplement faire

    inputs.dir("src/main/sass")

    et

    args = listOf("default")

    ?

    RépondreSupprimer
  2. En Groovy la tâche est automatiquement découverte. En Kotlin j'ai pas mal cherché et je n'ai trouvé que cette manière pour que ça marche. Si quelqu'un a mieux je suis preneur.

    Pour la deuxième question sur inputs.dir et args c'est vrai que les getters/seters sont implicites en Kotlin, je modifie le code. Merci du retour

    RépondreSupprimer

Remarque : Seul un membre de ce blog est autorisé à enregistrer un commentaire.