grails / grails-core

The Grails Web Application Framework
http://grails.org
Apache License 2.0
2.78k stars 950 forks source link

Grails Shell for Grails 7 #13569

Closed jamesfredley closed 1 week ago

jamesfredley commented 1 month ago

There is a need for Grails Shell 7 for Grails 7 to support plugins using Custom Scripts, other Custom Scripts, IntelliJ Grails Plugin including the Run Grails Command and all other plugin functionality, etc. This will coexist with the new Forge CLI as time allows for migration of code and documentation to the new Forge and Gradle ways.

Discussion: https://github.com/orgs/grails/discussions/13562

PRs where grails-shell was removed. https://github.com/grails/grails-core/pull/13407/files https://github.com/grails/grails-gradle-plugin/pull/313/files

https://youtrack.jetbrains.com/issue/IDEA-353327/IDE-does-not-recognize-Grails-6.2.0-projects https://youtrack.jetbrains.com/issue/IDEA-327614/Idea-Intellij-does-not-recognize-a-project-with-grails-6 https://youtrack.jetbrains.com/issue/IDEA-351413/IntelliJ-IDEA-2024.1-fails-to-load-Grails-6.2.0-project-correctly https://youtrack.jetbrains.com/issue/IDEA-356545/Grails-Resources-not-linkable-via-Editor-asset

https://github.com/grails/grails-core/issues/13523 - outstanding issue with using gradlew runCommand -Pargs="generate-controller sampleapp.ClassA"

codeconsole commented 1 month ago

@rainboyan are you able to help with this?

rainboyan commented 1 month ago

If bring Shell back, how about the Forge? Do we need to maintain two CLI, The Forge use Micronaut CLI and provides Web UI, but Shell should maintain https://GitHub.com/grails-profiles and release all the profiles again. They are totally different.

codeconsole commented 1 month ago

Right now we need grails-shell so that IntelliJ Grails Plugin isn't broken. It is not ideal to maintain two CLIs. We need the Web UI. Is it possible to migrate everything into the Micronaut CLI? For instance, is it possible to get GrailsApplicationCommands that are in a plugin to autocomplete in the Micronaut CLI? What do you recommend @rainboyan ?

jamesfredley commented 1 month ago

I don't think the Forge cli will handle the pieces missing from Grails Shell cli.

With the Forge (Picocli/Rocker template) path Forge handles application generation with a set of commands and features and Forge does not include or call Gradle. Everything build and historical custom plugin script related is handled by Gradle directly.

Forge covers part of what Grails Shell handled, the web UI pretty much surfaces it all, and diverts the rest to Gradle directly and through the migration of custom scripts to GrailsApplicationCommand like S2QuickstartCommand ./gradlew runCommand "-Pargs=s2-quickstart com.yourapp User Role --groupClassName=RoleGroup" vs ./grails s2-quickstart com.yourapp User Role --groupClassName=RoleGroup and calling gradle directly instead of the grails wrapper scripts. The grails wrapper is not included in new applications. grails test package vs ./gradlew -Dgrails.env=test assemble

"While the revamped CLI [Forge] offers enhanced performance, it operates entirely offline, lacking awareness of the Grails application or its plugins. This change disrupts the traditional approach to executing custom scripts within the Grails environment. Previously, developers could create custom scripts to automate tasks or extend functionality. However, with the CLI’s new offline mode, the concept of custom scripts becomes obsolete."

More details in the links on: https://github.com/orgs/grails/discussions/13562

Grails Forge CLI 6.2.0

grails> -h
Usage: grails [-hvVx] [COMMAND]
Grails CLI command line interface for generating projects and services.
Application generation commands are:

*  create-app NAME
*  create-webapp NAME
*  create-restapi NAME
*  create-plugin NAME
*  create-webplugin NAME

Options:
  -h, --help         Show this help message and exit.
  -v, --verbose      Create verbose output.
  -V, --version      Print version information and exit.
  -x, --stacktrace   Show full stack trace when exceptions occur.

