Part 1 How to deploy Adaptivist ScriptRunner scripts and objects

In this article I would like to talk on how to deploy Adaptivist Scriptrunner scripts and objects such as Behaviours, Listeners, Script Fragments, Scripted fields, REST endpoints to a Jira instance.

This article will consist of two parts. In the first part we will learn how to deploy scripts, and in the second part we will learn how to deploy ScriptRunner objects.

You can find the source code of the developed in this article plugin here.

Suppose, we have three Jira environments: dev, test and production. We develop our scripts and create objects in the dev environment, and then we move our configuration to the test and production environments. I can see three ways how we can do it:

  1. We can move everything manually.
  2. We can save all scripts in Git, create a deployment plan in Bamboo, which would move all scripts from one environment to another automatically on push. But still we would need to move objects manually.
  3. We could develop a script plugin. All scripts and objects would be installed in our environments upon plugin installation.

In this article we will discuss the third way. 

You can find information on script plugin here. You can find an example of such a plugin here.

In my opinion this sample plugin has several disadvantages:

  1. It includes plugins for several Atlassian products, but I would like to have a script plugin only for Jira.
  2. The plugin is created for Jira version 7.5.1 and ScriptRunner 5.1.7. I would like to use Jira 7.9.0 and ScriptRunner 5.3.9.
  3. The plugin does not use spring scanner. I would like to use it.

 Let us try to create our own plugin.

Create plugin

Open terminal and execute:

atlas-create-jira-plugin

Answer questions the following way:

Define value for groupId: : ru.matveev.alexey.scriptrunner 
Define value for artifactId: : scriptrunner-plugin
Define value for version: 1.0.0-SNAPSHOT: :
Define value for package: ru.matveev.alexey.scriptrunner: :
Confirm properties configuration:
groupId: ru.matveev.alexey.scriptrunner
artifactId: scriptrunner-plugin version: 1.0.0-SNAPSHOT
package: ru.matveev.alexey.scriptrunner
Y: : Y

 Modify pom.xml

Your pom.xml file should look like this (I made comments to the most important parts of the file):

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>
<!--
I added the parent pom.xml, which does all the magic. I took this pom.xml from the ScriptRunner sample plugin
-->
<parent>
<groupId>com.adaptavist.pom</groupId>
<artifactId>scriptrunner-jira-standard</artifactId>
<version>10</version>
<relativePath/>
</parent>

<groupId>ru.matveev.alexey.scriptrunner</groupId>
<artifactId>scriptrunner-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>

<organization>
<name>Example Company</name>
<url>http://www.example.com/</url>
</organization>

<name>scriptrunner-plugin</name>
<description>This is the ru.matveev.alexey.scriptrunner:scriptrunner-plugin plugin for Atlassian JIRA.</description>
<packaging>atlassian-plugin</packaging>

