Post Functions
A post function is a workflow function that performs automated actions after an issue transitions to a new status. ScriptRunner has several built-in post functions. Each function contains a condition that can be used to dismiss the rest of the script if it returns false. Most functions also have additional code that can execute to modify the final action of the function.
There are several ways to enhance your workflow using post functions, including:
-
Automatically add or remove an issue from the active sprint after it is transitioned.
-
Change the assignee of an issue after it’s transitioned.
-
Send a notification on the transition of an issue.
Limitations
Post functions in ScriptRunner for Jira Cloud are implemented as asynchronous webhooks. This means that:
-
Post functions cannot cancel a transition.
-
Ordering of post function execution is not defined (you cannot have one post function rely on the output of another).
-
The issue may be displayed to the user before all the post functions have executed. ScriptRunner attempts to indicate to the user that the issue has been updated in the background, but this is not guaranteed.
Create Post Function
-
Select the transition you wish to add the post function to.
-
Click Post Function→Add Post Function.
-
Select the ScriptRunner Post Function option then Add.
-
Select a post function from the list of available functions. For example Add/Remove From Script.
-
In the Description field, enter a short description of the post function.
-
Select Enable Post Function to enable it as soon as it is added.
Different options are available depending on the post function added, see the examples for each post function below for field descriptions, as well as Additional Code.
Tip
|
For help navigating to ScriptRunner workflow functions, follow the steps to navigate to workflow functions. |
Edit Post Function
-
Select the transition the post function is on.
-
Click Post Functions. A list of all post functions on the selected transition is shown.
-
To edit an existing post function, click the Pencil.
-
Edit the post function and click Update.
Fields
Post Function Condition
A post function Condition field provides additional logic to restrict execution beyond what is achievable using workflow schemes.
For example, issue.fields.summary ==~ /^(?i)foo./
ensures the function only executes if the *Summary starts with "foo" (case insensitive).
Other examples include:
-
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
The area immediately above the code editor displays the Script Context parameters already available in your code and a link to more documentation.
Additional Code
The Additional Code field allows users to enter a script to run an additional action after an issue is transitioned.
For example, you may want to add a comment when a parent issue is transitioned as part of a post function: addComment.body = "$ {issue.key} caused this to be transitioned"
.
The area immediately above the code editor displays the Script Context parameters already available in your code and a link to more documentation.
Script Context
Script Context provides a set of parameters/code variables that are automatically injected into your script to provide contextual data for the post function. They are also available for the Condition and Additional Code fields and are displayed immediately above the code editor.

