Closed jamesfredley closed 1 week ago
@rainboyan are you able to help with this?
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.
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 ?
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
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
@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'
}
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
@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.
You can also Reload the Gradle project and see the exception.
@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.
@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")
}
@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.
@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.
@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.
@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
}
@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?
@codeconsole It was these changes which you restored to gradle/assemble.gradle
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.
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?
@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 buildSrc
and 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
@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
@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")
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.
Is the Forge shell capable of loading auto completing Application Commands from plugins?
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
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.
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.
@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.
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'
}
}
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"