Jira Status mapping within one instance

Hi all,

I’m trying to get to the bottom of status mapping and I don’t seem to have any luck.

I have a two way sync between 2 Jira projects within the same instance, see below the current status mapping for issue type Story in this case:

Project A Project B
Backlog Backlog
Shovel-Ready Shovel-Ready
Discovery Discovery
In progress Development
Code Review Development
Preview Testing Development
Ready for Deployment Development
Ready for Testing Development
Verification Development
Pending STG Deployment Pending STG Deployment
Done Done
Blocked Blocked

Here what I have currently in Exalate incoming sync:

String returnMappedStatus(String remoteStatusName, String issueTypeName){

Map statusMapStory = \[

“Blocked” : “Blocked”,

“Backlog” : “Backlog”,

“Discovery”: “Discovery”,

“Shovel-Ready”: “Shovel-Ready”,

“In Progress”: “Development”,

“Code Review”: “Development”,

“Preview Testing”: “Development”,

“Ready for Deployment”: “Development”,

“Ready for Testing”: “Development”,

“Verification”: “Development”,

“Pending STG Deployment”: “Pending STG Deployment”,

“Done”: “Done”

\]

Map statusMapEpic = \[

“Backlog” : “Backlog”,

“Discovery”: “Discovery”,

“AX Acceptance”: “AX Acceptance”,

“Development”: “Development”,

“Ready for PQA”: “Pending PQA”,

“Pending PQA”: “Ready for PQA”,

“Done”: “Done”,

“Pending STG Deployment”: “Pending STG Deployment”,

“Blocked”: “Blocked”

\]

Map statusMapSpike = \[

“Backlog” : “Backlog”,

“In Progress”: “Development”,

“Development” : “In Progress”,

“Done”: “Done”,

“Blocked”: “Blocked”

\]

Map statusMapBug = \[

“Backlog” : “Backlog”,

“Open”: “Open”,

“Triage”: “Triage”,

“Unclear”: “Unclear”,

“Shovel-Ready”: “Shovel-Ready”,

“In Progress”: “Development”,

“Code Review”: “Development”,

“Preview Testing”: “Development”,

“Ready for Deployment”: “Development”,

“Ready for Testing”: “Development”,

“Verification”: “Development”,

“Pending STG Deployment”: “Pending STG Deployment”,

“Ready for PQA”: “Ready for PQA”,

“SIT”: “SIT”,

“Done”: “Done”

\]

if(issueTypeName == “Story”) return statusMapStory[remoteStatusName]

if(issueTypeName == “Epic”) return statusMapEpic[remoteStatusName]

if(issueTypeName == “Spike”) return statusMapSpike[remoteStatusName]

if(issueTypeName == “Bug”) return statusMapBug[remoteStatusName]

if(issueTypeName == “PQA Task”) return “To Do”

debug.error(“No mapping found for issue type ${issueTypeName}, please add the right mapping for this type in ‘returnMappedStatus(String remoteStatusName, String issueTypeName)’”)

}

String remoteStatusName = replica.status.name

String mappedStatus = returnMappedStatus(remoteStatusName, issue.typeName)

issue.setStatus(mappedStatus)

=================================================

This setup doesn’t seem to work. Anyone can help get this setup correctly?

Thanks

Hi @eugeniu,

Welcome to the community!

The overall logic looks fine. Are you getting any sync error from Exalate, or is the sync working but the status simply not changing?

From the script, it looks like the mapping is only being selected by issue type, not by project. Are you relying on issue type alone to determine which status mapping should apply, for example because certain issue types only exist in one of the two projects? If the same issue types exist in both projects, the script currently has no condition to distinguish which project-specific mapping should be used.

I would also recommend adding debugging to confirm the script is actually returning the expected mapped status. For example: throw new Exception(“${tmp}”) or with debug.error()

Hi Javier,

It’s actually a combination of both. Some of them the status is simply not changing and some of them I have errors.

Most common error messages are below:

  1. "Failing to transition because the transition found by algorithm `To Development` is no longer available for current step `Backlog` (10767) Please contact Exalate Support Available transitions: `Backlog`, `Blocked`, `Done`, `To Discovery` "
  2. “Failing to transition because the transition found by algorithm `In Progress` is no longer available for current step `Backlog` (10767) Please contact Exalate Support Available transitions: `Done`, `Backlog`, `Open`, `To Shovel Ready`”

Yes, I’m trying to go by issue type because each issue type has its own statuses but both projects have the same issue types.

You might be right, perhaps the script doesn’t know which project specific mapping should be used since I have the same issue types in both projects..

Is there a way you can help me with that condition?

Hi @eugeniu,

What the error is saying is that Exalate is trying to move the issue to the mapped status, but Jira can only do that if there is a valid workflow transition available from the issue’s current status. In your examples, the issue is in Backlog, but there is no direct transition to Development or In Progress, so Exalate fails because Jira only allows the transitions currently available from that step.

A couple of things need to be addressed. First, you do need to distinguish the mapping by project, because if both projects have the same issue types, then issueTypeName alone is not enough for the script to know which mapping logic to apply.

Second, even with the correct mapping, the target status must be reachable in the local workflow from the current status. So you will need to update your workflow to allow certain statustes to transition to the desired statuses.

You can add a project condition by checking the local project key. For example:


