SlideShare ist ein Scribd-Unternehmen logo
1 von 46
Downloaden Sie, um offline zu lesen
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-plugin myPlugin -profile plugin
| Plugin created at /private/tmp/myPlugin
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.
plugin vs. web-plugin
Trim your plugin!
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!
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!
• Likely hundreds in the last years!
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 behaviour
in the plugin lifecycle.
• Syntax has changed a bit from Grails 2.
Plugins features
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.
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/**/**'

}
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.
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"

}
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

}



}
Enhancing artefacts
import grails.artefact.Enhances

import groovy.transform.CompileStatic



@Enhances(['Controller', 'Service'])

@CompileStatic

trait DateSupport {



Date now() {

return new Date()

}



}
Modularisation
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.
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 {

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

}

}
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"

}
Aggregating Docs
task aggregateGroovyDoc(type: Groovydoc) {

group = JavaBasePlugin.DOCUMENTATION_GROUP



dependsOn subprojects.groovydoc

source subprojects.groovydoc.source

destinationDir file("${buildDir}/docs/groovydoc")

classpath = files(subprojects.groovydoc.classpath)

groovyClasspath = files(subprojects.groovydoc.groovyClasspath)

}
Publishing
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.
Bintray setup
• 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

}
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
Build setup
• Define rootProject.name in
settings.gradle.
• Define credentials in
~/.gradle/gradle.properties.
Running it
• Snapshot publishing:
• Release publishing:
$ ./gradlew artifactoryPublish
$ ./gradlew publishPlugin notifyPluginPortal
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
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.
• Apps come with a set of tests.
• Use features to test different configurations.
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
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
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
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.
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
Use case: the Spring
Security REST plugin
¡Muchas gracias!
Álvaro Sánchez-Mariscal

Weitere ähnliche Inhalte

Was ist angesagt?

Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...Alvaro Sanchez-Mariscal
 
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring SecurityDesarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring SecurityAlvaro Sanchez-Mariscal
 
Capybara with Rspec
Capybara with RspecCapybara with Rspec
Capybara with RspecOmnia Helmi
 
High Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring BootHigh Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring BootDaniel Woods
 
A Closer Look At React Native
A Closer Look At React NativeA Closer Look At React Native
A Closer Look At React NativeIan Wang
 
Building an API with Django and Django REST Framework
Building an API with Django and Django REST FrameworkBuilding an API with Django and Django REST Framework
Building an API with Django and Django REST FrameworkChristopher Foresman
 
Django rest framework
Django rest frameworkDjango rest framework
Django rest frameworkBlank Chen
 
Write an API for Almost Anything: The Amazing Power and Flexibility of Django...
Write an API for Almost Anything: The Amazing Power and Flexibility of Django...Write an API for Almost Anything: The Amazing Power and Flexibility of Django...
Write an API for Almost Anything: The Amazing Power and Flexibility of Django...Caktus Group
 
Building Web Apps in Ratpack
Building Web Apps in RatpackBuilding Web Apps in Ratpack
Building Web Apps in RatpackDaniel Woods
 
007. Redux middlewares
007. Redux middlewares007. Redux middlewares
007. Redux middlewaresBinh Quan Duc
 
Dropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stackDropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stackJacek Furmankiewicz
 
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...chbornet
 
Building RESTful APIs
Building RESTful APIsBuilding RESTful APIs
Building RESTful APIsSilota Inc.
 
Dropwizard and Groovy
Dropwizard and GroovyDropwizard and Groovy
Dropwizard and Groovytomaslin
 
Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"
Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"
Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"Fwdays
 
第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」
第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」
第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」Tsuyoshi Yamamoto
 

Was ist angesagt? (20)

Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
Creating applications with Grails, Angular JS and Spring Security - GR8Conf U...
 
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring SecurityDesarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
Desarrollo de aplicaciones con Grails 3, Angular JS y Spring Security
 
Introduction To Grails
Introduction To GrailsIntroduction To Grails
Introduction To Grails
 
Capybara with Rspec
Capybara with RspecCapybara with Rspec
Capybara with Rspec
 
High Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring BootHigh Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring Boot
 
