Create a Script Plugin

The process to create a script plugin is outlined on Setting up a Development Environment. For a basic plugin, it is only necessary to follow the guide up until the Advanced IntelliJ IDEA Configurations section.

For a more advanced plugin, read on.

Script Plugins

A script plugin is some ScriptRunner scripts and their configuration bundled as an Atlassian app.

Using a script plugin gives you two practical advantages, compared to configuring your scripts as normal through the ScriptRunner UI:

  1. Configuration as Code

    ScriptRunner supports storing the configuration of your extension points as code. You can bundle a descriptor file (YAML) into your script plugin that details the configuration for an extension point(s) so that as soon as the plugin is installed, your item is automatically configured.

    For example: You are able to provide an event listener, which uses a script inside a script root, and ship these files in a plugin. Upon the plugin’s installation, ScriptRunner detects it and installs all the items listed in the descriptor file.

    Upon disabling or removing the script plugin, these items are also removed.

  2. A Custom Script Root

    ScriptRunner supports looking up its script roots from inside another plugin. This means that it can automatically add the root of another plugin to its collection of script roots. This allows event listeners, built-in scripts, and other extension points to be loaded directly from those script roots.

Who This is For

  • Atlassian Experts and partners who would like to deliver a fully functional business process to a customer, without having to manually copy scripts to their server.

  • Developer teams which would like to implement common software development practices for their ScriptRunner scripts.

    Some examples include version control, automated testing, code review, and continuous integration.

Descriptor File (YAML)

Inside the src/main/resources/ directory of each individual module (jira, confluence, etc.) you will find a scriptrunner.yaml file. This is the descriptor file which contains the details of all your configured extension points. This file is where ScriptRunner looks for all the items that it will automatically configure upon the script plugin’s installation.

There should be an example item already present in the file, like the one shown below.

A YAML descriptor file, with an example item.

The code that needs to go inside the YAML file can be automatically generated using ScriptRunner’s Configuration Exporter built-in script.

The scriptrunner.yaml file should be at the root of the plugin’s jar file. Keeping it in src/main/resources will make sure this is always the case.

Quick Reload Plugin

If you ever modify any compiled code or the YAML descriptor file, you will need to re-install the Script Plugin in order to see your changes. Normally, this is done by running mvn package to build a new jar, then running mvn jira:install (or confluence:install, bitbucket:install as appropriate) to install the new jar into your application.

The ScriptRunner Samples project comes bundled with the Quick Reload Plugin, which will notice the updated jar (after running mvn package) and automatically re-install the plugin into your application.

Test

If you have written integration tests, they can be run using mvn verify. The command will:

  1. Start a host application.

  2. Run the integration tests inside the application.

  3. Shut down the application.

The above command runs your whole test suite.

If you would like to run just one test, you can start your application with mvn <app>:debug. Then once your app started, run your tests directly from IntelliJ by clicking the Run icon next to your test.

Known Limitations

There are some limitations with creating a script plugin:

  • If you disable or uninstall ScriptRunner, your script plugin is also disabled. It won’t be re-enabled automatically when you re-enable ScriptRunner. You have to enable it manually.

  • Certain extension points cannot be created or configured via the scriptrunner.yaml file. Take a look below to see what is supported.

    JiraConfluenceBitbucket

    Event Listeners

    Event Listeners

    Event Listeners

    REST Endpoints

    REST Endpoints

    REST Endpoints

    Fragments

    Fragments

    Fragments


    Macros

    Pre-hooks


    Jobs

    Post-hooks



    Merge Checks

Script Roots

Previously when entering a file to be run (console, workflow function, script field etc) you were required to give the full script path, or the path relative to the catalina.base directory.

This version introduces the concept of script roots - these are directories in whose files and subdirectories you can keep your scripts. The advantages of this is that changes to dependent classes will be detected automatically, and get automatically recompiled. Note - the one exception is when you first change a dependent class without having changed the class/script that’s actually called (a JQL function, workflow function etc). In this case, make some irrelevant change like adding a space to a comment to the calling script. After having done this, changes to the base or dependent class will trigger recompilation of both.

