One bug should exalate with many other projects

Originally asked by Venkatesh Pokala on 23 September 2020 (original question)


Hi Team,

We have a requirement that:

1. Project A( Source project)
2. Project B, C and D ( destination projects)

Project A- Bug1 exalated to project B,C and D with different connections.

Now

Bug1 ----------> Project B(Bug1)
-----------> Project C (Bug1)
-----------> project D(Bug1)

Based on the destination bugs, source bug1 should change the status.

Till now we have done for Bug to Bug mapping but now we need for one bug and multiple destination projects bugs.

Please help us as quickly as possible.

Thanks
Venkatesh.


Answer by Francis Martens (Exalate) on 23 September 2020

> Based on the destination bugs, source bug1 should change the status.

What are the business rules


Comments:

Venkatesh Pokala commented on 23 September 2020

1. Here I have one source project and 3 destinations projects.
2. I created the 3 different connections with status mapping ( SOURCE_to_DESTProject1, SOURCE_to_DESTProject2 and SOURCE_to_DESTProject3).
3. From Source BUG1 - Exalated by using connection SOURCE_to_DESTProject1
4. From the same Source BUG1- Exalated by using connection SOURCE_to_DESTProject2
5. From the same Source BUG1- Exalated by using connection SOURCE_to_DESTProject3
6. So, now one Source BUG1 cloned to 3 Bugs to 3 different projects.
7. My CASE If all 3 BUGS moved to ā€œIN PROGRESSā€ then SOURCE BUG1 SHOULD MOVE TO ā€œIN PROGRESSā€

Hope this will clear everything.

Thanks,
Venkatesh.

Francis Martens (Exalate) commented on 23 September 2020

What you can do is to track the remote status in 3 custom fields on the source bug
When all 3 turn to ā€˜In progressā€™, you can transition the local also.

Ie

On connection 1 - add in your incoming sync

issue.customFields."Remote Status Connection 1".value = replica.status.name

On connection 2 - add in your incoming sync

issue.customFields."Remote Status Connection 2".value = replica.status.name

On connection 3 - add in your incoming sync

issue.customFields."Remote Status Connection 3".value = replica.status.name

And then in each connection add something like

if (replica.status.name == "In Progress" && issue.customFields."Remote Status Connection 2".value == "In Progress" && issue.customFields."Remote Status Connection 3".value == "In Progress") {   issue.status = "In Progress
}
Francis Martens (Exalate) commented on 25 September 2020

Hi Venkatesh Pokala

I see you raised the same question on the Atlassian community site, which is totally fine
https://community.atlassian.com/t5/Jira-discussions/One-bug-should-clone-to-many-other-projects-locally/m-p/1490575

Iā€™m just wondering if my suggestion here is not sufficient for you to continue with your implementation.

Venkatesh Pokala commented on 25 September 2020

Hi Francis Martens (Exalate),

I tried your suggested way, but not working as expected. See the below logs and other script details. I really need your quick help to proceed further.

 Impact: ISSUELocal entity: F6755-5Remote entity: LAX20-225Connection: F6755_to_LAX20Error type: Incoming sync: update sync errorError Creation Time: 2020-08-05 23:23:37.384Error Detail Message: Script error for issue F6755-5. Details: Cannot get property 'Remote Status RAX20' on null object. 
Error line: Script109.groovy:39 Error Stack Trace: com.exalate.api.exception.script.ChangeProcessorException: Script error for issue F6755-5. Details: Cannot get property 'Remote Status RAX20' on null object. 
Error line: Script109.groovy:39
	at com.exalate.error.services.ScriptExceptionCategoryService$.wrapAsChangeProcessorException(ScriptExceptionCategoryService.scala:58)
	at com.exalate.processor.jira.JiraChangeIssueProcessor.changeIssue(JiraChangeIssueProcessor.java:163)
	at com.exalate.replication.request.UpdateIssueSyncRequestState.transition(UpdateIssueSyncRequestState.java:115)
	at com.exalate.replication.request.UpdateIssueSyncRequestState.transition(UpdateIssueSyncRequestState.java:33)
	at com.exalate.replication.in.RequestProcessorService.processSyncRequest(RequestProcessorService.java:324)
	at com.exalate.replication.in.RequestProcessorService.processSyncRequestsForIssue(RequestProcessorService.java:194)
	at com.exalate.replication.in.RequestProcessorService.processSyncRequests(RequestProcessorService.java:131)
	at com.exalate.replication.in.RequestWorker$1.run(RequestWorker.java:88)
	at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService$1.run(ClusteredSensitiveExecutorService.java:32)
	at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService$1.run(ClusteredSensitiveExecutorService.java:28)
	at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService.executeHandlingLocks(ClusteredSensitiveExecutorService.java:48)
	at com.exalate.node.util.concurrent.ClusteredSensitiveExecutorService.executeHandlingLocks(ClusteredSensitiveExecutorService.java:28)
	at com.exalate.replication.in.RequestWorker.run(RequestWorker.java:78)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: com.exalate.api.exception.script.ScriptException: Cannot get property 'Remote Status RAX20' on null object. 