Commands:
  create-app           Creates an application
  create-webapp        Creates an application
  create-plugin        Creates an Grails Plugin
  create-web-plugin    Creates an Grails Web Plugin
  create-restapi       Creates an REST API
  create-domain-class  Creates a Domain Class
  create-taglib        Creates a Grails TagLib
  create-interceptor   Creates a Interceptor Class
  create-service       Creates a Service Class
  create-controller    Creates a Grails Controller
jamesfredley commented 1 month ago

The migration to Forge (Picocli/Rocker template) also explains why the generated application.yml is so much simpler than it was historically. PR to put environments back into the default.

info:
  app:
    name: '@info.app.name@'
    version: '@info.app.version@'
    grailsVersion: '@info.app.grailsVersion@'
grails:
  mime:
    disable:
      accept:
        header:
          userAgents:
          - Gecko
          - WebKit
          - Presto
          - Trident
    types:
      all: '*/*'
      atom: application/atom+xml
      css: text/css
      csv: text/csv
      form: application/x-www-form-urlencoded
      html:
      - text/html
      - application/xhtml+xml
      js: text/javascript
      json:
      - application/json
      - text/json
      multipartForm: multipart/form-data
      pdf: application/pdf
      rss: application/rss+xml
      text: text/plain
      hal:
      - application/hal+json
      - application/hal+xml
      xml:
      - text/xml
      - application/xml
  views:
    gsp:
      encoding: UTF-8
      htmlcodec: xml
      codecs:
        expression: html
        scriptlet: html
        taglib: none
        staticparts: none
    default:
      codec: html
  controllers:
    defaultScope: singleton
dataSource:
  url: jdbc:h2:mem:devDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
  driverClassName: org.h2.Driver
  username: sa
  password: ''
  pooled: true
  jmxExport: true
  dbCreate: update
hibernate:
  cache:
    queries: false
    use_second_level_cache: false
    use_query_cache: false
codeconsole commented 1 month ago

@jamesfredley I am not a big fan of including the grails-shell in my production jar. Have you found a workaround for this?

IntelliJ plugin works:

implementation 'org.grails:grails-shell:6.1.2'

IntellJ plugin does not work:

developmentOnly 'org.grails:grails-shell:6.1.2'

compileOnly 'org.grails:grails-shell:6.1.2'

configurations {
    ... 
    localRuntimeOnly
    runtimeOnly.extendsFrom localRuntimeOnly
}

dependencies {
   ...
   localRuntimeOnly 'org.grails:grails-shell:6.1.2'
}
rainboyan commented 1 month ago

Right now we need grails-shell so that IntelliJ Grails Plugin isn't broken.

I have created a fresh app using Grails 6.2.0 but haven't reproduced the issues as you said.

Execute below command successfully in IDEA 2024.1.4, what am I missing?

runCommand "-Pargs=generate-controller Comment"

Also I installed spring-security-core plugin successfully, before executing the command s2-quickstart, I should create the missing file conf/spring/resources.groovy first.

| Error Command execution error: grails-app/conf/spring/resources.groovy (No such file or directory)

@codeconsole @jamesfredley

jamesfredley commented 1 month ago

@rainboyan The easiest ways to experience the issue with the IntelliJ Grails Plugin in the Run Configuration widget which will have an X on it for Grails run configuration. It does not impact directly calling Gradle commands. Since the IntelliJ Grails Plugin doesn't load all of the enhanced functionality it provides is not loaded. You can still technically develop and run the Grails app, you are just missing the plugin enhanced functionality.

image

You can also Reload the Gradle project and see the exception. image

rainboyan commented 1 month ago

@jamesfredley Yeah I got it.

The Tools/Grails menu will be available only after I added grails-shell dependency.

I think this issue is due to IntelliJ Grails Plugin, the plugin should be updated to Grails 6.2, it should remove the dependency. I guess it use GrailsCli class to recognise the project as a Grails project.

jamesfredley commented 1 month ago

@codeconsole the following will exclude it from the jar. Depending upon which generated lib or distribution you use you might need to also do this for one or more of bootWar, bootDistTar, bootDistZip, distTar, distZip or war