A Closer Look At React Native
A Closer Look At React NativeA Closer Look At React Native
A Closer Look At React Native
 
Building an API with Django and Django REST Framework
Building an API with Django and Django REST FrameworkBuilding an API with Django and Django REST Framework
Building an API with Django and Django REST Framework
 
Django rest framework
Django rest frameworkDjango rest framework
Django rest framework
 
Write an API for Almost Anything: The Amazing Power and Flexibility of Django...
Write an API for Almost Anything: The Amazing Power and Flexibility of Django...Write an API for Almost Anything: The Amazing Power and Flexibility of Django...
Write an API for Almost Anything: The Amazing Power and Flexibility of Django...
 
Building Web Apps in Ratpack
Building Web Apps in RatpackBuilding Web Apps in Ratpack
Building Web Apps in Ratpack
 
007. Redux middlewares
007. Redux middlewares007. Redux middlewares
007. Redux middlewares
 
Grails 101
Grails 101Grails 101
Grails 101
 
Dropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stackDropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stack
 
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
JHipster Conf 2018 : Connect your JHipster apps to the world of APIs with Ope...
 
Building RESTful APIs
Building RESTful APIsBuilding RESTful APIs
Building RESTful APIs
 
Dropwizard and Groovy
Dropwizard and GroovyDropwizard and Groovy
Dropwizard and Groovy
 
Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"
Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"
Alexander Mostovenko "'Devide at impera' with GraphQL and SSR"
 
Introduction to Grails
Introduction to GrailsIntroduction to Grails
Introduction to Grails
 
第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」
第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」
第1回名古屋Grails/Groogy勉強会「Grailsを始めてみよう!」
 
Introducing spring
Introducing springIntroducing spring
Introducing spring
 

Andere mochten auch

G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!Iván López Martín
 
Devoxx 2015 - Web Application Development using Grails and Docker
Devoxx 2015 - Web Application Development using Grails and DockerDevoxx 2015 - Web Application Development using Grails and Docker
Devoxx 2015 - Web Application Development using Grails and DockerTed Vinke
 
Connecting Connect with Spring Boot
Connecting Connect with Spring BootConnecting Connect with Spring Boot
Connecting Connect with Spring BootVincent Kok
 
From Grails to Android: A Simple Journey
From Grails to Android: A Simple JourneyFrom Grails to Android: A Simple Journey
From Grails to Android: A Simple JourneyAnnyce Davis
 
Creating ASTTs The painful truth
Creating ASTTs The painful truthCreating ASTTs The painful truth
Creating ASTTs The painful truthMario García
 
Continuous Delivery As Code
Continuous Delivery As CodeContinuous Delivery As Code
Continuous Delivery As CodeAlex Soto
 
Reactive Streams and the Wide World of Groovy
Reactive Streams and the Wide World of GroovyReactive Streams and the Wide World of Groovy
Reactive Streams and the Wide World of GroovySteve Pember
 

Andere mochten auch (11)

G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!G3 Summit 2016 - Dockerize your Grails!
G3 Summit 2016 - Dockerize your Grails!
 
Greach 2016 dockerize your grails
Greach 2016   dockerize your grailsGreach 2016   dockerize your grails
Greach 2016 dockerize your grails
 
Devoxx 2015 - Web Application Development using Grails and Docker
Devoxx 2015 - Web Application Development using Grails and DockerDevoxx 2015 - Web Application Development using Grails and Docker
Devoxx 2015 - Web Application Development using Grails and Docker
 
groovy & grails - lecture 3
groovy & grails - lecture 3groovy & grails - lecture 3
groovy & grails - lecture 3
 
Connecting Connect with Spring Boot
Connecting Connect with Spring BootConnecting Connect with Spring Boot
Connecting Connect with Spring Boot
 
From Grails to Android: A Simple Journey
From Grails to Android: A Simple JourneyFrom Grails to Android: A Simple Journey
From Grails to Android: A Simple Journey
 
Creating ASTTs The painful truth
Creating ASTTs The painful truthCreating ASTTs The painful truth
Creating ASTTs The painful truth
 
Geb for browser automation
Geb for browser automationGeb for browser automation
Geb for browser automation
 
