Updating Single-Select Custom Fields in Jira

Introduction

Once upon a time I spent a week writing a script to automate some functionality for Jira.  The script was supposed to assign issues based on certain criteria, and also update a custom field that contained the name of the team that was currently responsible for the ticket.

At the end of the week I had the script working according to the specifications.   We tested it on Friday afternoon, and all was well.
On Monday morning the project manager sent me an email, notifying me that the script now had to work a completely different way.  It also had to be finished by the end of that day, as Tuesday was the day they were using the script as part of a training session.

Updating the Script

The good news was that for the most part, the changes I had to make to the script were reductive. It had to do fewer things.   However, I had initially included the Custom Field update as part of the transition:

   def issueInputParameters = issueService.newIssueInputParameters()
    issueInputParameters.addCustomFieldValue(customFieldID, customFieldValue)
    //The request is for a new workstation, so set Next to Act to Tier 1 - IDIR Services
    issueInputParameters.setSummary(issue.summary + " - " + issue.getReporterUser().displayName)
    //Set the summary to the current summary plus the displayname of the reporter/requestor

Above you can see that the update to the custom field was added as a transition parameter.   The new script did away with the transitions, so I had to update the custom field in a different way. 

Ordinarily the process to update a custom field would be something like this:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.MutableIssue

def issueManager = ComponentAccessor.getIssueManager()

MutableIssue issue = issueManager.getIssueByCurrentKey("<key>")

def user = issue.getReporter()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def customField = customFieldManager.getCustomFieldObject(123456)
issue.setCustomFieldValue(customField, "New Value")

issueManager.updateIssue(user, issue, EventDispatchOption.DO_NOT_DISPATCH, false)

 

However, this script ran as a Listener, so the process is different.   I found an example from the Adaptavist Script Library that pretty clearly seemed to meet my requirements:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder

log.warn(issue.key)
// the name of the custom field to update
final customFieldName = '<customField>'

// the new value of the field
final newValue = '<value>'

def customFieldManager = ComponentAccessor.customFieldManager
def issue = event.issue

def customField = customFieldManager.getCustomFieldObjects(issue).findByName(customFieldName)
assert customField : "Could not find custom field with name $customFieldName"

customField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(customField), newValue), new DefaultIssueChangeHolder())

 

Notable is the lack of an updateIssue statement, as would be required in a standard script. This isn’t an oversight: the statement isn’t required in this case.

issueManager.updateIssue(user, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
//Not required for a Listener

I added the script to a Listener and tested it out. 

Nothing happened. 

The logs noted the key of the issue that I created, but the custom field wasn’t updated.  That was pretty strange, usually the Script Library examples are pretty solid. I double-checked that I had set the right Final values.  All appeared to be well. I tried a few tweaks and a few other methods from the internet, but none seemed to help. Eventually I went back to the original code snippet. I put the call to the updateValue method into a try/catch statement and logged the Exception.  The logs held an error for me:

java.lang.ClassCastException: class java.lang.String cannot be cast to class com.atlassian.jira.issue.customfields.option.Option

Now I was getting somewhere!

Resolving the Issue

From the error message I could see that the method didn’t like my attempt to cast a string to the Option class.   It was only then that I remembered that the custom field in question was a dropdown/single-select, not a freeform text field.   In the case of dropdown fields, you need to feed it an Option, rather than a simple string or integer.

I found a solution that worked for me on the Atlassian customer forums.  Here’s a stripped down example based on that link:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder

// the name of the custom field (single select list type)
final customFieldName = "<custom field name>"

// the value of the new option to set
final newValue = "<known value in the list of Options for the custom field>"

// the issue key to update
final issueKey = "<issue key>"

def issue = ComponentAccessor.issueManager.getIssueByCurrentKey(issueKey)
assert issue: "Could not find issue with key $issueKey"
//Get the target issue as an Issue object

def customField = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName(customFieldName)
assert customField: "Could not find custom field with name $customFieldName"
//Get the custom field as a Custom Field object

def availableOptions = ComponentAccessor.optionsManager.getOptions(customField.first().getRelevantConfig(issue))
//Return all of the valid options for the Custom Field

def optionToSet = availableOptions.find { it.value == newValue }
assert optionToSet: "Could not find option with value $newValue. Available options are ${availableOptions*.value.join(",")}"
//Define an Option object by finding it in the list of options we've already pulled from the custom field

customField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(customField), optionToSet), new DefaultIssueChangeHolder())
//Update the custom field with the new value

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *