Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Adaptivist Scriptrunner calculated script field works for individual issues, but fails in Issue Sear

Deleted user July 19, 2022

I have a calculated numeric script field intended to return an importance value based on various custom fields. When testing with any individual issue, this works; the number is visible on the issue and updated as I change elements and save.  

However, when I add this field as a column to a search, the column is blank and ScriptRunner history tells me "All of the last 15 executions have failed." It does appear that sorting works despite this. 

I suspect the failure has something to do with how the code is determining the issue to execute against, but I'm not well-versed in this language and don't fully understand why or how to fix it. Can anyone assist?

The Searcher is set to Number Range Searcher and JIRA has been re-indexed since that change. 

import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.jira.groovy.user.FieldBehaviours
import com.atlassian.jira.issue.MutableIssue

double weighted_rank = 0
double weight_percent = 0
double score = 0
double force_rank_value = 0

def issue = issue as MutableIssue
def customFieldManager = ComponentAccessor.getCustomFieldManager()

// 20% - JIRA Priority
score = 0
weight_percent = 22.2
def jira_priority = Integer.parseInt(issue.priorityObject.id)
if (jira_priority == 5) {score = 1}
if (jira_priority == 4) {score = 3}
if (jira_priority == 3) {score = 5}
if (jira_priority == 2) {score = 8}
if (jira_priority == 1) {score = 10}
weighted_rank = weighted_rank + score*weight_percent

// 5% - Future Clients Impacted
customfieldname = "Future Clients Impacted"
weight_percent = 6.7
score = 0
def future_clients = getCustomFieldValue(customfieldname)
if (future_clients != null) {
if (future_clients.getValue()== null) {score = 0}
if (future_clients.getValue()=="None") {score = 0}
if (future_clients.getValue()=="One") {score = 1}
if (future_clients.getValue()=="Few") {score = 2}
if (future_clients.getValue()=="Many") {score = 5}
if (future_clients.getValue()=="All") {score = 10}
weighted_rank = weighted_rank + score*weight_percent
}

// 15% - Current Clients Impacted
customfieldname = "Clients"
weight_percent = 13.3
score = 0

def client_list = customFieldManager.getCustomFieldObjects(issue).find { it.name == "Clients" }
def client_list_values = issue.getCustomFieldValue(client_list)

if (client_list_values != null) {
def numberOfSelections = client_list_values.size()
if (numberOfSelections == 0) {score = 0}
if (numberOfSelections == 1) {score = 1}
if (numberOfSelections == 2) {score = 3}
if (numberOfSelections > 2 && numberOfSelections < 5) {score = 6}
if (numberOfSelections > 4) {score = 10}
weighted_rank = weighted_rank + score*weight_percent
}

weighted_rank = weighted_rank / 10

// Force Rank
customfieldname = "Force Importance"
score = 0
def force_importance = getCustomFieldValue(customfieldname)
if (force_importance != null) {
if (force_importance.intValue() != null) {weighted_rank = force_importance.intValue()}
}

return weighted_rank

 

1 answer

1 accepted

0 votes
Answer accepted
PD Sheehan
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
July 19, 2022

Hi @[deleted] 

It looks to me that this script includes a combination of Behaviour and Scripted field aspects.

This line has no purpose in a Scripted Field: 

import com.onresolve.jira.groovy.user.FieldBehaviours

And it only works in Behaviour.

But other aspects of the script look like Customer Scripted Field to me.

However, the "getCustomFieldValue()" method which is being called in a couple of places doesn't exist in a normal Scripted Field.

So I wonder if this script ever worked and if somehow you have 2 versions of the same field. 1 is a scripted field which doesn't work and another is just a regular number custom field that's being set dynamically by a behaviour configuration. 

So the "All of the last 15 executions have failed" message refers to this broken script.

Here is a blindly rewritten version of the scripted field. I made some assumptions about the type of custom fields: 

  • Clients: Select (Multiple), or Insight Custom Field (multiple) or Scriptrunner Picker (multi)
  • Future Clients Impacted: Select (Single)
  • Force Importance: Number
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.customfields.option.Option

