Getting Started

JIRA Extension Points

This page is for users who want to move from JIRA Server to JIRA Cloud or from JIRA Cloud to JIRA Server and want to maintain ScriptRunner functionality.

Migration

Due to the differences in programming model and API no automatic migration between Server and Cloud exists. The process of migration involves analysing the desired functionality and translating that into the target platform. JIRA Cloud uses the Atlassian Connect framework to allow add-ons like ScriptRunner to provide additional functionality whereas JIRA Server (and Data Center) uses the Atlassian Plugins framework, known as Plugins v2 or P2. There are fundamental differences between Connect and P2 that directly impact ScriptRunner functionality and script writing. Some of the differences are:

Table 1. Platform Differences
P2 Connect

API

Java API - it is possible to call almost any of the Host application code directly. Plugins are running in the same JVM as the host application.

REST APIs are available to interact with the host application. Connect has access to a limited set of REST APIs as defined by the Product API Scopes, this means that Connect add-ons can only do things officially supported by the APIs, but it also means that APIs are less likely to change and add-ons are less likely to break as a result.

UI

Any part of the UI can be customised. Javascript runs as on the page in the same context and frame as the host application. Host application code can be manipulated and broken by add-ons and add-on code can easily be broken by host code (or its dependent libraries) updates.

Specific areas can be cusomised. Each add-on runs in its own iframe and Javascript Sandbox. Interaction with the host page is via a Javascript API.

Programming Model

In the same JVM as the host application. Events can be vetoed and code runs synchronously. A bug in add-on code can seriously affect application stability or performance.

Asynchronous. Runs as a completely separate service. No code runs in the same JVM as the host. Events are processed as webhooks that fired from the host and processed asynchronously by the add-on - no waiting for events to be processed. A failing add-on does not impact the performance of an Atlassian application (although functionality may be missing).

Authentication and Authorisation

Code can run as any user in the system including as no user (which is not the same as Anonymous). Authentication and authorisation can be bypassed.

Add-ons make requests as the add-on user or the user that initiated the interaction. It is not possible to bypass authorisation or authentication

In summary there are significant differences between the Connect and P2 frameworks and it is necessary to re-think how ScriptRunner scripts execute and interact with the host application when moving from Server to Cloud or Cloud to Server. The asynchronous nature of Connect has implications with regards to host interaction, for example in JIRA it is not possible to implement scripted validators, conditions or event listeners that prevent event processing. Similarly when writing ScriptRunner scripts for server hosts it is important to consider the impact that scripts will have, particularly when interacting with external systems that might be slow. As with most programming situations there are trade offs when writing scripts for both Cloud and Server and the limitations of Cloud are at the expense of stability and performance of the Atlassian application.

Features

ScriptRunner for JIRA Cloud is a product that is under development and investment is being made to add features to the platform. It doesn’t currently have the same feature set as the server version and some features are likely never to come to Cloud due to restrictions in the Cloud platform.

Table 2. Feature Differences
Feature Cloud Status

Workflow Functions

Implemented

JQL Functions

Implemented as 'JQL Aliases' and 'Enhanced Search'.

Script Listeners

Implemented, implementation differs when compared to Server due to inherent differences between Server and Cloud

Services

On the roadmap

Scripted Fields

On roadmap - partially possible with Script Listeners. Atlassian need to do some work before a full feature is possible

Workflow Conditions

On roadmap - likely to be restricted implementation

Workflow Validators

Not possible unless Atlassian add an extension point

Behaviours

Highly unlikely - There is no way to manipulate the Javascript on the JIRA page

REST API

Needs further input into usecases

Feedback on all these features would be most welcome via the Support Portal.

Migrating from ScriptRunner for JIRA Server to Cloud

Any migration from Server to Cloud will require rewriting scripts

The general approach to migrating a script from Server to Cloud is to analyse the purpose of the script, find the equivalent feature in Cloud (we have named them the same where possible) and rewrite the script. Interactions with APIs need to be replaced with calls to the appropriate REST APIs and it is possible that alternatives may need to be found for dependencies that are not available for ScriptRunner Cloud.

Grouping together operations

In a server script it is typical to call issue.setX() many time to update several fields of an issue at a time. When using ScriptRunner for JIRA Cloud these updates should be put into one issue update POST call to ensure that they are all included in the same changeset. Multiple calls to update the issue will issue multiple notifications which is not desirable. For example see the following two scripts which are from Workflow Functions:

import com.atlassian.jira.component.ComponentAccessor

import java.sql.Timestamp

def versionManager = ComponentAccessor.getVersionManager()
def projectComponentManager = ComponentAccessor.getProjectComponentManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def userUtil = ComponentAccessor.getUserUtil()

def project = issue.getProjectObject()

def version = versionManager.getVersion(project.getId(), "1.1")
def component = projectComponentManager.findByComponentName(project.getId(), "MyComponent")

if (version) {
    issue.setFixVersions([version])
}

if (component) {
    issue.setComponentObjects([component])
}

// a text field
def textCf = customFieldManager.getCustomFieldObject("customfield_12345")
issue.setCustomFieldValue(textCf, "Some text value")

