Getting Started

JIRA Extension Points

The Script Console is the place for running one-off ad hoc scripts, and for learning and experimenting with the JIRA REST API from ScriptRunner.

script console

Run As User

Code run from the Script Console can make requests back to JIRA using either the ScriptRunner Add-on user or the current user. See the Run As User section of Workflow Extensions for more information.

Samples

Take one of these samples and use it as a starting point for your own needs.

Get JIRA Version

Starting with a very simple script to read the JIRA version and display it in the console. API Reference.

get('/rest/api/2/serverInfo') (1)
        .queryString('doHealthCheck', 'true') (2)
        .asObject(Map) (3)
        .body (4)
        .version (5)
1 This is a get request to the serverInfo resource
2 Just as an example we see how to add a query string parameter of doHeathCheck and set it to true
3 asObject(Map) makes the request and converts the response into a Map
4 Calling .body on the result of asObject(Map) returns a Map representation of the JSON response
5 We now read the version property of the resulting Map

Show Issue Counts for Projects Based on JQL

Now let’s perform a JQL search to find all stories and group them into projects to determine which projects have the most stories

Map<String, Object> searchResult = get('/rest/api/2/search')
        .queryString('jql', 'issuetype = Story')
        .queryString('fields', 'project')
        .asObject(Map)
        .body (1)

def issues = (List<Map<String, Object>>) searchResult.issues (2)

issues.groupBy { issue -> (3)
    ((Map<String, Map>) issue.fields).project.key
}.collectEntries { pKey, issueList -> (4)
    [(pKey): issueList.size()]
}.toString() (5)
1 Perform the JQL search, specifying we are interested in the project field from the issue
2 Grab all the issues from the search
3 Take each issue and group them by project key
4 The resulting list can be transformed into pairs of project key and the number of issues with that project key
5 Turn the result into a String for display

Now the display of this isn’t great. It would be nice to output a html table so lets do that using Groovy’s MarkupBuilder.

Map<String, Object> searchResult = get('/rest/api/2/search')
        .queryString('jql', 'issuetype = Story')
        .queryString('fields', 'project')
        .asObject(Map)
        .body

def issues = (List<Map<String, Object>>) searchResult.issues

def mapping = issues.groupBy { issue -> (1)
    ((Map<String, Map>) issue.fields).project.key
}.collectEntries { pKey, issueList ->
    [(pKey): issueList.size()]
}

import static io.github.openunirest.http.Unirest.get

def writer = new StringWriter()
def builder = new MarkupBuilder(writer) (2)
builder.table(class: "aui") {
    thead {
        tr {
            th("Project Key")
            th("Count")
        }
    }
    tbody {
        mapping.each { projectKey, count ->
            tr {
                td {
                    b(projectKey)
                }
                td(count)
            }
        }
    }
}

return writer.toString()
1 Up until this point everything is the same, except we assign the result to mapping
2 A new MarkupBuild is created, note the import. The markup builder takes advantage of Groovy’s meta-programming so the static type checking will cause errors, this is nothing to be worried about.

Update an issue

Another common task is to update a field of an issue. In this case we set the summary to be a new summary

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}"
}
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

Adding a User or Group to a Project Role

Say we would like to add a user to a group. This can be quickly achieved using the following assuming that the user, group, project and role all exist

def username = 'charlie'
def groupName = 'jira-core-users'
def projectKey = 'TP'
def roleName = 'Developers'

def roles = get("/rest/api/2/project/${projectKey}/role")
        .asObject(Map).body (1)

String developersUrl = roles[roleName] (2)

assert developersUrl != null

def result = post(developersUrl)
    .header('Content-Type', 'application/json')
    .body([
            user: [username], (3)
            group: [groupName]
    ])
    .asString()

assert result.status == 200
result.statusText
1 First all the roles for the project are fetched
2 Then the url for the specified role is found to use to post to
3 In this case we have a group and a user to add, user and group must be arrays

Extracting the value from a select list custom field

This example shows how you can extract the value that has been specified inside a select list field on an issue.

