2
1
0

Hello,

We have the following use-case:


Jira (cloud) - Service-Now integration.


We have in service now a field called "Assignment level".  It can be 1,2,3 or 4. 


When this value changes in service-now, we want to add a comment in Jira with the level and the current assignment group. We achieved this by adding the following code:


    //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")
    }

This works fine with one exception. It also adds the comment when the issue is created in service-now, and we have only added this code in the else part of:

if(firstSync){ do stuff, but not add the assignment level anywhere}
else {
	this is where the above code is added
}

So the Jira ticket that gets created also immediately adds a comment with the message: "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".

Could we somehow stop this message at creation?

Thank you!
    CommentAdd your comment...

    2 answers

    1.  
      1
      0
      -1

      We found that it wasn't a problem of the code, but that in Service now we have a script adding those values a few seconds after the creation.

        CommentAdd your comment...
      1.  
        1
        0
        -1

        Can you provide the full code of your incoming sync - Jira side?

        1. Mihai Arama

          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!

        2. Francis Martens (Exalate)

          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?


        3. Mihai Arama

          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!

        4. Mihai Arama

          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!

        5. Francis Martens (Exalate)

          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.


        6. Mihai Arama

          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:


          <div style="display: none;">---BEGIN---</div>
          <p>Details:</p>
          <ol style="list-style-position: inside;">
          <li>Username of affected user(s):&nbsp; &nbsp; &nbsp;ex: ukdemo@hilti.biz</li>
          <li>Device Manufacturer and Model:&nbsp; &nbsp; &nbsp;ex: Apple iPhone X</li>
          <li>Device Operating System:&nbsp; &nbsp; &nbsp;ex: iOS 11.2.6</li>
          <li>Affected tools and their Serial Numbers (if applicable):&nbsp; &nbsp; &nbsp;ex: Hilti DX 5 (64632488) , Hilti SD 6H-A22 (15645625)</li>
          <li>Mobile Application version:&nbsp; &nbsp; &nbsp;ex: Hilti Connect v1.2.2</li>
          <li>Steps to reproduce:&nbsp; &nbsp; &nbsp;ex: Open the mobile application, attempt to login with username&nbsp;<a href="mailto:ukdemo@hilti.biz" rel="nofollow">ukdemo@hilti.biz</a>&nbsp;- got error message: System is busy</li>
          <li>Date &amp; Time when issue occurred:&nbsp; &nbsp; &nbsp;ex: 26-02-2018 - 13:15 CET</li>
          <li>Troubleshooting performed:&nbsp; &nbsp; &nbsp;ex: Attempted login on Android phone - login successful; Attempted login with different username on same phone - login failed</li>
          <li>Other details:&nbsp; &nbsp; ex: Other colleagues with different iOS phones can login successfully with this username</li>
          </ol>
          <div style="display: none;">---END—


          Do you think this could be, somehow, the cause?


          Thank you!

        CommentAdd your comment...