Blog

Så skriver, testar och publicerar du ett anpassat Gradle-plugin

JUL 14, 2017

Kom igång med din pluginutveckling med ett dokumenterat exempel

Thierry Lacour

A Belgian working from Malmö. Thierry has a Bachelor’s degree in Application Development and has been with us since 2015 as an Automation Toolsmith. He enjoys computer and tabletop gaming and is an infinite source of optimism and humor. A good man to have in a crisis.

En praktisk guide till att skriva, testa och publicera egna Gradle-pluginer, komplett med ett demorepository som ger dig en flygande start!

Introduktion

Pluginer är ett utmärkt sätt att distribuera Gradle-funktionalitet, oavsett om det handlar om publika pluginer som erbjuder verktygsintegrationer, som Artifactory-pluginet, eller företagspluginer som delar vanliga uppgifter internt, som de vi hjälper våra kunder att utveckla.

Tyvärr upplevde jag att dokumentationen och exemplen för att skriva ett eget Gradle-plugin var ganska utspridda. Jag bestämde mig för att skriva ett mycket grundläggande Gradle-plugin som en grund, tänkt att ge både mig och nu även dig en flygande start när du utvecklar ett eget Gradle-plugin. Det innehåller Hello, world!-uppgifter, tester och möjligheter att publicera. Jag skrev den här bloggen parallellt, som en form av dokumentation. Trevlig läsning!

Plugin-repositoryt

Du hittar grunden för Gradle-pluginet på GitHub i Praqma/gradle-plugin-bootstrap. Det är ett fullt fungerande Gradle-plugin. Använd det gärna som utgångspunkt – klona det bara och anpassa det efter dina behov.

Delarna

Jag går kort igenom de enskilda delar som utgör ett Gradle-plugin. Du hittar allt som nämns i repositoryt, men här beskriver jag dem mer ingående än vad som ryms i kommentarerna.

Startpunkten

Exempel finns i:src/main/groovy/com/praqma/demo/DemoPlugin.groovy

Det här är pluginets kärna. Här hittar du metoden apply, eftersom den implementerar org.gradle.api.Plugin. Gradle anropar metoden när det tillämpar ditt plugin på ett projekt. Här kan du lägga till dina uppgifter, utökningar och så vidare.

I exempelpluginet har jag flyttat sådant till en separat modul. Det är bara för att förhindra att huvudklassen för pluginet växer sig för stor. Se det som en rekommendation när du förväntar dig att lägga till många olika uppgifter i ditt plugin.

Registrera startpunkten

Exempel finns i:build.gradle

Innan Gradle kan tillämpa ditt plugin måste du tala om var det hittar det. Det gör du genom att tillämpa och konfigurera Gradle-pluginet java-gradle-plugin i filen build.gradle. Tillämpa pluginet via blocket plugins högst upp i filen build.gradle:

plugins {    id 'java-gradle-plugin' }

Konfigurera ditt plugin i blocket gradlePlugin, som tillhandahålls av java-gradle-plugin. I blocket plugins kan du lägga till en post för varje plugin i projektet. Vi håller det enkelt och har bara ett plugin, så vi lägger till ett godtyckligt namngivet block under det för att konfigurera pluginet och ange två egenskaper:

  • id är identifieraren för ditt plugin och används för att tillämpa det:plugins id: 'com.praqma.demo'

  • implementationClass pekar på klassen för startpunkten, så att Gradle kan hitta den. I det här fallet är det com.praqma.demo.DemoPlugin.

id är identifieraren för ditt plugin och används för att tillämpa det:

plugins {     id: 'com.praqma.demo' }

implementationClass pekar på klassen för startpunkten, så att Gradle kan hitta den. I det här fallet är det com.praqma.demo.DemoPlugin.

Den kompletta konfigurationen ser ungefär ut så här:

gradlePlugin {    plugins {        demoPlugin {            id = 'com.praqma.demo'            implementationClass = 'com.praqma.demo.DemoPlugin'        }    }}

Lägga till uppgifter

Exempel finns i:src/main/groovy/com/praqma/demo/greeting/GreetingModule.groovy

Här har jag lagt till två uppgifter: den ena visar hur du använder egenskaper från projektutökningar, den andra använder projektegenskaper. Att lägga till uppgifter i pluginet skiljer sig väldigt lite från att lägga till uppgifter i ett vanligt Gradle-projekt – anropa bara metoden task på projektet.