Error line: Script109.groovy:39
	at com.exalate.error.services.ScriptExceptionCategoryService.categorizeProcessorAndIssueTrackerExceptionsIntoScriptExceptions(ScriptExceptionCategoryService.scala:36)
	at com.exalate.processor.ExalateProcessor.executeProcessor(ExalateProcessor.java:48)
	at com.exalate.processor.jira.JiraChangeIssueProcessor.executeChangeProcessor(JiraChangeIssueProcessor.java:236)
	at com.exalate.processor.jira.JiraChangeIssueProcessor.changeIssue(JiraChangeIssueProcessor.java:139)
	... 18 more
Caused by: javax.script.ScriptException: javax.script.ScriptException: java.lang.NullPointerException: Cannot get property 'Remote Status RAX20' on null object
	at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:151)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at com.exalate.processor.ExalateProcessor.execute(ExalateProcessor.java:73)
	at com.exalate.processor.ExalateProcessor.executeProcessor(ExalateProcessor.java:46)
	... 20 more
Caused by: javax.script.ScriptException: java.lang.NullPointerException: Cannot get property 'Remote Status RAX20' on null object
	at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:348)
	at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:145)
	... 23 more
Caused by: java.lang.NullPointerException: Cannot get property 'Remote Status RAX20' on null object
	at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:57)
	at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:168)
	at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty(NullCallSite.java:44)
	at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
	at Script109.run(Script109.groovy:39)
	at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:345)
	... 24 more
Incoming sync data:  Summary:  bug multipleEntity Key:  LAX20-225(id: 344880)Encoded payload:  {"version":{"major":1,"minor":15,"patch":0},"hubIssue":{"components":[],"attachments":[],"voters":[],"customFields":{"ComponentA":{"id":14300.0,"name":"ComponentA","type":"OPTION","value":{"id":19031.0,"sequence":1.0,"value":"circle or SPC","disabled":false,"childOptions":[]}},"ComponentB":{"id":14301.0,"name":"ComponentB","type":"OPTION","value":{"id":19040.0,"sequence":0.0,"value":"APP","disabled":false,"childOptions":[]}},"Priority_HCP":{"id":10555.0,"name":"Priority_HCP","description":"","type":"OPTION","value":{"id":10675.0,"sequence":2.0,"value":"P3 (Low)","disabled":false,"childOptions":[]}},"Issue From":{"id":10560.0,"name":"Issue From","description":"Enter your account name. If issue from Support/Beta users, Kindly fill the ID Number field.","type":"OPTION","value":{"id":10712.0,"sequence":7.0,"value":"Beta","disabled":false,"childOptions":[]}}},"description":"test","project":{"id":17200.0,"key":"LAX20","name":"LAX20","lead":{"key":"fchua","active":true,"email":"Frederick.Chua@netgear.com","displayName":"Frederick Chua","username":"fchua"},"versions":[],"components":[]},"watchers":[],"fixVersions":[],"key":"LAX20-225","summary":"bug multiple","comments":[],"internalMap":{},"reporter":{"key":"pvenkatesh","active":true,"email":"Pokala.Venkatesh@netgear.com","displayName":"Venkatesh Pokala","username":"pvenkatesh"},"priority":{"id":"4","name":"Minor (P4)","description":"Minor loss of function, or other problem where easy workaround is present."},"labels":[],"customKeys":{},"workLogs":[],"issueType":{"id":"1","name":"Bug","description":"A problem which impairs or prevents the functions of the product."},"affectedVersions":[],"entityProperties":{},"status":{"id":"1","name":"OPEN","description":"The issue is open and ready for the assignee to start work on it.","category":{"id":2.0,"key":"new","name":"New"}}},"issueUrl":"https://njsdev.netgear.com/browse/LAX20-225"}
Script error for issue F6755-5. Details: Cannot get property 'Remote Status RAX20' on null object. Error line: Script109.groovy:39


Incoming script

