Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Mastering Grails 3
Plugins
Álvaro Sánchez-Mariscal
Álvaro Sánchez-Mariscal
Software Engineer
Grails Development Team
sanchezmariscala@ociweb.com
OCI is the new home of Grails
More at ociweb.com/grails
The Basics
Creating a Grails 3 plugin
$ grails create-plugin myWebPlugin
| Plugin created at /private/tmp/myWebPlugin
$ grails create...
Understanding profiles
• A profile defines:
• Project’s build.gradle.
• Commands: create-domain-class,
run-app, etc.
• Featu...
plugin vs. web-plugin
Trim your plugin!
Keep clean
• Start with the plugin profile whenever
possible.
• Remove empty and/or unwanted files/
folders.
• Otherwise, th...
The burtbeckwith bot
The burtbeckwith bot
• Watches messy plugin repos and sends a PR
to clean them up.
• 14 pull requests in the last 3 months...
The minimal plugin
• Folder containing:
• build.gradle
• src/main/groovy with plugin descriptor.
• Empty grails-app folder...
The plugin descriptor
• A class inside src/main/groovy. Extends
grails.plugins.Plugin.
• Can override methods to define beh...
Plugins features
Plugin configuration
• A plugin can define:
• Configuration values for the host Grails app.
• One of plugin.yml or plugin.g...
Excluding content
• In the plugin descriptor:
• In build.gradle:
// resources that are excluded from plugin packaging

def...
Command Line extensions
• Use create-script for code generation
commands.
• Runnable with the Grails CLI.
• Use create-com...
Scripts
• Base class:
org.grails.cli.profile.commands.script.GroovyScriptCommand
import org.grails.cli.interactive.complet...
Commands
import grails.dev.commands.ApplicationCommand

import grails.dev.commands.ExecutionContext



class MyCommand imp...
Enhancing artefacts
import grails.artefact.Enhances

import groovy.transform.CompileStatic