jar {
    rootSpec.exclude("**/grails-shell-*.jar")
}
jamesfredley commented 1 month ago

@rainboyan I couldn't locate the IntelliJ Grails plugin code, but it I'd guess it might look for Grails Wrapper additionally in Grails 4 and earlier projects. A good portion of the plugin relies on being able to call the grails shell, like the New menus which use grails create-*

Since so many projects are Grails 5 and earlier and there are still many current things with 6.2 that need to call grails shell, my opinion is that grails shell should stick around as the bridge until everything can easily work another way. When I read through those IntellIJ tickets at the top of this issue, I worried about how many devs gave up on Grails since the bridge was missing.

Grails Shell and Grails Forge CLI can coexist in the interim, I believe. Neither is included in a default application and Grails Forge CLI seems to be architected to be separate from the Grails app.

rainboyan commented 1 month ago

@jamesfredley yeah the Grails IntelliJ Grails Plugin is not Open Source, so I don't use it, I'm a heavy CLI user.

While I can't locate the plugin code, I'm sure IDEA uses grails-shell as a criterion to identify Grails projects.

Grails Shell and Grails Forge CLI can coexist in the interim, I believe.

I believe it too. But it also adds to the cost of maintenance, Grails Forge for CLI, Web and REST API, but grails-shell only for Grails Commands of IDEA.

rainboyan commented 1 month ago

@codeconsole

Is it possible to migrate everything into the Micronaut CLI? For instance, is it possible to get GrailsApplicationCommands that are in a plugin to autocomplete in the Micronaut CLI?

I have no idea. I'm not familiar with Micronaut CLI, if speed is the advantage of the GraalVM, but you will lose some dynamic flexibility. That's fair.

codeconsole commented 1 month ago

@jamesfredley there is an issue with that approach, you get 7MB in bonus jars to exclude

