Populating the JIRA Checklist plugin via groovy scriptrunner

Joshi Shushruth June 28, 2016

I am trying to populate the JIRA checklist plugin with a bunch of hard coded values using Post Functions, i think I have the necessary code to make it work, but I am trying to figure out what kind of Object the CheckList Plugin takes so it can be populated.

def cf = customFieldManager.getCustomFieldObjectByName("Checklist_Field")
def cfConfig = cf.getRelevantConfig(issue)
value = // JIRA CHECKLIST OBJECT?
issue.setCustomFieldValue(cf, value)

It doesn't seem to work when i use a List with string values. I am aware it needs a checked, and mandatory boolean along with a String for the name of the option, but I am not sure how to format it. I have tried using the OptionsManager using similar code to this: 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.fields.CustomField
def optionManager = ComponentAccessor.getOptionsManager()
def option = optionManager.allOptions.find {it.value == request_type_value6}
if (option) {
// this option already exists
} else {
    def newOption = optionManager.createOption(request_type7.getRelevantConfig(issue), null, 100, request_type_value6)
}

but that didnt work either.

Any suggestions would be great.  

4 answers

1 accepted

3 votes
Answer accepted
Yves Riel [Okapya]
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
June 29, 2016

Hi Joshi,

The value returned by the customfield is of a specific type (ChecklistItem) which means that pure strings will not work. When creating an item, to convert a json string to a CheklistItem, you need to get the customefieldType from the customfield and call getSingularObjectFromString. The string needs to be a json notation in the form

{"name" : "My Checklist Item", "checked" : true, "mandatory" : false}

You can then save the customfield value. When saving the customfield value, it needs to be a collection of ChecklistItems.

If you simply need to edit a checklist item, keep it in its ChecklistItem form and use its accessors.

By the way, not sure if you are aware but Checklist offers Post Workflow functions to change a checklist.

Joshi Shushruth June 29, 2016

Just a quick question, how would you go about adding multiple items to the checklist?

I tried doing this: 

 

{"name" : "My Checklist Item", "checked" : true, "mandatory" : false},{"name" : "Another Item", "checked" : true, "mandatory" : false},{"name" : "A Third Item", "checked" : true, "mandatory" : false}

I passed the above json into the getSingularObjectFromString, but that didnt work. Is there another method to use?

 

cheers

Yves Riel [Okapya]
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
June 29, 2016

Instead try to call getSingularObjectFromString for each json item and add the returned object to a collection. Then pass the collection to setCustomfieldValue.

Joshi Shushruth June 29, 2016

cheers, that worked. 

1 vote
Joshi Shushruth June 29, 2016

Excellent thank you @Whyves it worked, 

 

This was the code I used to get it working:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
def customFieldManager = ComponentAccessor.getCustomFieldManager();
def cf = customFieldManager.getCustomFieldObjectByName("Pre-Release Task");
def cfConfig = cf.getRelevantConfig(issue)
def cfType = cf.getCustomFieldType()
def value = cfType.getSingularObjectFromString('{"name" : "My Checklist Item", "checked" : true, "mandatory" : false}')
issue.setCustomFieldValue(cf, [value])

 

 

Ovidiu Vasilescu August 30, 2016

@Joshi Shushruth do you think it's possible to show the code you used to add multiple items to the checklist? 

Thanks a lot in advance, this is really useful!

Balvant Biradar July 5, 2017
def value1 = cfType.getSingularObjectFromString('{"name" : "Item1", "checked" : true, "mandatory" : false}')
def value2 = cfType.getSingularObjectFromString('{"name" : "Item2", "checked" : true, "mandatory" : true}')
def value3 = cfType.getSingularObjectFromString('{"name" : "Item3", "checked" : true, "mandatory" : false}')
def value4 = cfType.getSingularObjectFromString('{"name" : "Item4", "checked" : true, "mandatory" : false}')
log.warn " CRT value = ${crt_value} and CRT = ${crt}"
if (crt_value == "Request type")
{
 log.warn " CRT value = ${crt_value}"
issue.setCustomFieldValue(cf, [value1,value2,value3,value4])
}

 

Above code is working for adding multiple values in check list but issue is it is not maintaning order of each values.

It is changing order of items randomly 

I tried with ArrayList also but still not able to maintain order

Please help in knowing how to maintain order of items like

item1

item2

item3

...

..

Yves Riel [Okapya]
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
July 5, 2017

Usually, it will rank them in the order they are received. I'm surprised that an array list didn't work.

If you want to force a rank, add the "rank" property to the json string.

{"name" : "Item4", "checked" : true, "mandatory" : false, "rank": 0}

Balvant Biradar July 5, 2017

Hi Whyves,

Thanks for your help and I appriciate your quick turnaround

