Hi Community,
I have a custom script post-function which creates sub-tasks based on the objects selected in an insight custom field 'Data Sources'; it also sets the Summary of each sub-task as the 'Name' attribute for that insight object. The insight custom field may contain multiple objects and the script iterates through the selected objects creating a sub-task for each.
I also want to set the insight custom field 'Data Sources' in each sub-task with the object that it relates to. I thought that this would be easiest as a post function in the sub-task workflow on the Create transition that would take the Summary and use that to set the 'Data Sources' field (as they will be the same).
However I am struggling and would appreciate any help.
Here is what I have come up with from combining various sources but not quite there. I would really appreciate any help:
import customRiadaLibraries.insightmanager.InsightManagerForScriptrunner
import customRiadaLibraries.insightmanager.SimplifiedAttachmentBean
import com.riadalabs.jira.plugins.insight.services.model.*
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface
import java.sql.Connection
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.event.type.EventDispatchOption;
import com.riadalabs.jira.plugins.insight.services.model.ObjectBean
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.ObjectTypeAttributeFacade
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.onresolve.scriptrunner.runner.customisers.PluginModule
@WithPlugin("com.riadalabs.jira.plugins.insight")
@PluginModule IQLFacade iqlFacade
def summary = issue.getSummary()toString()
/* Insight custom field to set */
CustomField insightCF = ComponentAccessor.getCustomFieldManager().getCustomFieldObject(11700);
/* Get Insight IQL Facade from plugin accessor */
Class iqlFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade");
def iqlFacade = ComponentAccessor.getOSGiComponentInstanceOfType(iqlFacadeClass);
/* Specify the schema id as well as the IQL that will fetch objects. In this case all objects with Name matching the valueCF, be sure to include " around value */
def objects = iqlFacade.findObjectsByIQLAndSchema(16, "Name = \"" + summary + "\"");
issue.setCustomFieldValue(insightCF, objects);
How are you creating your subtasks?
Why not populate the data source with the object at that time?
Your existing should work mostly as is... here is a simplified version. I'd recommend including the object type in the IQL to make sure you don't get a false match
import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade
@WithPlugin("com.riadalabs.jira.plugins.insight")
@PluginModule IQLFacade iqlFacade
/* Specify the schema id as well as the IQL that will fetch objects. In this case all objects with Name matching the valueCF, be sure to include " around value */
def objects = iqlFacade.findObjects(16, /objectType = "Your Object Type" and Name = "$issue.summary"/);
if(objects){
/* Insight custom field to set */
def insightCF = ComponentAccessor.customFieldManager.getCustomFieldObject(11700)
issue.setCustomFieldValue(insightCF, objects)
}
A few notes...
1) findObjectsByIQLAndSchema is deprecated, you can just call findObjects with the schema ID as the first parameter
2) I like to use alternate delimiters for IQL strings to allow unescaped double quotes (either /text with (") quotes/ or """text with (") quotes"""
3) I thinks using string interpolation is easier to read than to use "string" + "string"
4) issue.summary is already a string by default, no need to recast
5) @WithPlugin and @PluginModule does the same thing as the classLoader getOSGiComponentInstanceOfType. You shouldn't have both in the same script
6) I re-arranged the order of some code so that you only fetch the custom field IF you actually found an object.
7) in groovy, you can shorten object.getSomthing() to object.something. Makes for short and easier to read code imo
Hi @PD Sheehan ,
Thank you so much for your response. The code you supplied works!
In response to your questions:
I still have an issue though. I wanted this script to be a post function on the create transition but although it does not fail, it does not set the object (I have tried putting as the second, fourth and last post function).
If I put as a post function on the next transition then it works? Any ideas why?
Thanks,
Tom
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Shre your create sub-task script, I'll help you get the customfield populated there.
It's better than doing it in the next workflow.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@PD Sheehan that would be great thanks. Here is the script; it creates a sub-task for each object selected in an insight/object custom field and also sets the summary of each sub-task as the name of the object.
import customRiadaLibraries.insightmanager.InsightManagerForScriptrunner
import customRiadaLibraries.insightmanager.SimplifiedAttachmentBean
import com.riadalabs.jira.plugins.insight.services.model.*
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface
import org.apache.log4j.Logger
import org.apache.log4j.Level
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.config.manager.PrioritySchemeManager
import com.atlassian.jira.issue.label.Label
def mylog = Logger.getLogger("com.acme.workflows")
mylog.setLevel(Level.DEBUG)
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def customFieldInsight = customFieldManager.getCustomFieldObject(12345)
def CusValue = issue.getCustomFieldValue(customFieldInsight)
InsightManagerForScriptrunner im = new InsightManagerForScriptrunner()
im.log.warn("IM is working")
CusValue.eachWithIndex { item, index ->
mylog.info("item="+item)
mylog.info("index="+index)
final parentIssueKey = issue.getKey()
final issueTypeName = 'Sub-task'
final priorityName = 'Medium'
def summary = item.toString() // summary will match the insight object name for the current iteration
def summarySub = summary.substring(0, summary.lastIndexOf(" (")) // removes the insight database ID from the string
def summarySet = summarySub
def issueService = ComponentAccessor.issueService
def constantsManager = ComponentAccessor.constantsManager
def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def prioritySchemeManager = ComponentAccessor.getComponent(PrioritySchemeManager)
def parentIssue = ComponentAccessor.issueManager.getIssueByCurrentKey(parentIssueKey)
assert parentIssue : "Could not find parent issue with key $parentIssueKey"
def subtaskIssueTypes = constantsManager.allIssueTypeObjects.findAll { it.subTask }
def subTaskIssueType = subtaskIssueTypes.findByName(issueTypeName)
assert subTaskIssueType : "Could not find subtask issue type with name $issueTypeName. Available subtask issue types are ${subtaskIssueTypes*.name.join(", ")}"
def reporter = issue.getReporter()
def currentUser = loggedInUser
def priorityId = constantsManager.priorities.findByName(priorityName)?.id ?: prioritySchemeManager.getDefaultOption(parentIssue)
def issueInputParameters = issueService.newIssueInputParameters().with {
setProjectId(parentIssue.projectObject.id)
setIssueTypeId(subTaskIssueType.id)
setReporterId(currentUser.username)
setAssigneeId(reporter.username)
setSummary(summarySet)
setPriorityId(priorityId)
}
def validationResult = issueService.validateSubTaskCreate(loggedInUser, parentIssue.id, issueInputParameters)
assert validationResult.valid : validationResult.errorCollection
def issueResult = issueService.create(loggedInUser, validationResult)
assert issueResult.valid : issueResult.errorCollection
def subtask = issueResult.issue
ComponentAccessor.subTaskManager.createSubTaskIssueLink(parentIssue, subtask, loggedInUser)
}
mylog.info("Field Value="+CusValue)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Have a look at the following.
I added some comments. Commented out some sections.
/**
* Used my IDE "optimize" imports which removes unused or unnecessary import
*/
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.fields.config.manager.PrioritySchemeManager
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import com.riadalabs.jira.plugins.insight.services.model.ObjectBean
import customRiadaLibraries.insightmanager.InsightManagerForScriptrunner
import org.apache.log4j.Level
import org.apache.log4j.Logger
/**
* This annotation allows the import of com.riadalabs classes. Not sure how that worked for you before.
* Maybe something in the insightManager
*/
@WithPlugin('com.riadalabs.jira.plugins.insight') insightPlugin
issue = issue as MutableIssue //this helps with IDE autocomplete and Script Editor status type checking
def mylog = Logger.getLogger("com.acme.workflows")
mylog.setLevel(Level.DEBUG)
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def customFieldInsight = customFieldManager.getCustomFieldObject(12345)
def CusValue = issue.getCustomFieldValue(customFieldInsight) as List<ObjectBean>
/**
* The insightmanager is not really used anywhere in this script
* I recommend removing it
*/
InsightManagerForScriptrunner im = new InsightManagerForScriptrunner()
im.log.warn("IM is working")
/**
* I moved the managers outside the each block. I don't know if once compiled it makes a difference
* But I don't like having these managers and services being executed multiple times.
*/
def issueService = ComponentAccessor.issueService
def constantsManager = ComponentAccessor.constantsManager
def loggedInUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def prioritySchemeManager = ComponentAccessor.getComponent(PrioritySchemeManager)
CusValue.eachWithIndex { item, index ->
mylog.info("item="+item)
mylog.info("index="+index)
final issueTypeName = 'Sub-task'
final priorityName = 'Medium'
/**
* YOU DON't NEED THIS SECTION: get item.label directory
*/
/*
def summary = item.toString() // summary will match the insight object name for the current iteration
def summarySub = summary.substring(0, summary.lastIndexOf(" (")) // removes the insight database ID from the string
def summarySet = summarySub
*/
/**
* YOU DONT't NEED THIS SECTION: the provided "issue" is already the correct object
*/
/*
final parentIssueKey = issue.getKey()
def parentIssue = ComponentAccessor.issueManager.getIssueByCurrentKey(parentIssueKey)
assert parentIssue : "Could not find parent issue with key $parentIssueKey"
*/
def subtaskIssueTypes = constantsManager.allIssueTypeObjects.findAll { it.subTask }
def subTaskIssueType = subtaskIssueTypes.findByName(issueTypeName)
assert subTaskIssueType : "Could not find subtask issue type with name $issueTypeName. Available subtask issue types are ${subtaskIssueTypes*.name.join(", ")}"
/**
* THIS SEEMS A LITTLE UNNECESSARY AND REDUNDANT
*/
/*
def reporter = issue.getReporter() //i changed to issue.reporter.username below
def currentUser = loggedInUser
*/
def priorityId = constantsManager.priorities.findByName(priorityName)?.id ?: prioritySchemeManager.getDefaultOption(issue)
def issueInputParameters = issueService.newIssueInputParameters().with {
setProjectId(issue.projectObject.id)
setIssueTypeId(subTaskIssueType.id)
setReporterId(loggedInUser.username)
setAssigneeId(issue.reporter.username)
setSummary(item.label)
setPriorityId(priorityId)
/**
* Add the object key of the current item to the insight customfield
*/
addCustomFieldValue(customFieldInsight.idAsLong, item.objectKey)
}
def validationResult = issueService.validateSubTaskCreate(loggedInUser, issue.id, issueInputParameters)
assert validationResult.valid : validationResult.errorCollection
def issueResult = issueService.create(loggedInUser, validationResult)
assert issueResult.valid : issueResult.errorCollection
def subtask = issueResult.issue
ComponentAccessor.subTaskManager.createSubTaskIssueLink(issue, subtask, loggedInUser)
}
mylog.info("Field Value="+CusValue)
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.
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.