Återigen är det inte alls nödvändigt att dela upp uppgifter i moduler. Det är bara en vana jag har för att undvika att pluginklassen utvecklas till ett tvåtusen rader långt monster.

Lägga till uppgiftstyper

Exempel finns i:src/main/groovy/com/praqma/demo/greeting/GreetingTask.groovysrc/main/groovy/com/praqma/demo/greeting/GreetingModule.groovy

Genom att skapa en anpassad uppgiftstyp kan plugin-användare basera sina egna uppgifter på din, på samma sätt som vi baserar våra uppgifter på uppgifterna Zip och Copy. För att distribuera dem behöver du bara inkludera dessa uppgiftsklasser i ditt plugin. Då kan användare definiera uppgifter av den typen genom att använda dess fullständigt kvalificerade namn. Till exempel:

import com.praqma.demo.greeting.GreetingTasktask myGreetingTask(type:GreetingTask) {    message = "Howdy"}

För att dina användare ska slippa importera uppgiften lägger du till uppgiftsklassen i projektets ExtraPropertiesExtension när pluginet tillämpas. Med det här smarta knepet kan användarna komma åt din uppgift med namnet du anger här, utan att behöva importera den.

project.ext.GreetingTask = com.praqma.demo.greeting.GreetingTask

Lägga till tillägg

Exempel finns i:src/main/groovy/com/praqma/demo/greeting/GreetingExtension.groovysrc/main/groovy/com/praqma/demo/greeting/GreetingModule.groovy

Tillägg exponerar egenskaper som plugin-användare kan ange. De är utmärkta när du vill låta användare konfigurera värden som dina uppgifter använder. I demo-pluginet kan användare konfigurera hälsningen som används i uppgiften helloWorld genom att ange egenskapen greeting.message i sin build.gradle-fil.

Om du vill lägga till egna tillägg i ditt plugin skapar du en enkel klass med några egenskaper och lägger till den som ett projekttillägg i pluginets apply-metod:

project.extensions.create('greeting', GreetingExtension)

Dessa egenskaper är tillgängliga via projektets tillägg, till exempel:

project.extensions.<extensionName>.<propertyName>

Testa pluginet

Jag går inte in på enhetstestning av Gradle-pluginet, eftersom det inte skiljer sig från enhetstestning i ett vanligt Groovy-projekt och det finns många bra resurser i ämnet (se resursavsnittet nedan). Däremot går jag igenom funktionella tester och hur du testar ditt plugin med en lokal publicering.

Funktionella tester

Exempel finns i:src/test/groovy/com/praqma/demo/greeting/GreetingModuleTest.groovy

Att skriva funktionella tester för ett Gradle-plugin är enkelt tack vare GradleRunner. Med JUnit-annotationerna @Rule och @Before kan du enkelt skapa en tillfällig katalog för varje test, med en build.gradle-fil som tillämpar ditt plugin. GradleRunner lägger till ditt plugin i det tillfälliga projektets classpath, så att det faktiskt kan tillämpa pluginet som testas. När du kör dina uppgifter via GradleRunner får du tillgång till build-resultatet och textutdata. Tillsammans med åtkomsten till den tillfälliga katalogen kan du kontrollera och verifiera att allt kördes som förväntat.

Publicera och testa på din lokala dator

Det går att publicera ditt plugin till datorns lokala Maven-repository. Då kan du tillämpa din lokala testpublicering i ett Gradle-projekt på datorn och testa ändringarna utan att publicera dem till ett delat repository. Det kräver lite konfiguration, men är ganska enkelt.

Publicera till det lokala Maven-repositoryt

Tillämpa pluginet maven-publish, som innehåller uppgiften publishToMavenLocal. Den här uppgiften publicerar alla dina definierade publiceringar till ditt lokala repository, så låt oss konfigurera en publicering för vårt plugin:

publishing {    publications {        pluginPublication (MavenPublication) {            from    components.java            groupId    project.group            artifactId    "demo"            version    project.version        }    }}

För att publicera pluginet i dess nuvarande skick till ditt lokala repository kör du gradle publishToMavenLocal.