It is working fine. Just adding code for others to help

I am new to Groovy scripting, since i worked as only Jira Admin , so kindly provide any document link in which, it has all properties and syntex etc like you mentioned above for rank.

Thanks in advance
Balvant

def value1 = cfType.getSingularObjectFromString('{"name" : "Item1", "checked" : true, "mandatory" : false , "rank" : 0}')
def value2 = cfType.getSingularObjectFromString('{"name" : "Item2", "checked" : true, "mandatory" : true  , "rank" : 1}')
def value3 = cfType.getSingularObjectFromString('{"name" : "Item3", "checked" : true, "mandatory" : false , "rank" : 2}')
def value4 = cfType.getSingularObjectFromString('{"name" : "Item4", "checked" : true, "mandatory" : false , "rank" : 3}')
def value5 = cfType.getSingularObjectFromString('{"name" : "Item5", "checked" : true, "mandatory" : false , "rank" : 4}')
def value6 = cfType.getSingularObjectFromString('{"name" : "Item6", "checked" : true, "mandatory" : true  , "rank" : 5}')
def value7 = cfType.getSingularObjectFromString('{"name" : "Item7", "checked" : true, "mandatory" : false , "rank" : 6}')
def value8 = cfType.getSingularObjectFromString('{"name" : "Item8", "checked" : true, "mandatory" : false , "rank" : 7}')

List item = new ArrayList();
item.add(value1)
item.add(value2)
item.add(value3)
item.add(value4)
item.add(value5)
item.add(value6)
item.add(value7)
item.add(value8)

log.warn " CRT value = ${crt_value} and CRT = ${crt} before insert"
if (crt_value == "Request_Type")
{ 
 issue.setCustomFieldValue(cf, item)
 log.warn "done with adding items ${item}"
}


 

 

Balvant Biradar July 5, 2017

Hi Whyves,

One small doubt, If we want to append few more values to existing Checklist because setCustomFieldValue is deleting all existing values and adding new values.

Suppose if i want to add item9, Item10, Item11 in next transition 

Thanks in advance

Balvant

Yves Riel [Okapya]
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
July 5, 2017

If you want to manipulate an existing list, you should get the customfield value first via its standard API (see other example on the forum) and then manipulate the list. You should avoid always rewriting the entire list.

So in essence:

  1. issue.getCustomfieldValue(customfield) will return a list of ChecklistItems
  2. Add/remove items to the list
  3. Save list to customfield.
Balvant Biradar July 5, 2017

Thanks for your help and suggestions.

Balvant Biradar February 4, 2019

Hi Yves,

Please could you help on how to add checklist from create event

I am not able to add checklist for create event, but using same below script I am able to add for other workflow transitions like open to In Progress.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
def customFieldManager = ComponentAccessor.getCustomFieldManager();
def cf = customFieldManager.getCustomFieldObjectByName("Checklist");
def cfConfig = cf.getRelevantConfig(issue)
def cfType = cf.getCustomFieldType()


def value1 = cfType.getSingularObjectFromString('{"name" : "Item1", "checked" : true, "mandatory" : false , "rank" : 0}')
def value2 = cfType.getSingularObjectFromString('{"name" : "Item2", "checked" : true, "mandatory" : true , "rank" : 1}')
def value3 = cfType.getSingularObjectFromString('{"name" : "Item3", "checked" : true, "mandatory" : false , "rank" : 2}')
def value4 = cfType.getSingularObjectFromString('{"name" : "Item4", "checked" : true, "mandatory" : false , "rank" : 3}')

log.warn "In side scripttttttttttttttttttt"

List item = new ArrayList();
item.add(value1)
item.add(value2)
item.add(value3)
item.add(value4)

issue.setCustomFieldValue(cf, item)
log.warn "END of script -------------------------------"
Yves Riel [Okapya]
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
February 6, 2019

Hi,

Maybe it's due to the order of your script? If your scripts somehow runs before Jira saves the issue, it will most likely be overridden by the issue which should also save the checklist data. In any case, accessing and saving the checklist data should be the same in any transition. I really think it's due to somehow Jira overwriting the Checklist data after you.

Yves 

Balvant Biradar February 6, 2019

Thanks Yves for your help

Eddy Fras October 9, 2019

Hi all,

Did I miss something or, as said in API doc for issue.setCustomFieldValue() : 

Sets a custom field value on this Issue Object, but does not write it to the database. This is highly misleading.

Are you making updates to issues but not storing these updates ?

Yves Riel [Okapya]
Marketplace Partner
Marketplace Partners provide apps and integrations available on the Atlassian Marketplace that extend the power of Atlassian products.
October 14, 2019

Hi Eddie,