When the plugin is first installed it will create a directory called "scripts" under your Jira home directory, and register it as one of its script roots. This should be sufficient for most users and no other configuration need be made. This is a logical place to store your scripts, as it’s preserved during Jira upgrades, and by definition will be accessible by all nodes in a clustered Jira.

You can create subdirectories for your scripts, perhaps dividing them up into the business processes they support. You can also create supporting or utility classes to be used by them, but ensure they have the correct package, otherwise you will get a compilation error.

For instance, a script and a class:

<jira-home>/scripts/foo.groovy

groovy
import util.Bollo log.debug ("Hello from the script") Bollo.sayHello()

<jira-home>/scripts/util/Bollo.groovy 

groovy
package util public class Bollo { public static String sayHello() { "hello sailor!!!" } }

Absolute paths outside of script roots will continue to work, although changes to dependent classes may not get picked up.

Upgrading from Previous Versions

In previous versions of ScriptRunner, relative paths were resolved to the container working directory, ie $catalina.base on Tomcat.

This is no longer the case,​ relative paths will be resolved relative to each of the script roots until a file is found. If you don’t wish to change all your paths, you can add a new script root, pointing to either the working directory, or better, to where you had your scripts.

For instance, let’s say your jira instance is in /usr/opt/jira, and you had your scripts in /usr/opt/scripts. Therefore you would have referred to them as ../scripts/foo.groovy.

Now you will add a new property pointing to your scripts dir:

set JAVA_OPTS=%JAVA_OPTS% -Dplugin.script.roots=/usr/opt/scripts

Resolving ../scripts/foo.groovy relative to this script path will have the same result.

If you have multiple roots then use a comma to delimit them.

If you are working on a script locally before deploying to production, you can set breakpoints in scripts or classes and attach the debugger.

If you are working on the plugin it makes sense to add the src and test directories from the checkout, so you can work on the scripts without having to recompile.

set JAVA_OPTS=%JAVA_OPTS% -Dplugin.script.roots=checkout-directory\src\main\resources,checkout-directory\src\test\resources

Script Root Search

ScriptRunner has the ability to search for scripts contained within your configured script roots. Wherever you were able to enter the path of a script to run, you can now search for the script directly in the script file input. You can search by script name, or traverse the sub-directory structure to find the script you’re looking for!

To help you easily find the scripts you’re looking for, here are a few tips:

Find a Script by Name

If you know the name of the script root you can simply start typing the name of the script you want in the normal file entry:

  1. Start typing the name of the script you want to find

  2. After typing the first character, the search will return results that you can select from

    If there are too many results, simply keep typing characters to refine the search.

  3. When your script is found, either:

    • Highlight the script you want by moving down to it with the keyboard (down key) then press "Enter"

      OR

    • Use the mouse to left-click the script you wish to select

  4. The script will now be loaded for use and the static-type checking will begin

Browse the Script Roots to Find a Script

If you don’t know the name of the file, but suspect that exists somewhere in one of your script roots, you can browse the directory structure under those roots until you find it:

  1. Start typing the name of the sub directory you want to browse in your script root

  2. After typing the first character, the search will return results that you can select from

    If there are lots of directories returned, you can simply keep typing to refine the search. As you add characters to your search phrase, the results will be refined.

  3. Once you find the directory you wish to check inside:

    • Left-click the desired directory

      OR

    • Press the "Down" key on the keyboard to highlight the entry, then press the "Tab" key

  4. Now you will see a list of scripts and subdirectories in that directory!

  5. Repeat that process until you find the script you are looking for

When you navigate into a directory, the results will only show the scripts in that directory. If you want to search ALL scripts, just remove all characters from the input and start again.

You can use tab completion to navigate the directory structure. If you go too far, simply remove the characters to the previous slash and then the search should come back with the correct results.

Result Types

This table demonstrates the different types of result that the search could return.

Table 1. Result Types

IconDescription

An executable groovy script

A sub-directory within one of your script roots

On this page