Getting Started

JIRA Extension Points

If you are familiar with extensions to workflows from JIRA Server then some of the concepts here are a little different. Post Functions are implemented as asynchronous webhooks. This means that.

Also missing from the cloud edition are Scripted Conditions and Scripted Validators. JIRA Cloud does not provide extension points to write equivalent extensions to ScriptRunner on JIRA Server

Post Functions

ScriptRunner has several built in Post Functions. Each function contains a condition script that can be used to veto the rest of the script by returning false. Most functions also have additional code that can execute to modify the final action of the function.

Conditions

Conditions are able to provide some additional logic to restrict execution beyond what is achievable using workflow schemes. For example issue.fields.summary ==~ /^(?i)foo.*/' will ensure that the function only executes if the summary starts with "foo" (case insensitive). Other examples are:

  • Never Execute : false

  • Match only a specific issue type : ((Map) issue.fields.issuetype)?.name == 'Task'

  • Ensure that fields are present, in this case assignee must be set : issue.fields.assignee != null

Additional Code

Each post function that takes additional code will have specific bindings inserted into the additional code script. Clicking the help icon will show which bindings are available with links to their documentation.

Provided Functions

Clone Issue

Clone Issue takes the issue and creates a clone of it in. You can specify the target project, issue type and the kind of link that is created back to the source issue. It is possible to totally override issueInput with a new structure by setting issueInput from additional code however this is not recommended.

Create Subtask

This function will create a subtask for the issue that is being transitioned. It will not do anything for issues that are subtasks. It is possible to specify the subtask type and title along with executing additional code. Additional code will have issueInput bound as the structure that will be used in the post to /rest/api/2/issue to create the subtask. Overriding issueInput is possible by setting issueInput as part of the script.

Fast-Track Transition Issue

Fast-track Transition Issue takes the issue and performs a transition on it immediately. An optional comment can be supplied. Transitions are specified by name, and must be valid for the issue that is to be transitioned. Due to limitations in the JIRA REST API it is not possible to validate transition names until execution.

Send Email

TODO: Currently blocked by SRCLOUD-64

Transition Parent Issue

A function for subtaks. This will do nothing for issues that are not subtasks. The specified transition will be performed on the parent of the subtask. As with Fast-Track Transition Issue, the transition name is provided and not validated.

Modify Issue

Modify Issue gives the script author the ability to update the issue or perform any action, by cancelling the update. The update may be cancelled by setting issueInput to null. This maybe useful to use a Post Function in a similar way to a Script Listener.

Example: Calculated Custom Field

This example is similar to the calculated field example for Script Listeners except in this case the calculation is only performed when the issue on transitions specified in the workflow.

// these 4 values will be installation dependent
def input1CfId = 'customfield_10033'
def input2CfId = 'customfield_10034'
def outputCfId = 'customfield_10035'

def input1 = issue.fields[input1CfId] as Integer (1)
def input2 = issue.fields[input2CfId] as Integer

if (input1 == null || input2 == null) { (2)
    logger.info("Calculation using ${input1} and ${input2} was not possible")
    return
}

def output = input1 + input2

if (output == (issue.fields[outputCfId] as Integer)) { (3)
    logger.info("already been updated")
    return
}

put("/rest/api/2/issue/${issue.key}") (4)
    .header("Content-Type", "application/json")
    .body([
        fields:[
                (outputCfId): output
        ]
    ])
    .asString()
1 Grab the values of the custom fields from the event
2 Sanity check for null values - the issue may not have a value for any input
3 Here we check to see if the output field already has the calculated value, if it does do nothing. This is important because an IssueUpdated event will fire for the update we are about to perform
4 Update the value of the custom field

Example: Post to HipChat

This is an example of a very simple HipChat post, that updates a room with a notification that an issue has been updated. Extending the example would give the author the ability to generate a more complex message.

def apiToken = "YOUR_SECRET_TOKEN" (1)

Unirest.clearDefaultHeaders() (2)
post("https://api.hipchat.com/v2/room/test room/notification")
        .header("Content-Type", "application/json")
        .queryString('auth_token', apiToken)
        .body([
                message       : "<p>${issue.key} Updated</p>",
                notify        : false,
                message_format: "html"
        ])
        .asString() (3)
issueInput = null (4)
1 Generate a HipChat API token and use it here
2 Clear the Unirest default headers to remove the JWT token header
3 Make the POST request to hipchat with the auth_token
4 Prevent the script from updating the issue