Simple Scripted Validators

Use the Simple scripted validator to run a simple embedded script that determines whether an issue should be permitted to transition to a particular status within a workflow. This validator allows you to write a Groovy script that can evaluate a wide range of conditions based on issue fields, workflow states, project properties, user permissions, and other contextual data. If validation fails, you can provide a custom error message that explains why the transition is not allowed. 

This validator is particularly useful for teams with unique process requirements that need to enforce specific criteria for issue lifecycle management.

Use this validator

  1. Go to Administration > Issues > Workflows.
  2. Select Edit on the workflow you want to add this validator to. 
  3. Select the transition you want to add this validator to.
  4. Under Options, select Validators.
  5. On the Transition page, select Add validator.
  6. Select Simple scripted validator [ScriptRunner].

  7. Select Add.
  8. Optional: Enter a note that describes the validator. This allows you to identify your workflow validator more easily.

  9. Enter a condition of your choice or enter one of the example scripts displayed further down this page.

    If the script returns true, the transition is allowed. If it returns false, the user will not be allowed to perform the transition, and an error message will appear.

  10. Enter an error message. This message displays to the user if the condition returns as false

  11. Optional: Select the field you want the error message to display against. Leave this option empty if you want the error to display at the top of a transition screen or as a pop-up.

    If the transition you are adding this validator to has a screen applied to it, make sure the field you select is on the transition screen.

  12. Select Update.

  13. Select Publish and choose if you want to save a backup copy of the workflow.

    You can now test to see if this workflow condition works.

Examples

Each of the examples below is based on specific workflows. Make sure you adjust the examples appropriately to suit your workflow/s.

Require a fix version if the resolution value is fixed

You can use the following script to make sure that when a user sets the resolution to Fixed, they also have to add the correct Fix Version:

Make sure the transition includes a Resolve Issue screen (or similar) that includes both the Resolution and Fix version.  A step-by-step walkthrough of this example is available on the Validators Tutorial page. 

groovy
issue.resolution.name != "Fixed" || issue.fixVersions

The above example could be set up as follows:

Image showing the completed validator

When a fix version is not provided, the error appears as follows:

Image showing the error message displaying

Check the resolution value

You can use the following script to validate that a particular resolution value is chosen:

groovy
issue.resolution?.name == 'Not an Issue'

 You might want to combine this validator with a check on the action name.

The above example could be set up as follows:

When a fix version is not provided, the error appears as follows:

Require a comment

You can use the following script to make sure a comment is added when the resolution of Won’t Fix is selected:

Make sure the transition includes a Resolve Issue screen (or similar) that includes the Resolution. Comments are automatically included in transition screens. 

groovy
issue.resolution?.name != "Won't Fix" || transientVars["comment"]

The above example could be set up as follows:

When Won't fix is selected, and a comment isn't provided, the error appears as follows:

Require a comment when the assignee is changed

You can check for changed fields by calling methods on originalIssue. This is the issue as it was before modifications made (during this transition) were applied.

You can use the following script to make sure a comment is added when the assignee is changed during a transition:

Make sure the transition includes a screen that includes the Assignee field. Comments are automatically included in transition screens. 

groovy
originalIssue.assigneeId == issue.assigneeId || transientVars["comment"]

The above example could be set up as follows:

When the assignee is changed and a comment isn't provided, the error appears as follows:

Make sure an option is selected for a custom field

For the following examples, make sure the transition you're applying the validator to includes a screen with the appropriate fields. 

  • Multiselect values are a collection of Option objects.
  • cfValues is a map-like structure where you can get the value of any custom field on the object. Note that the keys are the field name and not the id.

You can use the following script to make sure a certain option is selected from a multi-select custom field:

groovy
def values = cfValues['My Multi Select'] return values && (values*.value as Collection<String>).contains('A field value')

You can use the following script to make sure an option is selected for a single-select or radio button field:

groovy
cfValues['My Single Select']?.value == "A field value"

You can use the following script as a more complex example, where if the user sets the select-list field Demo to No, you require them to fill in a text field Reason for no demo:

groovy
cfValues['Demo']?.value != 'No' || cfValues['Reason for No Demo']

You can use the following script to make sure a custom field has a value:

If this condition returns null or an empty value, it will be evaluated as false and your chosen error will display.

groovy
cfValues['Custom Field Name']

