Originally asked by Johannes Glück on 11 February 2022 (original question)
Hi
Exalate works great for us…
However we now try to add subtask functionality on both sides… And the snippets taken from your knowledgebase lead to tickets with the proper ticket type, but are not added as subticket to the task on the receiving side.
Can you please help?
INGOING SCRIPT
/*
CUSTOM VERSION 1.9 FOR XXX RECEPTION DESK - Copyright XXX AG
for XXX.com
*/
def PROJECT_KEY = "TRD"
if(firstSync){
issue.projectKey = PROJECT_KEY
// Set type name from source issue, if not found set a default
issue.typeName = nodeHelper.getIssueType(replica.type?.name, issue.projectKey)?.name ?: "Task"
}
if (replica.project.key != PROJECT_KEY) {
issue.summary = "Duplikat - Duplicate"
issue.comments = commentHelper.addComment("Ticket wurde auf XXX Seite als Klon in ein internes Projekt zur weiteren Bearbeitung verschoben und bleibt erhalten, für den Fall, dass es sich hierbei um einen Fehler handelt.", issue.comments)
issue.resolution = nodeHelper.getResolution("Duplicate")
issue.setStatus("Won't Fix")
// stop sync if the local issue has been moved from the project - see https://docs.idalko.com/exalate/display/ED/How+to+unexalate+moved+issues+automatically#Howtounexalatemovedissuesautomatically-Stopthesynciftheissuehasbeenmovedtoanotherproject
// does not work right now (the implementation in the page either)
// AND perhaps (if moving back) it is better not to unexalate
// final def _syncInitService = com.atlassian.jira.component.ComponentAccessor
// .getOSGiComponentInstanceOfType(com.exalate.api.trigger.ISyncInitiationService.class)
// _syncInitService.unexalate(issue.key)
return
}
issue.typeName = nodeHelper.getIssueType(replica.type?.name, issue.projectKey)?.name ?: "Task"
issue.summary = replica.summary
issue.description = replica.description
issue.attachments = attachmentHelper.mergeAttachments(issue, replica)
issue.labels = replica.labels
issue.priority = replica.priority
issue.environment = replica.environment
issue.issueLinks = replica.issueLinks
issue.created = replica.created
issue.updated = replica.updated
/*
User Synchronization (Assignee/Reporter)
Set a Reporter/Assignee from the source side, if the user can't be found set a default user
You can use this approach for custom fields of type User
*/
def defaultUser = nodeHelper.getUserByUsername("XXX")
issue.reporter = nodeHelper.getUserByUsername(replica.reporter?.username) ?: defaultUser
issue.assignee = nodeHelper.getUserByUsername(replica.assignee?.username) ?: defaultUser
/*
Comment Synchronization
Sync comments with the original author if the user exists in the local instance
Remove original Comments sync line if you are using this approach
*/
issue.comments = commentHelper.mergeComments(issue, replica){ it.executor = nodeHelper.getUserByUsername(it.author?.username) }
/*
Status Synchronization
Sync status according to the mapping [remote issue status: local issue status]
If statuses are the same on both sides don't include them in the mapping
*/
def statusMapping = [/*"Open":"New", "To Do":"Backlog"*/]
def remoteStatusName = replica.status.name
issue.setStatus(statusMapping[remoteStatusName] ?: remoteStatusName)
/*
Custom Fields
This line will sync Text, Option(s), Number, Date, Organization, and Labels CFs
For other types of CF check documentation
Custom Fields
- Reproduce Steps
- Actual result
- Expected Result
issue.customFields."CF Name".value = replica.customFields."CF Name".value
*/
if ( replica.customFields.containsKey("Reproduce Steps") ) issue.customFields."Reproduce Steps".value = replica.customFields."Reproduce Steps".value
if ( replica.customFields.containsKey("Actual result") ) issue.customFields."Actual result".value = replica.customFields."Actual result".value
if ( replica.customFields.containsKey("Expected Result") ) issue.customFields."Expected Result".value = replica.customFields."Expected Result".value
if ( replica.customFields.containsKey("Detected on stage") ) issue.customFields."10400".value = replica.customFields."Detected on stage".value
/* Deal with new components */
issue.components = replica.components.collect { component ->
def remoteComponentLeadUsername = component.lead?.username
def localComponentLead = nodeHelper.getUserByUsername(remoteComponentLeadUsername)
nodeHelper.createComponent(
issue,
component.name,
component.description, // can also be null
localComponentLead?.key, // can also be null
component.assigneeType?.name() ?: "UNASSIGNED" // set a default as unassigned if there's no assignee type for the component
)
}
/* Deal with components in an issue */
issue.components = replica.components
.collect { remoteComponent ->
nodeHelper.getComponent(
remoteComponent.name,
nodeHelper.getProject(issue.projectKey)
)
}.findAll()
/* Deal with Epics */
if(replica.issueType.name == "Epic") {
issue.customFields."Epic Name".value = replica.customFields."Epic Name"?.value
}
Epic.receive()
/* Deal with subtasks */
if(firstSync && replica.parentId){
issue.typeName = "Sub-Task" //Make sure to use the right subtask type here.
def localParent = nodeHelper.getLocalIssueFromRemoteId(replica.parentId.toLong())
if(localParent){
issue.parentId = localParent.id
} else {
throw new com.exalate.api.exception.IssueTrackerException("Subtask cannot be created: parent issue with remote id " + replica.parentId + " was not found. Please make sure the parent issue is synchronized before resolving this error" )
}
}
OUTGOING SCRIPT
/*
CUSTOM VERSION 1.9 FOR XXX RECEPTION DESK - Copyright XXX AG
for XXX.com
*/
replica.key = issue.key
replica.type = issue.type
replica.assignee = issue.assignee
replica.reporter = issue.reporter
replica.summary = issue.summary
replica.description = issue.description
replica.labels = issue.labels
// do not export "internal" comments, see https://docs.idalko.com/exalate/display/ED/filterLocal
replica.comments = issue.comments.findAll { !it.internal }
replica.status = issue.status
replica.parentId = issue.parentId
replica.priority = issue.priority
replica.attachments = issue.attachments
replica.project = issue.project
replica.issueLinks = issue.issueLinks
replica.components = issue.components
replica.environment = issue.environment
replica.created = issue.created
replica.updated = issue.updated
//Comment these lines out if you are interested in sending the full list of versions and components of the source project.
//replica.project.versions = []
//replica.project.components = []
/*
Custom Fields
- Reproduce Steps
- Actual result
- Expected Result
*/
if ( issue.customFields.containsKey("11705") ) replica.customFields."Reproduce Steps" = issue.customFields."11705"
if ( issue.customFields.containsKey("11707") ) replica.customFields."Actual result" = issue.customFields."11707"
if ( issue.customFields.containsKey("11706") ) replica.customFields."Expected Result" = issue.customFields."11706"
if ( issue.customFields.containsKey("13300") ) replica.customFields."Detected on stage"= issue.customFields."13300"
/* Deal with Epics */
if(issue.issueType.name == "Epic") {
// ID is needed, as - when Epic Name is empty - only the ID would be unique (reason unknown)
// For fields in internal jira, please look here: https://XXX/rest/api/latest/field
replica.customFields."Epic Name" = issue.customFields."10011"
}
Epic.sendInAnyOrder()