<dependencies>
<!--
I excluded a couple of dependencies from the dependency below, because the plugin did not want to start for ScriptRunner versions higher than 5.3.0
-->
<dependency>
<groupId>com.onresolve.jira.groovy</groupId>
<artifactId>groovyrunner</artifactId>
<version>${scriptrunner.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>com.onresolve.scriptrunner.platform</groupId>
<artifactId>scriptrunner-test-libraries-jira</artifactId>
</exclusion>
<exclusion>
<groupId>jndi</groupId>
<artifactId>jndi</artifactId>
</exclusion>
<exclusion>
<groupId>jta</groupId>
<artifactId>jta</artifactId>
</exclusion>
<exclusion>
<groupId>is.origo.jira</groupId>
<artifactId>tempo-plugin</artifactId>
</exclusion>
<exclusion>
<groupId>com.tempoplugin</groupId>
<artifactId>tempo-core</artifactId>
</exclusion>
<exclusion>
<groupId>groovyrunner</groupId>
<artifactId>test</artifactId>
</exclusion>
<exclusion>
<groupId>com.atlassian.plugin.automation</groupId>
<artifactId>automation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-annotation</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-jira-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<productVersion>${jira.version}</productVersion>
<productDataVersion>${jira.version}</productDataVersion>
<!--
I increased JVM memory, because Jira 7.9.0 does not want to run with the default settings
-->
<jvmArgs>-Xms512M -Xmx1g</jvmArgs>
<enableQuickReload>true</enableQuickReload>
<enableFastdev>false</enableFastdev>
<applications>
<!--
I added Jira Software to the plugin because I want Jira Software to start on the atlas-run command.
-->
<application>
<applicationKey>jira-software</applicationKey>
<version>${jira.version}</version>
</application>
<!--
I added Jira Service Desk to the plugin because I want Jira Service Desk to start on the atlas-run command.
-->
<application>
<applicationKey>jira-servicedesk</applicationKey>
<version>${jira.servicedesk.application.version}</version>
</application>
</applications>
<instructions>
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
<Export-Package>
ru.matveev.alexey.scriptrunner.api,
</Export-Package>
<Import-Package>
org.springframework.osgi.*;resolution:="optional",
org.eclipse.gemini.blueprint.*;resolution:="optional",
*
</Import-Package>
<Spring-Context>*</Spring-Context>
</instructions>
</configuration>
</plugin>

<plugin>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<executions>
<execution>
<goals>
<goal>atlassian-spring-scanner</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
<configuration>
<scannedDependencies>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-external-jar</artifactId>
</dependency>
</scannedDependencies>
<verbose>false</verbose>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jira.version>7.9.0</jira.version>
<jira.servicedesk.application.version>3.12.0</jira.servicedesk.application.version>
<scriptrunner.version>5.3.9</scriptrunner.version>
<amps.version>6.3.6</amps.version>
<plugin.testrunner.version>1.2.3</plugin.testrunner.version>
<atlassian.spring.scanner.version>2.0.0</atlassian.spring.scanner.version>
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<testkit.version>6.3.11</testkit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
<!--
This is required to find the parent pom and ScriptRunner dependencies
-->
<repository>
<id>adaptavist-external</id>
<url>https://nexus.adaptavist.com/content/repositories/external</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
</repository>
</repositories>
</project>

Delete default folders

Delete the src/main/java folder and the src/test folder.

Create scripts

Let us create a couple of scripts, which we will use later in our listeners, scripted field, rest endpoint, script fragment and the script console:

src/main/resources/ru/matveev/alexey/main/listeners/listener.groovy

package ru.matveev.alexey.main.listeners

import org.slf4j.LoggerFactory;

def log = LoggerFactory.getLogger(this.getClass())
log.debug("listener {} executed", this.getClass())

src/main/resources/ru/matveev/alexey/main/rest/rest.groovy

package ru.matveev.alexey.main.rest

import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript

import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate

doSomething(httpMethod: "GET", groups: ["jira-administrators"]) { MultivaluedMap queryParams, String body ->
return Response.ok(new JsonBuilder([abc: 42]).toString()).build();
}

src/main/resources/ru/matveev/alexey/main/scriptedfields/scriptedfield.groovy

package ru.matveev.alexey.main.scriptedfields

import org.slf4j.LoggerFactory;
def log = LoggerFactory.getLogger(this.getClass())
log.debug("scripted field {} executed", this.getClass())

src/main/resources/ru/matveev/alexey/main/scripts/script.groovy

package ru.matveev.alexey.main.scripts

import org.slf4j.LoggerFactory;
def log = LoggerFactory.getLogger(this.getClass())
log.debug("script {} executed", this.getClass())

src/main/resources/ru/matveev/alexey/main/webfragments/webfragments.groovy

package ru.matveev.alexey.main.webfragments

import org.slf4j.LoggerFactory;
def log = LoggerFactory.getLogger(this.getClass())
log.debug("script {} executed", this.getClass())

 Test the plugin

Now we will run the plugin and have a look, if we can access our scripts.

Open terminal in the plugin folder and run the following command:

atlas-run

After Jira is launched, open localhost:8080/jira in your browser and login to Jira under admin:admin.

Let s set the DEBUG level for the ru.matveev package. Open cog wheel -> System->Logging and Profiling, click the Configure button:

 configure (1).jpg

Enter ru.matveev for the Package name, set DEBUG for the Logging Level and click the Add button.

Now we can try to execute one of our scripts.

Go to Add-ons -> Script Console. Choose the File tab and enter ru/matveev/alexey/main/scripts/script.groovy. You can also see that our plugin added a couple of new script roots, which means that ScriptRunner can see out scripts. You can read more about script roots here.

script.jpg

Click the Run button to execute the script:

script2.jpgWe can see that our script was executed, which means that we successfully added our scripts.

We will learn how to deploy ScriptRunner object in the second part of this tutorial. 

6 comments

Deleted user July 17, 2018

Hello,

I guess the code at "webfragments" is the code for scriptedfields.

Capture.PNG

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 17, 2018

No, web fragments and scripted fields are two totally different things. 

A web fragment is part of the ui - menu items, panels, buttons, etc.  ScriptRunner allows you to add your own, so you can add to the UI.  Most of us use web fragments to trigger scripts, or add information to a screen.

A scripted field is a field that looks at other data, works something out from it, and puts it on-screen in the same way all the other fields do.

Deleted user July 17, 2018

Yes sure haha, I said, in the tutorial, under the example of webfragment, there is the same code of the example of scriptedfield (look my screenshot).

Deleted user August 1, 2018

No correction (see my precedent comment) ?

Alexey Matveev
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
October 16, 2018

@[deleted] Corrected. Thank you :)

