**Introduction**
Migrating projects between Jira instances or platforms such as Jira and ServiceNow can be optimized with Exalate. As a senior Jira admin engineer, you need an accurate, scriptable, and secure strategy to ensure seamless migration of issues, workflows, and related data. This guide provides advanced examples, best practices, and considerations for controlled project migrations.
**Prerequisites**
Before starting a migration, ensure Exalate is installed and licensed on both source and target instances. Administrative rights in Jira are necessary to configure connections, field mappings, and custom scripts. Network connectivity between instances must be verified to ensure secure communication.
**Establishing Connections**
Create an Exalate connection between source and target environments by generating an invitation code and applying it to the counterpart. Connections define the sync direction and security context for migration. Properly configured connections prevent unauthorized access and ensure controlled project mapping.
**Configuring Sync Rules**
Exalate uses Groovy-based sync rules to specify how fields, comments, attachments, and statuses migrate. For project migration, rules must be carefully scoped to prevent accidental propagation of irrelevant data. Mapping custom fields and workflows is critical for maintaining project integrity.
**Examples**
1. Basic issue migration rule: Migrates issues from SRC to DEST while preserving summary and description.
“`javascript
if (replica.project.key == “SRC”) {
issue.projectKey = “DEST”
issue.summary = replica.summary
issue.description = replica.description
}
“`
2. Sync custom field mapping: Maps a custom field named Business Impact to ensure business-critical metadata is retained.
“`javascript
if (replica.customFields[“Business Impact”]) {
issue.customFields[“Business Impact”] = replica.customFields[“Business Impact”]
}
“`
3. Workflow status alignment: Maps differing workflow statuses between environments for consistency.
“`javascript
if (replica.status.name == “In Progress”) {
issue.status = nodeHelper.getStatus(“In Development”)
}
“`
4. Migrating comments: Iterates through all comments from source and adds them to the destination issue.
“`javascript
replica.comments.each { c ->
issue.comments += commentHelper.createComment(c.author, c.body)
}
“`
5. Attachment handling: Ensures all attachments from the source issue are migrated into the destination issue.
“`javascript
replica.attachments.each { a ->
attachmentHelper.addAttachment(issue, a)
}
“`
6. Limiting migration scope: Only migrates issues explicitly tagged with the label migrate.
“`javascript
if (replica.labels.contains(“migrate”)) {
issue.labels += “migrated”
}
“`
7. CLI invocation for bulk migration: Uses Jira CLI with Exalate connection to migrate a batch of issues defined in a CSV file.
“`
jira-cli –action runFromCsv –file migration_issues.csv –common “project=SRC” –exalateConnection DEST_CONN
“`
8. Preserving assignee mapping: Maps the assignee from the source instance using email to the destination user directory.
“`javascript
if (replica.assignee) {
issue.assignee = userHelper.getUserByEmail(replica.assignee.email)
}
“`
9. Scripted migration of sprint data: Transfers sprint information into the destination project for Agile board alignment.
“`javascript
if (replica.sprint) {
issue.customFields[“Sprint”] = replica.sprint.name
}
“`
10. Automating connection setup via REST API: Automates connection creation between Jira instances using REST API.
“`
curl -X POST -u admin:token -H “Content-Type: application/json”
https://dest-jira/rest/exalate/latest/connections -d ‘{“name”:”MigrationConn”,”type”:”basic”}’
“`
11. Ensuring issue type consistency: Maps issue type Bug in source to Defect in destination.
“`javascript
if (replica.issueType.name == “Bug”) {
issue.issueType = nodeHelper.getIssueType(“Defect”)
}
“`
12. Handling sub-tasks: Migrates sub-tasks by recreating them under the destination issue.
“`javascript
replica.subTasks.each { st ->
def sub = issueHelper.createSubTask(issue, st.summary, st.issueType)
sub.description = st.description
}
“`
13. Selective field exclusion: Excludes sensitive internal notes field from being migrated.
“`javascript
replica.customFields.remove(“Internal Notes”)
“`
14. Handling epic links: Maintains epic hierarchy during migration.
“`javascript
if (replica.customFields[“Epic Link”]) {
issue.customFields[“Epic Link”] = replica.customFields[“Epic Link”]
}
“