A focus of Script Runner 3 is being able to script other plugins, for instance JIRA Agile (Greenhopper), Structure, etc etc.

There are two annotations that allow this. The first is @WithPlugin(pluginKey) , which will effectively make classes provided by the target plugin available to your script.

The second is @PluginModule, which injects an instance of this module in to your script.

These annotations only work when running a script that is under a script root…​ not a script outside a script root, nor code pasted into the console.
JIRA Agile is a special case - see Working With JIRA Agile.

Example

Here is a minimal example for listing structures from the Structure plugin. The comments in the script give more information about the important elements.

import com.almworks.jira.structure.api.PermissionLevel
import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.almworks.jira.structure.api.StructureServices

// Grab only useful for IDE help, not for runtime. Alternatively you can just add this jar to the
// "provided" scope for the module
@Grab(group = 'com.almworks.jira.structure', module = 'structure-api', version = '8.4.0')

// Specify that classes from this plugin should be available to this script
@WithPlugin("com.almworks.jira.structure")

// Inject plugin module
@PluginModule
StructureServices structureServices

/*
    The script itself follows...
*/
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def structureManager = structureServices.getStructureManager()
def structures = structureManager.getAllStructures(user, PermissionLevel.VIEW, false)
structures.each {structure ->
    log.debug("Structure: ID: ${structure.id}, name: ${structure.name}")
}

Add Issue to Structure on Transition

Here is another example with Structure, a post-function which adds the current current issue to a named structure. You might want this done automatically when the issue has been triaged or CCB’d…​ you may not wish to consider it in your structure before this point: https://gist.github.com/jechlin/9786790.

All Descendants Must be Resolved Condition

Another example, a condition whereby all descendant issues in all structures containing this issue must be resolved. This is just for illustrative purposes and not necessarily a good idea, or production code: https://gist.github.com/jechlin/9861951

@WithPlugin

This is an annotation that you can put in your or on a class. It takes the plugin key as an argument. You can get the plugin key from Manage Plugins:

image2014 3 26%2014%3A46%3A1

When this annotation is present, the classloader for the target plugin is added to the list of classloaders when your script is compiled and run, so your imports from eg the Structure plugin will be resolved.

Currently there is no way to make this fail quietly if the plugin you request is not present - vote for - if this is an issue.

@PluginModule

Annotating a variable in a class or a script, will inject an instance of this type into your script. This is most commonly used for getting hold of a module defined in another plugin. In a traditional plugin you would use <component-import> to achieve the same thing.

If you are working with Structure you may use:

import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.almworks.jira.structure.api.StructureServices
...
@PluginModule
StructureServices structureServices

Structure is quite easy because given a StructureServices you can get all the other services from that.

Do not initialise the variable yourself, eg:

@PluginModule
StructureServices structureServices = null

will produce an error:

startup failed: General error during semantic analysis: Cannot set plugin module when field already initialised

If you are working with Intellij IDEA you may get a warning about uninitialised variables:

image2014 3 26%2015%3A10%3A11

You can disable this with //noinspection GroovyVariableNotAssigned on your first use of the variable.