Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Subtask Default Field

Brendan Byers June 29, 2017

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

0 votes
Brendan Byers July 21, 2017

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

0 votes
Stephen Cheesley [Adaptavist]
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.
July 5, 2017

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

Brendan Byers July 11, 2017

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

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events