Tillämpa ett lokalt publicerat plugin

För att tillämpa ett lokalt publicerat plugin i ditt projekt måste du lägga till ditt lokala Maven-repository som ett betrott repository i Gradle-projektet. Som tur är kan du göra det i Gradle genom att anropa mavenLocal() i closure-blocket repository i din build.gradle-fil. Till exempel:

buildscript {    repositories {        mavenLocal()    }    dependencies {        classpath "com.praqma:demo:1.0.0"    }}apply plugin: 'com.praqma.demo.DemoPlugin'

Nu kan du köra dina Gradle-buildar, och projektet använder din lokala distribution av pluginet.

Distribuera pluginet

Jag går igenom publicering både till det offentliga Gradle-plugin-repositoryt och till en valfri Artifactory-server. Projektet innehåller den konfiguration som behövs för båda. Ta bara bort den du inte kommer att använda och justera den andra.

Via Gradle-plugin-repositoryt

Konfiguration

Exempel finns i:build.gradle

Använd pluginet com.gradle.plugin-publish i ditt pluginprojekt. Konfigurera det via closuret pluginBundle, där du anger användbar information om ditt plugin, till exempel repositoryplats, en beskrivning och relevanta taggar.

pluginBundle {    website = 'https://github.com/Praqma/gradle-plugin-bootstrap'    vcsUrl = 'scm:git@github.com:Praqma/gradle-plugin-bootstrap.git'    tags = ['demo', 'example', 'quickstart']    plugins {        demoPlugin {            id = 'com.praqma.demo.DemoPlugin'            displayName = 'Gradle Multi Git plugin'            description = 'Demo plugin to use as a starting point for custom plugin development'        }    }}

Publicering

Pluginet com.gradle.plugin-publish innehåller de tasks som krävs för att publicera ditt plugin på pluginportalen.

Kör gradle login i ditt pluginrepository och följ instruktionerna för att auktorisera datorn att publicera ditt plugin.

Kör gradle publishPlugins för att faktiskt publicera ditt plugin på portalen.

Användning

När pluginet har publicerats kan det användas i andra Gradle-projekt via closuret plugins, med hjälp av pluginets id och version. Till exempel:

plugins {    id 'com.praqma.demo.DemoPlugin', version '1.0.0'}

Via Artifactory

Konfiguration

Exempel finns i:build.gradle

Använd och konfigurera pluginet com.jfrog.artifactory. I closuret artifactory konfigurerar du allt som pluginet behöver för att publicera pluginet på din Artifactory-server. Till exempel:

artifactory {    contextUrl = "http://devops.acmeindustries.com/artifactory"    publish {        repository {            repoKey     = 'plugins-release'            username    = 'joe'            password    = 's3cr3t-p4ss'            maven       = true        }        defaults{            publications("pluginPublication")    // Publication defined below        }    }}

Vi behöver fortfarande definiera vad vi publicerar, så använd pluginet maven-publish. Då kan du deklarera en MavenPublication som innehåller vårt plugin. Till exempel:

publishing {    publications {        pluginPublication (MavenPublication) {            from    components.java            groupId    project.group            artifactId    "demo"            version    project.version        }    }}

Publicering

Publicera ditt plugin genom att köra gradle artifactoryPublish.

Användning

För att använda pluginet måste du först hämta det. Registrera din Artifactory-server som ett repository och lägg till ditt plugin som ett beroende. Använd sedan pluginet på samma sätt som vilket annat plugin som helst. Här är ett exempel på konfiguration från ett projekt som använder vårt plugin:

buildscript {    repositories {        maven {            url = "http://devops.acmeindustries.com/artifactory/plugins-release"            credentials {                username = "joe"                password = "s3cr3t-p4ss"            }        }    }    dependencies {        classpath "com.praqma:demo:1.0.0"    }}apply plugin: "com.praqma.demo.DemoPlugin" // Apply with the plugin id

Avslutande kommentarer

Det här bör täcka grunderna för att komma igång med ett anpassat Gradle-plugin. Jag hoppas att det hjälper dig att skriva och distribuera egna, coola Gradle-plugin. Tankar, frågor och förslag är mycket välkomna – lämna dem gärna i kommentarsfältet nedan!

Referenser

  • DevOps

Subscribe to our newsletter