Avoid creating a new issue if it already exists

Originally asked by Serhiy Onyshchenko on 18 May 2022 (original question)


I’d like to exalate an issue from source side, but on destination I’d like to find the corresponding issue, and if it exists, connect the source issue to it instead of creating a new one on destination.


Answer by Serhiy Onyshchenko on 18 May 2022

Here’s an example I made for GitHub > Jira Cloud, where I’d used the Jira Cloud REST API to find the issue on Jira end corresponding to the GitHub issue. If Exalate finds one, I’m asking Exalate to link the GitHub issue to it.
As icing on the top, I’d also configured Exalate to avoid syncing comments that were already present.

Jira’s Incoming sync script:

def issueMapping = [
    "11":"DEV-6"
]
def localIssueKey = issueMapping[replica.key]
def c = new JiraClient(httpClient)
if (firstSync && localIssueKey) {
    def searchResult = c.http(
        "GET",
        "/rest/api/2/search",
        ["jql":["key=${localIssueKey}".toString()],"fields":["id,key"]],
        null,
        [:]
    ) { response ->
        if (response.code >= 300) {
            debug.error("GET /rest/api/2/search?jql=key%3D$localIssueKey failed: ${response.body}")
        } else {
          def js = new groovy.json.JsonSlurper()
          def json = js.parseText(response.body)
          json
        }
    }
    def paginate = { offset, results, getPageFn, getResultsFn ->
        def page = getPageFn(offset)
        def r = getResultsFn(page)
        results.addAll(r)
        if (page.total > 50 || page.startAt + page.maxResults < page.total) {
            return paginate(offset + page.maxResults, results, getPageFn, getResultsFn)
        } 
        return results
    }
    if(searchResult.issues.size() == 1) {
        def localIssue = searchResult.issues.first()
        issue.id = localIssue.id as String
        
        def jiraComments = paginate(
            0, [], { offset ->
                def commentResult = c.http(
                    "GET",
                    "/rest/api/2/issue/${localIssueKey}/comment",
                    ["startAt":[offset as String],"maxResults":[50 as String]],
                    null,
                    [:]
                ) { response ->
                    if (response.code >= 300) {
                        debug.error("GET /rest/api/2/issue/${localIssueKey}/comment?startAt=$offset&maxResults=50 failed: ${response.body}")
                    } else {
                      def js = new groovy.json.JsonSlurper()
                      def json = js.parseText(response.body)
                      json
                    }
                }
            }, { page -> 
                page.comments
            }
        )
        
        def commentsAndTraces = replica
            .addedComments
            .inject([comments:[], addedTraces:[]]) { result, comment ->
                
                def originatedOnGitHubSyncedToJira = { -> jiraComments.any { _c -> _c.author.accountId == "557058:c020323a-70e4-4c07-9ccc-3ad89b1c02ec" && _c.body.endsWith("commented: "+comment.body) } }
                def originatedInJiraSyncedToGitHub = { -> jiraComments.any { _c -> comment.author.key == "43809577" && comment.body.endsWith("commented: "+_c.body) } }

                if(!originatedOnGitHubSyncedToJira() && !originatedInJiraSyncedToGitHub()) {
                    result.comments += comment
                } else {
                    def trace = new com.exalate.basic.domain.BasicNonPersistentTrace(
                            com.exalate.api.domain.twintrace.TraceType.COMMENT,
                            null,
                            comment.remoteId as String,
                            com.exalate.api.domain.twintrace.TraceAction.NONE,
                            false
                    )
                    result.addedTraces += trace
                }
                result
            }
        replica.addedComments = commentsAndTraces.comments
        traces.addAll(commentsAndTraces.addedTraces)
        issue.comments     = commentHelper.mergeComments(issue, replica)
        issue.customKeys.somethingChanged = true
        return
    }
}

if(firstSync){
   issue.projectKey   = "DEV" 
   // 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)
issue.labels       = replica.labels


Happy Exalating!
Serhiy.


Answer by Elyashiv on 02 August 2022

Hi,

I’m using a local exalate - between 2 issues on the same Jira server instance.

How can I use this method in order to create a Jira-issue-link between the issues when connecting 2 already existingissues? and not when creating a new issue using exalate script

Thanks

CC: Harold Oconitrillo


Comments:

Serhiy Onyshchenko commented on 07 August 2022

Hey, Elyashiv

Same strategy: in the incoming script assign the issue.id property to point to the related issue, make sure to fill in the issue.projectKey and issue.typeName properties (so that Exalate’s validation of the issue variable doesn’t fail), use Jira API to create the issue link (for example, like this: https://docs.idalko.com/exalate/x/SQSOAQ).

Please, let me know if you have any questions.

Regards, Serhiy.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.