Update Custom Value from Calculated Field using "Scriptrunner for Jira" Custom Listener

Jessica Wolfe April 16, 2019

I am looking to create a Listener which updates the value of a number type custom field from a scripted calculated number field.  We are looking to use this value for reporting and would like it available as a field that can be used in the sprint burndown chart.  I tried the following but am getting errors when the listener is triggered.

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.ModifiedValue;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder;

def issue = event.issue as Issue
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser().name
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def EpicRiskScore = customFieldManager.getCustomFieldObjectByName("Epic Risk Score Total")
def EpicRiskScoreValue = issue.getCustomFieldValue(EpicRiskScore)
def tgtField = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Risk Score"}
def changeHolder = new DefaultIssueChangeHolder()
tgtField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(tgtField), EpicRiskScoreValue),changeHolder)

 

Log Error Below:

Time (on server): Tue Apr 16 2019 14:14:28 GMT-0400 (Eastern Daylight Time)

The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.

2019-04-16 18:14:28,041 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2019-04-16 18:14:28,041 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException
	at com.atlassian.jira.issue.IssueImpl.getCustomFieldValue(IssueImpl.java:896)
	at com.atlassian.jira.issue.Issue$getCustomFieldValue$14.call(Unknown Source)
	at Script225.run(Script225.groovy:16)

 Thanks in advance for any help around this solution :)

 

1 answer

0 votes
Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
April 16, 2019

I tried your script as is (only changed the field names) and it worked (using Jira 7.13.2).

So it may be down to the type of fields.

But I do see something unnecessary:

This: 

def tgtField = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Risk Score"}

 Could be simplified (and use the same  pattern as the other field):

def tgtField = customFieldManager.getCustomFieldObjectByName("Risk Score")

Then, you can split up that last line so that you get a clearer indication of where the issue is coming from (though the error message is pretty clear). 

def oldValue = issue.getCustomFieldValue(tgtField)
log.info "Old Value for 'Risk Score' was $oldValue"

//only attempt to update the target field if the new value is actually different
if(oldValue != EpicRiskScoreValue){
def modifiedValue = new ModifiedValue(oldValue,EpicRiskScoreValue)
tgtField.updateValue(null, issue, modifiedValue,changeHolder)

//you may want the ticket history to show that change, in that case you need to log it yourself
// requires import com.atlassian.jira.issue.history.ChangeLogUtils
def currentAppUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
ChangeLogUtils.createChangeGroup(curretnAppUser, issue, issue, changeHolder.getChangeItems(), false);

//Also, the above will not update the index for the issue, you must also do that yourself
// Requires
// import com.atlassian.jira.util.ImportUtils
// import com.atlassian.jira.issue.index.IssueIndexingService
ImportUtils.setIndexIssues(true)
ComponentAccessor.getComponent(IssueIndexingService.class).reIndex(issue)
ImportUtils.setIndexIssues(false)
}

 

You should be able to get a closer clue of what's wrong with your script. Look at what "oldValue" is or if you still get an error on getCustomFieldValue(tgtField)

Jessica Wolfe April 18, 2019

Thank you for your help!  I want to caveat this next part with I am not a developer and have really stretched my skillset here.  I've updated the script per your suggestions and still can't get it to work.  The fields in question are "Epic Risk Score Total" (adaptavist scripted number field) and "Risk Score" (number field).  I am attempting to listen for changes in the Epic Risk Score and copy that score to Risk Score.  Do you think the listener maybe unable to copy scripted number fields or listen for changes in these fields?  

Update Listener Script:

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.ModifiedValue;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder;
import com.atlassian.jira.util.ImportUtils;
import com.atlassian.jira.issue.history.ChangeLogUtils;
import com.atlassian.jira.issue.index.IssueIndexManager;
import com.atlassian.jira.issue.index.IssueIndexingService;

def issue = event.issue as Issue
def CurrentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser().name
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def EpicRiskScore = customFieldManager.getCustomFieldObjectByName("Epic Risk Score Total")
def EpicRiskScoreValue = issue.getCustomFieldValue(EpicRiskScore)
def tgtField = customFieldManager.getCustomFieldObjectByName("Risk Score")
def changeHolder = new DefaultIssueChangeHolder()
tgtField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(tgtField), EpicRiskScoreValue),changeHolder)

def oldValue = issue.getCustomFieldValue(tgtField)
log.info "Old Value for 'Risk Score' was $oldValue"

if(oldValue != EpicRiskScoreValue){
def modifiedValue = new ModifiedValue(oldValue,EpicRiskScoreValue)
tgtField.updateValue(null, issue, modifiedValue,changeHolder)


def currentAppUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
ChangeLogUtils.createChangeGroup(currentAppUser, issue, issue, changeHolder.getChangeItems(), false);

ImportUtils.setIndexIssues(true)
ComponentAccessor.getComponent(IssueIndexingService.class).reIndex(issue)
ImportUtils.setIndexIssues(false)

 

Log failure:

Time (on server): Tue Apr 16 2019 22:27:39 GMT-0400 (Eastern Daylight Time)

The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.

2019-04-17 02:27:39,385 ERROR [runner.AbstractScriptListener]: ************************************************************************************* 2019-04-17 02:27:39,385 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script> java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double at com.atlassian.jira.issue.customfields.impl.NumberCFType.getDbValueFromObject(NumberCFType.java:45) at com.atlassian.jira.issue.customfields.impl.AbstractSingleFieldType.createValue(AbstractSingleFieldType.java:143) at com.atlassian.jira.issue.fields.ImmutableCustomField.createValue(ImmutableCustomField.java:693) at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:410) at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:396) at com.atlassian.jira.issue.fields.OrderableField$updateValue.call(Unknown Source) at Script314.run(Script314.groovy:20)


It might also be helpful to see how I built the scripted field for Epic Risk Score Total:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager

CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
List<String> fieldNames = ["Business Risks Score","Scope Risk Score","Technical Risks Score","Technical Discovery and Debt Score","Validation Risks Score","Quality of Solutions Score","Organizational Risks Score","Capacity Risk Score","Dependency Risks Score"]
List<Integer> scores = []
for (String field : fieldNames){
def cf = customFieldManager.getCustomFieldObjectByName(field)
scores.add((Integer) issue.getCustomFieldValue(cf)?: 0)
}
return scores.sum {it}

Many thanks for any additional assistance you (or anyone else) can provide!

Suggest an answer

Log in or Sign up to answer