+--- org.grails:grails-shell:6.1.2
|    +--- org.apache.maven:maven-resolver-provider:3.9.6
|    |    +--- org.apache.maven:maven-model:3.9.6
|    |    |    \--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    +--- org.apache.maven:maven-model-builder:3.9.6
|    |    |    +--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    |    +--- org.codehaus.plexus:plexus-interpolation:1.26
|    |    |    +--- javax.inject:javax.inject:1
|    |    |    +--- org.apache.maven:maven-model:3.9.6 (*)
|    |    |    +--- org.apache.maven:maven-artifact:3.9.6
|    |    |    |    +--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    |    |    \--- org.apache.commons:commons-lang3:3.12.0
|    |    |    +--- org.apache.maven:maven-builder-support:3.9.6
|    |    |    \--- org.eclipse.sisu:org.eclipse.sisu.inject:0.9.0.M2
|    |    +--- org.apache.maven:maven-repository-metadata:3.9.6
|    |    |    \--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    +--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-spi:1.9.18
|    |    |    \--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-util:1.9.18
|    |    |    \--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-impl:1.9.18
|    |    |    +--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    |    +--- org.apache.maven.resolver:maven-resolver-spi:1.9.18 (*)
|    |    |    +--- org.apache.maven.resolver:maven-resolver-named-locks:1.9.18
|    |    |    |    \--- org.slf4j:slf4j-api:1.7.36
|    |    |    +--- org.apache.maven.resolver:maven-resolver-util:1.9.18 (*)
|    |    |    \--- org.slf4j:slf4j-api:1.7.36
|    |    +--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    \--- javax.inject:javax.inject:1
|    +--- org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-spi:1.9.18 (*)
|    |    +--- org.apache.maven.resolver:maven-resolver-util:1.9.18 (*)
|    |    \--- org.slf4j:slf4j-api:1.7.36
|    +--- org.apache.maven.resolver:maven-resolver-impl:1.9.18 (*)
|    +--- org.apache.maven.resolver:maven-resolver-transport-file:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-spi:1.9.18 (*)
|    |    \--- org.slf4j:slf4j-api:1.7.36
|    +--- org.apache.maven.resolver:maven-resolver-transport-http:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-api:1.9.18
|    |    +--- org.apache.maven.resolver:maven-resolver-spi:1.9.18 (*)
|    |    +--- org.apache.maven.resolver:maven-resolver-util:1.9.18 (*)
|    |    +--- org.apache.httpcomponents:httpclient:4.5.14 (*)
|    |    +--- org.apache.httpcomponents:httpcore:4.4.16
|    |    +--- commons-codec:commons-codec:1.16.0 -> 1.15
|    |    \--- org.slf4j:slf4j-api:1.7.36
|    +--- commons-codec:commons-codec:1.16.0 -> 1.15
|    +--- org.codehaus.groovy:groovy:3.0.11 -> 3.0.21
|    +--- org.slf4j:slf4j-api:1.7.36
|    +--- org.slf4j:jcl-over-slf4j:1.7.36 (*)
|    +--- org.grails:grails-bootstrap:6.1.2 -> 6.2.0 (*)
|    +--- org.grails:grails-gradle-model:6.1.2 -> 6.2.0
|    |    +--- org.codehaus.groovy:groovy:3.0.21
|    |    +--- org.slf4j:slf4j-api:1.7.36
|    |    \--- org.slf4j:jcl-over-slf4j:1.7.36 (*)
|    +--- org.apache.ant:ant:1.10.14 (*)
|    +--- org.codehaus.groovy:groovy-ant:3.0.11 -> 3.0.21 (*)
|    +--- org.codehaus.groovy:groovy-json:3.0.11 -> 3.0.21 (*)
|    +--- org.codehaus.groovy:groovy-jmx:3.0.11 -> 3.0.21
|    |    \--- org.codehaus.groovy:groovy:3.0.21
|    +--- org.fusesource.jansi:jansi:1.18
|    +--- jline:jline:2.14.6
|    +--- org.gradle:gradle-tooling-api:7.3-20210825160000+0000
|    |    \--- org.slf4j:slf4j-api:1.7.30 -> 1.7.36
|    +--- org.springframework.boot:spring-boot-cli:2.7.18
|    |    +--- org.springframework.boot:spring-boot-loader-tools:2.7.18
|    |    |    +--- org.apache.commons:commons-compress:1.21
|    |    |    \--- org.springframework:spring-core:5.3.31 -> 5.3.33 (*)
|    |    +--- com.vaadin.external.google:android-json:0.0.20131108.vaadin1
|    |    +--- jline:jline:2.11 -> 2.14.6
|    |    +--- net.sf.jopt-simple:jopt-simple:5.0.4
|    |    +--- org.apache.httpcomponents:httpclient:4.5.14 (*)
|    |    +--- org.apache.maven:maven-model:3.9.4 -> 3.9.6 (*)
|    |    +--- org.apache.maven:maven-resolver-provider:3.9.4 -> 3.9.6 (*)
|    |    +--- org.apache.maven.resolver:maven-resolver-connector-basic:1.9.14 -> 1.9.18 (*)
|    |    +--- org.apache.maven.resolver:maven-resolver-transport-file:1.9.14 -> 1.9.18 (*)
|    |    +--- org.apache.maven.resolver:maven-resolver-transport-http:1.9.14 -> 1.9.18 (*)
|    |    +--- org.apache.maven:maven-settings-builder:3.9.4
|    |    |    +--- org.apache.maven:maven-builder-support:3.9.4 -> 3.9.6
|    |    |    +--- org.codehaus.plexus:plexus-interpolation:1.26
|    |    |    +--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    |    +--- org.apache.maven:maven-settings:3.9.4
|    |    |    |    \--- org.codehaus.plexus:plexus-utils:3.5.1
|    |    |    \--- org.codehaus.plexus:plexus-sec-dispatcher:2.0
|    |    |         +--- org.codehaus.plexus:plexus-utils:3.4.1 -> 3.5.1
|    |    |         \--- org.codehaus.plexus:plexus-cipher:2.0
|    |    +--- org.sonatype.plexus:plexus-sec-dispatcher:1.4
|    |    |    +--- org.codehaus.plexus:plexus-utils:1.5.5 -> 3.5.1
|    |    |    \--- org.sonatype.plexus:plexus-cipher:1.4
|    |    +--- org.sonatype.sisu:sisu-inject-plexus:2.6.0
|    |    |    +--- org.codehaus.plexus:plexus-component-annotations:1.5.5
|    |    |    +--- org.codehaus.plexus:plexus-classworlds:2.5.2
|    |    |    +--- org.codehaus.plexus:plexus-utils:3.0.18 -> 3.5.1
|    |    |    \--- org.eclipse.sisu:org.eclipse.sisu.plexus:0.3.0
|    |    |         +--- org.eclipse.sisu:org.eclipse.sisu.inject:0.3.0 -> 0.9.0.M2
|    |    |         +--- org.codehaus.plexus:plexus-component-annotations:1.5.5
|    |    |         +--- org.codehaus.plexus:plexus-classworlds:2.5.2
|    |    |         \--- org.codehaus.plexus:plexus-utils:3.0.17 -> 3.5.1
|    |    +--- org.springframework:spring-core:5.3.31 -> 5.3.33 (*)
|    |    \--- org.springframework.security:spring-security-crypto:5.7.11 -> 5.8.13
|    \--- org.codehaus.plexus:plexus-component-api:1.0-alpha-33
|         +--- org.codehaus.plexus:plexus-classworlds:1.2-alpha-10 -> 2.5.2
|         \--- junit:junit:3.8.1 -> 4.13.2 (*)

