Synchronization is handled by processors which are responsible for sending data to the destination instance and processing received data from the other side.

Exalate uses synchronization processors to handle outgoing and incoming messages. We call them Sync Rules. You can find Sync Rules as a separate tab when you select the connection to edit.


What's a processor

A processor is a groovy based script which can be used to implement filtering, mapping, and transformation. These are essential operations in any synchronization.

Groovy is a dynamic language for the Java platform. Check out the following links to get more details about Groovy and how to develop in this language:


Processor types

There are 2 different processor types in the Sync Rules. Each with its own purpose. 

For more details check the synchronization process explanation.

Outgoing sync

Defines what information is sent to the destination side.

Exalate runs the outgoing sync processor when you start the synchronization or update the local issue which is under sync.

You can assign issue fields to a replica on the outgoing sync.  Check issue fields available for synchronization


variableexplanation
Inputissuelocal issue data you need to synchronize.
Outputreplicacopy of the issue data which will be sent to the destination instance.


Simple examples of the Outgoing sync rules

replica.summary     = issue.summary // send summary
replica.description = issue.description // send description
replica.comments    = issue.comments // send comments
replica.attachments = issue.attachments // send attachments

Condition example in the Outgoing Sync rules

Don't send anything when priority is trivial

// If the issue priority is "Trivial" don't send any data. In other cases send the summary, description, comments and attachments 

if (issue.priority.name = "Trivial") {
	return
}
replica.summary     = issue.summary
replica.description = issue.description 
replica.comments    = issue.comments
replica.attachments = issue.attachments

Incoming sync

When you receive data from the other side you need to apply this data on your instance. You can define how to handle the received information on your instance with the help of the incoming sync rules.

Exalate runs the incoming sync every time there's new data received from the remot side.  

When you receive the synchronization data from the remote side for the first time, Exalate creates the issue locally in your instance.

Starting from this moment the issue is considered under synchronization(under sync). From that moment every issue update will trigger the update of the synced issue on the other side. 


variableexplanation
Inputreplicainformation received from the source instance.

previousprevious information received from the source instance.
Outputissueissue object which will be used to create/update the local issue.

When you leave the incoming sync empty, then nothing is synchronized. Check the Unidirectional synchronization for more details.


Simple Incoming sync example


if(firstSync){
   // If it's the first sync for an issue and local copy of the 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 ?: "TEST"
   // Set type name from source issue, if not found set a default
   issue.typeName     = nodeHelper.getIssueType(replica.type?.name, issue.projectKey)?.name ?: "Task"
}
issue.summary      = replica.summary
issue.description  = replica.description
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)

 Incoming requests are distinguished based on the information stored in a replica.

So if you want to have different sync rules for the first synchronization and then others for synced issue updates you should use conditional statements

if (firstSync) { 
  return // don't create any issues, only sync changes to the issue which are already under sync
}
issue.summary = replica.summary
issue.description = replica.description
issue.labels = replica.labels
issue.comments = commentHelper.mergeComments(issue, replica)
issue.comments = attachmentHelper.mergeAttachments(issue, replica)



More advanced configuration

You can set your own values for the local issue based on the received data from the other side. 

For example, if the synced issue status changes to Done on the remote side → set the local issue status to Resolved.


To configure advanced conditions for your synchronization use script helper methods.

Check the example below.

// Create a request in the support project "SD", but if it's a critical issue in the customer's WEB project, assign it to Kevin Spacey
 
issue.project = nodeHelper.getProject("SD")

if (replica.priority.name = "Critical" && replica.project.key = "WEB") {
 	issue.assignee = nodeHelper.getUser("kspacey") // assign to Kevin
	issue.priority = nodeHelper.getPriority("Blocker")
} else {
	issue.priority = nodeHelper.getPriority("Major")
}
 
issue.summary = replica.summary
issue.projectKey = "SD"
issue.typeName = "Request"


Default configuration

By default, Exalate configures some basic scripts in the Sync Rules for your convenience.

Below is the default configuration of the Outgoing and Incoming sync.

It helps to synchronize basic issue data: summary, description, comments, resolution, status, attachments and project.

Default Outgoing sync

replica.key            = issue.key
replica.type           = issue.type 
replica.assignee       = issue.assignee 
replica.reporter       = issue.reporter
replica.summary        = issue.summary
replica.description    = issue.description
replica.labels         = issue.labels
replica.comments       = issue.comments
replica.resolution     = issue.resolution
replica.status         = issue.status
replica.parentId       = issue.parentId
replica.priority       = issue.priority
replica.attachments    = issue.attachments
replica.project        = issue.project

Default Incoming sync 

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 ?: "TEST"
   // Set type name from source issue, if not found set a default
   issue.typeName     = nodeHelper.getIssueType(replica.type?.name, issue.projectKey)?.name ?: "Task"
}
issue.summary      = replica.summary
issue.description  = replica.description
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)