Make sure no other sub-tasks have the same value for a custom field on issue creation

You can use the following script to make sure, on the creation of a sub-task, that none of the other sub-tasks of the parent issue have the same value for a particular custom field:

if (!issue.isSubTask()) {
    return true
}

def parent = issue.parentObject
def selectedValue = issue.getCustomFieldValue('SelectListA')

!parent.subTaskObjects.any { subtask ->
    subtask.getCustomFieldValue('SelectListA') == selectedValue
}
Copy

The above example could be set up as follows:

When the option selected is the same as another sub-task for the parent issue, the error appears as follows:

You can put any amount of code in the Condition field. If you don’t explicitly include a return, the result of the last statement executed defines whether the validator accepts or rejects the transition.

Check for attachments

You can use the following script to check that at least one PDF file is attached:

groovy
issue.getAttachments().find { it.filename.endsWith(".pdf") }

The attachment must have existed before the transition was applied to the issue. If you have the Attachments field on the screen, you cannot get newly added attachments in this way.

If your workflow requires specific attachments at certain stages, your validator can either:

The above example could be set up as follows:

When the transition is attempted without a PDF attachment associated with an issue, the error appears as follows:

Check the status or properties of sub-tasks

The following script examples can be used to check the status or properties of sub-tasks relative to their parent issue during a transition.

Make sure all subtasks are resolved

You can use the following script to make sure that all subtasks of an issue are resolved:

groovy
issue.subTaskObjects.every { it.resolution }

Make sure at least one subtask is resolved

You can use the following script to make sure there is at least one subtask is resolved:

groovy
!issue.subTaskObjects || issue.subTaskObjects.any { it.resolution }

Make sure the issue has at least one subtask which is In Progress

You can use the following script to make sure the issue has at least one subtask which is In Progress:

groovy
issue.subTaskObjects.any { it.status.name == "In Progress" }

To check custom field values of subtasks, cfValues is not available, so you must use custom field manager to get hold of the custom field object, as shown in Make sure no other sub-tasks have the same value for a custom field on issue creation.

Check properties of the parent issue

For subtasks, you can check properties of the parent by using parentObject.

You can use the following script to make sure the parent is In Progress:

groovy
!issue.isSubTask() || issue.parentObject.status.name == "In Progress"
The first clause is unnecessary if you are applying this validator only to a subtask type(s). However, if you apply the validator to all tasks, the first clause is there to prevent a NullPointerException if the script is run on an issue that is not a sub-task, as standard issues do not have a parentObject.

Check linked issues

You can use issueLinkManager to retrieve all outward links. For example, you could use the following to check that the issue has at least one outward Duplicate link:

groovy
issueLinkManager.getOutwardLinks(issue.id)*.issueLinkType.name.contains('Duplicate')

You could expand on this example and use it practically. For example, you can use the following script to make sure an issue has at least one outward Duplicate link when the resolution is set to Duplicate:

For the following examples, make sure the transition you're applying the validator to includes a screen with the Resolution field included. 

groovy
issue.resolution.name != "Duplicate" || issueLinkManager.getOutwardLinks(issue.id)*.issueLinkType.name.contains('Duplicate')

The above example could be set up as follows:

When the transition is resolved as Duplicate and a duplicate issue is not linked, the error appears as follows:

If you have the Issue Links field on a form and want to validate links that occur during this transition, check out the examples on the Validating Attachments/Links in Transitions page.

Check the values of a cascading select field

A cascading select field allows users to select a value from a parent drop-down and a related value from a child drop-down. In the following example scripts, cfValues is a map-like structure that holds the current values of custom fields.

You can use the following script to check that both drop-downs of a cascading select are filled:

groovy
cfValues["CascadingSelect"]?.keySet()?.size() == 2

You can use the following script to check that the first dropdown of a cascading select is AAA and the second is a1:

groovy
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption cfValues['CascadingSelect'].values().collect { (it as LazyLoadedOption).value } == ['AAA', 'A1']

You can use the following script to check the first option of the cascading select is AAA:

groovy
cfValues["CascadingSelect"]?.get(null)?.value == "AAA"

You can use the following script to check the second option of the cascading select is a1:

groovy
cfValues["CascadingSelect"]?.get("1")?.value == "A1"

The first example above could be set up as follows:

When the transition is attempted and the cascading select does not have both drop-down options filled, the error appears as follows:


Related content

On this page