Subtask Default Field

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.

 

2 answers

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 ;-)

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

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

Suggest an answer

Log in or Sign up to answer
Atlassian Community Anniversary

Happy Anniversary, Atlassian Community!

This community is celebrating its one-year anniversary and Atlassian co-founder Mike Cannon-Brookes has all the feels.

Read more
Community showcase
Bridget Sauer
Published Thursday in Marketplace Apps

Calling all developers––You're invited to Atlas Camp 2018

 Atlas Camp   is our developer event which will take place in Barcelona, Spain  from the 6th -7th of   September . This is a great opportunity to meet other developers and get n...

243 views 0 6
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you