How to Sync Epics from Azure to Jira

Originally asked by Harinder Singh on 26 August 2020 (original question)


Hi All

I am having an issue, can you provide me sample code on how to sync Epic from Azure to Jira, I am able to sync Epic from Jira to Azure but not from Azure to JIRA. while syncing I am getting below error.

Please help. Thank you.

Error Detail Message:

Field The issue type selected is invalid.: issuetype.

The issue type is Epic


Answer by Francis Martens (Exalate) on 26 August 2020

Hi Singh,

Can you provide your incoming sync script on the Jira side?


Comments:

Harinder Singh commented on 27 August 2020

Hi Martens

Please see below script

if(firstSync){
   // If it's the first sync for an issue (local issue does not exist yet)
   // Set project key from source issue, if not found set a default
   issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"
   // Set type name from source issue, if not found set a default
  issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?:"Task"
}
issue.summary      = replica.summary
issue.description  = replica.description
issue.labels       = replica.labels
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)
if(replica.assignee!=null){
issue.assignee     = nodeHelper.getUserByEmail(replica.assignee.email) == null ? null : nodeHelper.getUserByEmail(replica.assignee.email);
}
issue.creator      = replica.creator
issue.issueLinks   = replica.issueLinks
issue.labels       = replica.labels
issue.timeSpent          = replica.timeSpent
issue.originalEstimate   = replica.originalEstimate
issue.remainingEstimate  = replica.remainingEstimate
issue.customFields."Acceptance Criteria".value = replica.AcceptanceCriteria
Francis Martens (Exalate) commented on 27 August 2020

The first sync section of the incoming script on the Jira side dictates how an epic needs to be created

if(firstSync){
   // If it's the first sync for an issue (local issue does not exist yet)
   // Set project key from source issue, if not found set a default
   issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"
   // Set type name from source issue, if not found set a default
  issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?:"Task"
}

Whenever the exalate needs to create an epic, it is important that it knows that an epic needs to be created.

Assume that you only want to create Epics, make sure that the type name is set to ā€œepicā€

(the ā€¦ in the code block below denotes that other statements can be set there, you will have to replace it with something that makes sense)

if (firstSync) {
	...
    // only create epics
	issue.typeName = "Epic"
	...
}

Now - Epics has one required field - the Epic Name - so you add that bit of logic to your incoming sync script.

if (firstSync) {
   ...
   // only create epics
   issue.typeName = "Epic"

   // set the epic name to the same as the issue summary
   issue.customFields."Epic Name".value = replica.summary   
   ...
}


Of course you donā€™t only have epics in AzureNode, but also issues.
In the outgoing sync of the azure side - the workitem.type is copied into the replica

A workitem.type has a couple of properties such as description, name ā€¦

So based on that information, you can decide either to create an epic, or a story

if (firstSync) {
   ...
   if (replica.type?.name == "epic") {
	   issue.typeName = "Epic"

	   // set the epic name to the same as the issue summary
   	   issue.customFields."Epic Name".value = replica.summary   
   } else {
       issue.typeName = "Story"
   }
   ...
}

This way you can construct the required logic, step by step.

PS - in your incoming script you have the following line

issue.assignee     = nodeHelper.getUserByEmail(replica.assignee.email) == null ? null : nodeHelper.getUserByEmail(replica.assignee.email);

You can simplify it to

issue.assignee     = nodeHelper.getUserByEmail(replica.assignee.email)
Harinder Singh commented on 27 August 2020

Hi Martens

sorry, but it did not work, please see attached my incoming script, and also please see attached incoming payload. If you can make something from it.

Incoming Script

if(firstSync){
   // If it's the first sync for an issue (local issue does not exist yet)
   // Set project key from source issue, if not found set a default
   issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"
   // Set type name from source issue, if not found set a default
   
    if (replica.type?.name == "epic") {
	   issue.typeName = "Epic"
   	   issue.customFields."Epic Name".value = replica.summary  
   }else{
    issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?: "Task"
   }
   
}

Payload

