This script allows you to preserve the Jira parent/sub-task hierarchy when synchronizing issues from Jira to Azure DevOps.
For example:
Jira Azure DevOps
PROJ-100 Task → User Story 123
└─ PROJ-101 → └─ Task 124
Sub-task Child
The Jira sub-task’s parent is sent through the replica, and Exalate resolves the corresponding synchronized Azure DevOps work item before assigning it as the parent.
Script Overview
On the Jira side, we include the issue’s parentId in the replica:
replica.parentId = issue.parentId
On the Azure DevOps side, we use:
syncHelper.getLocalIssueKeyFromRemoteId()
to find the Azure DevOps work item that corresponds to the Jira parent.
Final Solution
Jira Outgoing Sync
Add the following to the Jira outgoing sync:
replica.parentId = issue.parentId
For regular Jira issues without a parent, parentId will simply be empty.
Azure DevOps Incoming Sync
On the Azure DevOps side, resolve the Jira parent to its corresponding local work item:
//
if (replica.parentId) {
def localParent = syncHelper.getLocalIssueKeyFromRemoteId(
replica.parentId.toLong()
)
if (localParent) {
workItem.parentId = localParent.id
}
}
A complete example could look like:
if (firstSync) {
def typeMap = [
"Task" : "User Story",
"Sub-task": "Task"
]
workItem.typeName =
nodeHelper.getIssueType(typeMap[replica.type?.name])?.name ?: "Task"
workItem.summary = replica.summary
}
workItem.description = replica.description
// Jira Parent -> Azure DevOps Parent
if (replica.parentId) {
def localParent = syncHelper.getLocalIssueKeyFromRemoteId(
replica.parentId.toLong()
)
if (localParent) {
workItem.parentId = localParent.id
}
}
Notes
- The Jira parent issue should already be synchronized with Azure DevOps before the sub-task is synchronized.
Version
5.37.0