need to turn off transitive as well

    implementation('org.grails:grails-shell:6.1.2') {
        transitive = false
    }
codeconsole commented 1 month ago

@jamesfredley so I am wondering how we can get IntelliJ to resolve grails-shell in 6.2.1 without having to put it in the build path. We probably need to first figure out how it is resolving it in 5.x

git clone https://github.com/codeconsole/website
cd website
./gradlew dependencies|grep grails-shell 
# no grails-shell is resolved in any configuration

Does it have something to do with the grails-wrapper.jar? https://github.com/codeconsole/website/tree/5.3.2

@rainboyan thoughts?

jamesfredley commented 1 month ago

@codeconsole It was these changes which you restored to gradle/assemble.gradle

https://github.com/grails/grails-core/commit/624c421ae055a820e2f80459b273a35560463454#diff-17de776cf455cc117e083046d7ff463380a53ea6c58d8bf241388ce504b6032e

I just tested it against your website project using Grails 6.2.1-SNAPSHOT and grails shell 6.1.2 is available for IntelliJ, but does not get put into the build path.

codeconsole commented 1 month ago

I just tested it against your website project using Grails 6.2.1-SNAPSHOT and grails shell 6.1.2 is available for IntelliJ, but does not get put into the build path.

@jamesfredley I am not following you?Why would 6.1.2 be available? wouldn't it be 6.2.1-SNAPSHOT?

jamesfredley commented 1 month ago

@codeconsole I was getting grails-shell:6.1.2 because of org.grails:grails-gradle-plugin:6.1.2 in buildSrc, which I didn't check. For my projects I stopped using buildSrcand went back to buildscript{} in the main build.gradle file.

So updating gradle.properties

grailsVersion=6.2.1-SNAPSHOT
grailsGradlePluginVersion=6.2.1-SNAPSHOT

and buildSrc/gradle.build

implementation("org.grails:grails-gradle-plugin:6.2.1-SNAPSHOT")

gives you grails-shell:6.2.1-SNAPSHOT on the runtimeClasspath

codeconsole commented 1 month ago

@jamesfredley so my previous comment was in regards to why it has to be added and in a 5.x project it does not.

./gradlew buildEnvironment 
classpath
+--- org.grails:grails-gradle-plugin:5.3.0
|    +--- org.grails:grails-shell:5.3.0

shows grails-shell being a dependency of the grails-gradle-plugin so we need to add that back so it doesn't have to be added manually.

@rainboyan @jamesfredley should we roll back profile task as well? https://github.com/grails/grails-gradle-plugin/pull/313

jamesfredley commented 1 month ago

