if(firstSync){ //project mapping def projectMapping = [ "IZO":"AEM", "IZOINT":"ACS" ] /* Issue Type Mapping */ //map issue types between source and destination instances. def issueTypeMapping = [ // "remote issue type" : "local issue type" "Research": "Task", "Requirements": "Task", "Documentation": "Task", "Designs": "Task", "Wireframes": "Task", "Bug": "Bug", "Development": "Task", "Feature Request": "Improvement", "Story": "Story", "Task": "Task", "Subtask": "Sub-task", "Sub-task": "Sub-task", "Subtask Design": "Sub-task", "Epic" : "Epic" ] issue.typeName = issueTypeMapping[replica.type?.name] ?: "Task" // Set type name from source issue, if not found set a default // issue.typeName = nodeHelper.getIssueType(replica.typeName)?.name ?: "Task" // ["REMOTE PROJECT KEY": "LOCAL PROJECT KEY"] issue.projectKey = projectMapping[replica.project.key] //debug.error("remote project key = ${replica.project.key}, mspped to ${projectMapping[replica.project.key]}") if (replica.parentId) { def localParent = nodeHelper.getLocalIssueFromRemoteId(replica.parentId.toLong()) if(localParent){ issue.parentId = localParent.id } else { throw new com.exalate.api.exception.IssueTrackerException("Subtask cannot be created: parent issue with remote id " + replica.parentId + " was not found. Please make sure the parent issue is synchronized before resolving this error" ) } } //debug.error("issue.parentid = ${issue.parentId} issue.typename = ${issue.typeName} remote project key = ${replica.project.key}, mspped to ${projectMapping[replica.project.key]}") } issue.summary = replica.summary issue.description = replica.description issue.labels = replica.labels //issue.comments = commentHelper.mergeComments(issue, replica) issue.attachments = attachmentHelper.mergeAttachments(issue, replica) /* User Synchronization (Assignee/Reporter) Set a Reporter/Assignee from the source side, if the user can't be found set a default user You can use this approach for custom fields of type User */ def defaultUser = nodeHelper.getUserByEmail("akruck@maark.com") issue.reporter = nodeHelper.getUserByEmail(replica.reporter?.email) ?: defaultUser issue.assignee = nodeHelper.getUserByEmail(replica.assignee?.email) ?: defaultUser /* Comment Synchronization Sync comments with the original author if the user exists in the local instance Remove original Comments sync line if you are using this approach */ issue.comments = commentHelper.mergeComments(issue, replica) { it.executor = nodeHelper.getUserByEmail(it.author?.email) } /* Status Synchronization Sync status according to the mapping [remote issue status: local issue status] If statuses are the same on both sides don't include them in the mapping */ /* Status Mapping */ def statusMappingAEM = [ "Open" : "Backlog", "Created" : "Backlog", "Blocked" : "Blocked", "In Progress" : "In Progress", "In Code Review" : "In Progress", "Ready to Deploy" : "In Progress", "On Dev" : "In Progress", "Selected for Release" : "Ready for Staging", "Ready for Deploy" : "Ready for Staging", "Staging Review" : "UAT", "Done" : "Production Check", "DONE" : "Production Check", "Code Review" : "In Progress", "Stage Review" : "UAT", "Client Review" : "UAT", "Under Review" : "UAT", "Internal Review" : "In Progress", "Requirements Check" : "In Progress", "Reopened" : "In Progress" ] def statusMappingACS = [ "Open" : "Backlog", "Reopened" : "Backlog", "Blocked" : "Blocked", "In Progress" : "In Progress", "Code Review" : "In Progress", "Ready For Deploy" : "In Progress", "Ready for Deploy" : "In Progress", "Internal Review" : "In Progress", "Under Review" : "UAT", "Done" : "Production Check", "DONE" : "Production Check" ] def statusMapping = issue.projectKey == "AEM" ? statusMappingAEM : statusMappingACS def targetStatus = statusMapping[replica.status?.name] if (!targetStatus) { debug.error("The remote status '${replica.status?.name}' is not found in the status mapping ") } issue.setStatus(targetStatus) /* OLD STATUS MAPPING CODE def statusMapping = [ "Open" : "Backlog", "Blocked" : "Blocked", "In Progress" : "In Progress", "In Code Review" : "In Progress", "Ready to Deploy" : "In Progress", "On Dev" : "In Progress", "Selected for Release" : "Ready for Staging", "Ready for Deploy" : "Ready for Staging", "Staging Review" : "UAT", "Done" : "Closed", "DONE" : "Closed", "Code Review" : "In Progress", "Stage Review" : "UAT", "Client Review" : "UAT", "Under Review" : "UAT", "Internal Review" : "In Progress", "Requirements Check" : "In Progress" ] def remoteStatusName = replica.status.name issue.setStatus(statusMapping[remoteStatusName] ?: remoteStatusName) */ /* Priority Mapping def priorityMapping = [ // remote side priority <-> local side priority "Highest": "Highest", "High": "High", "Low": "Low", "Lowest": "Lowest", ] def priorityName = priorityMapping[replica.priority?.name] ?: "Low" // set default priority in case the proper urgency could not be found issue.priority = nodeHelper.getPriority(priorityName) */ // this will overwrite the current time tracking information issue.timeSpent = replica.timeSpent issue.originalEstimate = replica.originalEstimate issue.remainingEstimate = replica.remainingEstimate //any issue that is synced via Exalate will get an "exalate" label for easy identification if (replica.issueType.name != "fakeissuetype") { issue.labels += nodeHelper.getLabel("exalate") } /* VERSION SYNC */ // for the create processor, be sure that the project is set to the issue variable before running the following code //issue.projectKey = "AEM" //Included only on create processor issue.fixVersions = replica.fixVersions.collect { v -> nodeHelper.createVersion(issue, v.name, v.description) } // assign fix versions from JIRA A to JIRA B issue.fixVersions = replica .fixVersions // ensure that all the fixVersions are available on B .collect { v -> nodeHelper.createVersion(issue, v.name, v.description) } // assign affected versions from JIRA A to JIRA B issue.affectedVersions = replica .affectedVersions .collect { v -> nodeHelper.createVersion(issue, v.name, v.description) } /* VERSION SYNC update - Exalate support September 2, 2021 issue.projectKey = "AEM" if(replica.fixVersions) { issue.fixVersions = replica .fixVersions .collect { v -> nodeHelper.getVersion(v.name, project) } .findAll{it !=null} } else {issue.fixVersions = replica .fixVersions .collect { v -> nodeHelper.createVersion(issue, v.name, v.description) } } issue.affectedVersions = replica .affectedVersions .collect { v -> nodeHelper.getVersion(v.name, project) } .findAll {it !=null} */ //Epic sync works using an external scrip on Jira On-prem, may require update if fails try { Epic.receive() } catch(e){ com.atlassian.jira.component.ComponentAccessor .getOSGiComponentInstanceOfType(com.exalate.api.error.IErrorService.class) .addError(syncRequest, e, com.exalate.api.domain.ErrorEntityType.ISSUE, null, false) throw e } /* Custom Fields This line will sync Text, Option(s), Number, Date, Organization, and Labels CFs For other types of CF check documentation issue.customFields."CF Name".value = replica.customFields."CF Name".value */ //debug.error("Rankvalue is ${replica.customKeys."RankValue"?.asString()}") // Copy the customKeys field 'RankValue' to the text field 'Remote Master Rank' issue.customFields."Remote Master Rank".value = replica.customKeys."RankValue" issue.customFields."Remote Issue Key".value = replica.key