Hello, any documentation or other community posts on the below points would be amazing! 

  • How to map Components (Jira) into a Components custom field in ADO
  • How to retain parent-child links when Story->Epic (in Jira) becomes User Story->Feature (ADO)
  • Is there any way to clean up the formatting of fields copied across? We have lots of tables/images that are just coming across as a massive block of text
  • When I manually Exalate, the item gets auto assigned to me it seems – can this be changed?
  • In Jira we have a custom field for ASOS Team(s) (multi select) which I want to populate as part of the area path in ADO:
    For example – Jira - ASOS Team(s) = Alpha
    Azure DevOps desired behaviour for Area Path = WebPlatform/Alpha

Thank you! 


    CommentAdd your comment...

    2 answers


      Hi there,

      Hope this helps!

      Components sync from Jira to ADO:

      Jira Outgoing:

      replica.components = issue.components

      Azure Incoming:

      workItem."Components field" = replica.components?.first().name

      Epic Parent child relationship Jira to ADO:

      Jira Outgoing:

      replica.customFields."Epic Link" =  issue.customFields."Epic Link"

      Azure Incoming:

      if (replica.customFields."Epic Link".id){
          def localParent = syncHelper.getLocalIssueKeyFromRemoteId(replica.customFields."Epic Link".id.toLong())
              workItem.parentId = localParent.id

      Clean format Description, Summary, Comments or customFields Jira to ADO:

      Jira Outgoing:

      replica.description = nodeHelper.getHtmlField(issue, "description")
      replica.summary = nodeHelper.getHtmlField(issue, "summary")
      replica.comments = nodeHelper.getHtmlComments(issue)
      replica."MyCustomField" = nodeHelper.getHtmlField(issue, "customfield_10111")

      Azure Incoming:

      workItem.description  = replica.description
      workItem.summary      = replica.summary
      workItem.comments     = commentHelper.mergeComments(workItem, replica)
      workItem."Azure Field" = replica."MyCustomField"

      Clean format Description, Summary, Comments or customFields ADO to Jira:
      Azure Outgoing:

      replica.summary = workItem.summary
      replica.description = workItem.description
      replica.comments = nodeHelper.stripHtmlFromComments(workItem.comments)
      replica."Azure Field" = workItem."Azure Field"

      Jira Incoming:

      import com.exalate.transform.HtmlToWiki
      HtmlToWiki htw = new HtmlToWiki()                                  
      issue.summary = htw.transform(replica.summary)
      issue.description = htw.transform(replica.description)
      issue.comments = commentHelper.mergeComments(issue, replica)
      issue.customFields."Jira Field".value = replica."Azure Field"?.value

      Sync Assignee Jira to ADO, auto assign?

      You might need to check if there is any automation in place or misconfiguration. You may comment out the assignee field to see if the behaviour persists. If it does, then ADO is the responsible.

      //workItem.assignee = replica.assignee

      Sync Custom Field Multi Select Jira to areaPath ADO:

      Outgoing Jira

      replica.customFields."Multi" = issue.customFields."Multi"

      Incoming Azure

      def multiMap = ["Alpha":"WebPlatform\\Alpha",
      areaOption = replica.customFields."Multi".value?.collect {it -> it?.value}
      workItem.areaPath = multiMap[areaOption]

      Kind regards,


        CommentAdd your comment...

        Thanks Ariel Aguilar

        • For components - how should I handle items that do not have a component? As they are bringing the following error:

        • The HTML formatting works great - thank you!

        • I couldn't get parent child linking to work, here is my code:
          Jira Outgoing:

          replica.key            = issue.key
          replica.type           = issue.type
          replica.reporter       = issue.reporter
          replica.summary        = issue.summary
          replica.description    = nodeHelper.getHtmlField(issue, "description")
          replica.labels         = issue.labels
          replica.comments       = nodeHelper.getHtmlComments(issue)
          replica.status         = issue.status
          replica.parentId       = issue.parentId
          replica.priority       = issue.priority
          replica.attachments    = issue.attachments
          replica.project        = issue.project
          replica.components     = issue.components
          replica.AcceptanceCriteria = nodeHelper.getHtmlField(issue, "customfield_10301")
          replica.customFields."Epic Link" =  issue.customFields."Epic Link"

          ADO Incoming:

             // Set type name from source entity, if not found set a default
             workItem.projectKey  =  "WebPlatform"
             def typeMap = [
                 "Story" : "User Story",
                 "Epic" : "Feature",
                 "Bug" : "Bug",
                 "Sub-task" : "Task",
             workItem.typeName = nodeHelper.getIssueType(typeMap[replica.type?.name],workItem.projectKey)?.name 
          workItem.summary      = replica.summary
          workItem.description  = replica.description
          workItem.attachments  = attachmentHelper.mergeAttachments(workItem, replica)
          workItem.comments     = commentHelper.mergeComments(workItem, replica)
          workItem.labels       = replica.labels
          workItem.priority     = replica.priority
          workItem."Microsoft.VSTS.Common.AcceptanceCriteria" = replica.AcceptanceCriteria
          workItem."Components" = replica.components?.first().name
          if (replica.customFields."Epic Link".id){
              def localParent = syncHelper.getLocalIssueKeyFromRemoteId(replica.customFields."Epic Link".id.toLong())
                  workItem.parentId = localParent.id
          def statusMap = [
                 // "remote status name": "local status name"
                   "To Do" : "New",
                   "Backlog" : "New",
                   "Refining" : "New",
                   "Discovery" : "New",
                   "Refined" : "New",
                   "3 Amigo" : "Approved",
                   "Ready for Dev" : "Approved",
                   "In Progress" : "Active",
                   "In Development" : "Active",
                   "Ready for Code Review" : "Active",
                   "Code Review" : "Active",
                   "Ready for Testing" : "Active",
                   "In Testing" : "Test",
                   "Test" : "Test",
                   "Branch Test" : "Test",
                   "Merge Test" : "Test",
                   "Ready for Release" : "Resolved",
                   "On Hold" : "Resolved",
                   "Live" : "Closed",
                   "Done" : "Closed"
          def remoteStatusName = replica.status.name
          issue.setStatus(statusMap[remoteStatusName] ?: remoteStatusName)
        1. Ariel Aguilar

          I see, you might try to change the line to:

          workItem."Components field" = replica.components?.first()?.name

          When you say the epic/story relation is not working, is the Epic already synchronized?

        2. Nicolas Brown

          Unfortunately that doesn't work either (sad)

          Epic isn't synchronizing (but it also is being copied into ADO as a Feature)

        3. Nicolas Brown

          Hey Ariel Aguilar I had a call with Dhiren Notani today and he talked me through the component part. It was just a small tweak to:

          if (replica.components){
          workItem."Components" = replica.components?.first().name
        CommentAdd your comment...