{
  "version": {
    "major": 1,
    "minor": 14,
    "patch": 0
  },
  "hubIssue": {
    "areaPath": "ExalateJiraSyncTest",
    "iterationPath": "ExalateJiraSyncTest\\Sprint 1",
    "components": [],
    "attachments": [],
    "voters": [],
    "customFields": {},
    "description": "epic description",
    "project": {
      "key": "ExalateJiraSyncTest",
      "name": "ExalateJiraSyncTest"
    },
    "watchers": [],
    "fixVersions": [],
    "issueLinks": [],
    "key": "5192",
    "summary": "Epic",
    "comments": [],
    "internalMap": {
      "areaPath": "ExalateJiraSyncTest",
      "iterationPath": "ExalateJiraSyncTest\\Sprint 1"
    },
    "reporter": {
      "key": "540259f3-4429-44a7-b8a7-3123459we1a306",
      "active": false,
      "email": "someone@some.com",
      "displayName": "someoneName",
      "username": "someone@some.com"
    },
    "priority": {
      "id": "2"
    },
    "labels": [
      {
        "label": "tag"
      }
    ],
    "customKeys": {},
    "workLogs": [],
    "issueType": {
      "name": "Epic"
    },
    "affectedVersions": [],
    "entityProperties": {},
    "status": {
      "name": "New"
    }
  },
  "issueUrl": "https://dev.azure.com/masked_url"
}
Francis Martens (Exalate) commented on 27 August 2020

> It did not work

Can you be more specific?

Harinder Singh commented on 27 August 2020

Same error message, it does not recognize the issue type as Epic.

Error Detail Message:

Field The issue type selected is invalid.: issuetype.

FYI: If I create Epic from Jira and sync to Azure it works fine but payload from Jira side is different and it has more fields under issueType, but from Azure side only name under issueType json.

Can you create Epic in Azure and sync with Jira? are you able to do that? can you share those scripts with me?

Francis Martens (Exalate) commented on 27 August 2020

Is the if branch of the code being run.
You can check by throwing an exception

just insert

...
thrown new Exception("the remote type is ${remote.type.name}")....
Harinder Singh commented on 27 August 2020

Yes its working I have tested that before also, I am able to convert Epic to Task using the above code but that is not my requirement.

Can you try on your side creating Epic and sync to Jira from Azure? If you try then you can debug it properly I think.

Francis Martens (Exalate) commented on 27 August 2020

Again - can you answer my question?

> Is the if branch of the code being run.

Harinder Singh commented on 27 August 2020

No sorry, itā€™s not running, I tried above Exception and did not throw. (old community)

Harinder Singh commented on 27 August 2020

Hi

I made below changes and If Branch is now running but now I am getting a different errors.

Error Detail Message:

Field Field ā€˜customfield_10005ā€™ cannot be set. It is not on the appropriate screen, or unknown.: customfield_10005.

Incoming Script

if(firstSync){
   issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"
   
    if (nodeHelper.getIssueType(replica.typeName)?.name=="Epic"){
	    
	    issue.typeName = "Epic"
   	    issue.customFields."Epic Name".value = replica.summary  
   	   
   	  
   	   //thrown new Exception("the remote type is ${remote.type.name}");
   	   
   }else{
    issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?: "Task"
   }
   
}
Francis Martens (Exalate) commented on 27 August 2020

You can simplify the if with

...
if (replica.typeName == "Epic") {
...
  

Regarding the Epic Name not found.

Are you on cloud?

Harinder Singh commented on 28 August 2020

Yes, I am on the cloud,

after simplifying If condition as you mention I am still getting same error, please advise.

Error Detail Message:

Field Field ā€˜customfield_10005ā€™ cannot be set. It is not on the appropriate screen, or unknown.: customfield_10005.

Francis Martens (Exalate) commented on 28 August 2020

Can you check if the epic name is on the screen for creating an epic? Can you provide a screenshot of the Jira screen when creating an epic?

Harinder Singh commented on 31 August 2020

Hi Martens

Please see screenshot attached for both JIRA and Azure.

FYI on Jira side project is of Classic with Scrum.

Harinder Singh commented on 01 September 2020

Hi Martens any update? please advise thank you.

Francis Martens (Exalate) commented on 02 September 2020

The only way to reproduce this problem is to remove the epic name field from the form. So I donā€™t have an immediate clue why this works. A hunch

Can you change

issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"

into

issue.projectKey   = "AZ"

and

issue.customFields."Epic Name".value = replica.summary  

into

issue.customFields."Epic Name".value = "Hello World"

Thanks

Harinder Singh commented on 03 September 2020

Thanks Martens, Epic is working but now I am getting same error for Task.

Not able to sync new tasks now.

I have tried hard code issueType also to Task nothing is working. is this some bug in the plugin?

Error Detail Message:

Field The issue type selected is invalid.: issuetype.

Francis Martens (Exalate) commented on 03 September 2020

> Epic is working

Can you share what you did how it is working

> now I am getting same error for Task.

Can you share your incoming sync on the Jira side again?

Harinder Singh commented on 03 September 2020

Hi Martens

Please see below scripts

if(firstSync){
   //issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"
   issue.projectKey = "AZ"
    if (replica.typeName == "Epic"){
	    issue.typeName = "Epic"
   	    issue.customFields."Epic Name".value = replica.summary
   	   //throw new com.exalate.api.exception.IssueTrackerException("Error " + nodeHelper.getIssueType(replica.typeName)?.name + "" )
   }else{
       //throw new com.exalate.api.exception.IssueTrackerException(replica.typeName)
        issue.typeName = nodeHelper.getIssueType(replica.typeName)?.name ?: "Task"
   }
}
issue.summary      = replica.summary
issue.description  = replica.description
issue.labels       = replica.labels
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)
if(replica.assignee!=null){
issue.assignee     = nodeHelper.getUserByEmail(replica.assignee.email); // == null ? null : nodeHelper.getUserByEmail(replica.assignee.email);
}
if(replica.reporter!=null){
    issue.reporter = nodeHelper.getUserByEmail(replica.reporter.email);
}
issue.creator      = replica.creator
issue.issueLinks   = replica.issueLinks
issue.labels       = replica.labels
issue.timeSpent          = replica.timeSpent
issue.originalEstimate   = replica.originalEstimate
issue.remainingEstimate  = replica.remainingEstimate
issue.customFields."Acceptance Criteria".value = replica.AcceptanceCriteria
//issue.parentId     = replica.parentId