if(firstSync && replica.project.key == "Dest1"){
issue.projectKey = "SOURCE"
issue.typeName = nodeHelper.getIssueType(replica.typeName)?.name ?: "Bug"
}
if(firstSync && replica.project.key == "SOURCE"){
issue.projectKey = "Dest1"
issue.typeName = nodeHelper.getIssueType(replica.typeName)?.name ?: "Bug"
}
if(replica.project.key == "Dest1"){
//sue.projectKey = "Dest2"
def statusMapping = ["New":"New", "OPEN":"OPEN", "To Be Fixed":"To Be Fixed", "Fixed":"Fixed", "CTS-Fixed":"CTS-Fixed", "Pending":"Pending", "Re-Open":"Re-Open"]
def remoteStatusName = replica.status.name

if (issue.project.key == "SOURCE") {
def remoteStatusDest1 = issue.customField."Remote Status Dest1".value
def remoteStatusDest2 = issue.customField."Remote Status Dest2".value

if (remoteStatusDest1 == "Rejected" && remoteStatusDest2 == "Rejected") {
issue.status = "Rejected"
}
if (remoteStatusDest1 == "Closed" && remoteStatusDest2 == "Closed") {
issue.status = "Closed"
}
}
issue.setStatus(statusMapping[remoteStatusName] ?: remoteStatusName)

}



issue.summary = replica.summary
issue.description = replica.description
issue.labels = replica.labels
issue.comments = commentHelper.mergeComments(issue, replica)
issue.attachments = attachmentHelper.mergeAttachments(issue, replica)
issue.customFields."ComponentA".value = replica.customFields."ComponentA"?.value
issue.customFields."ComponentB".value = replica.customFields."ComponentB"?.value
issue.customFields."Issue From".value = replica.customFields."Issue From"?.value
issue.customFields."Priority_HCP".value = replica.customFields."Priority_HCP"?.value
issue.customFields."16001".value = replica.status.name

Please help me on this.

Thanks,

Venkatesh.

Francis Martens (Exalate) commented on 26 September 2020

The error message is

> Cannot get property ā€˜Remote Status RAX20ā€™ on null object

The problem is on line 19 of your script. You should inspect it there.
Also your incoming script is using ā€˜issue.customFieldā€™. You should be careful as the customField array is named ā€˜issue.customFieldsā€™ (with an s)

Please review

Venkatesh Pokala commented on 28 September 2020

Hi Francis Martens (Exalate),

Seems like iā€™m closer now. Can you please me how to resolve the below error?

Cannot cast object 'OPEN' with class 'java.lang.String' to class 'com.exalate.api.domain.hubobject.v1_2.IHubStatus'. Error line: Script70.groovy:17

In coming script

if(firstSync && replica.project.key == "RAX20"){
   issue.projectKey   = "F6755"
   issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?: "Bug"
}
if(firstSync && replica.project.key == "F6755"){
   issue.projectKey   = "RAX20"
   issue.typeName     = nodeHelper.getIssueType(replica.typeName)?.name ?: "Bug"
}
//if(replica.project.key == "RAX20"){
   //def remoteStatusName = replica.status.name
  // def remoteStatusRAX20 = issue.customFields."Remote Status RAX20".value
   //def remoteStatusLAX20 = issue.customFields."Remote Status LAX20".value
if (issue.project.key == "F6755") {
   def remoteStatusRAX20 = issue.customFields."Remote Status RAX20".value
   def remoteStatusLAX20 = issue.customFields."Remote Status LAX20".value
  if (replica.status.name == "OPEN" && issue.customFields."Remote Status LAX20".value == "OPEN") {   
    issue.status = "OPEN"  

}
}

   
issue.summary      = replica.summary
issue.description  = replica.description
issue.labels       = replica.labels
issue.comments     = commentHelper.mergeComments(issue, replica)
issue.attachments  = attachmentHelper.mergeAttachments(issue, replica)
issue.customFields."ComponentA".value = replica.customFields."ComponentA"?.value
issue.customFields."ComponentB".value = replica.customFields."ComponentB"?.value
issue.customFields."Issue From".value = replica.customFields."Issue From"?.value
issue.customFields."Priority_HCP".value = replica.customFields."Priority_HCP"?.value
//issue.customFields."16001".value = replica.status.name
issue.customFields."Remote Status RAX20".value = replica.status.name
//issue.customFields."Remote Status LAX20".value = replica.status.name


Please help me

Juan Grases commented on 28 September 2020

Hi, the problem is on line:

issue.status = "OPEN"  

it should be:

issue.setStatus("OPEN")

Take into account that setStatus is case sensitive, so it would probably rather be:

issue.setStatus("Open")
Venkatesh Pokala commented on 29 September 2020

Hi @Juan,

Thanks a ton. It is working as expected. One quick question, if I have multiple bugs with one source bug. Then I need to create a separate customfield for each connection?

Thanks,

Venkatesh.