The Script Context for Additional Code and Conditions contain:
-
baseUrl - Base URL to make API requests against. This is the URL used for relative request paths. For example, if you make a request to
/rest/api/2/issue
we use the baseUrl to create a full request path. -
logger - Logger to use for debugging purposes.
-
issue - Transitioned issue details available as a map, for more details, see Get Issue REST API Reference.
-
transitionInput - The transition for the issue as a map, for more details, see Atlassian Connect Workflow Post Function Documentation.
Run as User
Post Functions can make requests back to Jira using either the add-on user (ScriptRunner Add-On User) or the user that performed the transition that triggered the post function (Initiating User).
When using the Initiating User, any action occurring as a result of the function is registered as being performed by them. For example, if an issue is commented on, the comment comes from the Initiating User rather than the obscure ScriptRunner Add-on User who may have nothing to do with the issue/project affected.
Permissions are considered when executing actions. The user selected in the Run as User field must have the correct permissions to do the action specified. Typically the ScriptRunner Add-on User has project admin permissions; however, this can be restricted. The Initiating User may have higher permissions than the ScriptRunner Add-on User.
Note
|
If your scripts are triggered by events invoked by another add-on, they are run as the ScriptRunner Add-on User user even if you set it up to be run as the current user because it’s not possible to impersonate other add-on users. We assume that a user is an add-on user if its name starts with a prefix ' add-on_'. |
Built-in Post Functions
ScriptRunner supplies several built-in post functions.
Add/Remove to/from Sprint
Using this post function, you can either add an issue to an active sprint or remove it from its current sprint after a transition.
For example, on the Start Progress transition, you can apply this post function to add the transitioned issue to the current sprint automatically. Although this does not follow scrum methodology, there may be times the team has finished all work in a sprint, and this post function allows issues to be added to the sprint automatically.
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Add/Remove from Sprint built-in post function.
-
Add a description of the post function in Description for example, Add Issue to Sprint.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the issue is added/removed to/from sprint. See Conditions for examples.
-
Select the Action you want to trigger after transition (either Add to Sprint or Remove from Sprint).
-
Choose the Board Name. The function picks the first active sprint from that board.
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Assign Issue
Assign Issue takes the issue and assigns it to the last assignee with a specified role or from a user group. You must specify either project role or a user group. If both are defined, the project role is used, and the user group is skipped.
For example, a developer finishes working on an issue and marks it as Ready to Test. After the issue is transitioned, the issue is automatically assigned to a tester. The tester rejects the issue, and it returns to the development team. The last user assigned in the development role is re-assigned to the issue. The dev can then fix the issue, and transition it back to the QA team. When they do, the issue is re-assigned to the same tester (last user in the tester role).
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Assign Issue built-in post function.
-
Add a description of the post function in Description for example, Assign to last developer.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the issue is assigned. See Conditions for examples.
-
Either select a Project Role (for example, Developer) or User Group. The last user with this role/in this user group is selected after the issue has transitioned.
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Clone Issue
Clone Issue creates a clone of a selected issue and optionally links the two issues. Specify the target project, issue type, link type, and link direction (between the source issue and the clone). For example, you have a ticket for a potential new hire. When this ticket transitions to Hired you want to automatically clone the issue to the IT board so the team can set up their login details.
Tip
|
It is possible to override issueInput with a new structure by setting issueInput from additional code; however, this is not recommended.
|
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Clone Issue built-in post function.
-
Add a description of the post function in Description for example, Create IT ticket.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the issue is cloned. See Conditions for examples.
-
Select an Issue Type for the cloned issue. Leave this field blank to make the cloned issue the same type as the source issue.
-
Select a Target Project; this is the project the new cloned issue is assigned to. Leave this field blank to clone the issue to the same project as source issue.
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
Select a link type under Link Name. The source issue and the clone are linked using this link type. Leave blank for no link.
-
Select the Link Direction between the source issue and the clone.
-
In the Additional Code field modify the
issueInput
structure before it is used as the POST body to/rest/api/2/issue
to create the issue. For example, add a label, set an assignee, or update the summary of the clone. -
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Supported Field Types
The Clone Issue function only copies Jira system fields and any custom fields which have the following types:
-
Checkbox
-
Date picker
-
Date time picker
-
Labels
-
Number field
-
Radio button
-
Select list
-
Multi-select list
-
Single text field
-
Multi-row text field
-
URL field
-
User picker
-
Group picker
-
Multi-select group picker
-
Project picker
-
Multi-select user picker
-
Version picker
-
Multi-select version picker
Note
|
Fields created by other plugins might not be supported. However, it is possible to add additional code to the configuration to include them. |
Create Sub-task
Create a sub-task for the issue being transitioned.
Specify the sub-task type and title along with executing additional code.
Additional code has issueInput
bound as the structure that is used in the post to /rest/api/2/issue
to create the sub-task.
Overriding issueInput
is possible by setting issueInput
as part of the script.
For example, a ticket needs to be checked by several departments before it is considered Done. Using this post function, you can automatically create sub-tasks for these departments when a ticket is created.
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Create Sub-task built-in post function.
-
Add a description of the post function in Description for example, Department sub-tasks.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the sub-task is created. See Conditions for examples.
-
Enter a short Sub-task Summary.
-
Select the sub-task Issue Type
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
In the Additional Code field, modify the sub-task structure before it is used as the POST body to /rest/api/2/issue to create the sub-task.
-
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Create Sub-task Example
Here is the code we run under the hood in the provided function, modified so you can run it in the script console:
// Here we specify and retrieve the details of the parent issue
// If you copied this code into a Post Function or an issue-related Script Listener you could remove
// the first 5 lines of code as an issue variable would already be available to your script
def parentKey = 'DEMO-1'
def issueResp = get("/rest/api/2/issue/${parentKey}")
.asObject(Map)
assert issueResp.status == 200
def issue = issueResp.body as Map
// We retrieve all issue types
def typeResp = get('/rest/api/2/issuetype')
.asObject(List)
assert typeResp.status == 200
def issueTypes = typeResp.body as List<Map>
// Here we set the basic subtask issue details
def summary = "Subtask summary"
def issueType = "Sub-task"
def issueTypeId = issueTypes.find { it.subtask && it.name == issueType }?.id
assert issueTypeId : "No subtasks issue type found called '${issueType}'"
def createDoc = [
fields: [
project: (issue.fields as Map).project,
issuetype: [
id: issueTypeId
],
parent: [
id: issue.id
],
summary: summary
]
]
// Now we create the subtask
def resp = post("/rest/api/2/issue")
.header("Content-Type", "application/json")
.body(createDoc)
.asObject(Map)
def subtask = resp.body
assert resp.status >= 200 && resp.status < 300 && subtask && subtask.key != null
subtask
Fast-track Transition Issue
Use Fast-track Transition Issue to immediately transition an issue if the provided condition is true. Transitions are specified by name and must be valid for the issue that is to be transitioned.
Note
|
Due to limitations in the Jira REST API, it is not possible to validate transition names until execution. |
For example, all issues that have the issue priority Major should be escalated to get additional sign-off after creation.
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Fast-track Transition Issue built-in post function.
-
Add a description of the post function in Description for example, Requires Additional Approval.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the issue is transitioned. See Conditions for examples.
-
Enter a comment to add during the transition in Transition Comment.
NoteA comment is only added if the transition allows adding a comment. -
Enter a Transition ID. This is the ID of the transition you wish to perform on the issue.
NoteThe transition ID is found on the Edit page of a workflow. It is the number in brackets after the transition name. For example, the ID for the transition OPEN (1) is 1. -
Alternatively to using the Transition ID, you can specify a Transition Name. TIP: It is recommended that a transition ID is used instead of the transition name because, in some cases, it is not possible to find transition ID by name (for example, if the Hide From User Condition is configured on the transition).
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
In the Additional Code field, modify the
transition
structure before it is used as the PUT body to/rest/api/2/issue/<issue.id>/transition
to modify the issue when transitioned. -
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Modify Issue
Update the issue, or perform any action on the issue after a transition.
TIP: Cancel an update by setting issueInput
to null
. Cancelling an update allows you to use this post function in a similar way to a script listener.
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Modify Issue built-in post function.
-
Add a description of the post function in Description for example, Change assignee when approved.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the issue is modified. See Conditions for examples.
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
Modify the
issueInput
structure in Additional Code before it is used as the POST body to/rest/api/2/issue/<issue id>/notify
to modify the issue.TipRunning as the add-on user adds overrideScreenSecurity=true
as a query parameter to allow editing fields that are not on the screen.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Run Script
Run arbitrary code after a transition.
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Run Script built-in post function.
-
Add a description of the post function in Description.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the script is run. See Conditions for examples.
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
In the Code field, add the code to run when the condition is true. For example, link an issue, update an issue or add a comment.
-
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Send Notification
Generate an email notification to send to a number of users and/or groups including Watchers, Voters, the Reporter, and Assignee.
Note
|
The notify API, which this script uses, contains a validation rule preventing users from notifying themselves. This means that the execution fails if the user being notified is the same user who executed the script. |
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Send Notification built-in post function.
-
Add a description of the post function in Description for example, Notify when work starts.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the notification is sent. See Conditions for examples.
-
Specify who receives the notification:
-
Select the users to notify. Check to notify watchers, voters, the reporter, or assignee.
-
Choose users to send the notification to in the Users field.
-
Enter the Groups to send the notification to.
NoteSpecify a minimum of one recipient.
-
-
Enter the notification Subject.
-
Enter the notification body ad Groovy code in Message.
TipUse the Email Template example as a starting point. -
Pick the user to run the script as in Run As. See Run as User for more information.
-
Modify the
notification
structure in Additional Code before it is used as the POST body to/rest/api/2/issue/<issue id>/notify
to send the notification. -
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
The following is an example of constructing an email from the issue details.
Use the following in the Condition field to specify that the issue must have an assignee:
issue.fields.assignee != null
Enter the following into the Message field to retrieve the value for the 'TextFieldB' custom field and construct the notification body:
def fields = get('/rest/api/2/field')
.asObject(List)
.body as List<Map>
def customFieldId = fields.find { it.name == 'TextFieldB' }.id as String (1)
def customFieldValue = (issue.fields[customFieldId] as Map)?.value
"""Dear ${issue.fields.assignee?.displayName},
The ${issue.fields.issuetype.name} ${issue.key} with priority ${issue.fields.priority?.name} has been assigned to you.
Description: ${issue.fields.description}
Custom field value: ${customFieldValue}
Regards,
${issue.fields.reporter?.displayName}"""
-
Retrieve the custom field ID for the 'TextFieldB' custom field
Transition Parent Issue
Transition the parent issue of a sub-task.
Note
|
This post function is only valid for sub-tasks and will not work on parent issues, or issues with no sub-tasks. |
The specified transition is performed on the parent of the sub-task when a condition is met. As with Fast-Track Transition Issue, the transition name is provided and not validated.
-
Select a transition.
-
Click Post Functions→Add Post Function.
-
Select ScriptRunner Post Function and click Add.
-
Select the Transition Parent Issue built-in post function.
-
Add a description of the post function in Description for example, Transition parent when done.
-
Check Enable Post Function to make this post function active as soon as creation is finished.
-
Add additional Groovy code in the Conditions field that returns a boolean value determining the condition for which the issue is transitioned. See Conditions for examples.
-
Enter a comment to add during the transition in Transition Comment.
NoteA comment is only added if the transition allows adding a comment. -
Enter a Transition ID. This is the ID of the transition you wish to perform on the parent issue.
NoteThe transition ID is found on the Edit page of a workflow. It is the number in brackets after the transition name. For example, the ID for the transition OPEN (1) is 1. -
Alternatively to using the Transition ID, you can specify a Transition Name. TIP: It is recommended that a transition ID is used instead of the transition name because, in some cases, it is not possible to find transition ID by name (for example, if the Hide From User Condition is configured on the transition).
-
Pick the user to run the script as in Run As. See Run as User for more information.
-
In the Additional Code field, modify the
transition
structure before it is used as the PUT body to/rest/api/2/issue/<issue.id>/transition
to modify the issue when transitioned. -
Click Add.
Note
|
See the available Script Context for Condition and Additional Code fields in the Script Context section. |
Example Custom Scripts
Calculated Custom Field
This example is similar to the calculated field example for Script Listeners except in this case, the calculation occurs when the issue transitions to a specific status in a workflow.
// get custom fields
def customFields = get("/rest/api/2/field")
.asObject(List)
.body
.findAll { (it as Map).custom } as List<Map>
def input1CfId = customFields.find { it.name == 'Custom Field 1' }?.id
def input2CfId = customFields.find { it.name == 'Custom Field 2' }?.id
def outputCfId = customFields.find { it.name == 'Output Custom Field' }?.id
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)
// .queryString("overrideScreenSecurity", Boolean.TRUE) (5)
.header("Content-Type", "application/json")
.body([
fields:[
(outputCfId): output
]
])
.asString()
-
Grab the values of the custom fields from the event
-
Sanity check for null values - the issue may not have a value for any input
-
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
-
Update the value of the custom field
-
If using the Add-on user to run the script, it is possible to set the overrideScreenSecurity property to modify fields that are not on the current screen
Create Sub-task
Run this code in the Script Console to create a sub-task.
// Here we specify and retrieve the details of the parent issue
// If you copied this code into a Post Function or an issue-related Script Listener you could remove
// the first 5 lines of code as an issue variable would already be available to your script
def parentKey = 'DEMO-1'
def issueResp = get("/rest/api/2/issue/${parentKey}")
.asObject(Map)
assert issueResp.status == 200
def issue = issueResp.body as Map
// We retrieve all issue types
def typeResp = get('/rest/api/2/issuetype')
.asObject(List)
assert typeResp.status == 200
def issueTypes = typeResp.body as List<Map>
// Here we set the basic subtask issue details
def summary = "Subtask summary"
def issueType = "Sub-task"
def issueTypeId = issueTypes.find { it.subtask && it.name == issueType }?.id
assert issueTypeId : "No subtasks issue type found called '${issueType}'"
def createDoc = [
fields: [
project: (issue.fields as Map).project,
issuetype: [
id: issueTypeId
],
parent: [
id: issue.id
],
summary: summary
]
]
// Now we create the subtask
def resp = post("/rest/api/2/issue")
.header("Content-Type", "application/json")
.body(createDoc)
.asObject(Map)
def subtask = resp.body
assert resp.status >= 200 && resp.status < 300 && subtask && subtask.key != null
subtask
Post to Slack
Use this example to send a simple Slack post, notifying users that an issue has been updated.
def apiToken = 'YOUR_SECRET_TOKEN' (1)
def msg = [
channel: 'your-channel-here', (2)
username: 'Any Username Here', (3)
icon_emoji: ':rocket:',
text: "${issue.key} Updated", (4)
]
post('https://slack.com/api/chat.postMessage')
.header('Content-Type', 'application/json')
.header('Authorization', "Bearer ${apiToken}")
.body(msg)
.asString()
-
Generate a Slack API token and use it here. This API token should be saved as a script variable.
-
Add the name of the channel you wish to post to.
-
Enter the username ScriptRunner will post as.
-
Enter the notification text.
Link to an Issue
Automatically link the issue being transitioned to another issue.
def issueId = issue.id
def link = post('/rest/api/2/issueLink')
.header('Content-Type', 'application/json')
.body([
type: [ name: "Blocks" ],
outwardIssue: [ id: issueId ], // This is the issue that the link 'starts' at
inwardIssue: [ key: 'EX-1' ] // You'll need to specify an issue ID or key here
])
.asString()
assert link.status == 201
Add a Customer Facing Comment on a Linked Service Desk
This script allows you to add a comment on a linked Jira Cloud service desk after the transition of an issue. For example, you may want to let a bug reporter know that the related development is marked as complete.
Note
|
We advise you run this script as the ScriptRunner Add-on User. |
// Define a counter which will be the number of support tickets updated by this script
def counter = 0
// Define the Service Desk Issuetypes you only want updated if a linked Jira software issue is closed
def serviceDeskIssueTypes = [
"Incident",
"Feature Request"
]
// Find the linked issues
def linkedIssues = issue.fields.issuelinks
// Loop over each linked issue
linkedIssues.each {
// For each linked issue, comment only on Service Desk Tickets
if (serviceDeskIssueTypes.contains(it.outwardIssue.fields.issuetype.name)) {
def commentResp = post("/rest/api/2/issue/${it.outwardIssue.key}/comment")
.header('Content-Type', 'application/json')
.body([
body: """
Good news! We've now completed the development work related to this ticket.
""" // Define on the line above what you want the comment to look like to customers on the Service Desk ticket
])
.asObject(Map)
counter ++
// Log info about which Service Desk ticket was just updated
logger.info("Issue ${issue.key} has been closed. \nService Desk ticket ${it.outwardIssue.key} has been commented to inform affected customers.")
}
}
return "The script finished successfully. ${counter} support ticket/s were commented on."