# HowTo synchronize issue relations from ADO to Jira Cloud

**URL:** https://community.exalate.com/t/howto-synchronize-issue-relations-from-ado-to-jira-cloud/5629
**Category:** General Questions
**Tags:** azuredevops-jiraclou, azuredevops, jira-cloud, script, migrated\_question
**Created:** [November 4, 2024, 8:17am UTC](https://community.exalate.com/t/howto-synchronize-issue-relations-from-ado-to-jira-cloud/5629 "2024-11-04T08:17:50Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![xl8bot](https://dub1.discourse-cdn.com/flex018/user_avatar/community.exalate.com/xl8bot/32/324_2.png) [@xl8bot](https://community.exalate.com/u/xl8bot)
#### Post date: [November 4, 2024, 8:17am UTC](https://community.exalate.com/t/howto-synchronize-issue-relations-from-ado-to-jira-cloud/5629/1 "2024-11-04T08:17:50Z")

</div>

_Originally asked by Thorsten on 14 November 2023 [(original question)](https://oldcommunity.exalate.com/questions/98927139)_

* * *

Hi,

I can’t find anything in the documentation on how to synchronize ticket relationships other than parent/child from ADO to Jira Cloud. I need to implement following relationships as soon as possible:

- “Relates to”
- “Is related”
- “Blocks”
- “Is Blocked by”
- “Duplicates”
- “Is Duplicated by”
- “Tests”
- “Is Tested by”

Can some please help me with this case?

BR,

Thorsten

* * *

#### Comments:

> **Javier Pozuelo commented on 16 November 2023**
>
> > Hello Thorsten,
> 
> Let me test these relationships and I will get back to you later today.

> **Javier Pozuelo commented on 16 November 2023**
>
> > Hello Thorsten,
> 
> I need some clarification on how you want to synchronize these relationships. Let’s say you have a work Item in ADO that is related to another one, when you Exalate it to Jira Cloud, what do you expect to happen when the ADO Work Item and the Jira Cloud ticket are synchronized?

> **Thorsten commented on 17 November 2023**
>
> > Hi Javier,
> 
> I expect the ADO ticket’s relations to also exist in Jira, so that the same relations exist in Jira as in ADO. The relations only need to be synced from ADO to Jira and not back, which might make it easier.
> 
> Is that enough of an answer for you?
> 
> BR,
> 
> Thorsten

> **Javier Pozuelo commented on 17 November 2023**
>
> > Hello Thorsten,
> 
> Thank you for the clarification. We are working on an implementation for this use case, I will have an update for you by Monday.
> 
> Kind Regards

---

<div class="post-metadata">

### Author: ![xl8bot](https://dub1.discourse-cdn.com/flex018/user_avatar/community.exalate.com/xl8bot/32/324_2.png) [@xl8bot](https://community.exalate.com/u/xl8bot)
#### Post date: [November 4, 2024, 8:17am UTC](https://community.exalate.com/t/howto-synchronize-issue-relations-from-ado-to-jira-cloud/5629/2 "2024-11-04T08:17:51Z")

</div>

_Answer by Javier Pozuelo on 20 November 2023_

Hello Thorsten,

- In ADO, the “Parent-Child” relationship can be mapped to the “Epic-Story” or “Sub-task” relationships in Jira.
- ADO doesn’t have a relationship type “Block”, but the “Predecessor-Successor” relationship in ADO is equivalent to the “Blocks” relationship in Jira.
- Jira Cloud doesn’t have Issue link types “Testing”

You need to place the following script in theOutgoing Sync of Azure DevOps. This will run an API call that gets all the relations from the Azure DevOps workItem and adds it to the replica, so it can be sent over to Jira Cloud.

**Outgoing Sync of Azure DevOps**

```auto
replica.parentId = workItem.parentId

def res = httpClient.get("/_apis/wit/workitems/${workItem.key}?\$expand=relations&api-version=6.0",false)
if (res.relations != null)
replica.relations = res.relations

```

In the Incoming sync of Jira Cloud we need to parse the relations data being sent by ADO and make an API call to find the Issue that needs to be linked.  
I have made the following relationships for you in the script below

- ADO’s “Predecessor-Successor” relationships maps to Jira’s “Blocks” relationship
- ADO’s “Related” relationship to Jira’s “Relates” relationship.
- ADO’s “Duplicate” relationship to Jira’s “Duplicate” relationship

**Incoming Sync of Jira Cloud**

```auto
replica.relations.each {
    relation ->
    if (relation.attributes.name == "Duplicate"){
            def a = syncHelper.getLocalIssueKeyFromRemoteId(relation.url.tokenize('/')[7])//?.urn   
           // debug.error(issue.issueLinks[0].otherIssueId.toString())
            if (issue.issueLinks[0]?.otherIssueId != a.id){
                def res = httpClient.put("/rest/api/2/issue/${issue.key}", """
                {
                   "update":{
                      "issuelinks":[
                         {
                            "add":{
                               "type":{
                                  "name":"Duplicate"
                               },
                               "outwardIssue":{
                                  "key":"${a.urn}"
                               }
                            }
                         }
                      ]
                   }
                }
                """)
            }
        } else if(relation.attributes.name == "Related"){
            def a = syncHelper.getLocalIssueKeyFromRemoteId(relation.url.tokenize('/')[7])//?.urn   
            if (issue.issueLinks[0]?.otherIssueId != a.id){
                def res = httpClient.put("/rest/api/2/issue/${issue.key}", """
                {
                   "update":{
                      "issuelinks":[
                         {
                            "add":{
                               "type":{
                                  "name":"Relates"
                               },
                               "outwardIssue":{
                                  "key":"${a.urn}"
                               }
                            }
                         }
                      ]
                   }
                }
                """)
            }
        }else if(relation.attributes.name == "Predecessor"){
            def a = syncHelper.getLocalIssueKeyFromRemoteId(relation.url.tokenize('/')[7])//?.urn   
            if (issue.issueLinks[0]?.otherIssueId != a.id){
                def res = httpClient.put("/rest/api/2/issue/${issue.key}", """
                {
                   "update":{
                      "issuelinks":[
                         {
                            "add":{
                               "type":{
                                  "name":"Blocks"
                               },
                               "outwardIssue":{
                                  "key":"${a.urn}"
                               }
                            }
                         }
                      ]
                   }
                }
                """)
            }
        }
}

```

In case you want more information or try to make this sync bidirectional, this answer is based on the following documentation: [Jira Cloud Azure DevOps: Bi-directional hierarchy sync](https://oldcommunity.exalate.com/display/exacom/Jira+Cloud+Azure+DevOps%3A+Bi-directional+hierarchy+sync)_(old community)_

Kind regards

* * *

#### Comments:

> **Thorsten commented on 27 November 2023**
>
> > Hi Javier Pozuelo,
> 
> sorry for the late response I haven’t been available for the last week. Thank you for your detailed answer, I have tested the whole thing and it’s working. _(old community)_
> 
> BR,
> 
> Thorsten

---

<div class="post-metadata">

### Author: ![xl8bot](https://dub1.discourse-cdn.com/flex018/user_avatar/community.exalate.com/xl8bot/32/324_2.png) [@xl8bot](https://community.exalate.com/u/xl8bot)
#### Post date: [November 4, 2024, 8:17am UTC](https://community.exalate.com/t/howto-synchronize-issue-relations-from-ado-to-jira-cloud/5629/3 "2024-11-04T08:17:52Z")

</div>

_Answer by Thorsten on 26 January 2024_

Hi,

I don’t know why, but the script snippet no longer works or maybe it only worked in the tests where I hadn’t synchronized dozens of issues using a bulk operation.

I’ll try to describe the problem: if I have 2 tickets that have a relation to each other, the script aborts in this line with the following error message:

```auto
if (issue.issueLinks[0]?.otherIssueId != a.id){

```

```auto
Cannot get property 'id' on null object 

```

If I change the line as follows, no error occurs but the relations are not created either:

```auto
if (issue.issueLinks[0]?.otherIssueId != a?.id){

```

However, if I change one of the tickets (with the “a?.id” snippet), the change and also the relation are entered.  
To me it looks like we have a chicken and egg problem here, because the variable “a.id” has no content during the first sync because the ticket does not yet exist at this point.

Is there a way to generate the ticket before the relation part of the script is running?

BR,

Thorsten

* * *

#### Comments:

> **Javier Pozuelo commented on 01 February 2024**
>
> > Hello Thorsten,
> 
> Could you try adding store(issue) in the firstSync block?

---

<div class="post-metadata">

### Author: ![xl8bot](https://dub1.discourse-cdn.com/flex018/user_avatar/community.exalate.com/xl8bot/32/324_2.png) [@xl8bot](https://community.exalate.com/u/xl8bot)
#### Post date: [November 6, 2024, 8:18am UTC](https://community.exalate.com/t/howto-synchronize-issue-relations-from-ado-to-jira-cloud/5629/4 "2024-11-06T08:18:20Z")

</div>

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.
