Introduction
Warning: Despite our best efforts, code can change without notice due to a variety of factors. If you encounter an issue in any of the code shown here and find that a specific block of code is not correct, or is causing errors, please check with the Community to find an updated version.
Getting a workflow orchestration between 2 different workflows defined and implemented is already a challenge. The fact is that Jira allows having multiple workflows per project/issue type, and arranging that dance is a real challenge.
We assume that you already have a good understanding of the power of the StatusSync.groovy externalized script - which acts as your personal transition agent.
Defining the Orchestration
To meet this challenge, it is very important to do a throughout analysis of the different permutations.
- For each source workflow
- For each status
- For each target workflow
- For each status
- What transition needs to be made
- For each status
- For each target workflow
- For each status
This can grow exponentially, as the semantics of each transition can be different.
The Status Matrix
The status - matrix is a first approach where you define for each source issue status the target issue status.
| Transition | Open | In Progress | In Review | Closed |
|---|---|---|---|---|
| Todo | x |
|
|
|
| Under development |
|
x |
|
|
| Done |
|
|
x |
|
This results in a transition map
def transitionMap = {
"Todo" : "Open",
"Under development" : "In Progress",
"Done" : "In Review"
}
statusSync.receive ( transitionMap, ...)Seems simple, doesn't it?
Of course it is never that simple, because the source workflows can have conflicting target statuses.
| Transition | Open | In Progress | In Review | Closed |
|---|---|---|---|---|
| Todo | x |
|
|
|
| Under development |
|
x |
|
|
| Done |
|
|
x
if target issue is a bug |
x
if target issue is a task |
How do you solve these apparently conflicting specifications? The difference is that the target status is different depending on the target status.
This translates into the following snippet:
//Define the different transitionMaps
def transitionMapBug = {
"Todo" : "Open",
"Under development" : "In Progress",
"Done" : "In Review"
}
def transitionMapTask = {
"Todo" : "Open",
"Under development" : "In Progress",
"Done" : "Closed"
}
if (issue.issueType?.name == "Bug") {
statusSync.receive ( transitionMapBug, ...)
} else {
statusSync.receive ( transitionMapTask, ...)
}
Depending on the issue type, one or another map is being used.
Using Resolutions
In many cases, it is sufficient to know if an issue is being resolved or not.
- When a remote issue is not yet resolved, the local issue should be 'waiting for development'
- When a remote issue is resolved, the local issue should be moved to status 'to review'
The code snippet is as follows:
/*
** Two transitions have been configured on all workflows
**
** - autoResolve - an any to resolve transition
** - autoOpen - an any to open transition
** Both transitions are hidden for the user.
** the autoResolve sets the local resolution. and the autoOpen clears the local resolution.
*/
// the following line will transition an issue in case that the resolution of the remote issue changed
if (previous.resolution?.name != replica.resolution?.name) {
// if the replica.resolution changed compared to the previous sync, transition depending on the value of resolution
// if the value of the replica.resolution is null - use 'autoOpen', else 'autoResolve'
workflowHelper.transition(replica.resolution ? "autoResolve" : "autoOpen", issue)
}