Jira Expression Examples
The Jira expression examples highlighted in this section can be used for either conditions or validators and on all transitions unless noted otherwise.
Jira expression framework limitation: nested condition
Jira expressions do not support nested if
statements. For example, the following expression will fail:
if (issue.summary.length > 10 ) {
if(issue.assignee) {
// ...
}
}
You can instead combine this into a single expression, as shown in the example below:
if (issue.summary.length > 10 && issue.assignee) {
// ...
}
Require Attachments
You want a PDF of the contract agreement attached to an issue before work can begin, so developers know what was agreed with the client. This script ensures at least one PDF file is attached before the Start Progress transition is available for the issue.
issue.attachments.some(attachment => attachment.mimeType == 'application/pdf')
If you want to require a specific minimum number of PDFs, use the following script:
issue.attachments.filter(attachment => attachment.mimeType == 'application/pdf').length > 2
Edit length > 0
to the minimum number of PDFs required.
Restrict Transition Permissions
As a team lead, you want to restrict the transition of issues to specific status for certain user groups or project roles. This condition only shows a certain transition option to users belonging to the groups or roles specified.
Restrict to Project Role
user.getProjectRoles(project).some(p => p.name == "userrole")
Replace userrole
with the project role you want to be able to transition the issue (for example, Developers). Roles apply to projects only, whereas user groups are global. See the Atlassian documentation for information on managing project roles.
Restrict to User Groups
user.groups.includes('usergroup')
Replace usergroup
with the group of users you want to be able to transition the issue (for example, Administrators). See the Atlassian documentation for information on viewing, creating, or deleting groups.
Require Sub-Tasks
As a project manager, you want developers to add sub-tasks to issues so you can see the steps required to complete an issue. You want to prevent the transition of an issue if it has no sub-tasks. This script only shows the transition option if the issue has at least one sub-task.
issue.subtasks.length > 0
Edit length > 0
to the minimum number of sub-tasks required.
Sub-Tasks Must be Done
You want to enforce that Done means all sub-tasks are completed by hiding the Done transition option of an issue when there are outstanding sub-tasks. This script only shows the transition option when all sub-tasks have the Done resolution.
issue.subtasks.every(subtask => subtask.status.name == 'Done')
Edit subtask.status.name
== 'Done'
if you require a different sub-task resolution or status.
Sub-Tasks Must Have Assignee
You want to make sure all sub-tasks have been assigned before the parent issue can be transitioned to In Progress. This script only shows the In Progress transition option on a parent issue when all sub-tasks have assignees.
issue.subtasks.every(subtask => subtask.assignee != null)
Subtask type and status
This expression checks whether all subtasks of a certain type are at a specific status.
issue
.subtasks
.filter(s => s.issueType.name == 'Scope Change')
.every(d => d.status.name == 'Done')
Require One Linked Issue
You have a support portal and a separate support development instance. You want to ensure that all issues created on the support development instance are linked to their corresponding user-facing ticket on the support portal. Ensure all issues created on one Jira instance are linked with their corresponding issue on another instance.
issue.links.length > 0
You can edit this script to make other fields required. For example, replace links
with fixVersions
or components.
Multi-Select List or Checkbox Field Must be Populated with Specific Value
You want to enforce that issues have a specific value selected in a multi-select list or checkbox before progressing.
issue.customfield_10263 ?
issue.customfield_10263.some(option => option.value == "End Users") :
false
Replace customfield_10263
in the example with the ID of the multi-select list or checkbox field of your instance. To find the custom field ID, navigate to <JiraBaseURL>/secure/admin/ViewCustomFields.jspa
and Edit the required field. The field ID is shown.
Multi-Select or Checkbox must be populated with one specific value
issue.customfield_10214 ?
issue.customfield_10214.some(option => option.value == "A") :
false
Multi-Select or Checkbox field equals a specific set of values
issue.customfield_10214 ?
issue.customfield_10214.map(option => option.value) == ['Yes', 'No'] :
false
Sub-Tasks Must Be In Progress
As a project manager, you want to ensure all sub-tasks have been started before progress can start on the parent issue to keep issues aligned. Ensure all sub-tasks are In Progress before a parent issue can be transitioned to In Progress.
issue.subtasks.every(subtask => subtask.status.name == 'In Progress')
Minimum Length of Issue Description
As a support manager, you want to ensure that all reported bugs have detailed descriptions so you can replicate and solve them as easily as possible. By setting a minimum character length, you can enforce thorough descriptions of all issues before they can be created.
issue.description.plainText.length > 30
Change length > 30
to specify the minimum number of required characters.
Minimum Length of All Comments
As a support manager, you want to ensure that all comments have detailed descriptions. By setting a minimum character length, you can enforce meaningful comments on all issues before they can be created.
issue.comments.every(comment => comment.body.plainText.length > 10)
Issue Must be in the Current Active Sprint
As a project manager, you want to ensure that only issues planned in the current sprint are worked on. Allow work to be started only on issues that are in the current active sprint.
issue.sprint?.state == 'active'
Require Attachments
As a project manager, you want to ensure the required number of attachments have been added to an issue as it transitions, to align with business processes. Ensure a minimum number of attachments have been added as an issue transitions.
issue.attachments.filter(attachment => attachment.id == null).length == 3
Change length ==3
to specify the minimum number of required attachments. The transition screen must be configured with the Attachments field, to allow users to submit the attachments during the transition.
Require at least Two PDF Attachments are Added During the Current Transition
issue.attachments.filter(attachment => attachment.id == null && attachment.mimeType == 'application/pdf').length > 1
Checks the Issue Has Been in a Status Previously
issue.changelogs.some(c =>
c.items.some(i => i.toString == 'In Progress')
)
Field(s) Required
For text fields, single, multi selects, and radio buttons, checkboxes, and cascading select fields:
issue.customfield_10040 != null
For cascading select field:
// for parent value
issue.customfield_10266?.value != null
// both parent and child (you cannot set the child without the parent)
issue.customfield_10266?.child?.value != null
This example checks that a text field (possibly supporting rich text) is required:
let plainTextValue = value => typeof value == 'Map' ? new RichText(value).plainText : value ;
plainTextValue(issue.customfield_10080 != null) && plainTextValue(issue.customfield_10080) != ''
Linked Issues
Use the Linked Issues Condition to control whether or not a user can transition an issue based on the status or resolution of linked issues.
// Check all linked issue are in certain status
issue.links.every(l => l.linkedIssue.status.name == 'Done')
// Check all linked issues of a certain link type are at certain status
issue.links
.filter(l => l.type.inward == 'is blocked by')
.every(l => l.linkedIssue.status.name == 'Done')
// Check all linked issues have a resolution
issue.links.every(l => l.linkedIssue.resolution != null)
// Check all linked issues of a certain link type have a resolution
issue.links
.filter(l => l.type.inward == 'is blocked by')
.every(l => l.linkedIssue.resolution != null)
Regular Expressions
The Regular Expression condition is only available on all strings, including text fields and option values.
Checks that the description contains the string `SRJ-` then any amount of digits, for example to match an issue tracker key:
issue.description.plainText.match("SRJ-\d+") != null
Checks if the regular expression exists in any part of the text field value.
issue.customfield_10206 ?
issue.customfield_10206.match("SRJ-\d+") != null :
false
User in Field(s)
This expression will check whether the current user is selected within a custom user picker field.
For user picker single select:
issue.customfield_10213?.displayName == 'A User'
// or using accountId
issue.customfield_10213?.accountId == '5cf7c174eba28b4ea84a7cb5'
For user picker multi select:
issue.customfield_10219 ?
issue.customfield_10219.some(user => user.displayName == 'A User') :
false
This expression will check whether the current user group is selected within a custom group picker field, either by account ID or username.
For group picker single select:
issue.customfield_10077?.name == 'jira-admins'
For group picker multi select:
issue.customfield_10078 ?
issue.customfield_10078.some(c => c.name == 'jira-admins') :
false
User(s) and User Group(s)
Check the current user is one of a specified list.
['User A','User B','User C'].includes(user.displayName)
Check the current user is in within a group of a specified list
['Group A','Group B', 'Group C'].some(g => user.groups.includes(g))
Issue Must Have at Least One PDF Attachment
issue.attachments.some(attachment => attachment.mimeType == 'application/pdf')
Issue Must Have at Least Three PDF Attachments
issue.attachments.filter(attachment => attachment.mimeType == 'application/pdf').length > 3
Specify the Current User Must be in a Defined List of Users
The example checks by user account ID, but you can also use user.displayName.
['accountIdHere', 'accountIdHere'].includes(user.accountId)
Current Logged-in User Has Added at Least One Comment
issue.comments.some(c => c.author.accountId == user.accountId)
Field(s) Changed
Check whether a specified field has been changed in the issue's lifetime.
issue.changelogs.some(c => c.items.some(i => i.field == 'Field Name'))
Last Field Changed
Check whether a specified field has been changed within the issue lifetime.
issue.changelogs[0].items.some(i => i.field == 'Field Name')
Require at Least One Fix Version
issue.fixVersions.length > 0
Require at Least One Component
issue.components.length > 0
Description Field Must Contain More Than 30 Characters
issue.description.plainText.length > 30
Require All Issues in an Epic Must Be Done
issue.isEpic && issue.stories.every(story => story.status.name == 'Done')
Require Specific Users in a Project can Create Issues of a Specified Type
In this example, only members of the Developers role can create Bug issue types, but all users can create other issue types.
issue.issueType.name == 'Bug' ?
user.getProjectRoles(project).map(p => p.name).includes("Developers") :
true
Specify that One of Two Label Fields Must Have a Value
Note that you should replace 'customfield_12345
' and 'customfield_67890
' in the example below with IDs of the label fields inside your instance:
issue.customfield_12345 != null || customfield_67890 != null
Date comparison
The following system fields return a Date
object: created
, update
, and resolutionDate
.
Checks whether an issue was created more than 7 days ago:
issue.created < new Date().minusDays(7)
Checks whether an issue was updated within the last 2 hours:
issue.updated > new Date().minusHours(2)
Checks whether an issue was resolved within the last 30 days:
issue.resolutionDate ?
issue.resolutionDate >= new Date().minusDays(30) :
false
The following system fields return a CalendarDate
object: dueDate
.
Checks whether an issue is due within the next 3 months:
issue.dueDate ?
issue.dueDate <= new CalendarDate().plusMonths(3) :
false
Caution: dueDate
and resolutionDate
, along with custom fields, can be null. Always check for null values before performing operations on them.
Date
custom fields have a string value, but can be converted to a calendar date like so: new CalendarDate(issue.customfield_10200)
Checks whether a date custom field is 30 days or more in the future from today's date:
issue.customfield_10200 ?
new CalendarDate(issue.customfield_10200) >= new CalendarDate().plusDays(30) :
false
Date time
custom fields have a string value, but can be converted to a date time like so: new Date(issue.customfield_10217)
Checks whether a date time custom field is less than 6 hours in the future:
issue.customfield_10217 ?
new Date(issue.customfield_10217) <= new Date().plusHours(6) :
false
Verify issue type
Returns true for issues with issue type: Bug or Task.
["Bug", "Task"].includes(issue.issueType.name)
Require a comment on transition
issue.comments.some(comment => comment.id == null)
Example of incorrect condition script
Run code will not execute as the return result is a list of objects.
issue.comments.map(c => c.body)
Comments
Require a comment during transition:
issue.comments.some(comment => comment.id == null)
All existing comments must be public (for Jira Service Management):
issue.comments.every(c => !c.properties["sd.public.comment"].internal)
If there is a comment on transition, it must be an internal comment (note that the `internal` property is a string during transition!):
issue.comments.every(c => c.id != null || c.properties["sd.public.comment"].internal == 'true')
All comments have a minimum length:
issue.comments.every(comment => comment.body.plainText.length > 10)
Field is not empty
The following examples check the field is not empty (that is, it's a required field).
At least one of two label fields must have a value:
Checks if the issue type is Bug or Task:
["Bug", "Task"].includes(issue.issueType.name)
Require a comment during transition:
issue.comments.some(comment => comment.id == null)