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
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:
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
@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?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The script now works correctly, thank you. I just had to add a null test for Future Clients impacted. Much appreciated.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.