Hi,
I am trying to have a custom text field called "Initiative" that exists in all issue types populated from Story to sub-task using scriptrunner. I am new to scriptrunner and only have admin access to a dev server for exploration so may be unfamiliar with admin settings needed to make this work.
Reference: https://scriptrunner.adaptavist.com/5.4.47/jira/recipes/behaviours/subtask-default-fields.html
Problems:
parentIssueId
form field. Once you have that you can load that issue, get the fields, and set them on the Create Issue dialog." Parent IssueID is not a field I can add to the form.Script (I removed some error-causing items that I don't think I need and retained some standard fields to inherit values from parent):
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 = ['Initiative']
List<CustomField> parentFields = customFieldManager.getCustomFieldObjects(parentIssue)
parentFields.each { cf ->
if (copyCustomFields && !copyCustomFields.contains(cf.name)) {
return
}
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<Option>) {
parentValue = parentValue as List<Option> //This cast is just to placate the static type checker
getFieldById(cf.id).setFormValue(parentValue.collect { it.optionId })
} else {
getFieldById(cf.id).setFormValue(parentValue)
}
}
looking at all the help you have been provided couldn't resist asking one for myself :D
Thank you first of all.
Can the same thing work for cloning issue in post function script?
I want to add multiple custom fields into description of the issue being cloned.
I am new to scriptrunner and cannot find a good place to look for this feature.
Thank you in advance
Hello @wajdan zahid ,
I would advise you create a new question for a thorough answer (you can ping me there), this one is getting messy. It is possible to copy field values to another issue. I am not sure if there is a way to detect that the issue is being cloned upon creation, and I would need to do some testing.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hey Antoine:
Tried your script above (to copy custom field value from parent) and got this:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Antoine Berry How difficult would something like this be to implement based on linked issues? So if I have stories that are derived from features (a level my team added into our hierarchy) I would like a text field flowed from my feature to my story.
Thanks!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Laci ,
It would be possible, but you would have to go through some extra steps, since each issue can be linked to multiple issues, with different link types. Here is a snippet that you can use to retrieve the linked issues and use the same logic as above :
import com.atlassian.jira.issue.link.IssueLink;
import com.atlassian.jira.component.ComponentAccessor;
def allOutIssues = [];
List<IssueLink> allOutIssueLink = ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.getId());
for (Iterator<IssueLink> outIterator = allOutIssueLink.iterator(); outIterator.hasNext();) {
IssueLink issueLink = (IssueLink) outIterator.next();
allOutIssues << issueLink.getDestinationObject();
}
def allInIssues = [];
List<IssueLink> allInIssueLink = ComponentAccessor.getIssueLinkManager().getInwardLinks(issue.getId());
for (Iterator<IssueLink> outIterator = allInIssueLink.iterator(); outIterator.hasNext();) {
IssueLink issueLink = (IssueLink) outIterator.next();
allOutIssues << issueLink.getDestinationObject();
}
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I thought it would be good to summarize what finally worked here:
Goals:
Goal 1 Post Function (Copy custom field from Epic to Story upon create):
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
["Initiative"].each { cfname ->
def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == cfname}
log.error("cf : " + cf)
log.error("issue : " + issue)
def epicCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
if (!cf || !epicCf) {return}
def epic = issue.getCustomFieldValue(epicCf) as Issue
if (!epic) {return}
def cfValue = cf.getValue(epic)
log.error("cfValue : " + cfValue)
issue.setCustomFieldValue(cf, cfValue)
}
4. Screen capture:
Goal 2 Post Function (Copy custom field from Story to sub-task upon create):
mport com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.index.IssueIndexingService
def customFieldManager = ComponentAccessor.getCustomFieldManager()
int cfId = 11002
def cf = customFieldManager.getCustomFieldObject(cfId)
log.error("cf : " + cf)
log.error("issue : " + issue)
def cfValue = issue.getCustomFieldValue(cf)
log.error("cfValue : " + cfValue)
def cfParentValue = issue.getParentObject().getCustomFieldValue(cf)
log.error("cfParentValue : " + cfParentValue)
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
issue.store()
issueIndexingService.reIndex(issue)
if (issue.isSubTask()){
cf.updateValue(null, issue, new ModifiedValue(cfValue, cfParentValue), new DefaultIssueChangeHolder())
log.error("Custom field updated on issue " + issue.getKey() + " with value " + cfParentValue)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Barbara,
As for your first script, I would advise to update it from setCustomField(cf... method to cf.updateValue(... because as you can see here setCustomField does not write in the database. Although in that case, since you have a re-index postfunction, it is working.
You can also remove
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
issue.store()
issueIndexingService.reIndex(issue)
in the second script I think (or place it after the update).
Interesting to see these two different approachs anyway. :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Antoine,
I think I will leave the post functions separate for now since the epic one did not seem to work when I moved to follow the original issue create. I would like your feedback on how to modify the following so it writes to the database though. I'm not exactly sure where to change "setCustomField(cf... method to cf.updateValue(... ":
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
["Initiative"].each { cfname ->
def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == cfname}
log.error("cf : " + cf)
log.error("issue : " + issue)
def epicCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
if (!cf || !epicCf) {return}
def epic = issue.getCustomFieldValue(epicCf) as Issue
if (!epic) {return}
def cfValue = cf.getValue(epic)
log.error("cfValue : " + cfValue)
issue.setCustomFieldValue(cf, cfValue)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
Try this script :
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Initiative"}
def epicCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
if (!cf || !epicCf) {return}
def epic = issue.getCustomFieldValue(epicCf) as Issue
if (!epic) {return}
def cfEpicValue = epic.getCustomFieldValue(cf)
def cfCurrentValue = issue.getCustomFieldValue(cf)
cf.updateValue(null, issue, new ModifiedValue(cfCurrentValue, cfValue), new DefaultIssueChangeHolder())
issue.setCustomFieldValue(cf, cfValue)
Here you are retrieving the fields by name, i'd suggest using the ID but it is up to you.
Also you can remove the logs from the other script if you don't want to flood.
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sorry, sloppy of me. Use
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Initiative"}
def epicCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
if (!cf || !epicCf) {return}
def epic = issue.getCustomFieldValue(epicCf) as Issue
if (!epic) {return}
def cfEpicValue = epic.getCustomFieldValue(cf)
def cfCurrentValue = issue.getCustomFieldValue(cf)
cf.updateValue(null, issue, new ModifiedValue(cfCurrentValue, cfEpicValue), new DefaultIssueChangeHolder())
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
How did we fix this again?
2019-04-05 15:13:40,552 ERROR [workflow.ScriptWorkflowFunction]: cf : Initiative 2019-04-05 15:13:40,560 ERROR [workflow.ScriptWorkflowFunction]: issue : test new code with logging 2019-04-05 15:13:40,609 ERROR [workflow.ScriptWorkflowFunction]: Custom field updated on issue null with value TP3-1 Initiative without Portfolio
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Just place the postfunction after the "Create issue orginally" postfunction. :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I Antoine - I am trying to do the same thing with labels now. Here is my code:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.issue.label.Label
//variables for issue re-index after changing the value
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
boolean wasIndexing = ImportUtils.isIndexIssues();
// Get Custom Field as string (Epic Link)
def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")
// Get Custom Field Value as String
CustomField epicLink = customFieldManager.getCustomFieldObjectByName('Epic Link');
String EpicName = issue.getCustomFieldValue(epicLink);
if(EpicName){
// Get Epic from Issue
def epicIssue = issue.getCustomFieldValue(epicLinkCf) as Issue
// Get Labels from Epic
def currentValue = epicIssue.getLabels()
// Set Label to Story
issue.setLabels(currentValue);
}
And here's what the log says:
2019-04-10 18:25:17,196 ERROR [workflow.ScriptWorkflowFunction]: ************************************************************************************* 2019-04-10 18:25:17,208 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: TP3-22, actionId: 1, file: <inline script> groovy.lang.MissingPropertyException: No such property: customFieldManager for class: Script536 at Script536.run(Script536.groovy:17)
Maybe because I'm not familiar with all of the jira functions and methods here so if you could help me with this one then recommend a class or book I would greatly appreciate it!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Barbara Schnell ,
As you can see in the logs you variable customFieldManager does not exist. If you look in the previous script you have an example :
def customFieldManager = ComponentAccessor.getCustomFieldManager()
You have a lot of resources online. You can start here for ScriptRunner. Otherwise if you need (paid) classes I guess you could check the atlassian portal ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks - I think I am close with this label inherit script but am still getting errors. The inherit cf Initiative post function precedes this script after original issue create:
Script:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.issue.label.Label
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
log.error("issue : " + issue)
//variables for issue re-index after changing the value
//def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
//boolean wasIndexing = ImportUtils.isIndexIssues();
// Get Custom Field as string (Epic Link)
def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")
// Get Custom Field Value as String
CustomField epicLink = customFieldManager.getCustomFieldObjectByName('Epic Link');
String EpicName = issue.getCustomFieldValue(epicLink);
if(EpicName){
// Get Epic from Issue
def epicIssue = issue.getCustomFieldValue(epicLinkCf) as Issue
log.error ("epicIssue : " +epicIssue)
// Get Labels from Epic
def epicLabel = epicIssue.getLabels()
log.error("epicLabel : " + epicLabel)
// Set Label to Story
issue.setLabels(epicLabel);
}
Errors:
2019-04-12 12:31:29,528 ERROR [workflow.ScriptWorkflowFunction]: issue : TP3-29 2019-04-12 12:31:29,530 ERROR [workflow.ScriptWorkflowFunction]: epicIssue : TP3-2 2019-04-12 12:31:29,531 ERROR [workflow.ScriptWorkflowFunction]: epicLabel : [label1, label2]
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Well those are not real errors, it appears as "ERROR" because you loggued that way :
log.error(.....)
You could use log.debug or log.info instead depending on how your log level is configured...
These logs actually look fine, does that not work ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
That's what I figured but the label values are not getting set on the story from the epic. The script seems to complete successfully but the labels field is empty.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I think the issue comes from
issue.setLabels
Try using LabelManager object like in this topic.
It's the same as when I did not recommend
issue.setCustomfield
:)
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I guess this is over my head. I'm not sure I'm following you. And why I can't use issue.setLabels.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I don't know, actually there is nothing in the doc, so maybe it should work correctly. Documentation only states that setCustomfieldValue method does not write values in the database.
Try to use this instead :
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
labelManager.setLabels(currentUser, issue.getId(), epicLabel, false, false)
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Please provide the whole message, it is truncated.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Have you actually tried to save as is ? Groovy console will often preview errors, which are not actually errors in groovy because object types can be implicit.
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I did and was able to save.
Here are the errors:
Time (on server): Fri Apr 12 2019 10:31:11 GMT-0600 (Mountain Daylight Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2019-04-12 16:31:11,241 ERROR [workflow.ScriptWorkflowFunction]: ************************************************************************************* 2019-04-12 16:31:11,244 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: TP3-33, actionId: 1, file: <inline script> java.lang.ClassCastException: com.atlassian.jira.issue.label.Label cannot be cast to java.lang.String at com.atlassian.jira.issue.label.DefaultLabelManager.validateLabels(DefaultLabelManager.java:267) at com.atlassian.jira.issue.label.DefaultLabelManager.setLabels(DefaultLabelManager.java:60) at com.atlassian.jira.issue.label.LabelManager$setLabels$0.call(Unknown Source) at Script701.run(Script701.groovy:47)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
As you can see the setLabels method is expecting Strings instead of Labels. Give this a try :
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
if (epicLabel != null && epicLabel.size()){
def labels = []
for (Label label:epicLabel){
labels.add(label.getLabel())
}
labelManager.setLabels(currentUser, issue.getId(), labels, false, false)
}
without forgetting this import :
import com.atlassian.jira.issue.label.Label
I did not try it but this is my best guess.
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Groovy didn't like the nested expression. See attached and this link:
https://github.com/fabric8io/fabric8/issues/2707
error:
The script could not be compiled: <pre>org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: Script730.groovy: 54: expecting '}', found '' @ line 54, column 2. } ^ 1 error </pre>.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It was sloppy of me, I forgot something, sorry...
if (epicLabel != null && epicLabel.size() > 0){
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
No problem at all. I appreciate the help. However still getting the same error.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Could you please copy the whole script so I can more easily check what is wrong ?
Thanks.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sure:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.issue.label.Label
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
log.info("issue : " + issue)
//variables for issue re-index after changing the value
//def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
//boolean wasIndexing = ImportUtils.isIndexIssues();
// Get Custom Field as string (Epic Link)
def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")
// Get Custom Field Value as String
CustomField epicLink = customFieldManager.getCustomFieldObjectByName('Epic Link');
String EpicName = issue.getCustomFieldValue(epicLink);
//LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def labels = labelManager.getLabels(issue.id).collect{it.getLabel()}
if(EpicName){
// Get Epic from Issue
def epicIssue = issue.getCustomFieldValue(epicLinkCf) as Issue
log.info ("epicIssue : " +epicIssue)
// Get Labels from Epic
def epicLabel = epicIssue.getLabels()
log.info("epicLabel : " + epicLabel)
// Set Label to Story
// issue.setLabels(epicLabel);
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
if (epicLabel != null && epicLabel.size() > 0){
def labels = []
for (Label label:epicLabel){
labels.add(label.getLabel())
}
labelManager.setLabels(currentUser, issue.getId(), labels, false, false)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
As expected you are missing a bracket at the end, please try :
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.util.IssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.index.IssueIndexingService
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.util.ImportUtils
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.issue.label.Label
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
log.info("issue : " + issue)
//variables for issue re-index after changing the value
//def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
//boolean wasIndexing = ImportUtils.isIndexIssues();
// Get Custom Field as string (Epic Link)
def epicLinkCf = customFieldManager.getCustomFieldObjectByName("Epic Link")
// Get Custom Field Value as String
CustomField epicLink = customFieldManager.getCustomFieldObjectByName('Epic Link');
String EpicName = issue.getCustomFieldValue(epicLink);
//LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def labels = labelManager.getLabels(issue.id).collect{it.getLabel()}
if(EpicName){
// Get Epic from Issue
def epicIssue = issue.getCustomFieldValue(epicLinkCf) as Issue
log.info ("epicIssue : " +epicIssue)
// Get Labels from Epic
def epicLabel = epicIssue.getLabels()
log.info("epicLabel : " + epicLabel)
// Set Label to Story
// issue.setLabels(epicLabel);
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager)
def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
if (epicLabel != null && epicLabel.size() > 0){
def labels = []
for (Label label:epicLabel){
labels.add(label.getLabel())
}
labelManager.setLabels(currentUser, issue.getId(), labels, false, false)
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
That worked!
Except I needed to modify the last part to this based on my version of jira:
labelManager.setLabels(currentUser,issue.id,labels.toSet(),false,false)
I really appreciate your help on these!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Nice, good job fixing that. What version are you using ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
Are ou trying to do this in behaviours, or in a postfunction / script listener ?
For the latter, you can use this snippet to copy the field value of the parent issue :
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.component.ComponentAccessor
//Your custom field ID
int cfId = 10100
def cf = customFieldManager.getCustomFieldObject(cfId)
def cfValue = issue.getCustomFieldValue(cf)
def cfParentValue = issue.getParentObject().getCustomFieldValue(cf)
cf.updateValue(null, issue, new ModifiedValue(cfValue, cfParentValue), new DefaultIssueChangeHolder())
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am using a post function. Is the above the entirety of the code I would need? Or are you saying to add this to mine above?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Your code looks like a behaviours script, which would not work in a post function.
The code above will update the custom field (id 10100) with the value of this field on the parent issue. So make sure the post function is on a sub-task workflow only or use this condition to check that the issue is a sub-task :
if (issue.isSubTask()){ ...
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
ok, I used the approach of hovering over the custom field to get the cfid (mentioned here https://community.atlassian.com/t5/Jira-questions/How-can-I-find-the-ID-of-a-custom-field-in-Jira-5/qaq-p/272632)
This is the post function now and it still does not work. Do I need a separate workflow for sub-task?
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.component.ComponentAccessor
int cfId = 1102
def cf = customFieldManager.getCustomFieldObject(cfId)
def cfValue = issue.getCustomFieldValue(cf)
def cfParentValue = issue.getParentObject().getCustomFieldValue(cf)
if (issue.isSubTask()){
cf.updateValue(null, issue, new ModifiedValue(cfValue, cfParentValue), new DefaultIssueChangeHolder())}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I should mention I have another post function after this one on Create that updates the Initiative on issue from the Epic based on epic link. This works fine:
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = issue as MutableIssue
["Initiative"].each { cfname ->
def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == cfname}
def epicCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
if (!cf || !epicCf) {return}
def epic = issue.getCustomFieldValue(epicCf) as Issue
if (!epic) {return}
def cfValue = cf.getValue(epic)
issue.setCustomFieldValue(cf, cfValue)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Barbara,
I think there is a typo in your custom field id because it cannot be 4 digits only. Go to Custom fields > Configure :
As for your script, I usually encourage to use custom field ID instead of name (so you are fine if any admin changes the name). But of course it is up to you.
However I strongly recommand using
cf.updateValue(...
instead of
issue.setCustomFieldValue(cf, cfValue)
because as you can see here https://docs.atlassian.com/software/jira/docs/api/7.1.2/com/atlassian/jira/issue/IssueImpl.html setCustomFieldValue does not write the value in the database.
Antoine
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks - you were right - I was missing a zero. I made the change and still no luck however.
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.component.ComponentAccessor
int cfId = 11002
def cf = customFieldManager.getCustomFieldObject(cfId)
def cfValue = issue.getCustomFieldValue(cf)
def cfParentValue = issue.getParentObject().getCustomFieldValue(cf)
if (issue.isSubTask()){
cf.updateValue(null, issue, new ModifiedValue(cfValue, cfParentValue), new DefaultIssueChangeHolder())}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Time (on server): Thu Apr 04 2019 07:47:35 GMT-0600 (Mountain Daylight Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2019-04-04 13:47:35,841 ERROR [workflow.ScriptWorkflowFunction]: ************************************************************************************* 2019-04-04 13:47:35,858 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: null, actionId: 1, file: <inline script> groovy.lang.MissingPropertyException: No such property: customFieldManager for class: Script239 at Script239.run(Script239.groovy:8)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sorry, forgot to add the customFieldManager definition. Add this line after the imports :
def customFieldManager = ComponentAccessor.getCustomFieldManager()
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
ok, and now this:
Time (on server): Thu Apr 04 2019 07:54:08 GMT-0600 (Mountain Daylight Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2019-04-04 13:54:08,702 ERROR [workflow.ScriptWorkflowFunction]: ************************************************************************************* 2019-04-04 13:54:08,708 ERROR [workflow.ScriptWorkflowFunction]: Script function failed on issue: null, actionId: 1, file: <inline script> java.lang.NullPointerException at com.atlassian.jira.issue.IssueImpl.getCustomFieldValue(IssueImpl.java:898) at com.atlassian.jira.issue.Issue$getCustomFieldValue$0.call(Unknown Source) at Script243.run(Script243.groovy:10)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks for providing the logs. Can you update your script as :
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.component.ComponentAccessor
def customFieldManager = ComponentAccessor.getCustomFieldManager()
int cfId = 11002
def cf = customFieldManager.getCustomFieldObject(cfId)
log.error("cf : " + cf)
log.error("issue : " + issue)
def cfValue = issue.getCustomFieldValue(cf)
log.error("cfValue : " + cfValue)
def cfParentValue = issue.getParentObject().getCustomFieldValue(cf)
log.error("cfParentValue : " + cfParentValue)
if (issue.isSubTask()){
cf.updateValue(null, issue, new ModifiedValue(cfValue, cfParentValue), new DefaultIssueChangeHolder())}
It will make easier keeping track of the variables used in there. Execute your script and please provide the logs again :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
ok, here are the logs with the script from above:
Time (on server): Thu Apr 04 2019 08:12:56 GMT-0600 (Mountain Daylight Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2019-04-04 14:12:56,054 ERROR [workflow.ScriptWorkflowFunction]: cf : Initiative 2019-04-04 14:12:56,058 ERROR [workflow.ScriptWorkflowFunction]: issue : test 11002 - test 3 2019-04-04 14:12:56,058 ERROR [workflow.ScriptWorkflowFunction]: cfValue : null 2019-04-04 14:12:56,061 ERROR [workflow.ScriptWorkflowFunction]: cfParentValue : TP-2 Initiative 1
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Did it work this time ? there is no error message.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The script completed successfully but the field did not get populated. Errors posted above seem to point to the workflow.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Could you add a log in the next line as well so we can make sure the script executed correctly ?
if (issue.isSubTask()){
cf.updateValue(null, issue, new ModifiedValue(cfValue, cfParentValue), new DefaultIssueChangeHolder())
log.error("Custom field updated on issue " + issue.getKey() + " with value " + cfParentValue)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
ok - now it seems like it thinks it's updating the field but since the issue is null, it's not. Why is the issue null in the error below?
Time (on server): Thu Apr 04 2019 08:31:55 GMT-0600 (Mountain Daylight Time)
The following log information was produced by this execution. Use statements like:log.info("...") to record logging information.
2019-04-04 14:31:55,112 ERROR [workflow.ScriptWorkflowFunction]: cf : Initiative 2019-04-04 14:31:55,112 ERROR [workflow.ScriptWorkflowFunction]: issue : test initiative 3 2019-04-04 14:31:55,113 ERROR [workflow.ScriptWorkflowFunction]: cfValue : null 2019-04-04 14:31:55,114 ERROR [workflow.ScriptWorkflowFunction]: cfParentValue : TP-2 Initiative 1 2019-04-04 14:31:55,123 ERROR [workflow.ScriptWorkflowFunction]: Custom field updated on issue null with value TP-2 Initiative 1
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Well it seems that your issue does not have a key (I have no idea why). The issue object is not null since it is printed correctly.
Are you completely sure it did not update (is the custom field on the view screen?) ? You could quickly check in a filter by adding the custom field as a column.
If it did not update...
Is "test initiative 3" the summary of the issue ?
Could you screenshot your issue view screen ?
How are you triggering your post function ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes, I'm sure it is not updated (from jql and edit issue). The issue getting updated is a sub-task. Does jira see a sub-task as just another issue?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Absolutely. From a groovy point of view there is no difference.
Try adding this import
import com.atlassian.jira.issue.index.IssueIndexingService
And these lines at the end :
def issueIndexingService = ComponentAccessor.getComponent(IssueIndexingService)
issue.store()
issueIndexingService.reIndex(issue)
Also could you provide a screenshot of the transition post-functions ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am triggering the post function at the Create transition as a custom script using scriptrunner.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ok, then it is most likely because the script post-function is not the last executed. Please place it at the last spot (especially after "Creates the issue originally").
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
When I added the line above I got this error:
Screenshot of transition post functions here:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes you definitely need to place the script post function after the "Create the issue originally". Then you probably do not need the store and reindex part in the script.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
That did it! Thanks so much for your help on this! What is interesting here is that I did not need to do that for the story to inherit the custom field from the epic. Can you help me understand why?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Glad to help ! Please mark the answer as accepted so people with the same issue are lead on this topic. :)
The problem was that the sub-task was not "fully" created at execution time, so we could not update the value on a object that does not exist yet.
I guess your first script copies the Initiative from the Epic to the Story ? And this sub-task is the child of the Story ? In that case the Epic and Story are already created so the sub-task creation happening afterwards has no impact. :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Is it possible to combine these 2 post functions? if sub-task... else ...? If not - I am stuck again unless I have separate workflows for sub-task vs others.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes absolutely, you can test against the issue type. Are you still stuck ?
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.