Just noticed the description myself now but I thought that the data was persisted to the DB. We would have to validate but to my knowledge this methods calls the custom field type method which updates the data. Otherwise, you can call the updateIssue or updateValue on the custom field type to persist the data.

Yves

0 votes
Barb O'Connell December 18, 2019

I've tried both of these code suggestions (with Array and without), but I'm getting the error, note it's for the Array example but get similar error with other example):

{code}

[Static type checking] - Cannot find matching method com.atlassian.jira.issue.Issue#setCustomFieldValue(com.atlassian.jira.java.util.ArrayList). Please check if the declared type is correct and if the method exists.

{code}

Has anyone had this problem or have an idea how to fix it?

Maxime Lefebvre _Okapya_
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.
December 18, 2019

Hi Barb!

Your error message seems to indicate that you are passing only one parameter (the array) to the `setCustomFieldValue` function, but this function receives two parameters: The Custom Field and the Value.

Could you validate the method call and possibly link us the part of your code that has the error.

Regards,

Barb O'Connell December 19, 2019

Sorry I used the code as exactly above with only a substitution of my custom field name, which is "DoD"

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
def customFieldManager = ComponentAccessor.getCustomFieldManager();
def cf = customFieldManager.getCustomFieldObjectByName("DoD");
def cfConfig = cf.getRelevantConfig(issue)
def cfType = cf.getCustomFieldType()


def value1 = cfType.getSingularObjectFromString('{"name" : "Item1", "checked" : true, "mandatory" : false , "rank" : 0}')
def value2 = cfType.getSingularObjectFromString('{"name" : "Item2", "checked" : true, "mandatory" : true , "rank" : 1}')
def value3 = cfType.getSingularObjectFromString('{"name" : "Item3", "checked" : true, "mandatory" : false , "rank" : 2}')
def value4 = cfType.getSingularObjectFromString('{"name" : "Item4", "checked" : true, "mandatory" : false , "rank" : 3}')

log.warn "In side scripttttttttttttttttttt"

List item = new ArrayList();
item.add(value1)
item.add(value2)
item.add(value3)
item.add(value4)

issue.setCustomFieldValue(cf, item)
log.warn "END of script -------------------------------"

 

Error is on the second to last line:

issue.setCustomFieldValue(cf, item)

I didn't alter it much because this looked like a good test which I could alter later once working. 

Thanks for your help!

-Barb

Maxime Lefebvre _Okapya_
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.
December 19, 2019

Hi Barb!

I believe I understand what is happening. The issue provided by your scope (by ScriptRunner?) is not a MutableIssue, so it cannot be modified.

The first thing I would try is to cast your issue as a MutableIssue or IssueImpl but this would only work if the Issue is of that type already.

import com.atlassian.jira.issue.MutableIssue

...

((MutableIssue) issue).setCustomFieldValue(cf, item);

If this error is showing in your Script Editor only, I would suggest you to still save that code and try it out, since sometimes the code runs properly even if the Script Editor tells it won't.

Regards,

Barb O'Connell December 20, 2019

Thanks Maxime.  Using MutableIssue has removed the error message but sadly the outcome doesn't update the checklist.  I'll keep experimenting.

Maxime Lefebvre _Okapya_
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.
December 20, 2019

Hi Barb,

Using setCustomFieldValue does not update the Issue by itself, an IssueService must be used to save the changes. Usually ScriptRunner does that automatically at the end of an Issue Listener.

If you are inside a Listener, can you tell me which one? If you are using Behaviors, I believe you are not using the right tool and you should take a look at Listeners. (Both comes with ScriptRunner).

Regards,

Barb O'Connell December 20, 2019

Thank you ... I'm using Project Automation add-on.  The trigger is ticket transition and the action is this scriptrunner script.

Barb O'Connell January 3, 2020

I got a little help locally and wanted to post the final version if it can be of help to others. Thanks Maxime for your patience.

{code}

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def customFieldManager = ComponentAccessor.getCustomFieldManager();
def cf = customFieldManager.getCustomFieldObjectByName("Checklist");
def cfConfig = cf.getRelevantConfig(issue)
def cfType = cf.getCustomFieldType()
def value = cfType.getSingularObjectFromString('{"name" : "something", "checked" : false, "mandatory" : false}')
((MutableIssue) issue).setCustomFieldValue(cf, [value])
ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false
Like # people like this
Maurice Langlois October 5, 2020

Hi,

I wanted to do the same thing, have checklist items populated through the create subtask post script function.

I tried your script but I get that error message for the line:

def customFieldManager = ComponentAccessor.getCustomFieldManager();

Error is: Variable "customFieldManager" masks a binding variable of the same name. Please choose a different name for variable: "customFIeldManager".

I tried a different name but then I get other errors...

Any hints?

Thanks!

