Custom Exalate "connectFeatureToFeature" script query

Originally asked by Sahil Yadav on 02 February 2024 (original question)


Hi Team,

We have a custom script which simulates Exalate “Connect” operation as below during first sync.

Scenario Flow (Customer Jira to Our Jira):

  1. User creates a Feature manually in our Jira.
  2. Customer user creates feature manually in their Jira providing a label with our Feature key created in Step-1.
  3. With the help of our feature key mentioned in Customer Jira, while establishing first sync, we are using below small custom script:

Script snippet

if (firstSync) {

if(replica.typeName == “Feature”){
connectFeatureToFeature()
}

}

void connectFeatureToFeature() {
String projectKey = issue.getProjectKey()
final String INTERNAL_KEY_REGEX = “^${projectKey}-\\d+”

Issue jiraSyncedIssue = ComponentAccessor.getIssueManager().getIssueObject(issue.getKey())

IHubLabel label = getLabelOfIssueKeyPerRegex(jiraSyncedIssue, INTERNAL_KEY_REGEX)

if (label) {

String issueKey = label.getLabel()

Issue jiraIssue = ComponentAccessor.getIssueManager().getIssueObject(issueKey) if(jiraIssue){

[issue.id](http://issue.id) = jiraIssue.getId() as Long

}

}

}

The major problem we are facing in this situation is:

We are able to successfully connect Customer Feature to our exiting Feature by script, but whatever Attachments and Comments were previously added by our user during Feature creation are getting deleted/removed during first sync only.

Incoming script line used for syncing comments as below:

issue.comments = commentHelper.mergeComments(issue, replica)

and we do not have any incoming script for syncing attachments so we were expecting that our side attachments should remain as it is.

Note: All other system fields and customfield values remain as it is and it is working as expected.

So, could you please suggest on how to resolve issue only for attachments and comments?


Answer by Sahil Yadav on 27 February 2024

Thankyou Syed. It is working fine now after updating scripts as suggested below.


Comments:

Syed Majid Hassan commented on 27 February 2024

Glad to hear that!

Thanks

Majid

Answer by Kiran Kalyani Barhanpure on 12 March 2024

Hello Syed Majid Hassan

After adding above script we are facing below issue.

we have found a bug that due to this script, None of the customField values are getting updated during first sync in our Production. Once we trigger another update, then only customfield values are updated.

Thanks,
Kiran Barhanpure


Answer by Sahil Yadav on 05 March 2024

Hello Majid,

we have found a bug in above script… all the process works well related to attachment and comments but during first sync activity none of the customFields values get updated. Only system fields get updated due to this provided script.

Could you please provide a fix for this issue?

Thanks,

Sahil Yadav


Comments:

Syed Majid Hassan commented on 12 March 2024

Hi Sahil,

If you review my script, it does not deal with any custom fields at all, as you would not expect it to. I have no idea about the configuration on your end regarding custom fields. But you can extend the script to include the custom fields, Or vice versa i.e. include my firstSync block in your existing code.

Hope it helps.

Thanks

Majid

Kiran Kalyani Barhanpure commented on 13 March 2024

Hello Syed Majid Hassan

On the Amdocs side, we already have your provided scipt in firstSync, so the problem is that none of the customField values are getting updated during the first sync in our production. Once we trigger another update, then only custom field values are updated. If we remove your script, it works as expected.

So which part of your script is blocking sync changes in the first sync?

Syed Majid Hassan commented on 13 March 2024

If you review the firstSync block, it has no mention of any custom fields.

You need to add your custom fields within the firstSync block for them to be updated on the first event please.

Sahil Yadav commented on 22 March 2024

Hello Majid,

we have not added customfields in firstSync block for more than 2 years and still it worked before and Even today, if we remove your new script it works where we only simply mention script line as :

issue.id = jiraIssue.id

The only issue with above single line is it removes existing attachments and comments and thats why we are trying to add your script to avoid it. But it does not mean that we had to add all customFields in firstSync block.

As soon as we add new lines provided here, it stops working. So there must be something that is creating problem by adding your scripts. Do let us know if you would like to setup a call with screen sharing to resolve this issue?

Answer by Syed Majid Hassan on 16 February 2024

Hi Sahil Yadav,

I was able to reproduce your scenario and resolve it. The video attachment has the details, but here is the script that I used in the Incoming (you will need to modify it to use the logic of your labels etc.):

Expand source

import com.atlassian.jira.component.ComponentAccessor

if(firstSync){
   issue.projectKey   = "SYEDB" 
   issue.typeName     = nodeHelper.getIssueType(replica.type?.name, issue.projectKey)?.name ?: "Task"
   
   def issueManager = ComponentAccessor.issueManager
   def mainIssue = issueManager.getIssueByCurrentKey(replica.customFields."Majids Field"?.value)
 
    if (mainIssue){     
        // Connect through Exalate
        def issueKey = new com.exalate.basic.domain.BasicIssueKey(mainIssue.id, mainIssue.key)
        def hubObjVersion = new com.exalate.basic.domain.BasicSemanticVersion(1, 0, 0);
        def hubObjectHelperFactory = com.atlassian.jira.component.ComponentAccessor
          .getOSGiComponentInstanceOfType(com.exalate.api.hubobject.IHubObjectHelperFactory.class)
        def hubObjectHelper = hubObjectHelperFactory.get(hubObjVersion)
        def hubIssue = hubObjectHelper.getHubIssueOnOutgoingProcessor(issueKey)
        hubIssue.getProperties().each { k, v ->
            issueBeforeScript[k] = v
            if (v instanceof Map) {
                def newV = [:]
                newV.putAll(v)
                issue[k] = newV
            } else {
                issue[k] = v
            }
        }
        hubIssue.entrySet().each { entry ->
           def k = entry.key
           def v = entry.value
           issueBeforeScript.putAll([k:v])
           issue.putAll([k:v])
        }
        issueBeforeScript.id = null
        issue.id = mainIssue.id
        issue.key = mainIssue.key
        issue.customKeys.somethingIsChanged = true

        // take care of comments, attahchments and workLogs:
        replica.comments.each { replicaComment ->
            // Check if the comment already exists in the local issue based on author email, creation date, and content
            def existingComment = issue.comments.find { 
                it.body == replicaComment.body
            }
            if (existingComment) {
                def trace = new com.exalate.basic.domain.BasicNonPersistentTrace()
                 .setType(com.exalate.api.domain.twintrace.TraceType.COMMENT)
                 .setToSynchronize(true)
                 .setLocalId(existingComment.id as String) 
                 .setRemoteId(replicaComment.remoteId as String)
                 .setAction(com.exalate.api.domain.twintrace.TraceAction.NONE)
                traces.add(trace)
            }
        }
        replica.attachments.each { replicaAttachment ->

            def existingAttachment = issue.attachments.find {
                it.filename == replicaAttachment.filename &&
                it.filesize == replicaAttachment.filesize
            }
        
            if (existingAttachment) {
                def trace = new com.exalate.basic.domain.BasicNonPersistentTrace()
                    .setType(com.exalate.api.domain.twintrace.TraceType.ATTACHMENT)
                    .setToSynchronize(true)
                    .setLocalId(existingAttachment.id as String) 
                    .setRemoteId(replicaAttachment.remoteId as String)
                    .setAction(com.exalate.api.domain.twintrace.TraceAction.NONE)
                traces.add(trace)
            }
            return issueKey
        }
    }
}
issue.summary      = replica.summary
issue.description  = replica.description
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)
issue.labels       = replica.labels

Video explanation:

Hope it helps.

Thanks

Majid