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.

This example cannot be used on the Create transition. Use the Start Progress transition.

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
Note that you can add an OR / AND logical operator where more than one field needs to be checked.

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

(warning) 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)

On this page