// The issue key
def issueKey = '<IssueKeyHere>'

// Fetch the issue object from the key
def issue = get("/rest/api/2/issue/${issueKey}")
        .header('Content-Type', 'application/json')
        .asObject(Map)
        .body

// Get all the fields from the issue as a Map
def fields = issue.fields as Map

// Get the Custom field to get the option value from
def customField = get("/rest/api/2/field")
        .asObject(List)
        .body
        .find {
                (it as Map).name == '<CustomFieldNameHere>'
        } as Map

// Extract and store the option from the custom field
def value = (fields[customField.id] as Map).value

// Return the option value
return "The value of the select list from the ${customField.name} custom field is: ${value}"

Extracting the values from a multi select list custom field

This example shows how you can extract the values that have been specified inside a multi select list field on an issue.

// The issue key
def issueKey = '<IssueKeyHere>'

// Fetch the issue object from the key
def issue = get("/rest/api/2/issue/${issueKey}")
        .header('Content-Type', 'application/json')
        .asObject(Map)
        .body

// Get all the fields from the issue as a Map
def fields = issue.fields as Map

// Get the Custom field to get the option value from
def customField = get("/rest/api/2/field")
        .asObject(List)
        .body
        .find {
    (it as Map).name == '<CustomFieldNameHere>'
} as Map

// Extract and store the option from the custom field
def values = fields[customField.id] as List<Map>

// Get each of the values from the multi select list field and store them
def fieldValues = values.collect {
    it.value
}

// Return the option values
return "The values of the multi select list from the ${customField.name} custom field are: ${fieldValues}"

Extracting the value from a radio button custom field

This example shows how you can extract the value that has been specified inside a radio button field on an issue.

// The issue key
def issueKey = '<IssueKeyHere>'

// Fetch the issue object from the key
def issue = get("/rest/api/2/issue/${issueKey}")
        .header('Content-Type', 'application/json')
        .asObject(Map)
        .body

// Get all the fields from the issue as a Map
def fields = issue.fields as Map

// Get the Custom field to get the option value from
def customField = get("/rest/api/2/field")
        .asObject(List)
        .body
        .find {
    (it as Map).name == '<CustomFieldNameHere>'
} as Map

// Extract and store the option from the radio buttons custom field
def radioButtonValue = (fields[customField.id] as Map).value

// Return the option value
return "The value of the radio buttons from the ${customField.name} custom field is: ${radioButtonValue}"

Extracting the values from a checkbox custom field

This example shows how you can extract the values that have been specified inside a checkbox field on an issue.

// The issue key
def issueKey = '<IssueKeyHere>'

// Fetch the issue object from the key
def issue = get("/rest/api/2/issue/${issueKey}")
        .header('Content-Type', 'application/json')
        .asObject(Map)
        .body

// Get all the fields from the issue as a Map
def fields = issue.fields as Map

// Get the Custom field to get the option value from
def customField = get("/rest/api/2/field")
        .asObject(List)
        .body
        .find {
    (it as Map).name == '<CustomFieldNameHere>'
} as Map

// Extract and store the option from the custom field
def checkboxValues = fields[customField.id] as List<Map>

// Get each of the values from the checkbox field and store them
def checkboxFieldValues = checkboxValues.collect {
    it.value
}

// Return the option values
return "The values of the checkboxes from the ${customField.name} custom field are: ${checkboxFieldValues}"

This example shows how you can create a link to an external URL on an issue.

// The url for the link
def linkURL = '<LinkURLHere>'

// the title for the link
def linkTitle = '<LinkTitleHere>'

// The issue key
def issueKey = '<IssueKeyHere>'

// Create the link on the specified issue
def result = post("/rest/api/2/issue/${issueKey}/remotelink")
        .header('Content-Type', 'application/json')
        .body([
        object: [
                title:linkTitle,
                url:linkURL
        ]

])
        .asObject(String)

// Check if the link created succesfully
if (result.status == 201) {
    return "Remote link with name of ${linkTitle} which links to ${linkURL} created successfully"
} else {
    return "${result.status}: ${result.body}"
}