August 9, 2022

ScriptRunner: set custom field with change visible in the history log

I had some troubles to get the changes done in a ScriptRunner listener visible in the issue history. I share in this post my learnings.

Problem description

I wanted to set a custom field in a ScriptRunner listener and have the change documented in the issue history and being able to trigger an email notification (issue updated event).

First attempt

My first known approach to set a custom field did not trigger an issue update (it was more like a silent change).
Looking for how to make the issue change visible I have found this solution still based on the issueManager.
I have tried it but couldn't get it to work (no change visible in the issue history).

Second attempt

Then I came to this resource that is based on issueService.
After a test, this works properly i.e. the change is visible in the issue history.

Final solution

Still I needed to change the solution provided in the Script Library.

The structure made it hard to use in my listener script because I was looping on links and had many issues to handle (not only the current one)

I have refactored the original library solution so that the function takes an issue as input argument.
Also one subfunction to get the custom field by name wasn't really needed.

You can see an extract of my final result in this gist:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.model.ChangeItem
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
def issue = event.issue
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def customField = customFieldManager.getCustomFieldObjectByName("FieldName") // write here your FieldName
def cfOptions = ComponentAccessor.optionsManager.getOptions(customField.getRelevantConfig(issue)) // there is only one context for this custom field - so one can get the options one time for all
def issueManager = ComponentAccessor.getIssueManager()
def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def issueService = ComponentAccessor.issueService
def issueInputParameters = issueService.newIssueInputParameters()
// Define Value to set
def FieldValue = "Value"
// Set CustomField Value
issueInputParameters.with {
// set custom fields with options (select lists, checkboxes, radio buttons)
addCustomFieldValue(customField.id, *getOptionIds(customField,cfOptions,FieldValue))
}
def updateValidationResult = issueService.validateUpdate(loggedInUser, inwardLinkedIssue.id, issueInputParameters)
assert updateValidationResult.valid: updateValidationResult.errorCollection
def issueUpdateResult = issueService.update(loggedInUser, updateValidationResult, EventDispatchOption.ISSUE_UPDATED, true)
assert issueUpdateResult.valid: issueUpdateResult.errorCollection
/**
* Given a custom field name and option values, retrieve their ids as String
* @param customField CustomField
* options: ComponentAccessor.optionsManager.getOptions(customField.getRelevantConfig(issue))
* @param values The values in order to get their ids
* @return List < String > The ids of the given values
*/
List<String> getOptionIds(CustomField customField, options, String... values) {
options.findAll {
it.value in values.toList()
}*.optionId*.toString()
}

See also

Update a Single-Select (Drop Down) Custom Field - Adaptavist Library

Update the Value of Custom Fields through the Script Console - Adaptavist Library

Scriptrunner listener updates not showing in Issue...

Updating a custom field with and without keeping history – JIRA Programming – JIRA Scripting, Plugin and Report Development, ScriptRunner & Tempo tips