Note: Groovy scripting is disabled by default for security reasons. Development work on the groovy API was halted, and it will eventually be fully deprecated. Groovy scripting can also cause performance issues and damage your Nexus Repo instance It is recommended to use the REST API for development rather than using Groovy scripting. For more information see this article.
This article summarizes how to setup tooling to enable groovy script development for Nexus Repository 3. IDE code completion is helpful in order know which API options are available to your scripts.
1. Start with the git project from the Sonatype Nexus Community nexus-scripting-examples source code repo:
$ git clone git@github.com:sonatype-nexus-community/nexus-scripting-examples.git Cloning into 'nexus-scripting-examples'...
2. Change into the nexus-scripting-examples directory.
3. Open the sub-directory 'nexus-script-example' as either a Gradle or Maven project in an IDE.
4. Edit an existing script, or add a new one. For example, add a new script to the 'src/main/groovy' folder, and name the script 'myscript.groovy'.
Use some sample code that simply writes the names of your repositories to the nexus.log.
Here's the code:
import org.sonatype.nexus.repository.Repository repository.repositoryManager.browse().each { Repository currentRepository -> // do some stuff in each repository log.info("Found repository: " + currentRepository) }
Great. But does it work? Only one way to find out, and that is to run it in Nexus Repository 3.
5. One way to run this script is to copy and paste the code into a new 'Execute script' task in Nexus Repository 3. Then manually 'Run' the task.
View your nexus.log, and you should see output similar to that below showing the task ran successfully.
2017-12-19 14:48:13,224-0500 INFO [qtp1818518593-61] admin org.sonatype.nexus.quartz.internal.task.QuartzTaskInfo - Task 'mytask' [script] runNow 2017-12-19 14:48:13,224-0500 INFO [qtp1818518593-61] admin org.sonatype.nexus.quartz.internal.task.QuartzTaskInfo - Task 'mytask' [script] state change WAITING -> RUNNING 2017-12-19 14:48:13,243-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptEngineManagerProvider - Detected 2 engine-factories 2017-12-19 14:48:13,244-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptEngineManagerProvider - Engine-factory: Oracle Nashorn v1.8.0_131; language=ECMAScript, version=ECMA - 262 Edition 5.1, names=[nashorn, Nashorn, js, JS, JavaScript, javascript, ECMAScript, ecmascript], mime-types=[application/javascript, application/ecmascript, text/javascript, text/ecmascript], extensions=[js] 2017-12-19 14:48:13,245-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptEngineManagerProvider - Engine-factory: Groovy Scripting Engine v2.0; language=Groovy, version=2.4.11, names=[groovy, Groovy], mime-types=[application/x-groovy], extensions=[groovy] 2017-12-19 14:48:13,245-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptEngineManagerProvider - Default language: groovy 2017-12-19 14:48:13,251-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Task log: /Users/bhamail/sonatype/support/nexus3/nexus-3.6.2-01-mac/sonatype-work/nexus3/log/tasks/script-20171219144813.log 2017-12-19 14:48:13,265-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.groovy.GroovyScriptEngineFactory - Created engine: org.sonatype.nexus.internal.script.groovy.GroovyScriptEngine@6b5c2fae 2017-12-19 14:48:13,612-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=proxy, format=nuget, name='nuget.org-proxy'} 2017-12-19 14:48:13,613-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=hosted, format=maven2, name='maven-releases'} 2017-12-19 14:48:13,613-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=group, format=nuget, name='nuget-group'} 2017-12-19 14:48:13,613-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=hosted, format=maven2, name='maven-snapshots'} 2017-12-19 14:48:13,613-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=proxy, format=maven2, name='maven-central'} 2017-12-19 14:48:13,613-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=hosted, format=nuget, name='nuget-hosted'} 2017-12-19 14:48:13,613-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.internal.script.ScriptTask - Found repository: RepositoryImpl$$EnhancerByGuice$$990c1f4d{type=group, format=maven2, name='maven-public'} 2017-12-19 14:48:13,615-0500 INFO [quartz-7-thread-4] *SYSTEM org.sonatype.nexus.quartz.internal.task.QuartzTaskInfo - Task 'mytask' [script] state change RUNNING -> WAITING (OK)
6. Interactive Debugging - "Keep it Classy"
When executed, Groovy scripts are compiled to files in: sonatype-work/nexus3/tmp/groovy-classes. Only "class" objects get a matching .class file in this folder. The name of the .class file allows IDE's to map breakpoints in the groovy source code to locations in the compiled .class file.
So, to enable interactive remote debugging of groovy scripts, you need to enclose the groovy code you wish to debug in a groovy class. Keep in mind some objects are not visible inside the class, so you may need to pass such objects into the class (for example: 'log', and 'repo' below):
import org.sonatype.nexus.repository.Repository class MyGroovyClass { private final log private final repo MyGroovyClass(log, repo) { this.log = log this.repo = repo } void doStuff() { repo.repositoryManager.browse().each { Repository currentRepository -> // do some stuff in each repository log.info("Found repository: " + currentRepository) } } } new MyGroovyClass(log, repository).doStuff()
To interactily debug this script, you need to launch Nexus Repository 3 with remote debug enabled. To do so, stop Nexus, and edit: nexus-<version>/bin/nexus.vmoptions. Add the following to the top of the nexus.vmoptions file:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
Save the nexus.vmoptions file and restart Nexus Repository 3. You should see something like the output below in the nexus.log (or console), indicating remote debugging is active.
$ ./nexus-3.7.0-04/bin/nexus run Listening for transport dt_socket at address: 5005 ...
Create a remote debug "configuration" in your IDE, using port 5005:
Now set a break point on some code inside the groovy class (the example below has a breakpoint on line 15, "log.info..."). Run the IDE remote debug configuration (which attaches to the already running Nexus instance). When you execute the "mytask" task in Nexus (updated with your new "classy" groovy script), you will see the execution pause on the break point you defined in your IDE. The screenshot below shows the paused execution and allows you to inspect the state of variables at this point in the execution.
For the curious, more info about Groovy scripts and classes is available here: http://groovy-lang.org/structure.html#_public_static_void_main_vs_script
It is easy to unintentionally do real damage to your Nexus instance with groovy scripts. Please see: Groovy: Close those transactions or else...