if (replica.typeName=="Bug"){
    issue.customFields."Repro Steps".value = replica.ReproSteps
    issue.customFields."Severity".value = replica.Severity
    issue.customFields."System Info".value = replica.SystemInfo
}
if (replica.typeName=="Impediment"){
    issue.customFields."Resolution".value = replica.Resolution    
}



Harinder Singh commented on 03 September 2020

Hi Martens

just to add, I have created new connection with basic incoming scripts no change still I am getting error. please help see below default incoming script

if(firstSync){
   // If it's the first sync for an issue (local issue does not exist yet)
   // Set project key from source issue, if not found set a default
   issue.projectKey   = nodeHelper.getProject(replica.project?.key)?.key ?: "AZ"
   // Set type name from source issue, if not found set a default
   issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?: "Task"
}
issue.summary      = replica.summary
issue.description  = replica.description
issue.labels       = replica.labels
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)


Harinder Singh commented on 03 September 2020

Hi Martens

any update? I am stuck with my project now because of Task. please help asap. thank you.

Francis Martens (Exalate) commented on 03 September 2020

We have seen this in the past where you have multiple issue types with the same name
(Task)

Can you check if this is the case.

Harinder Singh commented on 04 September 2020

Hi Martens, I found a workaround, since its bug or not that some time Epics doesnā€™t work and some time Task, I have created new Issue Type with a similar workflow and board ā€œEpicsā€ yes with ā€˜sā€™ because cant have duplicate. I did the same for Tasks and now all are working fine.

just sync Epic with Epics, Task with Task.

the problem I am finding is that during first sync some time exalate cant find issue type even though it exists. Just create custom issueType and sync with them. So far this is working now, will let you know if it breaks.

Hope this help others too.

Francis Martens (Exalate) commented on 04 September 2020

Good to hear that you found a way - kudos

Just for our information - do you have multiple issue types with the same name in the Jira configuration - can you do a quick check

Harinder Singh commented on 04 September 2020

I dont have multiple issuetypes under my project but however for other projects could be.

These are my issueTypes. mostly custom

Francis Martens (Exalate) commented on 04 September 2020

Hmm - that view is completely different from what we see.
What is the link to that view - can you share it without the baseurl (ie the xyz.atlassian.net)

Harinder Singh commented on 04 September 2020

So you goto your project then click on Project Settings ā†’ Issue Types

Francis Martens (Exalate) commented on 04 September 2020

OK - thanks.

Can you access the issuetypes in the system settings and see if there are any duplicates
/secure/admin/ViewIssueTypes.jspa

Harinder Singh commented on 04 September 2020

No duplicates, all different but alot of sub-task with different names

Francis Martens (Exalate) commented on 04 September 2020

Ok thanks.

Answer by Francis Martens (Exalate) on 08 September 2020

Hi Harinder Singh

Another customer who had about the same problem came back to us with following message

I have managed to find the problem and my solution works now.
The Epic sync is not working in Jira cloud if the Epic Colour field is not on screen. I fixed it and now everything works fine based on your guide - no custom scripting was necessary.

You might revisit the implementation of the epic sync and use the native epic object.


Comments:

Harinder Singh commented on 08 September 2020

Hi Martens so i just need to add colour screen, hmmm ok iā€™ll give a try thank you.

Francis Martens (Exalate) commented on 08 September 2020

Let me know

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