Hi all,
i have to copy a value from one Insight Custom Filed to another in the same issue
Tried the corresponding build in Scriptrunner script, with this, something is happening, but it only sets the Attributes from the source customfield in to the target custom field.
But as this two custom fields have not all attributes the same i need not just a copy of the existing values, i wanna force Jira to choose the right insight entry and display then the attributes in the target Custom field (same if the user would choose the entry manually)
I tried this way:
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade
import com.atlassian.jira.event.type.EventDispatchOption // Update Issue (customField)
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.ImmutableCustomField
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.bc.issue.search.SearchService // run JQL
import com.atlassian.jira.jql.parser.JqlQueryParser // run JQL
import com.atlassian.jira.web.bean.PagerFilter // run JQL
def issueManager = ComponentAccessor.issueManager
def CustomFieldManager = ComponentAccessor.getCustomFieldManager();
def userUtil = ComponentAccessor.getUserUtil();
@WithPlugin("com.riadalabs.jira.plugins.insight")
@PluginModule IQLFacade iqlFacade
@PluginModule ObjectFacade objectFacade
@PluginModule ObjectTypeAttributeFacade objectTypeAttributeFacade
def issue = issueManager.getIssueObject("ISSP-4904") // your issue key here
//CustomField Manager
def customFieldManager = ComponentAccessor.getCustomFieldManager()
// This gets data from the corresponding Customer Field
def customerCF = (CustomFieldManager.getCustomFieldObjectsByName("Customer"))[0];
def String customerStr = issue.getCustomFieldValue(customerCF);
def String customerID = customerStr.substring(customerStr.indexOf("-") + 1, customerStr.indexOf(")")); //gets only value in (..)
def int customerNR = customerID.toInteger()
log.warn(customerStr)
log.warn(customerID)
log.warn(customerNR)
def objectAttributeUserID = objectFacade.loadObjectAttributeBean(customerNR, 860)
def String objectAttributeUserIDValue = objectAttributeUserID.getObjectAttributeValueBeans()[0].getValue()
log.warn(objectAttributeUserID)
log.warn(objectAttributeUserIDValue)
def iamuserCF = ComponentAccessor.customFieldManager.getCustomFieldObject(11601)
log.warn(objectAttributeUserIDValue)
issue.setCustomFieldValue(iamuserCF,objectAttributeUserID)
//This method will store the provided issue to the JIRA datastore.
issueManager.updateIssue(userUtil.getUserByName("Jira Automation"), issue, EventDispatchOption.DO_NOT_DISPATCH, false)
... but I'm always struggling with the last line, the update code:
issueManager.updateIssue(userUtil.getUserByName("Jira Automation"), issue, EventDispatchOption.DO_NOT_DISPATCH, false)
it gets me this error:
2022-07-22 07:56:26,810 ERROR [common.UserScriptEndpoint]: Script console script failed: java.lang.ClassCastException: class com.riadalabs.jira.plugins.insight.services.model.ObjectAttributeBean cannot be cast to class java.util.Collection (com.riadalabs.jira.plugins.insight.services.model.ObjectAttributeBean is in unnamed module of loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @3e20abcb; java.util.Collection is in module java.base of loader 'bootstrap') at com.riadalabs.jira.plugins.insight.services.jira.customfield.DefaultObjectCustomField.updateValue(DefaultObjectCustomField.java:87) at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:430) at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:400) at com.atlassian.jira.issue.managers.DefaultIssueManager.updateFieldValues(DefaultIssueManager.java:716) at com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue(DefaultIssueManager.java:667) at com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue(DefaultIssueManager.java:653) at com.atlassian.jira.issue.managers.RequestCachingIssueManager.updateIssue(RequestCachingIssueManager.java:217) at com.atlassian.jira.issue.IssueManager$updateIssue$30.call(Unknown Source) at Script1204.run(Script1204.groovy:56)
I also tried to use other attribute values which are available on both fields - even the copy "Label" to "Label" Attribute is not working...
Is there a way to do this?
Thank you in advance
Regards Marco
Hi Marco
The clue in your error is
ObjectAttributeBean cannot be cast to class java.util.Collection
This is saying that you are trying to store an ObjectAttributeBean but Jira expects some kind of "Collection".
Specifically, Insight Customer fields can only accept collections of ObjectBean (even if multiple is not enabled, then you need a collection of size 1).
So we need to find the part of your script that generates the ObjectAttributeBean and make sure you retrieve the value from it (I assume that's a reference attribute and therefore the value will be an object reference)
Here is a fixed (and a bit cleaned up) version of your script
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade
import com.riadalabs.jira.plugins.insight.services.model.ObjectBean
def issueManager = ComponentAccessor.issueManager
def customFieldManager = ComponentAccessor.customFieldManager
def automationUser = ComponentAccessor.userManager.getUserByName('Jira Automation')
@WithPlugin("com.riadalabs.jira.plugins.insight")
@PluginModule ObjectFacade objectFacade
def issue = issueManager.getIssueObject("ISSP-4904") // your issue key here
// This gets data from the corresponding Customer Field
def customerCF = customFieldManager.getCustomFieldObjectsByName("Customer")[0]
//insight fields store array of ObjectBeanss
def customerObjects = issue.getCustomFieldValue(customerCF) as List<ObjectBean>
def customerObject = customerObjects[0] //assume single customer
log.warn("customerObject has key=$customerObject.objectKey, id=$customerObject.id, and label=$customerObject.label")
def objectAttributeUserID = objectFacade.loadObjectAttributeBean(customerObject.id, 860)
def referencedUserObjectId = objectAttributeUserID.objectAttributeValueBeans[0].referencedObjectBeanId
def referenceUserObject = objectFacade.loadObjectBean(referencedUserObjectId)
log.warn("referenceUserObject has key=$referenceUserObject.objectKey, id=$referenceUserObject.id, and label=$referenceUserObject.label")
def iamuserCF = ComponentAccessor.customFieldManager.getCustomFieldObject(11601)
issue.setCustomFieldValue(iamuserCF, [referenceUserObject])
//This method will store the provided issue to the JIRA datastore.
issueManager.updateIssue(automationUser, issue, EventDispatchOption.DO_NOT_DISPATCH, false)
A few pointers
def String ... is like saying def def or String String. If you want to set the type of a variable, just declare it with that type, don't include def. def is used to declare an untyped object variable that can change the underlying type at will during runtime.
Don't type cast the getCustomFieldValue to String, especially if it's not a simple text field.
By keeping it as "def" and adding the type we expect with the "as List<ObjectBean>" at the end, we can tell the compiler what to expect.
But bonus, you now have access to methods like getId() or getObjectKey() or getLabel() of objectBean as you'll see in the log.warn statement.
And there is no longer any need for fancy string manipulation to get the id.
We can replace getValue with getReferenceObjectBeanId so that we can get a property typed integer value for the reference.
Which allows us to load a new objectbean.
Then we can apply objectbean as a list (surrounded by []) to the custom field.
Final pointer, after doing all that above, you index will not be updated. So searches will not work until the issue is re-indexed for another reason.
I've taken to using issueService instead of issueManager wherever I can.
To do that, use the following line instead of your last 2:
def issueService = ComponentAccessor.issueService
def iip = issueService.newIssueInputParameters()
iip.setSkipScreenCheck(true) //optional
iip.addCustomFieldValue(iamuserCF.id, referenceUserObject.objectKey)
def validationResult = issueService.validateUpdate(automationUser, issue.id, iip)
assert validationResult.valid : validationResult.errorCollection.errors
issueService.update(automationUser, validationResult, EventDispatchOption.DO_NOT_DISPATCH,false)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.