Nexus 3 Groovy Script development environment setup

This article summarizes how to setup tooling to enable groovy script development for Nexus 3. IDE code completion is essentially required in order know which API options are available to your scripts.

1. Start with the project from the 'Nexus Book Examples' source code repo:

$ git clone git@github.com:sonatype/nexus-book-examples.git
Cloning into 'nexus-book-examples'...

2. Checkout the 'nexus-3.x' branch, which contains the examples:

$ cd nexus-book-examples
$ git checkout -t origin/nexus-3.x

This tells git to create a new local branch and name the new local branch with the same name as the remote branch, and sets up the new branch to track the remote branch. At this point you should see a 'scripting' folder, as shown below:

$ ls
README.asciidoc	ant-ivy		gradle		raw
ant-aether	ant-tasks	maven		scripting

If you don't see the scripting folder, double check you are on the 'nexus-3.x' branch.

3. Open the sub directory 'scripting/nexus-script-example' in an IDE (IntelliJ IDEA is used here).

NexusScriptExample-IDEA-Open.png

4. Edit an existing script, or add a new one. Here we add a new script to the 'groovy' folder, and name the script 'myscript.groovy'.

First try at a 'mygroovy.script' that simply writes the names of your repositories to the nexus.log.

NexusScriptExample-LogRepos1.png

A second rewrite does the same thing, and is less verbose. 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)
}

NexusScriptExample-LogRepos2.png

Great. But does it work? Only one way to find out, and that is to run it in Nexus.

5. One way to run this script is to copy and paste the code into a new 'Execute script' task in Nexus. Then manually 'Run' the task. 

NX3-ExecTask.png

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 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. 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:

RemoteDebugConfig.png

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.

GroovyBreakPoint.png

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

Have more questions? Submit a request

0 Comments

Article is closed for comments.
Powered by Zendesk