Continuous Delivery As Code
Continuous Delivery As CodeContinuous Delivery As Code
Continuous Delivery As Code
 
Reactive Streams and the Wide World of Groovy
Reactive Streams and the Wide World of GroovyReactive Streams and the Wide World of Groovy
Reactive Streams and the Wide World of Groovy
 
Grooscript and Grails 3
Grooscript and Grails 3Grooscript and Grails 3
Grooscript and Grails 3
 

Ähnlich wie Mastering Grails 3 Plugins - Greach 2016

Ähnlich wie Mastering Grails 3 Plugins - Greach 2016 (20)

Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)
 
Building Grails Plugins - Tips And Tricks
Building Grails Plugins - Tips And TricksBuilding Grails Plugins - Tips And Tricks
Building Grails Plugins - Tips And Tricks
 
Gradle
GradleGradle
Gradle
 
Grails 3.0 Preview
Grails 3.0 PreviewGrails 3.0 Preview
Grails 3.0 Preview
 
Making the Most of Your Gradle Builds
Making the Most of Your Gradle BuildsMaking the Most of Your Gradle Builds
Making the Most of Your Gradle Builds
 
Custom plugin
Custom pluginCustom plugin
Custom plugin
 
Grails Custom Plugin
Grails Custom PluginGrails Custom Plugin
Grails Custom Plugin
 
OpenCms Days 2012 - Developing OpenCms with Gradle
OpenCms Days 2012 - Developing OpenCms with GradleOpenCms Days 2012 - Developing OpenCms with Gradle
OpenCms Days 2012 - Developing OpenCms with Gradle
 
Bugzilla Installation Process
Bugzilla Installation ProcessBugzilla Installation Process
Bugzilla Installation Process
 
Spring boot
Spring bootSpring boot
Spring boot
 
Grails Connecting to MySQL
Grails Connecting to MySQLGrails Connecting to MySQL
Grails Connecting to MySQL
 
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
Grails 0.3-SNAPSHOT Presentation WJAX 2006 EnglishGrails 0.3-SNAPSHOT Presentation WJAX 2006 English
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
 
Catalyst MVC
Catalyst MVCCatalyst MVC
Catalyst MVC
 
Generators
GeneratorsGenerators
Generators
 
Grails Plugins
Grails PluginsGrails Plugins
Grails Plugins
 
GradleFX
GradleFXGradleFX
GradleFX
 
Config/BuildConfig
Config/BuildConfigConfig/BuildConfig
Config/BuildConfig
 
Config BuildConfig
Config BuildConfigConfig BuildConfig
Config BuildConfig
 
Before & After Docker Init
Before & After Docker InitBefore & After Docker Init
Before & After Docker Init
 
Config BuildConfig
Config BuildConfigConfig BuildConfig
Config BuildConfig
 

Mehr von Alvaro Sanchez-Mariscal

Asynchronous and event-driven Grails applications
Asynchronous and event-driven Grails applicationsAsynchronous and event-driven Grails applications
Asynchronous and event-driven Grails applicationsAlvaro Sanchez-Mariscal
 
Reactive microservices with Micronaut - GR8Conf EU 2018
Reactive microservices with Micronaut - GR8Conf EU 2018Reactive microservices with Micronaut - GR8Conf EU 2018
Reactive microservices with Micronaut - GR8Conf EU 2018Alvaro Sanchez-Mariscal
 
Reactive microservices with Micronaut - Greach 2018
Reactive microservices with Micronaut - Greach 2018Reactive microservices with Micronaut - Greach 2018
Reactive microservices with Micronaut - Greach 2018Alvaro Sanchez-Mariscal
 
Creating applications with Grails, Angular JS and Spring Security
Creating applications with Grails, Angular JS and Spring SecurityCreating applications with Grails, Angular JS and Spring Security
Creating applications with Grails, Angular JS and Spring SecurityAlvaro Sanchez-Mariscal
 
Efficient HTTP applications on the JVM with Ratpack - JDD 2015
Efficient HTTP applications on the JVM with Ratpack - JDD 2015Efficient HTTP applications on the JVM with Ratpack - JDD 2015
Efficient HTTP applications on the JVM with Ratpack - JDD 2015Alvaro Sanchez-Mariscal
 