Olivier MOREAU May 20, 2020

Dear all,

Thanks very much for this very useful tutorial @Alexey Matveev

It works fine perfectly for me.

I have updated the pom.xml file for those who wants to deploy scriptrunner plugins in 2020 (The exclusions are not mandatory but if not added, there is an error while deploying an OSGi test component, but the server starts anyway).

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.adaptavist.pom</groupId>
<artifactId>scriptrunner-jira-standard</artifactId>
<version>24</version>
<relativePath/>
</parent>

<groupId>com.mycompany</groupId>
<artifactId>my-scriptrunner-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>

<organization>
<name>My Company</name>
<url>http://www.my-company.fr/</url>
</organization>

<name>scriptrunner-plugin</name>
<description>This is the com.carrefour.vital:jira4vital-scriptrunner plugin for Atlassian JIRA.</description>
<packaging>atlassian-plugin</packaging>

<dependencies>
<dependency>
<groupId>com.onresolve.jira.groovy</groupId>
<artifactId>groovyrunner</artifactId>
<version>${scriptrunner.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>com.onresolve.scriptrunner.platform</groupId>
<artifactId>scriptrunner-test-libraries-jira</artifactId>
</exclusion>
<exclusion>
<groupId>jndi</groupId>
<artifactId>jndi</artifactId>
</exclusion>
<exclusion>
<groupId>jta</groupId>
<artifactId>jta</artifactId>
</exclusion>
<exclusion>
<groupId>is.origo.jira</groupId>
<artifactId>tempo-plugin</artifactId>
</exclusion>
<exclusion>
<groupId>com.tempoplugin</groupId>
<artifactId>tempo-core</artifactId>
</exclusion>
<exclusion>
<groupId>groovyrunner</groupId>
<artifactId>test</artifactId>
</exclusion>
<exclusion>
<groupId>com.atlassian.plugin.automation</groupId>
<artifactId>automation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-annotation</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-jira-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<productVersion>${jira.version}</productVersion>
<productDataVersion>${jira.version}</productDataVersion>
<httpPort>2990</httpPort>
<jvmArgs>-Xms512M -Xmx1g</jvmArgs>
<enableQuickReload>true</enableQuickReload>
<enableFastdev>false</enableFastdev>
<applications>
<application>
<applicationKey>jira-software</applicationKey>
<version>${jira.version}</version>
</application>
</applications>
<instructions>
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
<Export-Package>
com.my-company.scriptrunner.api,
</Export-Package>
<Import-Package>
org.springframework.osgi.*;resolution:="optional",
org.eclipse.gemini.blueprint.*;resolution:="optional",
*
</Import-Package>
<Spring-Context>*</Spring-Context>
</instructions>
</configuration>
</plugin>

<plugin>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<executions>
<execution>
<goals>
<goal>atlassian-spring-scanner</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
<configuration>
<scannedDependencies>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-external-jar</artifactId>
</dependency>
</scannedDependencies>
<verbose>false</verbose>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jira.version>8.4.0</jira.version>
<scriptrunner.version>6.0.2-p5</scriptrunner.version>
<amps.version>6.3.21</amps.version>
<plugin.testrunner.version>1.2.3</plugin.testrunner.version>
<atlassian.spring.scanner.version>2.0.0</atlassian.spring.scanner.version>
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<testkit.version>6.3.11</testkit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
<repository>
<id>adaptavist-external</id>
<url>https://nexus.adaptavist.com/content/repositories/external</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
</repository>
</repositories>

</project> 

 

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events