@Enhances(['Controller', 'Se...
Modularisation
Modularisation
• If your plugin becomes to grow, you might
end up creating a monolith.
• You can modularise your plugins a...
Modularisation
Monolithic plugin
Multi-module plugin
Modularisation
• Benefits:
• Optional dependencies.
• Smaller JAR files.
• Build logic reuse.
Modularisation setup
• settings.gradle:
include ‘myPlugin-core', ‘myPlugin-domain' //etc
Modularisation setup
• Root build.gradle:
allprojects {

apply plugin:"idea"

}



subprojects { Project project ->

ext {...
Modularisation setup
• Sub-module build.gradle:
dependencyManagement {

imports {

mavenBom "org.grails:grails-bom:$grails...
Publishing
Artifact publication
• Snapshots:
• Using the artifactory Gradle plugin.
• Published in OJO (oss.jfrog.org).
• Releases:
•...
Bintray setup
• For Snapshots:
Build setup
artifactory {

contextUrl = 'http://oss.jfrog.org'

publish {

repository {

repoKey = 'oss-s...
grailsPublish {

user = bintrayUser

key = bintrayKey

portalUser = pluginPortalUser

portalPassword = pluginPortalPasswor...
Build setup
• Define rootProject.name in
settings.gradle.
• Define credentials in
~/.gradle/gradle.properties.
Running it
• Snapshot publishing:
• Release publishing:
$ ./gradlew artifactoryPublish
$ ./gradlew publishPlugin notifyPlu...
Plugin portals
• Once your packages are published in your
Bintray repo, go to https://
bintray.com/grails/plugins and clic...
Testing
Testing with a profile
• You can create a profile and use it as a TCK
for your plugin:
• Create test apps from that profile...
Profile descriptor
description: Creates a test app for Spring Security REST plugin

build:

excludes:

- org.grails.grails...
Feature descriptor
description: First configuration of GORM

dependencies:

build:

- "org.grails.plugins:hibernate4:5.0.0...
Build setup
task generateProfileConfig << {

copy {

from 'profile.yml.tmpl'

into '.'

rename { String fileName -> fileNa...
Skeleton
• Put in the skeleton all your test files and
resources.
• You can use features to have different sets of
tests, r...
Test them all!
for feature in `ls ../spring-security-rest-testapp-profile/features/`

do

grails create-app -profile 

org...
Use case: the Spring
Security REST plugin
Thank you!
Álvaro Sánchez-Mariscal
Mastering Grails 3 Plugins - GR8Conf US 2016
Upcoming SlideShare
Loading in …5
×

Mastering Grails 3 Plugins - GR8Conf US 2016

597 views

Published on

With Grails 3, the plugin development experience changes a little bit compared to that of Grails 2. In this talk, Álvaro (member of the Grails team at OCI, Grails committer and author of several plugins) will cover several topics to understand how plugins work in Grails 3, focusing on best practices.

The session is structured as a set of tips and tricks with code samples in the following areas: modularisation, build system, testing and publishing.

Published in: Software
  • Be the first to comment

Mastering Grails 3 Plugins - GR8Conf US 2016

  1. 1. Mastering Grails 3 Plugins Álvaro Sánchez-Mariscal
  2. 2. Álvaro Sánchez-Mariscal Software Engineer Grails Development Team sanchezmariscala@ociweb.com
  3. 3. OCI is the new home of Grails More at ociweb.com/grails
  4. 4. The Basics
  5. 5. Creating a Grails 3 plugin $ grails create-plugin myWebPlugin | Plugin created at /private/tmp/myWebPlugin $ grails create-plugin myPlugin -profile plugin | Plugin created at /private/tmp/myPlugin
  6. 6. Understanding profiles • A profile defines: • Project’s build.gradle. • Commands: create-domain-class, run-app, etc. • Features: hibernate, json-views, etc. • Skeleton: files and folders.
  7. 7. plugin vs. web-plugin
  8. 8. Trim your plugin!
  9. 9. Keep clean • Start with the plugin profile whenever possible. • Remove empty and/or unwanted files/ folders. • Otherwise, the burtbeckwith bot will send you a cleanup pull request!
  10. 10. The burtbeckwith bot
  11. 11. The burtbeckwith bot • Watches messy plugin repos and sends a PR to clean them up. • 14 pull requests in the last 3 months! • Likely hundreds in the last years!
  12. 12. The minimal plugin • Folder containing: • build.gradle • src/main/groovy with plugin descriptor. • Empty grails-app folder. • Everything else can be removed.
  13. 13. The plugin descriptor • A class inside src/main/groovy. Extends grails.plugins.Plugin. • Can override methods to define behaviour in the plugin lifecycle. • Syntax has changed a bit from Grails 2.
  14. 14. Plugins features
  15. 15. Plugin configuration • A plugin can define: • Configuration values for the host Grails app. • One of plugin.yml or plugin.groovy. • Configuration for running the plugin as an application, to test it. • application.yml / application.groovy.
  16. 16. Excluding content • In the plugin descriptor: • In build.gradle: // resources that are excluded from plugin packaging
 def pluginExcludes = [
 '**/com/example/myplugin/tests/**'
 ] jar {
 exclude 'com/example/myplugin/tests/**/**'
 }
  17. 17. Command Line extensions • Use create-script for code generation commands. • Runnable with the Grails CLI. • Use create-command for interacting with a loaded Grails application. • Runnable with the Grails CLI or as a Gradle task.
  18. 18. Scripts • Base class: org.grails.cli.profile.commands.script.GroovyScriptCommand import org.grails.cli.interactive.completers.DomainClassCompleter
 
 description( "Generates a controller that performs REST operations" ) {
 usage "grails generate-resource-controller [DOMAIN CLASS]"
 argument name:'Domain Class', description:"The name of the domain class", required:true
 completer DomainClassCompleter
 flag name:'force', description:"Whether to overwrite existing files"
 }
 
 if(args) {
 generateController(*args)
 generateViews(*args)
 generateUnitTest(*args)
 generateFunctionalTest(*args)
 } else {
 error "No domain class specified"
 }
  19. 19. Commands import grails.dev.commands.ApplicationCommand
 import grails.dev.commands.ExecutionContext
 
 class MyCommand implements ApplicationCommand {
 
 @Override
 boolean handle(ExecutionContext ctx) {
 def dataSource = applicationContext.getBean(DataSource)
 //Run some SQL...
 
 return true
 }
 
 }
  20. 20. Enhancing artefacts import grails.artefact.Enhances
 import groovy.transform.CompileStatic
 
 @Enhances(['Controller', 'Service'])
 @CompileStatic
 trait DateSupport {
 
 Date now() {
 return new Date()
 }
 
 }
  21. 21. Modularisation
  22. 22. Modularisation • If your plugin becomes to grow, you might end up creating a monolith. • You can modularise your plugins as you would do with your apps.
  23. 23. Modularisation Monolithic plugin Multi-module plugin
  24. 24. Modularisation • Benefits: • Optional dependencies. • Smaller JAR files. • Build logic reuse.
  25. 25. Modularisation setup • settings.gradle: include ‘myPlugin-core', ‘myPlugin-domain' //etc
  26. 26. Modularisation setup • Root build.gradle: allprojects {
 apply plugin:"idea"
 }
 
 subprojects { Project project ->
 ext {
 grailsVersion = project.grailsVersion
 gradleWrapperVersion = project.gradleWrapperVersion
 }
 
 repositories {
 //Common repos
 }
 
 version "1.0.0.M1"
 group "org.grails.plugins"
 
 apply plugin: "org.grails.grails-plugin"
 
 dependencies {
 //Common deps
 }
 }
  27. 27. Modularisation setup • Sub-module build.gradle: dependencyManagement {
 imports {
 mavenBom "org.grails:grails-bom:$grailsVersion"
 }
 applyMavenExclusions false
 }
 
 dependencies {
 compile project(":myPlugin-core")
 
 compile "com.example:library:1.0.0"
 }
  28. 28. Publishing
  29. 29. Artifact publication • Snapshots: • Using the artifactory Gradle plugin. • Published in OJO (oss.jfrog.org). • Releases: • Using the grails-plugin-publish Gradle plugin. • Published in Bintray.
  30. 30. Bintray setup
  31. 31. • For Snapshots: Build setup artifactory {
 contextUrl = 'http://oss.jfrog.org'
 publish {
 repository {
 repoKey = 'oss-snapshot-local'
 username = bintrayUser
 password = bintrayKey
 }
 defaults {
 publications('maven')
 }
 }
 }
 
 artifactoryPublish {
 dependsOn sourcesJar, javadocJar
 }
  32. 32. grailsPublish {
 user = bintrayUser
 key = bintrayKey
 portalUser = pluginPortalUser
 portalPassword = pluginPortalPassword
 
 repo = 'plugins'
 githubSlug = 'alvarosanchez/my-plugin'
 license = 'APACHE 2.0'
 title = "My Plugin"
 desc = "A very cool Grails plugin"
 developers = [
 alvarosanchez: "Alvaro Sanchez-Mariscal"
 ]
 } • For Releases: Build setup
  33. 33. Build setup • Define rootProject.name in settings.gradle. • Define credentials in ~/.gradle/gradle.properties.
  34. 34. Running it • Snapshot publishing: • Release publishing: $ ./gradlew artifactoryPublish $ ./gradlew publishPlugin notifyPluginPortal
  35. 35. Plugin portals • Once your packages are published in your Bintray repo, go to https:// bintray.com/grails/plugins and click on “Include my package”. • Grails 3: http://grails.org/plugins.html • Grails 2: http://grails.org/plugins
  36. 36. Testing
  37. 37. Testing with a profile • You can create a profile and use it as a TCK for your plugin: • Create test apps from that profile. • Apps come with a set of tests. • Use features to test different configurations.
  38. 38. Profile descriptor description: Creates a test app for Spring Security REST plugin
 build:
 excludes:
 - org.grails.grails-core
 dependencies:
 compile:
 - "org.grails.plugins:spring-security-rest:${pluginVersion}"
 - "org.grails:grails-datastore-rest-client:5.0.0.RC3"
 testCompile:
 - "com.codeborne:phantomjsdriver:1.2.1"
 - "org.seleniumhq.selenium:selenium-api:2.47.1"
 - "org.seleniumhq.selenium:selenium-firefox-driver:2.47.1" profile.yml.tmpl
  39. 39. Feature descriptor description: First configuration of GORM
 dependencies:
 build:
 - "org.grails.plugins:hibernate4:5.0.0.RC2"
 compile:
 - "org.grails.plugins:hibernate4"
 - "org.hibernate:hibernate-ehcache"
 - "org.grails.plugins:spring-security-rest-gorm:${pluginVersion}"
 runtime:
 - "com.h2database:h2" features/gorm1/feature.yml.tmpl
  40. 40. Build setup task generateProfileConfig << {
 copy {
 from 'profile.yml.tmpl'
 into '.'
 rename { String fileName -> fileName.replaceAll '.tmpl', '' }
 expand pluginVersion: project.version
 }
 
 file('features').eachDir { feature ->
 copy {
 from "features/${feature.name}/feature.yml.tmpl"
 into "features/${feature.name}/"
 rename { String fileName -> fileName.replaceAll '.tmpl', '' }
 expand pluginVersion: project.version
 }
 }
 }
 
 compileProfile.dependsOn generateProfileConfig
  41. 41. Skeleton • Put in the skeleton all your test files and resources. • You can use features to have different sets of tests, resources and configuration. • Define global configuration values in profile’s root skeleton folder.
  42. 42. Test them all! for feature in `ls ../spring-security-rest-testapp-profile/features/`
 do
 grails create-app -profile 
 org.grails.plugins:spring-security-rest-testapp-profile:$pluginVersion 
 -features $feature $feature && cd $feature && ./gradlew check && cd ..
 done
  43. 43. Use case: the Spring Security REST plugin
  44. 44. Thank you! Álvaro Sánchez-Mariscal

×