def issue = issue as MutableIssue
def customFieldManager = ComponentAccessor.customFieldManager

//get the field and value that allow use to quit the script early
def forceImportanceCf = customFieldManager.getCustomFieldObjectsByName('Force Importance')[0]
def forceImportanceValue = issue.getCustomFieldValue(forceImportanceCf)
if (forceImportanceValue) {
return forceImportanceValue as Integer
//if this is encoutnered, the forceImportanceValue is return by the script and the rest is not executed
}

//get all the other custom fields we'll need to make calculations
def futureClientsImpactedCf = customFieldManager.getCustomFieldObjectsByName('Future Clients Impacted')[0]
def clientsCf = customFieldManager.getCustomFieldObjectsByName('Clients')[0]
//get the values for those custom fields
def futureClientsImpacted = issue.getCustomFieldValue(futureClientsImpactedCf) as Option
def clients = issue.getCustomFieldValue(clientsCf) as List ?: [] //this ensures that even if the field returns null, we still have a size 0 array

//create a map of priority to score values - easy to modify
def priorityScoreMap = [
1: 10,
2: 8,
3: 5,
4: 3,
5: 1
]
//create a map of Select option to score values - easy to modify
def futureClientCountScoreMap = [
(null): 0,
None : 0,
One : 1,
Few : 2,
Many : 5,
All : 10
]
//we can't use a simple map since we want range and greater than, a simple closure/function with switch statment works well for that
def getCurrentClientScore = { countOfCurrentClients ->
switch (countOfCurrentClients) {
case 0:
return 0
break
case 1:
return 1
case 2:
return 3
break
case 3..4:
return 6
break
case { it > 4 }:
return 10
}
}
//calculate the partial score from priority
def priorityScore = priorityScoreMap[issue.priority.id as Integer]
def priorityWeight = 22.2
def weightedPriorityScore = priorityScore * priorityWeight

//calculate the partial score from future client selection
def futureClientScore = futureClientCountScoreMap[futureClientsImpacted.value]
def futureClientWeight = 6.7
def weightedFutureClientScore = futureClientScore * futureClientWeight

//calculate the partial score from the size of clients
def currentClientWeight = 13.3
def weightedCurrentClientScore = getCurrentClientScore(clients.size()) * currentClientWeight

//add all the partial ranks together
def weightedRank = weightedPriorityScore + weightedFutureClientScore + weightedCurrentClientScore

return (weightedRank / 10) as Integer
Deleted user July 20, 2022 edited

@PD Sheehan thank you for that insightful and well-documented refactor. It seems to be having the same problem, though. In testing, I changed the code to this:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.customfields.option.Option

def issue = issue as MutableIssue

def weightedRank = 10

return (weightedRank / 10) as Integer

Editing any single issue, the field shows 1 as expected (or any other value I define weightedRank to be; it's definitely using this specific code, our instance has no defined behaviors or same-named fields elsewhere), and Scriptrunner/Fields/History shows the execution as succeeding for that particular issue. 

However, when I do an issue search with that column visible, History then shows "All of the last 15 executions have failed" and the column shows no value in search.

If I remove the "def issue" line, all issues show 1 in the column as expected. 

The logs for each execution are truncated at 300 lines, but I do see this:

Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject  at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)  at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)

Any thoughts? 

PD Sheehan
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
July 20, 2022

Ah, ok, I haven't experienced this particular issue.

But just remove that line. It's not needed for execution.
It's just there to tell an external IDE or the Script Editor static type checking what to expect.

You might see errors in the Script Editor (if you store your script as a file).

But it will be fine in the Scripted Field editor (since the in-line script editor for a script field will inject the issue object into the script's binding).

Deleted user July 20, 2022

The script now works correctly, thank you. I just had to add a null test for Future Clients impacted. Much appreciated.

Suggest an answer

Log in or Sign up to answer