Stateless authentication with OAuth 2 and JWT - JavaZone 2015
Stateless authentication with OAuth 2 and JWT - JavaZone 2015Stateless authentication with OAuth 2 and JWT - JavaZone 2015
Stateless authentication with OAuth 2 and JWT - JavaZone 2015Alvaro Sanchez-Mariscal
 
Stateless authentication for microservices - GR8Conf 2015
Stateless authentication for microservices - GR8Conf 2015Stateless authentication for microservices - GR8Conf 2015
Stateless authentication for microservices - GR8Conf 2015Alvaro Sanchez-Mariscal
 
Stateless authentication for microservices - Spring I/O 2015
Stateless authentication for microservices  - Spring I/O 2015Stateless authentication for microservices  - Spring I/O 2015
Stateless authentication for microservices - Spring I/O 2015Alvaro Sanchez-Mariscal
 
Stateless authentication for microservices - Greach 2015
Stateless authentication for microservices - Greach 2015Stateless authentication for microservices - Greach 2015
Stateless authentication for microservices - Greach 2015Alvaro Sanchez-Mariscal
 
Stateless authentication for microservices applications - JavaLand 2015
Stateless authentication for microservices applications -  JavaLand 2015Stateless authentication for microservices applications -  JavaLand 2015
Stateless authentication for microservices applications - JavaLand 2015Alvaro Sanchez-Mariscal
 
Stateless authentication for microservices
Stateless authentication for microservicesStateless authentication for microservices
Stateless authentication for microservicesAlvaro Sanchez-Mariscal
 
Stateless token-based authentication for pure front-end applications
Stateless token-based authentication for pure front-end applicationsStateless token-based authentication for pure front-end applications
Stateless token-based authentication for pure front-end applicationsAlvaro Sanchez-Mariscal
 
Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)
Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)
Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)Alvaro Sanchez-Mariscal
 
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)Alvaro Sanchez-Mariscal
 

Mehr von Alvaro Sanchez-Mariscal (20)

Serverless functions with Micronaut
Serverless functions with MicronautServerless functions with Micronaut
Serverless functions with Micronaut
 
Asynchronous and event-driven Grails applications
Asynchronous and event-driven Grails applicationsAsynchronous and event-driven Grails applications
Asynchronous and event-driven Grails applications
 
6 things you need to know about GORM 6
6 things you need to know about GORM 66 things you need to know about GORM 6
6 things you need to know about GORM 6
 
Reactive microservices with Micronaut - GR8Conf EU 2018
Reactive microservices with Micronaut - GR8Conf EU 2018Reactive microservices with Micronaut - GR8Conf EU 2018
Reactive microservices with Micronaut - GR8Conf EU 2018
 
Reactive microservices with Micronaut - Greach 2018
Reactive microservices with Micronaut - Greach 2018Reactive microservices with Micronaut - Greach 2018
Reactive microservices with Micronaut - Greach 2018
 
Practical Spring Cloud
Practical Spring CloudPractical Spring Cloud
Practical Spring Cloud
 
Creating applications with Grails, Angular JS and Spring Security
Creating applications with Grails, Angular JS and Spring SecurityCreating applications with Grails, Angular JS and Spring Security
Creating applications with Grails, Angular JS and Spring Security
 
Efficient HTTP applications on the JVM with Ratpack - JDD 2015
Efficient HTTP applications on the JVM with Ratpack - JDD 2015Efficient HTTP applications on the JVM with Ratpack - JDD 2015
Efficient HTTP applications on the JVM with Ratpack - JDD 2015
 
Stateless authentication with OAuth 2 and JWT - JavaZone 2015
Stateless authentication with OAuth 2 and JWT - JavaZone 2015Stateless authentication with OAuth 2 and JWT - JavaZone 2015
Stateless authentication with OAuth 2 and JWT - JavaZone 2015
 
Stateless authentication for microservices - GR8Conf 2015
Stateless authentication for microservices - GR8Conf 2015Stateless authentication for microservices - GR8Conf 2015
Stateless authentication for microservices - GR8Conf 2015
 
