Answer by Francis Martens (Exalate) on 15 March 2022
Can you provide the full code of your incoming sync - Jira side?
Comments:
Mihai Arama commented on 15 March 2022
Hi,
Sure.
if(firstSync){
issue.projectKey = "ESNIT"
// 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.key + " - " + replica.summary
issue.description = nodeHelper.toMarkDownFromHtml(replica.description_html)
issue.customFields."URL".value = remoteIssueUrl
// Priority sync
def priorityMapping = [
// Snow incident priority <-> Jira issue priority
"1 - Critical": "Blocker",
"2 - High": "Major",
"3 - Medium": "Minor",
"4 - Low": "Trivial"
]
def defaultPriority = "Low"
def priorityName = priorityMapping[replica.priority?.name] ?: defaultPriority // set default priority in case the proper urgency could not be found
issue.priority = nodeHelper.getPriority(priorityName)
// this part will add the hardcoded "PROD" and "CST" values + the values from 4 service-now fields, if they exist, to the jira labels;
// also adding the H Software Product and the HSP Categories values to Components
def listOfLabels = ['PROD', 'CST']
def listOfComponents = []
if (replica.H_software_product) {
def HSoftwareProductValue = replica.H_software_product.display_value
def noSpacesHSofwareProductValue = HSoftwareProductValue.replaceAll(" ","_")
listOfLabels.add(noSpacesHSofwareProductValue)
listOfComponents.add(HSoftwareProductValue)
}
if (replica.H_spc1) {
def HSoftwareProductCategory1Value = replica.H_spc1.display_value
def noSpacesHSoftwareProductCategory1Value = HSoftwareProductCategory1Value.replaceAll(" ","_")
listOfLabels.add(noSpacesHSoftwareProductCategory1Value)
listOfComponents.add(HSoftwareProductCategory1Value)
}
if (replica.H_spc2) {
def HSoftwareProductCategory2Value = replica.H_spc1.display_value
def noSpacesHSoftwareProductCategory2Value = HSoftwareProductCategory2Value.replaceAll(" ","_")
listOfLabels.add(noSpacesHSoftwareProductCategory2Value)
listOfComponents.add(HSoftwareProductCategory2Value)
}
if (replica.H_spc3) {
def HSoftwareProductCategory3Value = replica.H_spc1.display_value
def noSpacesHSoftwareProductCategory3Value = HSoftwareProductCategory3Value.replaceAll(" ","_")
listOfLabels.add(noSpacesHSoftwareProductCategory3Value)
listOfComponents.add(HSoftwareProductCategory3Value)
}
def project = issue.project ?: nodeHelper.getProject(issue.projectKey)
for (eachComponent in listOfComponents){
def component = nodeHelper.getComponent(eachComponent, project)
if(!component) {nodeHelper.createComponent(
issue,
eachComponent,
null,
null,
null
)
def newComponent = nodeHelper.getComponent(eachComponent, project)
issue.components += newComponent
} else {issue.components += component}
}
for (eachLabel in listOfLabels){
issue.labels += nodeHelper.getLabel(eachLabel)
}
// this part will create a mapping between the SNOW Country and Jira MO, and add the field value.
def CountryToMOMapping = [
// Snow incident country <-> Jira issue MO
"BR": "Brazil",
"DE": "Germany"
]
def defaultMO = "Brazil"
def MOName = CountryToMOMapping[replica.country.display_value] ?: defaultMO // set default MO in case the proper MO could not be found
issue.customFields."MO".value = MOName //sets the MO in Jira
//using the above created MOName, map the MO to a Region, and set it in Jira
def MOToRegionMapping = [
"Brazil": "W2",
"Germany": "E3"
]
def regionName = MOToRegionMapping[MOName]
issue.customFields."Region".value = regionName
/* def MOToHubLeaderMapping = [
"Brazil": "mihai.arama@externals.H.com",
"Germany": "sascha.g@H.com"
]
def defaultUser = nodeHelper.getUserByEmail(MOToHubLeaderMapping[MOName]) */
issue.reporter = nodeHelper.getUserByEmail(replica.opened_by) // ?: defaultUser
issue.attachments = attachmentHelper.mergeAttachments(issue, replica)
issue.customFields."SAP Customer Nr.".value = replica.H_customer.display_value
// if(issue.description[-1] != issue.description) {
// issue.description = commentHelper.mergeComments(issue, replica)
//}
} else {
def statusMapping = ["Closed (resolved)":"Done"]
def remoteStatusName = replica.state
if (remoteStatusName == "Closed (resolved)") {
issue.setStatus(statusMapping[remoteStatusName] ?: remoteStatusName)
}
if (!replica.state.equals(previous?.state)) {
statusCommentString = "The Service-Now ticket's status is: " + replica.state
issue.comments = commentHelper.addComment(statusCommentString, issue.comments)
}
//issue.attachments = attachmentHelper.mergeAttachments(issue, replica)
//issue.description = nodeHelper.toMarkDownFromHtml(replica.description_html)
//issue.comments = commentHelper.mergeComments(issue, replica)
if (!replica.description_html[0] && !replica.description_html.equals(previous?.description_html)) {
descriptionCommentString = "The Service-Now ticket's Description was updated to: " + "\n" + nodeHelper.toMarkDownFromHtml(replica.description_html)
issue.comments = commentHelper.addComment(descriptionCommentString, issue.comments)
}
issue.attachments += replica.addedAttachments
//issue.comments += replica.addedinternalworknotes
if (!replica.internalworknotes.equals(previous?.internalworknotes)) {
fullInternalWorkNotes = nodeHelper.toMarkDownFromHtml(replica.internalworknotes)
// each new internal comment in service now starts with a \n\n ...
def newRowDouble = fullInternalWorkNotes.indexOf("\n\n")
// if \n\n is found, take left side
if(newRowDouble != -1) {
latestInternalNotes = fullInternalWorkNotes.substring(0, newRowDouble);
} else {
latestInternalNotes = fullInternalWorkNotes
}
workNotesCommentString = "New Service-Now Internal Work Notes were added: " + "\n" + latestInternalNotes
issue.comments = commentHelper.addComment(workNotesCommentString, issue.comments)
}
//this next part handles escalation and de-escalation on the service now ticket
if (replica.assignment_level > (previous?.assignment_level)){
escalationCommentString = "The Service-Now ticket has been escalated. The new assignment level is: " + replica.assignment_level + " and the assignment group is: " + replica.assignment_group.display_value
issue.comments = commentHelper.addComment(escalationCommentString, issue.comments)
issue.setStatus("Backlog")
}
if (replica.assignment_level < (previous?.assignment_level)){
deescalationCommentString = "The Service-Now ticket has been de-escalated. The new assignment level is: " + replica.assignment_level + " and the assignment group is: " + replica.assignment_group.display_value
issue.comments = commentHelper.addComment(deescalationCommentString, issue.comments)
issue.setStatus("Backlog")
}
}
/*
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
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
*/
/*
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
*/
Thank you for your quick reply!
Francis Martens (Exalate) commented on 15 March 2022
This code segment looks very impressive.
Can you add a debug.error statement to the right block and see why the ‘addComment’ is being triggered?
Mihai Arama commented on 16 March 2022
Hi Francis,
I’m not sure if I added it correctly.
if (replica.description_html.equals(previous?.description_html)) {
descriptionCommentString = "The Service-Now ticket's Description was updated to: " + "\n" + nodeHelper.toMarkDownFromHtml(replica.description_html)
issue.comments = debug.error(commentHelper.addComment(descriptionCommentString, issue.comments))
}
I now get this:
No signature of method: com.exalate.hubobject.jira.DebugHelper.error() is applicable for argument types: (ArrayList) values: [[BasicHubComment{@body=`The Service-Now ticket’s Description was updated to: ---BEGIN--- Short description of problem Attach screenshot of any error messages AT Doc Software version Computer information (operating system, connected to internet, re-installation tried) Attach software log files ---END---`, @id=`null`, @remoteId=`null`, @author=`null`, @created=`null`, @updateAuthor=`null`, @updated=`null`, @group=`null`, @role=`null`, @internal= `true`, @executor= `null`}]] Possible solutions: error(java.lang.String), every(), iterator(), grep(), macro(groovy.lang.Closure), print(java.io.PrintWriter)
But I assume that’s not how the debug statement should be used. Any tips there, please?
Thank you!
Francis Martens (Exalate) commented on 16 March 2022
Nope - clearly not
Check details
https://docs.idalko.com/exalate/display/ED/debug.error
Just add it on its own line
Mihai Arama commented on 16 March 2022
Hello,
I tried adding it like this:
if (replica.description_html.equals(previous?.description_html)) {
descriptionCommentString = "The Service-Now ticket's Description was updated to: " + "\n" + nodeHelper.toMarkDownFromHtml(replica.description_html)
issue.comments = commentHelper.addComment(descriptionCommentString, issue.comments)
debug.error(commentHelper.addComment(descriptionCommentString, issue.comments))
}
and I get:
No signature of method: com.exalate.hubobject.jira.DebugHelper.error() is applicable for argument types: (ArrayList) values: [[BasicHubComment{@body=`The Service-Now ticket’s Description was updated to: ---BEGIN--- Short description of problem Attach screenshot of any error messages AT Doc Software version Computer information (operating system, connected to internet, re-installation tried) Attach software log files ---END---`, @id=`null`, @remoteId=`null`, @author=`null`, @created=`null`, @updateAuthor=`null`, @updated=`null`, @group=`null`, @role=`null`, @internal= `true`, @executor= `null`}, …]] Possible solutions: error(java.lang.String), every(), iterator(), grep(), macro(groovy.lang.Closure), print(java.io.PrintWriter)
Also, just adding debug.error() does not get me anything.
Also, I do not actually get an error, I just get the value synchronized in a moment when I don’t need it synchronized.
Please let me know if you have any suggestions.
Thank you!
Francis Martens (Exalate) commented on 16 March 2022
a) debug.error expects a string. commentHelper.addComment is returning a comment array so that can not work
With debug.error - you can print out the value of certain variables, like
debug.error(“The value of firstSync is ${firstSync}”)
b) try to understand why that section of the code is being executed by looking at the logic and find out why it is getting there.
Mihai Arama commented on 16 March 2022
Hello,
Thank you for the explanation.
I used two statements:
if (!replica.description_html.equals(previous?.description_html)) {
descriptionCommentString = "The Service-Now ticket's Description was updated to: " + "\n" + nodeHelper.toMarkDownFromHtml(replica.description_html)
issue.comments = commentHelper.addComment(descriptionCommentString, issue.comments)
//debug.error("The value of the previous description is ${previous?.description_html}")
//debug.error("The value of the current description is ${replica.description_html}")
}
This is the output for them:
The value of the previous description is
Details:
Username of affected user(s): ex: ukdemo@hilti.biz
Device Manufacturer and Model: ex: Apple iPhone X
Device Operating System: ex: iOS 11.2.6
Affected tools and their Serial Numbers (if applicable): ex: Hilti DX 5 (64632488) , Hilti SD 6H-A22 (15645625)
Mobile Application version: ex: Hilti Connect v1.2.2
Steps to reproduce: ex: Open the mobile application, attempt to login with username ukdemo@hilti.biz - got error message: System is busy
Date & Time when issue occurred: ex: 26-02-2018 - 13:15 CET
Troubleshooting performed: ex: Attempted login on Android phone - login successful; Attempted login with different username on same phone - login failed
Other details: ex: Other colleagues with different iOS phones can login successfully with this username
The value of the current description is
Details:
Username of affected user(s): ex: ukdemo@hilti.biz
Device Manufacturer and Model: ex: Apple iPhone X
Device Operating System: ex: iOS 11.2.6
Affected tools and their Serial Numbers (if applicable): ex: Hilti DX 5 (64632488) , Hilti SD 6H-A22 (15645625)
Mobile Application version: ex: Hilti Connect v1.2.2
Steps to reproduce: ex: Open the mobile application, attempt to login with username ukdemo@hilti.biz - got error message: System is busy
Date & Time when issue occurred: ex: 26-02-2018 - 13:15 CET
Troubleshooting performed: ex: Attempted login on Android phone - login successful; Attempted login with different username on same phone - login failed
Other details: ex: Other colleagues with different iOS phones can login successfully with this username
I compared the texts and they appear to be the same.
However, in service-now, this is a text field for which I can get the HTML source code, which is:
---BEGIN---
Details:
-
Username of affected user(s): ex: ukdemo@hilti.biz
-
Device Manufacturer and Model: ex: Apple iPhone X
-
Device Operating System: ex: iOS 11.2.6
-
Affected tools and their Serial Numbers (if applicable): ex: Hilti DX 5 (64632488) , Hilti SD 6H-A22 (15645625)
-
Mobile Application version: ex: Hilti Connect v1.2.2
-
Steps to reproduce: ex: Open the mobile application, attempt to login with username [hilti.biz](mailto:ukdemo@<a href=)" rel=“nofollow”>ukdemo@hilti.biz - got error message: System is busy
-
Date & Time when issue occurred: ex: 26-02-2018 - 13:15 CET
-
Troubleshooting performed: ex: Attempted login on Android phone - login successful; Attempted login with different username on same phone - login failed
-
Other details: ex: Other colleagues with different iOS phones can login successfully with this username
---END—
Do you think this could be, somehow, the cause?
Thank you!