@codeconsole gradle/assemble.gradle in https://github.com/grails/grails-core/commit/624c421ae055a820e2f80459b273a35560463454#diff-17de776cf455cc117e083046d7ff463380a53ea6c58d8bf241388ce504b6032e was "why it has to be added [in 6.2] and in a 5.x project it does not". It works on 6.2.1-SNAPSHOT just like on 5.3.2. No need to add the dependency manually.

What you found on the org.grails:grails-gradle-plugin dependencies is another reason. So two reasons it was there, but either is enough.

task grailsCreateStartScripts(type: GrailsCreateStartScripts) {
    description = "Creates OS specific scripts to run grails-shell as a JVM application."
    mainClass.set('org.grails.cli.GrailsCli')
    applicationName = 'grails'
    defaultJvmOpts = ["-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-XX:CICompilerCount=3"]
    outputDir = file('bin')
    classpath = rootProject.childProjects['grails-shell'].configurations.runtimeClasspath
    projectArtifacts = rootProject.childProjects['grails-shell'].tasks['jar'].outputs.files.collect { "dist/${it.name}" }
    doLast {
        ant.replace(file: file('bin/grails'), token: 'media/gradle.icns', value: 'media/icons/grails.icns')
        ant.chmod(file: file('bin/grails'), perm: 'ugo+rx')
    }
}

grails-shell needs profiles to run the app, gradle does not

> Task :buildSrc:build UP-TO-DATE

CONFIGURE SUCCESSFUL in 2s
1 actionable task: 1 up-to-date
Error |
Could not resolve all dependencies for configuration ':profile'. Type 'gradle dependencies' for more information

profile ("org.grails.profiles:web")

rainboyan commented 1 month ago

If we don't use Shell to create apps with Profiles, it is not needed anymore. But Grails 6 doesn't provide replacements for Angular React Vue profiles, I don't know developers are still using these profiles, these repositories haven't been updated for 2 years.

codeconsole commented 1 month ago

Is the Forge shell capable of loading auto completing Application Commands from plugins?

jamesfredley commented 1 month ago

No, this is the complete list of commands for Forge.

Quote from https://medium.com/@puneetbehl/a-comprehensive-guide-to-custom-application-command-in-grails-framework-f7496406ac50: "it operates entirely offline, lacking awareness of the Grails application or its plugins. This change disrupts the traditional approach to executing custom scripts within the Grails environment."

  create-app           Creates an application
  create-webapp        Creates an application
  create-plugin        Creates an Grails Plugin
  create-web-plugin    Creates an Grails Web Plugin
  create-restapi       Creates an REST API
  create-domain-class  Creates a Domain Class
  create-taglib        Creates a Grails TagLib
  create-interceptor   Creates a Interceptor Class
  create-service       Creates a Service Class
  create-controller    Creates a Grails Controller
sdelamo commented 3 weeks ago

Grails moved in the direction of embracing Gradle instead of maintaining two ways of doing the same thing. The old grails shell commands and grails tasks.

jamesfredley commented 3 weeks ago

This effort is to provide time and a bridge until a higher percentage can be converted from the old Grails Shell CLI way to the new ways:

When Grails Shell was removed in Grails 6 for new default Grails apps, several significant things broke, that will still be there in 7, and this is an attempt to make that transition smoother, especially for new grails developers.

codeconsole commented 3 weeks ago

@sdelamo from what James is saying it is not 2 ways of doing the same thing if embracing gradle is not even capable of doing the same thing.

The way it was removed completely broke everything. Grails 6.2 resulted in a completely broken cli and completely broke the InteliJ plugin which a large percentage of developers depend on.

fernando88to commented 1 day ago

For IntelliJ Idea to recognize and function normally with the Grails 6.2.0 project, I added the dependency

implementation 'org.grails:grails-shell:6.1.2

To exclude it from the final artifact, I put it in the build.gradle like this: if I don't remove the Grails shell from the final artifact, it will give an error when deploying to Tomcat.

configurations {
    developmentOnly
    runtimeClasspath {
        // Excludes from database-migration
        exclude group: 'org.grails', module: 'grails-shell'
    }
}