...
Jira expressions is like any problem “solved” by the government or some service provided by the government. Yes, it technically does the job but the experience usually leaves a lot to be desired. While you can use Jira expressions if you really want to, another solution may be to approach the problem from another direction. Instead executing the script that decides if the transition can/should be performed right at that moment in time like conditions and validators do, you could use scripts to pre-calculate the answer. Using listeners you could store the answer to that question in invisible issue fields called issue entity properties. Then, with expressions you could simply check the value of that property thus created a truly scripted solution and minimizing the need to use expressions.
Example
Below is an example of a validator that controls whether or not a user can transition an issue based on the status or resolution of linked issues.
Code Block |
---|
// custom script validator
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.opensymphony.workflow.InvalidInputException
def current_user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def query = /assignee = currentUser() and project = "$issue.projectObject.name" and statusCategory = "In Progress"/ // searching for current user having in-progress issues in current project
def jql = ComponentAccessor.getComponent(JqlQueryParser).parseQuery(query)
def page_filter = new PagerFilter(1) // 1 = search only 1 issue
def in_progress_issues = ComponentAccessor.getComponent(SearchService).search(current_user, jql, page_filter)
if(in_progress_issues){ // exist at least one in-progress issue
invalidInputException = new InvalidInputException("VALIDATION FAILED MESSAGE YOU WANT")
}else{
true // true = validation is pass
} |
...
Goal: I've got an issue type of "Dev ask" that uses a workflow that is standard for all subtasks. When this groundwork status is updated to "Complete", I want to check that all sibling subtasks are assigned (because this is just part of the responsibilities for the person who completes the groundwork task). If any are Unassigned this transition should fail.
Jira Expressions
Code Block |
---|
issue.issueType.name.match('^(Dev Task)$') == null ||
(issue.issueType.name.match('^(Dev Task)$') != null &&
issue.parent.subtasks.filter(subtask => subtask.assignee != null).length ==
issue.parent.subtasks.length)? true : false |
Power Scripts alternative solution
The alternative solution is to prepopulate the result of the condition or validator much the same way the Jira Cloud prepopulates JQL functions. A SIL Listener updates hidden field values for the issue (issue entity properties) with the result. Then, in the workflow a condition/validator is added that simply checks the value of that hidden property.
Benefits
SIL is easier to write compared to Jira expressions
SIL is easier to read compared to Jira expressions
SIL is easier to test compare to Jira expressions
SIL Listener or Post function script
In this example this script should be placed on the “Complete” transition for the subtask workflow. However, this script can also be used as a listener script that is trigger when the issue is updated.
Code Block |
---|
boolean passConditionValue = true; if(issueType == "Dev Task") { for(string s in subtasks(parent)) { if(s.issueType == "Dev Task && isNull(s.assignee)) { return true; } else if (issue.project.key == 'PROJECT' )passConditionValue {= false; new Issue('PROJECT-1234').description.plainText.includes(issue.customfield_1235); } else if (issue.project.key == 'PROJECT2' ) { new Issue('TEST-1235').description.plainText.includes(issue.customfield_1235); } else { return false; }} } } setIssueEntityPropertyValue(key, "passCondition", passConditionValue); |
Jira Expression that uses SIL script value
The benefit of this expressions condition/validator is that is can work any action that uses this method. The expression can be copied from workflow to workflow with only the name of property requiring an update. There is no need to master the difficult expressions syntax.
Code Block |
---|
JSON.stringify(issue.properties[' |
...
passCondition']).includes(' |
...
true') |