
How to work with Jira plugin from ScriptRunner or how to avoid code duplication
- Tutorial
In this article, I would like to discuss the problem of code duplication in the Adaptivist ScriptRunner.
When you start writing scripts in ScriptRunner, you usually write all the code in one script and then add this script to the post function, validator, condition, and the like.
Everything goes well until you find a mistake in the code, or there are no changes in business requirements. At this point, you understand that you need to correct not one script, but several scripts with changed logic, and even worse, you don’t remember which scripts you need to correct.
You can run a search in the directory in which the scripts are located, but as practice shows, such a solution to the problem almost always leaves bugs in the code.
This is a classic code duplication issue.
Let's try to get rid of code duplication.
The easiest way to solve the problem is to create a helper class in which the common parts of the code will be located, and the groovy script will access this helper class.
Let's try to implement this.
First, create a helper class called UtilHelper.groovy in the scripts / groovy / util directory:
Then create a post function called postfunction.groovy in the scripts / groovy / directory. In this function post, we will call the getMessage function from our helper class.
In order not to complicate the example, we will not add a post function to the business process, but call it from the Script Console:

We received a message from the UitlHelper.groovy file. So our method 1 worked.
Now I would like to talk about the pitfalls of this method:
I tested this code on ScriptRunner version 5.2.2
The following problems are possible on earlier versions of ScriptRunner:
To avoid the problems of this implementation method, as well as to obtain a number of additional advantages, I would suggest a different way to solve the problem with code duplication.
This method is based on the fact that we have a plugin that contains common code. Thus, we could use common code both in our development plugins and in ScriptRunner.
In my previous article, I talked about how to make a plugin that can be accessed from other plugins. The plugin was called jira-library. The plugin provided the LibraryService with the getLibraryMessage function. Let's try to call this function.
The jira-library plugin can be found here . The plug-in must be assembled by the team to
Next, we need to write a script in ScriptRunner that will access the jira-library plugin. For this, @WithPlugin and @PluginModule annotations are used. @WithPlugin allows you to import jira-library plugin classes, and @PluginModule allows you to embed (inject) LibraryService into a script. Read more about the principle of operation of these annotations here .
The script will look like this:
Let's try to run it in the script console:

The screenshot shows that the message from the jira-library plugin was displayed. So our solution works.
With this implementation method, the following problems arise:
The advantages of this approach are as follows:
When you start writing scripts in ScriptRunner, you usually write all the code in one script and then add this script to the post function, validator, condition, and the like.
Everything goes well until you find a mistake in the code, or there are no changes in business requirements. At this point, you understand that you need to correct not one script, but several scripts with changed logic, and even worse, you don’t remember which scripts you need to correct.
You can run a search in the directory in which the scripts are located, but as practice shows, such a solution to the problem almost always leaves bugs in the code.
This is a classic code duplication issue.
Let's try to get rid of code duplication.
Method 1
The easiest way to solve the problem is to create a helper class in which the common parts of the code will be located, and the groovy script will access this helper class.
Let's try to implement this.
First, create a helper class called UtilHelper.groovy in the scripts / groovy / util directory:
package groovy.util;
public class UtilHelper {
public static String getMessage() {
return "util helper message";
}
}
Then create a post function called postfunction.groovy in the scripts / groovy / directory. In this function post, we will call the getMessage function from our helper class.
package groovy
import groovy.util.UtilHelper;
log.error(UtilHelper.getMessage())
In order not to complicate the example, we will not add a post function to the business process, but call it from the Script Console:

We received a message from the UitlHelper.groovy file. So our method 1 worked.
Now I would like to talk about the pitfalls of this method:
I tested this code on ScriptRunner version 5.2.2
- If I add the postfunction.groovy file as an inline script to the script console,
then the UitlHelper class is not always found for import. - I originally created postfunction.groovy in the scripts / groovy directory, and then moved the file to the scripts / groovy / util directory. But despite this, I could still import the class from the scripts / groovy / directory.
The following problems are possible on earlier versions of ScriptRunner:
- A static compilation error occurs due to the fact that the compiler cannot find the imported UtilHelper class. When the script starts, the script runs without errors.
- If you make changes to the auxiliary class, the script does not see the changes in the auxiliary class until you make changes to the script.
To avoid the problems of this implementation method, as well as to obtain a number of additional advantages, I would suggest a different way to solve the problem with code duplication.
Method 2
This method is based on the fact that we have a plugin that contains common code. Thus, we could use common code both in our development plugins and in ScriptRunner.
In my previous article, I talked about how to make a plugin that can be accessed from other plugins. The plugin was called jira-library. The plugin provided the LibraryService with the getLibraryMessage function. Let's try to call this function.
The jira-library plugin can be found here . The plug-in must be assembled by the team to
atlas-mvn package и
install in Jira.Next, we need to write a script in ScriptRunner that will access the jira-library plugin. For this, @WithPlugin and @PluginModule annotations are used. @WithPlugin allows you to import jira-library plugin classes, and @PluginModule allows you to embed (inject) LibraryService into a script. Read more about the principle of operation of these annotations here .
The script will look like this:
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import ru.matveev.alexey.tutorial.library.api.LibraryService
@WithPlugin("ru.matveev.alexey.tutorial.library.jira-library")
@PluginModule
LibraryService libraryService
log.error(libraryService.getLibraryMessage()
Let's try to run it in the script console:

The screenshot shows that the message from the jira-library plugin was displayed. So our solution works.
With this implementation method, the following problems arise:
- In version higher than 5.1. the script only works as inline. In order for the script to work from a file, you need to write a script like this:
import com.onresolve.scriptrunner.runner.customisers.PluginModule import com.onresolve.scriptrunner.runner.customisers.WithPlugin import ru.matveev.alexey.tutorial.library.api.LibraryService import com.onresolve.scriptrunner.runner.ScriptRunnerImpl @WithPlugin("ru.matveev.alexey.tutorial.library.jira-library") LibraryService pl = ScriptRunnerImpl.getPluginComponent(LibraryService) log.error(pl.getLibraryMessage())
The bug is open in Adaptivist.
The advantages of this approach are as follows:
- You can make general code for both developed plugins and scripts in ScriptRunner
- You can implement in your own plugin what ScriptRunner does not support, and then use the plugin functionality in ScriptRunner. For example, this way you can implement feature rotation (feature toggle) . You can create a module such as webwork, which will enable or disable some functionality, and place it in the plugins section. Next, you can export a service that will inform the script in ScriptRunner whether the required functionality is enabled. If enabled, the script will perform the necessary actions.