All interaction with Jira must be through the REST APIs provided. Atlassian provides comprehensive documentation including the JSON Schema for responses and request bodies which describe the shape of the JSON. For effective usage of ScriptRunner it is important to have an understanding of how to interact with Jira using the REST API.

Authentication and Authorization

All REST requests made from ScriptRunner are performed as either the ScriptRunner user or as the user that initiated the action. The initiating user is the current user of the Script Console, the user that performed the action to cause an event to fire or the user that performed a workflow transition that caused a Post Function to run. Atlassian Connect Add-ons must also register for API scopes. These work in a similar way to the permissions that are granted to iOS or Android apps, when installing the Jira Administrator can see the scopes that any given add-on is requesting. ScriptRunner requests all scopes as it is not know beforehand what any given user will want to do. Even given this there are restrictions on the APIs that are available to ScriptRunner.

  • No private APIs are available, only those specifically white-listed by Atlassian

  • Scopes are documented for

  • It is possible for Project Administrators to remove access to a particular add-on by modifying the permissions for a project.

Authentication from user scripts is handled by an authentication proxy builtin to ScriptRunner. Each script invocation is given a temporary authentication token to use to make requests into this proxy which will then perform the necessary request signing to make the authenticated request to your Jira instance. In this way authenticated requests happen transparently. Tokens that are handed to scripts are only valid for two minutes. Responses that come through the proxy have URLs modified to go through the proxy so that URLs in the JSON response can be used directly without manipulation. For example the following code shows how to fetch a project from an issue get.

String projectUrl = get("/rest/api/2/issue/EX-1").asObject(Map).body['fields']['project']['self']

get(projectUrl).asObject(Map).body.name
GROOVY

Unirest

The HTTP library provided by ScriptRunner is Unirest. Unirest is a simple, lightweight library that makes interacting with REST APIs simple and straightforward. It was chosen due to the minimal dependencies (based on Apache HTTP Client 4.5), flexibility (JSON mapping support is built in and object mapping provided by Jackson) and the clarity of API.

Unirest, Unirest.get, Unirest.post, Unirest.put, Unirest.head and Unirest.options are included in all scripts as import static which means no imports are needed in order to make HTTP requests. The base url to the ScriptRunner authentication proxy is filled in along with the authentication headers so making REST calls is as simple as copying and pasting from the Jira REST documentation.

Examples

Get issue types:

get('/rest/api/2/issuetype').asString().body

Create an issue:

def projectKey = 'TP'
def taskType = get('/rest/api/2/issuetype').asObject(List).body.find { it['name'] == 'Task' }['id'] (1)

post('/rest/api/2/issue') (2)
        .header('Content-Type', 'application/json')
        .body(
        [
                fields: [
                        summary    : 'Task Summary',
                        description: "Don't forget to do this!.",
                        project    : [
                                key: projectKey
                        ],
                        issuetype  : [
                                id: taskType
                        ]
                ]
        ])
        .asString().body (3)
GROOVY
  1. Use the issuetype REST endpoint to get all issuetypes, parse into a list, and find the type with name Task, then take the id of that type
  2. Make the post request to create the issue in the specified project with the specified issuetype

  3. It is important to note that the request is only made when one of the as* methods are called. asString() takes response and makes it available in .body as a String. asObject(Object) will use Jackson to parse the response from JSON

Update an issue:

def issueKey = 'TP-1' (1)
def newSummary = 'Updated by a script'

def result = put("/rest/api/2/issue/${issueKey}") (2)
    //.queryString("overrideScreenSecurity", Boolean.TRUE) (3)
    .header('Content-Type', 'application/json') (4)
    .body([
        fields: [
                summary: newSummary
        ]
    ])
    .asString() (5)

if (result.status == 204) { (6)
    return 'Success'
} else {
    return "${result.status}: ${result.body}"
}
GROOVY
  1. Issue key and new summary to set
  2. Create the rest PUT request - see documentation

  3. You must pass overrideScreenSecurity=true if you are trying to amend fields that are not visible on the screen - Note you must use the Add-on user when setting overrideScreenSecurity=true

  4. Important to set the content type of the PUT, and then the body content as a Groovy Map

  5. Calling .asString() executes the put and parses the result as a string

  6. The REST request responds with a 204 (no content) so there is no point reading the body

It is really important to pass overrideScreenSecurity in request url, if your request wants to change fields that are not visible on the screen. If you don’t, request response will be 403 with message that you don’t have permission to do that.