Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Next challenges

Recent achievements

  • Global
  • Personal

Recognition

  • Give kudos
  • Received
  • Given

Leaderboard

  • Global

Trophy case

Kudos (beta program)

Kudos logo

You've been invited into the Kudos (beta program) private group. Chat with others in the program, or give feedback to Atlassian.

View group

It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

Copy custom field (user object) to sub-task using script runner behaviour

I have a custom user picker field on both the parent and sub-task. When a sub-task is created, I would like to copy the user specified in the parent task to the same field in the sub-task. The field is called "Projektleiter".

I tried using the example in the ScriptRunner documentation but it doesn't work. Here's what I have.

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

OutlookDate outlookDate = ComponentAccessor.getComponent(OutlookDateManager).getOutlookDate(Locale.getDefault())

// REMOVE OR MODIFY THE SETTING OF THESE FIELDS AS NECESSARY
getFieldById(COMPONENTS).setFormValue(parentIssue.componentObjects*.id)

// 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 = ['Projektleiter']

List<CustomField> parentFields = customFieldManager.getCustomFieldObjects(parentIssue)

for (def cf in parentFields) {
if (copyCustomFields && !copyCustomFields.contains(cf.name)) {
        return
    }

def parentValue = cf.getValue(parentIssue) as List<Option>

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



Maybe it's different for a user field. Can somebody help?

Thanks and BR.

1 answer

1 accepted

1 vote
Answer accepted

The value of a user picker field is not List<Option>. You have to use ApplicationUser as class. Or List<ApplicationUser> if it's a multi user picker.

def parentValue = cf.getValue(parentIssue) as ApplicationUser

The part including and below if (parentValue instanceof Timestamp) { can be removed.
Best,
Henning

Hi Henning

Thanks for your help so far.

After adding "as ApplicationUser", I get the error "Unable to resolve class ApplicationUser". The field is only a single user picker.

Do I have to import something maybe for it to work?

Thanks and BR

Marius

Yes, you have to import the ApplicationUser class.

import com.atlassian.jira.user.ApplicationUser

Henning 

Ok, I took a look at the original script and I think there is only one thing missing for handling user fields. I added it to the script:

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.user.ApplicationUser
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 = []

List<CustomField> parentFields = customFieldManager.getCustomFieldObjects(parentIssue)

for (def cf in parentFields) {
if (copyCustomFields && !copyCustomFields.contains(cf.name)) {
return
}

def parentValue = cf.getValue(parentIssue)

if (!parentValue) {
return
}

log.debug("parentValue: ${parentValue?.class} for field ${cf.name}")

if (parentValue instanceof Timestamp) {
getFieldById(cf.id).setFormValue(outlookDate.formatDMY(parentValue as Timestamp))
} else if (parentValue instanceof Option) {
getFieldById(cf.id).setFormValue((parentValue as Option).optionId)
} else if (parentValue instanceof List && parentValue[0] instanceof Option) {
getFieldById(cf.id).setFormValue((parentValue as List<Option>)*.optionId)
} else if (parentValue instanceof ApplicationUser) {
getFieldById(cf.id).setFormValue((parentValue as ApplicationUser).name)
} else {
getFieldById(cf.id).setFormValue(parentValue)
}
}

I think setting a user field via setFormValue() has to use the username (ApplicationUser.name) and not the ApplicationUser object.

Please make your changes and try it again.

Best regards,
Henning

There was a small error in the last if condition.

grafik.png

I removed that particular else if part because I think it's not necessary for my case and then saved the script. However, when I opened the parent task and clicked on Create Sub-Task the field Projektleiter is still empty.

grafik.png

grafik.png

I also noticed that the assignee has not been set either. Summary, Components, Priority and Due Date have been successfully set. Not that I necessarily want the assignee to be set. I just think it's suspicious that both user fields seem to have issues.

BR

Marius

Do you see DEBUG messages in the atlassian-jira.log? If not could you try to add 

import org.apache.log4j.Level
log.setLevel(Level.DEBUG)

to the code at the beginning and try again.

Henning

I've added both lines and also this one.

log.debug("--------------------This is to test Behaviours Logging----------------")

Unfortunately, this test message is the only debug message I'm able to find in the log file after trying to create a sub-task.

Mmh, so we need more  debug messages. Try before both return statements.

Is the customfield name correct? Maybe translated?

Added:

log.debug("1. Return")

and

log.debug("2. Return")

After testing, I can see the message "1. Return" in the log file. However, I tried commenting out these to if conditions before and it wouldn't copy the user either way. But still odd that it enters the first if condition.

The name is correct. It's in German.

grafik.png

I know, I'm a native German speaker. My question was because if the user has a different language selected and the customfield is translated, it may not match.

Nevertheless let's try to see what the list of customfields of the parent issue contains. Please add 

log.debug "ParentFields: ${parentFields*.name}"

after List<CustomField> parentFields = customFieldManage... and try again.

Ah, I see. We're currently not working with translations. Everything is usually in German.

Here's the log message.

ParentFields: [Beobachter, Checkliste, Hide Comment Field, Kasse, Lieferant(en) & Partner, Projektleiter, issueFunction]*.name

For every field besides Projektleiter there should be a "1. Return" debug message.

Please change log.debug("1. Return") to 

log.debug("1. Return: $cf.name")

 and add

log.debug "ParentValue: $parentValue"

below def parentValue = cf.getValue(parentIssue).

I think we got it!

After applying your changes:

--------------------This is to test Behaviours Logging----------------
ParentFields: [Beobachter, Checkliste, Hide Comment Field, Kasse, Lieferant(en) & Partner, Projektleiter, issueFunction]*.name
1. Return: Beobachter

I then tried and replaced the return statement with 'continue':

--------------------This is to test Behaviours Logging----------------
ParentFields: [Beobachter, Checkliste, Hide Comment Field, Kasse, Lieferant(en) & Partner, Projektleiter, issueFunction]*.name
1. Return: Beobachter
1. Return: Checkliste
1. Return: Hide Comment Field
1. Return: Kasse
1. Return: Lieferant(en) & Partner
ParentValue: VollrathM(vollrathm)
parentValue: class com.atlassian.jira.user.DelegatingApplicationUser for field Projektleiter
1. Return: issueFunction

grafik.png

The field is now filled correctly! :)

What do you think? Is this the correct way?

Yes! That's easy (as always :-)).

Someone changed the source in the documentation.. in version 5.0.7 it's using "parentFields.each { CustomField cf ->" instead of the for loop (since v5.0.8 of the documentation). Within each{} a "return" leaves the closure only for one element. In a for loop it has nothing special to say, so it leaves the script...

I normaly don't use for loops so I didn't catched it :-) Well done!

I filed a bug at Adaptavist. 

Is the assignee working now?

I think it has to be

getFieldById(ASSIGNEE).setFormValue(parentIssue.assignee?.name)

Hi Henning

Unfortunately, the assignee still does not work. However, since my original post is solved, I'll go ahead and mark your answer as accepted :)

Thank you again for your support. I'm glad we got it working.

BR

Marius

I would like to add to your script one if before options

 

if (parentValue instanceof List && ((List)parentValue)[0] instanceof ApplicationUser) {
  getFieldById(cf.id).setFormValue((parentValue as List<Option>)*.name)
}

Suggest an answer

Log in or Sign up to answer
TAGS

Community Events

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

Find an event

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

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you