String returnMappedStatus(String remoteStatusName, String issueTypeName, String localProjectKey) {

    if (localProjectKey == "PROJA") {
        if (issueTypeName == "Story") {
            Map statusMapStory = [
                "Backlog": "Backlog",
                "Shovel-Ready": "Shovel-Ready",
                "Discovery": "Discovery",
                "In Progress": "Development",
                "Code Review": "Development",
                "Preview Testing": "Development",
                "Ready for Deployment": "Development",
                "Ready for Testing": "Development",
                "Verification": "Development",
                "Pending STG Deployment": "Pending STG Deployment",
                "Done": "Done",
                "Blocked": "Blocked"
            ]
            return statusMapStory[remoteStatusName]
        }
    }

    if (localProjectKey == "PROJB") {
        if (issueTypeName == "Story") {
            Map statusMapStory = [
                "Backlog": "Backlog",
                "Shovel-Ready": "Shovel-Ready",
                "Discovery": "Discovery",
                "Development": "In Progress",
                "Pending STG Deployment": "Pending STG Deployment",
                "Done": "Done",
                "Blocked": "Blocked"
            ]
            return statusMapStory[remoteStatusName]
        }
    }

}

String remoteStatusName = replica.status.name
String mappedStatus = returnMappedStatus(remoteStatusName, issue.typeName, issue.project.key)

if (mappedStatus) {
    issue.setStatus(mappedStatus)
}

This is an example of the story issue type, you can modify the mappins to fit your workflow.

Hi Javier,

Thanks for help with this. I just used the exact snippet you provided for “Story” and things seem to be moving correctly now.

Will it be similar for the “Bugs” as well? I noticed that your if statement block for PROJB is skipping a few statuses. Is that intentional?

Hi @eugeniu,

I’m glad to hear that script worked for you!

Yes it was intentional, the reason why I removed some of the mappings for “PROJB” is because you have the following on the mappings for “Project A”:

                "In Progress": "Development",
                "Code Review": "Development",
                "Preview Testing": "Development",
                "Ready for Deployment": "Development",
                "Ready for Testing": "Development",
                "Verification": "Development",

This works when you are mapping multiple different remote statuses (remote:local) to a single local status. But when we are looking at it from the other side “Project B” we cannot map "Development into multiple different statuses. So I decided to remove all the duplicate and just map it to a single status:

"Development": "In Progress"

I chose “In Progress” but you can change it according to your workflow.

Hi Javier,

Thanks for clarification.

I did apply the same logic for all my issue types and I noticed a small issue with the Epics. See the script below:

if (localProjectKey == “HORIZONS”) {

    *if (issueTypeName == "Epic") {*

        *Map statusMapEpic = \[*

“Backlog”: “Backlog”,

“Discovery”: “Discovery”,

“AX Acceptance”: “AX Acceptance”,

“Development”: “Development”,

“Pending STG Deployment”: “Pending STG Deployment”,

“Ready for PQA”: “Pending PQA”,

“Blocked”: “Blocked”,

“Done”: “Done”

        *\]*

return statusMapEpic[remoteStatusName]

    *}*

*}*

if (localProjectKey == “LXPART”) {

if (issueTypeName == “Epic”) {

        *Map statusMapEpic = \[*

“Backlog”: “Backlog”,

“Discovery”: “Discovery”,

“AX Acceptance”: “AX Acceptance”,

“Development”: “Development”,

“Pending STG Deployment”: “Pending STG Deployment”,

“Pending PQA”: “Ready for PQA”,

“Blocked”: “Blocked”,

“Done”: “Done”

        *\]*

return statusMapEpic[remoteStatusName]

    *}*

*}*

String remoteStatusName = replica.status.name
String mappedStatus = returnMappedStatus(remoteStatusName, issue.typeName, issue.project.key)

if (mappedStatus) {
issue.setStatus(mappedStatus)
}

So the issue I have noticed is that when we reach the status “Pending PQA”, on the other project it does not flip it to "Ready for PQA" and the sync is saying that the tickets are in sync even tho they are not. Do you know what I might be missing here?

HI @eugeniu,

I think the issue may be that when the mapping does not find a match, mappedStatus becomes null, and because of this condition:

if (mappedStatus) {
    issue.setStatus(mappedStatus)
}

Exalate simply skips the status update without throwing an error. That can make the sync appear successful even though the status was not actually changed.

I’d recommend adding a debug condition so you can confirm what value is being returned:

if (!mappedStatus) {
    debug.error("No status mapping found. Local project: ${issue.project.key}, Issue type: ${issue.typeName}, Remote status: ${remoteStatusName}")
}

issue.setStatus(mappedStatus)

This should confirm whether Pending PQA is actually being received as replica.status.name, whether the script is entering the LXPART part, and whether it is returning Ready for PQA.

Is it only happening with this status and issue type?

Hi Javier,
Thanks for getting back to me on this.

Yes so far I see it only for this status and issue type.

As for the debug condition, should I just add the snipper you shared as an addition or do i need to replace it with my existing one :

if (mappedStatus) {

issue.setStatus(mappedStatus)

}

Let me know.

Hi @eugeniu,

You don’t need to replace your existing condition, just add the debug alongside it so we can see what’s happening.


debug.error("Project: ${issue.project.key}, Type: ${issue.typeName}, Remote: ${remoteStatusName}, Mapped: ${mappedStatus}, Current: ${issue.status?.name}")

if (mappedStatus) {
    issue.setStatus(mappedStatus)
} else {
    debug.error("No mapping found for Remote status '${remoteStatusName}' on project ${issue.project.key}")
}

There is two debug lines, use one at a time, since debug line stops the sync. The first debug checks for everything, the second one will trigger when the mapping is null. You can comment the first one out if everything is correct.