Ratpack 101 - GR8Conf 2015
Ratpack 101 - GR8Conf 2015Ratpack 101 - GR8Conf 2015
Ratpack 101 - GR8Conf 2015
 
Ratpack 101 - GeeCON 2015
Ratpack 101 - GeeCON 2015Ratpack 101 - GeeCON 2015
Ratpack 101 - GeeCON 2015
 
Stateless authentication for microservices - Spring I/O 2015
Stateless authentication for microservices  - Spring I/O 2015Stateless authentication for microservices  - Spring I/O 2015
Stateless authentication for microservices - Spring I/O 2015
 
Stateless authentication for microservices - Greach 2015
Stateless authentication for microservices - Greach 2015Stateless authentication for microservices - Greach 2015
Stateless authentication for microservices - Greach 2015
 
Stateless authentication for microservices applications - JavaLand 2015
Stateless authentication for microservices applications -  JavaLand 2015Stateless authentication for microservices applications -  JavaLand 2015
Stateless authentication for microservices applications - JavaLand 2015
 
Stateless authentication for microservices
Stateless authentication for microservicesStateless authentication for microservices
Stateless authentication for microservices
 
Stateless token-based authentication for pure front-end applications
Stateless token-based authentication for pure front-end applicationsStateless token-based authentication for pure front-end applications
Stateless token-based authentication for pure front-end applications
 
Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)
Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)
Workshop: Creating RESTful API’s with Grails and Spring Security (GR8Conf 2014)
 
Embrace the frontend revolution
Embrace the frontend revolutionEmbrace the frontend revolution
Embrace the frontend revolution
 
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
DevQA: make your testers happier with Groovy, Spock and Geb (Greach 2014)
 

Kürzlich hochgeladen

HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 

Kürzlich hochgeladen (20)

HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 

Mastering Grails 3 Plugins - Greach 2016

  • 2. Álvaro Sánchez-Mariscal Software Engineer Grails Development Team sanchezmariscala@ociweb.com
  • 3.
  • 4. OCI is the new home of Grails More at ociweb.com/grails
  • 6. 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
  • 7. 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.
  • 10. 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!
  • 12. 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!
  • 13. The minimal plugin • Folder containing: • build.gradle • src/main/groovy with plugin descriptor. • Empty grails-app folder.
  • 14. 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.
  • 16. 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.
  • 17. 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/**/**'
 }
  • 18. 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.
  • 19. 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"
 }
  • 20. 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
 }
 
 }
  • 21. Enhancing artefacts import grails.artefact.Enhances
 import groovy.transform.CompileStatic
 
 @Enhances(['Controller', 'Service'])
 @CompileStatic
 trait DateSupport {
 
 Date now() {
 return new Date()
 }
 
 }
  • 23. 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.
  • 25. Modularisation • Benefits: • Optional dependencies. • Smaller JAR files. • Build logic reuse.
  • 26. Modularisation setup • settings.gradle: include ‘myPlugin-core', ‘myPlugin-domain' //etc
  • 27. 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
 }
 }
  • 28. 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"
 }
  • 29. Aggregating Docs task aggregateGroovyDoc(type: Groovydoc) {
 group = JavaBasePlugin.DOCUMENTATION_GROUP
 
 dependsOn subprojects.groovydoc
 source subprojects.groovydoc.source
 destinationDir file("${buildDir}/docs/groovydoc")
 classpath = files(subprojects.groovydoc.classpath)
 groovyClasspath = files(subprojects.groovydoc.groovyClasspath)
 }
  • 31. 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.
  • 33. • 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
 }
  • 34. 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
  • 35. Build setup • Define rootProject.name in settings.gradle. • Define credentials in ~/.gradle/gradle.properties.
  • 36. Running it • Snapshot publishing: • Release publishing: $ ./gradlew artifactoryPublish $ ./gradlew publishPlugin notifyPluginPortal
  • 37. 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
  • 39. 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.
  • 40. 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
  • 41. 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
  • 42. 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
  • 43. 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.
  • 44. 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
  • 45. Use case: the Spring Security REST plugin