Hi,
I'm trying to make sense of the example provided for ScriptRunner behaviours to copy values from a parent to a subtask but am running into problems:
https://scriptrunner.adaptavist.com/latest/jira/recipes/behaviours/subtask-default-fields.html
If I run the script unedited it throws a series of exceptions:
[c.a.p.r.c.error.jersey.ThrowableExceptionMapper] Uncaught exception thrown by REST service: groovy/lang/GroovyObject java.lang.NoClassDefFoundError: groovy/lang/GroovyObject at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.lang.ClassLoader.defineClass(ClassLoader.java:642) . . . Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:775)
I commented out everything beneath this line:
// IF YOU DON'T WANT CUSTOM FIELDS COPIED REMOVE EVERYTHING BELOW HERE
Now it runs without errors though it doesn't seem to copy for some fields (such as labels)
I know specifically the customfields I want to copy and have their ids and am wondering if there is a simplier way to address these specific fields rather then the looping solution presented in the example.
My Jira Instace is 7.3.8 and Scriptrunner is 5.0.11 so both are fairly current and I'm not sure if the errors are recently introduced or something.
Any assitance would be appriciated. Thank you.
I was able to resolve this problem using a different method based of a simailr problem I found here
Basically I added the following code as part of a custom script post-function within the workflow used only by the sub-task type that need to inherit this informaiton from the parent:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.UpdateIssueRequest
import com.atlassian.jira.issue.fields.CustomField
MutableIssue parentIssue = (MutableIssue) issue.getParentObject()
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
// Inheriting Product Feild from Parent
CustomField cfProductCopyFrom = customFieldManager.getCustomFieldObject("customfield_10702")
CustomField cfProductCopyTo = customFieldManager.getCustomFieldObject("customfield_10702")
def cfProductCopyVal = parentIssue.getCustomFieldValue(cfProductCopyTo)
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
if (cfProductCopyVal != null)
{
issue.setCustomFieldValue(cfProductCopyTo, parentIssue.getCustomFieldValue(cfProductCopyFrom))
ComponentAccessor.getIssueManager().updateIssue(user, issue, UpdateIssueRequest.builder().eventDispatchOption(EventDispatchOption.ISSUE_UPDATED).sendMail(false).build() )
}
Hopefully this can help others and if there is any feedback please let me know
Hey Brendan,
I'm sorry that your having issues with the example script. I didn't get the same exception as you when I ran the script out of the box, however I did need to play with it to get the custom fields working. I have tested the below (modified) script and that will retrieve and display all of the custom fields that you add to the copyCustomFields list.
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.customfields.option.Option import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.web.util.OutlookDate import com.atlassian.jira.web.util.OutlookDateManager import com.onresolve.jira.groovy.user.FieldBehaviours import com.onresolve.jira.groovy.user.FormField import groovy.transform.BaseScript import java.sql.Timestamp import static com.atlassian.jira.issue.IssueFieldConstants.* @BaseScript FieldBehaviours fieldBehaviours FormField field = getFieldById(getFieldChanged()) FormField parent = getFieldById("parentIssueId") Long parentIssueId = parent.getFormValue() as Long if (!parentIssueId || field.getFormValue()) { // this is not a subtask, or the field already has data return } def issueManager = ComponentAccessor.getIssueManager() def parentIssue = issueManager.getIssueObject(parentIssueId) def customFieldManager = ComponentAccessor.getCustomFieldManager() // REMOVE OR MODIFY THE SETTING OF THESE FIELDS AS NECESSARY getFieldById(SUMMARY).setFormValue(parentIssue.summary) getFieldById(PRIORITY).setFormValue(parentIssue.getPriorityObject().id) OutlookDate outlookDate = ComponentAccessor.getComponent(OutlookDateManager).getOutlookDate(Locale.getDefault()) getFieldById(DUE_DATE).setFormValue(outlookDate.formatDMY(parentIssue.getDueDate())) getFieldById(COMPONENTS).setFormValue(parentIssue.componentObjects*.id) getFieldById(AFFECTED_VERSIONS).setFormValue(parentIssue.affectedVersions*.id) getFieldById(FIX_FOR_VERSIONS).setFormValue(parentIssue.fixVersions*.id) getFieldById(ASSIGNEE).setFormValue(parentIssue.assigneeId) getFieldById(ENVIRONMENT).setFormValue(parentIssue.environment) getFieldById(DESCRIPTION).setFormValue(parentIssue.description) getFieldById(SECURITY).setFormValue(parentIssue.securityLevelId) getFieldById(LABELS).setFormValue(parentIssue.labels) // IF YOU DON'T WANT CUSTOM FIELDS COPIED REMOVE EVERYTHING BELOW HERE // IF YOU ONLY WANT SOME FIELDS INHERITED ADD THEM TO THE LIST BELOW, OR LEAVE EMPTY FOR ALL // eg ['Name of first custom field', 'Name of second custom field'] List copyCustomFields = ["Custom Value"] List<CustomField> parentFields = customFieldManager.getCustomFieldObjects(parentIssue) for (def cf in parentFields) { if (copyCustomFields && copyCustomFields.contains(cf.name)) { def parentValue = cf.getValue(parentIssue) if (!parentValue) { return } getFieldById(cf.id).setFormValue(parentValue) log.debug("parentValue: ${parentValue?.class} for type ${cf.name}") if (parentValue instanceof Timestamp) { getFieldById(cf.id).setFormValue(outlookDate.formatDMY(parentValue)) } else if (parentValue instanceof Option) { getFieldById(cf.id).setFormValue(parentValue.optionId) } else if (parentValue instanceof List && parentValue[0] instanceof Option) { getFieldById(cf.id).setFormValue(parentValue*.optionId) } else { getFieldById(cf.id).setFormValue(parentValue) } } }
Note: Regarding your custom fields the point of the script is to allow you to reference your fields by name to make your life easier.
If you still need to reference the field by ID just confirm the ID field you are using and I'll come back to you with a different solution ;-)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you Stephen,
The script above does appear to work but with a number of caveats.
Firstly it only appears to copy the value provided when that field is present in the appropriate screen. Initially I wanted this to happen invisibly and didn’t include the custom field on the create screen and it would not work until I added it. The behaviour itself is triggered off the Summary field.
Secondly we make use of another add-on called Quick Sub Tasks to generate many subtasks at once. This however seems to bypass the behaviour entirely. Is there a ways to ensure the behavior is triggered on this? I tried adding a condition for the Create Action but this seems to have no effect.
Lastly we don’t necessarily need to reference ID I just thought it might be easier than going through the entire list of custom fields since the fields that we need are known. If I can get around the other issues mentioned the name solution seems to work fine.
My ultimate goal here is to copy the parent values for two custom fields into a sub task at creation time without worrying or involving the end user creating the task. If they change them after the fact thats fine. I’ve tried adapting the script into a post function on the workflow of the subtask but haven’t got very far on this yet.
Any further advice or assistance would be greatly appreciated.
Thank you,
Brendan
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.