Maxime Lefebvre _Okapya_
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.
October 6, 2020

Looks like you already have a `customFieldManager` variable in your script environment, probably automatically added by Scriptrunner for you, so you can potentially just remove that line of code.

So we will need to know about other errors you have when you changed its name.

Maurice Langlois October 6, 2020

First, if I removed the line : def customFieldManager = ComponentAccessor.getCustomFieldManager();

Then I get this warning for line:

def cf = customFieldManager.getCustomFieldObjectByName("Checklist");

"use CustomFieldManager.getCustomFieldObjectsByName(string) instead"

... So it says to add an "s" to Object. But doing this brings a couple of errors:

For line: def cfConfig = cf.getRelevantConfig(issue):

"Static type checking - Cannot find matching method java.util.Collection#getRelevantConfig (com.atlassian.jira.issue.Mutable. Please check if the decalred type is correct and if the method exists."

Got this static error also with lines:

def cfType = cf.getCustomFieldType()
def value = cfType.getSingularObjectFromString('{"name" : "something", "checked" : false, "mandatory" : false}')

((MutableIssue) issue).setCustomFieldValue(cf, [value])
ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)

 

So then I tried to rename the variable to custFieldManager:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()


def custFieldManager = ComponentAccessor.getCustomFieldManager();
def cf = custFieldManager.getCustomFieldObjectByName("Checklist");
def cfConfig = cf.getRelevantConfig(issue)
def cfType = cf.getCustomFieldType()
def value = cfType.getSingularObjectFromString('{"name" : "something", "checked" : false, "mandatory" : false}')
((MutableIssue) issue).setCustomFieldValue(cf, [value])
ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)

Then again on the line:

def cf = custFieldManager.getCustomFieldObjectByName("Checklist");
I get this message: "use CustomFieldManager.getCustomFieldObjetsByName(String) instead

So it wants me to add an "s" after Object in there... And to use "CustomFieldManager" lol.

So by doing this, again get the static type errors mentioned above.

Maxime Lefebvre _Okapya_
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.
October 6, 2020

Thank you for the detailed explanation!

If you look at documentation of the Custom Field Manager, you will see there is a getCustomFieldObjectByName method but it is deprecated.

What you are seeing is potentially only a warning (and not an actual error that prevents the code from executing at run time).

In Jira, many custom fields can have the same name, so Atlassian did not consider safe to retrieve a custom field by name, that is why they deprecated it in favor of using a method that returns All custom fields with that name (getCustomFieldObjectsByName).

But the best would be to actually use another method getCustomFieldObject(Long id) instead, which is safe since it retrieves your Custom Field by unique ID. You can find out your custom field ID by looking at the browser URL parameters while configuring your field (secure/admin/ConfigureCustomField!default.jspa?customFieldId=10101). So in that example, you would replace the line for:

  • def cf = customFieldManager.getCustomFieldObject(10101L);
    • OR
  • def cf = customFieldManager.getCustomFieldObject("customfield_10101");

I hope this helps :)

Regards,

Maurice Langlois October 6, 2020

I used the FieldObject with the custom field ID and it validated without errors or warnings.

But then when trying to switch to my status that creates the subtasks (the code below is in my create subtask post script function), I then get this workflow error:

org.ofbiz.core.entity.GenericTransactionException: Commit failed, rollback previously requested by nested transaction.

It seems that you have tried to perform an illegal workflow operation.

If you think this message is wrong, please contact your Jira administrators.

 

Code used:

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

def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def CustomFieldManager = ComponentAccessor.getCustomFieldManager();
def cf = CustomFieldManager.getCustomFieldObject("customfield_19900");

def cfConfig = cf.getRelevantConfig(issue)
def cfType = cf.getCustomFieldType()
def value = cfType.getSingularObjectFromString('{"name" : "something", "checked" : false, "mandatory" : false}')
((MutableIssue) issue).setCustomFieldValue(cf, [value])
ComponentAccessor.getIssueManager().updateIssue(user, issue, EventDispatchOption.ISSUE_UPDATED, false)

 

Thanks for your patience :)

Maxime Lefebvre _Okapya_
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.
October 6, 2020

The error message is unfortunately not specific enough to indicate to what is happening. You could check your Jira logs and see if there is a more complete error message in it.

Where is your script running? A Listener, a Post Function? Depending on when the script is executed, you might want to try removing the last line of the script that causes the update and see if the issue still gets updated and the error prevented.

Also, we've got a bunch of Script Examples now in our documentation, one of those might work better.

If your use-case is very simple (adding items on transition), you might be better off with a Checklist Post Function.

Regards

0 votes
MattS
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.
June 30, 2016

To find the object type I usually retrieve an existing value and call getClass().getName() on that object

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events