Disclaimer
- This is an experimental feature and there is no guarantee of its stability, as it didn't run through a complete validation cycle
- The feature can evolve and even be retracted in case it doesn't meet our quality criteria
- We love to get feedback on experimental features which can be sent to support@exalate.com
The post-exalate processor executes a change on the original issue once the synchronization has been finished. It's an advanced option of the Sync Rules configuration.
| property name | type | description |
|---|---|---|
| issueKey | IssueKey | A key of an issue that was synchronized |
remoteIssueKey | IssueKey | A Key of an issue, created on the other side |
jiraIssue | MutableIssue | An issue that was synchronized |
isParentIssue | Boolean | True if the issue was initiating the sync |
workflowUtil | WorkflowUtil | Helper method for JIRA issue transitions |
jiraProxyUser | ApplicationUser | The proxy user configured in General Settings |
You can use the Post exalate processor to automate some actions, which should be done once the issue has been synchronized. For example:
- Sync sub-tasks after parent issue sync
- Sync epic stories, after epic sync
- Update a custom field with the remote issue key
- Transition Exalated issue
- Delete an issue if the twin has been deleted
Sync Sub-tasks after Parent Issue Sync
import com.exalate.api.replication.out.IEventSchedulerService
import com.atlassian.jira.component.ComponentAccessor
import com.exalate.basic.domain.BasicIssueKey
import com.exalate.api.domain.trigger.ExalateJiraEventType
if(isParentIssue && eventType == ExalateJiraEventType.EXALATED){
final def eventScheduler = ComponentAccessor.getOSGiComponentInstanceOfType(IEventSchedulerService.class)
def stm = ComponentAccessor.getSubTaskManager()
def subtasks = stm.getSubTaskObjects(jiraIssue)
subtasks.each{
def subtaskKey = new BasicIssueKey(it.id, it.key)
eventScheduler.schedulePairEvent(subtaskKey, connection)
}
}Sync epic Stories, after epic Sync
import com.exalate.api.replication.out.IEventSchedulerService
import com.atlassian.jira.component.ComponentAccessor
import com.exalate.basic.domain.BasicIssueKey
import com.exalate.api.domain.trigger.ExalateJiraEventType
def getStories = { BasicIssueKey epicExIssueKey ->
def esClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.atlassian.greenhopper.api.issuelink.ManagedIssueLinkTypesService")
def es = ComponentAccessor.getOSGiComponentInstanceOfType(esClass)
if (es == null) {
throw relationLevelErrorInternal("Unable to load the epic link manager, even though the Jira Agile plugin is found. The script is wrong and should be adapted")
}
def iltResult = es.getEpicLinkIssueLinkType()
if (!iltResult.isValid()) {
def errorCollection = iltResult.errorCollection
throw relationLevelErrorInternal(
"Unable to get the story-epic issue link: " +
"\n\tErrors: " + errorCollection?.errors +
"\n\tReasons: " + errorCollection?.reasons
)
}
def epicLinkType = iltResult.get()
if (epicLinkType == null) {
throw relationLevelErrorInternal(
"Epic Link Type is null. Something is terribly wrong with either your Jira Agile installation or your script."
)
}
def stories = ComponentAccessor.getIssueLinkManager().getOutwardLinks(epicExIssueKey.id)
.findAll { epicLinkType.id.equals(it.linkTypeId) }
.collect { it.destinationObject }
return stories.collect { ["id" : it.id, "key": it.key]}
}
if(isParentIssue && eventType == ExalateJiraEventType.EXALATED){
final def eventScheduler = ComponentAccessor.getOSGiComponentInstanceOfType(IEventSchedulerService.class)
def stories = getStories(issueKey)
stories.each{
eventScheduler.schedulePairEvent(new BasicIssueKey(it.id, it.key), connection)
}
}Update a Custom Field with the Remote Issue Key
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.event.type.EventDispatchOption
import com.exalate.api.domain.trigger.ExalateJiraEventType
if(isParentIssue && eventType == ExalateJiraEventType.EXALATED){
def cf = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Remote Issue Key")
jiraIssue.setCustomFieldValue(cf, remoteIssueKey.getURN())
ComponentAccessor.getIssueManager().updateIssue(jiraProxyUser, jiraIssue, EventDispatchOption.ISSUE_UPDATED, false)
}
Transition Exalated Issue
import com.exalate.api.domain.trigger.ExalateJiraEventType if(eventType == ExalateJiraEventType.EXALATED) workflowUtil.doTransition(jiraProxyUser, jiraIssue, "Start Progress")
Delete an Issue if the Twin has been Deleted
import com.atlassian.jira.component.ComponentAccessor
import com.exalate.api.domain.trigger.ExalateJiraEventType
def issueService = ComponentAccessor.getIssueService()
if(isParentIssue && eventType == ExalateJiraEventType.DELETED){
def validation = issueService.validateDelete(jiraProxyUser, jiraIssue.id)
log.info("validation of the delete is ${validation.isValid()} and error collection is ${validation.getErrorCollection()}")
if (validation.isValid()) {
log.info("Going to delete issue with key ${jiraIssue.key}")
issueService.delete(jiraProxyUser, validation)
}
}