// a date time field - add 7 days to current datetime
def dateCf = customFieldManager.getCustomFieldObject("customfield_12346") // Date time fields require a Timestamp
issue.setCustomFieldValue(dateCf, new Timestamp((new Date() + 7).time))

// a user custom field
def userCf = customFieldManager.getCustomFieldObject("customfield_12347")
issue.setCustomFieldValue(userCf, userUtil.getUserByName("admin")) // User CFs require an ApplicationUser

// system fields
issue.setDescription("A generated description")
issue.setDueDate(new Timestamp((new Date() + 1).time)) // set due date to tomorrow
// get custom fields
def customFields = get("/rest/api/2/field")
        .asObject(List)
        .body
        .findAll { (it as Map).custom } as List<Map>

def toUpdate1CfId = customFields.find { it.name == 'Custom Field 1' }?.id
def toUpdate2CfId = customFields.find { it.name == 'Custom Field 2' }?.id
def toUpdate3CfId = customFields.find { it.name == 'Custom Field 3' }?.id

def tomorrowStr = (new Date() + 1).format("yyyy-MM-dd'T'HH:mm:ssZ", TimeZone.getTimeZone("UTC")) // date format in iso8601
def resp = put("/rest/api/2/issue/\${issue.key}")
        .header('Content-Type', 'application/json')
        .body([
        fields: [
                fixVersions      : ['1.1'],
                component        : ['MyComponent'],
                description      : 'A generated description',
                (toUpdate1CfId): 'Some text value',
                (toUpdate2CfId): tomorrowStr,
                (toUpdate3CfId): 'admin'
        ]
])
        .asString()
assert resp.status == 204

Notice that the Cloud script is much shorter, and all of the updates occur in the same API call. There are no managers involved or other API calls. The documentation for the update is much simpler and smaller than the equivalent server implementation too, however there are a couple of things that should be pointed out. The fixVersion and component must exist or the whole update will fail, and the fields must be visible on screens.

Fields must be visible on the edit screens for them to be updated by the issue edit API
Assertions for response codes will print out the response body and relevant information. A good pattern is to use assert resp.status == 200 (replace 200 with the correct response code). Successful APIs call may respond with 204, others with 200, 201 or 303 depending on the API in use.

Logging

Logging in scripts is very helpful when debugging. In cloud scripts anything printed to stdout using println, or using a logger.info('message') call will be available in the Logs page, and in the execution history of Script Listeners and Workflow Functions. As noted above, usage of assertions can also help debugging and diagnosing the behaviour of scripts.

Behaviours

There is no way to implement Behaviours scripts in Cloud. Atlassian do not allow add-ons to inject Javascript or other frontend resources into the page. Please create a suggestion in the ScriptRunner Cloud support portal for features you’d like to see. Due to the limitations in the Atlassian Connect platform however, any behaviour related functionality will likely not be possible.

Pitfalls

Asynchronous Event Processing

Asynchronous execution of functions and events means that any updates performed by scripts will happen after the page loads for the user. However, ScriptRunner has a feature that will notify users when issues have been updated. The order of event processing is not preserved, so when multiple scripts are triggered from the same event the ordering is arbitrary and will likely not be consistent.

Event Triggering

Updates made in scripts will cause events to be fired. This means that Script Listeners need to check values before updating them as the script may trigger due to a previous invocation of the same script.

Edit Screen

When using the edit issue API, fields must be visible on the Edit screen for the issue to be modified.

Migration Approach

Migration has three stages. First analysis of the functionality of the existing scripts, next an analysis of the APIs and ScriptRunner features should be done and finally the implementation of the new scripts.

Note that at the time of writing only Script Listeners and Workflow Functions are implemented for ScriptRunner for JIRA Cloud but Scripted fields that make calculations purely based on the state of the issue can be implemented as Script Listeners. The Script Registry Built-in script can be used to find all ScriptRunner scripts. Each script should be analysed to determine if the functionality is desired and possible within the Cloud feature set. Once the scripts to be migrated have been identified writing out the script in pseudo code making the intention clear is a good next step.

Each interaction with JIRA should be compared against the REST API docs and the ScriptRunner features. Some features of ScriptRunner for JIRA have not yet been implemented in the cloud edition. Feature requests and Suggestions are welcome in the ScriptRunner Cloud support portal.

The final task is to re-implement the relevant scripts using ScriptRunner for JIRA Cloud.

Please ask on Atlassian Answers for any migration help. Be sure to mention Cloud or Server in your question.

Migrating from ScriptRunner for JIRA Cloud to Server

Any migration from Cloud to Server will require rewriting scripts

The process of migrating from Cloud to Server is a more straight forward procedure, but care still has to be taken. All ScriptRunner features in the Cloud version are available in the Server edition. The process for migration follows the same general path of discovery, analysis and implementation so much of the migration approach for Server to Cloud also applies to Cloud to Server.

First find all scripts in ScriptRunner for JIRA Cloud and analyse the functionality. Remember that ScriptRunner for JIRA Server has first class support for calculated fields. Next each script needs to be ported from the REST API into the Java API. The ScriptRunner for JIRA Server documentation has examples and guides for implementing scripts.