It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

scriptrunner get incoming json

Hello,

I am trying to create rest endpoint in scriptrunner to parse incoming json (webhook from another jira)

Here is an example of incoming json:

{
"any parameter": "#009900",
"issue": "S-1",
"iconUrl": "/images/icons/priorities/lowest.png",
"name": "Fred"
}

 

And my rest endpoint code (there are some extra classes):

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.PriorityManager
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls
import com.atlassian.jira.issue.fields.rest.json.beans.CommentJsonBean
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import groovy.json.JsonBuilder
import org.codehaus.jackson.map.ObjectMapper
import groovy.json.JsonSlurper
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate


doSomething(
httpMethod: "POST"
) { MultivaluedMap queryParams, String body ->

String jsonString = "body"

JsonSlurper slurper = new JsonSlurper()
Map parsedJson = slurper.parseText(jsonString)
String idValue = parsedJson.issue
String idValue2 = parsedJson.get("issue")
return "issue"
}

 My curl:

curl -X POST -H "Content-type: text/json" --data "@priority.json" http://jira_url/rest/scriptrunner/latest/custom/doSomething

When I put my json as a file I ve got errors in the response:

{
"message": "Unable to determine the current character, it is not a string, number, array, or object\n\nThe current character read is 'b' with an int value of 98\nUnable to determine the current character, it is not a string, number, array, or object\nline number 1\nindex number 0\nbody\n^",
"stack-trace": "groovy.json.JsonException: Unable to determine the current character, it is not a string, number, array, or object\n\nThe current character read is 'b' with an int value of 98\nUnable to determine the current character, it is not a string, number, array, or object\nline number 1\nindex number 0\nbody\n^\n\tat org.apache.groovy.json.internal.JsonParserCharArray.decodeValueInternal(JsonParserCharArray.java:202)\n\tat org.apache.groovy.json.internal.JsonParserCharArray.decodeValue(JsonParserCharArray.java:153)\n\tat org.apache.groovy.json.internal.JsonParserCharArray.decodeFromChars(JsonParserCharArray.java:43)\n\tat org.apache.groovy.json.internal.JsonParserCharArray.parse(JsonParserCharArray.java:380)\n\tat org.apache.groovy.json.internal.BaseJsonParser.parse(BaseJsonParser.java:110)\n\tat Script234$_run_closure1.doCall(Script234.groovy:24)\n\tat com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint$_doEndpoint_closure2.doCall(UserCustomScriptEndpoint.groovy:225)\n\tat com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint$_doEndpoint_closure2.doCall(UserCustomScriptEndpoint.groovy)\n\tat com.onresolve.scriptrunner.runner.diag.DiagnosticsManagerImpl$DiagnosticsExecutionHandlerImpl$_execute_closure1.doCall(DiagnosticsManagerImpl.groovy:345)\n\tat com.onresolve.scriptrunner.runner.diag.DiagnosticsManagerImpl$DiagnosticsExecutionHandlerImpl$_execute_closure1.doCall(DiagnosticsManagerImpl.groovy)\n\tat com.onresolve.scriptrunner.runner.ScriptExecutionRecorder.withRecording(ScriptExecutionRecorder.groovy:13)\n\tat com.onresolve.scriptrunner.runner.ScriptExecutionRecorder$withRecording.call(Unknown Source)\n\tat com.onresolve.scriptrunner.runner.diag.DiagnosticsManagerImpl$DiagnosticsExecutionHandlerImpl.execute(DiagnosticsManagerImpl.groovy:343)\n\tat com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.doEndpoint(UserCustomScriptEndpoint.groovy:215)\n\tat com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.postUserEndpoint(UserCustomScriptEndpoint.groovy:123)\n",
"status-code": "INTERNAL_SERVER_ERROR"
}

 Can someone help me?

 

Thanks a lot. 

3 answers

3 accepted

1 vote
Answer accepted
Hana Kučerová Community Leader Aug 01, 2020

Hi @Николай Киселев ,

this row seems strange to me:

String jsonString = "body"

 I think the variable jsonString would contain 4 characters "body" not the provided json data.

Hello,

I processed with the script. Now I can gather issuekeys from the text field. But I don't know how to add a comments and transition found issues

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.PriorityManager
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls
import com.atlassian.jira.issue.fields.rest.json.beans.CommentJsonBean
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import groovy.json.JsonBuilder
import org.codehaus.jackson.map.ObjectMapper
import groovy.json.JsonSlurper
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import com.atlassian.jira.user.*;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager

@BaseScript CustomEndpointDelegate delegate


doSomething(
httpMethod: "POST"
) { MultivaluedMap queryParams, String body ->


JsonSlurper slurper = new JsonSlurper()
Map parsedJson = slurper.parseText(body)
String idValue = parsedJson.issue
log.info(idValue)
String idValue2 = parsedJson.get('issue')
def output = idValue2.findAll("SUP-[0-9]+")
def IssueManager issueMgr = ComponentAccessor.getIssueManager();
Issue issue = issueMgr.getIssueObject('output')
//and here is a comment added and all found issues will be transitioned to in progress
}

I appreciate any help.  

Hana Kučerová Community Leader Aug 03, 2020

Hi,

you need to add something like this:

import com.atlassian.jira.bc.issue.IssueService
import com.atlassian.jira.workflow.JiraWorkflow
import com.atlassian.jira.issue.IssueInputParameters

ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
CommentManager commentManager = ComponentAccessor.getCommentManager()

// comment issue
String commentBody = 'comment text'
commentManager.create(issue, loggedInUser, commentBody, false)

// transition issue
IssueService issueService = ComponentAccessor.getIssueService()
JiraWorkflow workflow = ComponentAccessor.getWorkflowManager().getWorkflow(issue)

IssueInputParameters issueInputParameters = issueService.newIssueInputParameters()
String actionName = 'In Progress'
int actionId = workflow.getAllActions().findByName(actionName)?.getId()

IssueService.TransitionValidationResult transitionValidationResult = issueService.validateTransition(loggedInUser, issue.getId(), actionId, issueInputParameters)
assert transitionValidationResult.isValid(): transitionValidationResult.errorCollection

IssueService.IssueResult transitionResult = issueService.transition(loggedInUser, transitionValidationResult)
assert transitionResult.isValid(): transitionResult.errorCollection

Issue comment is quite easy, status change is more complicated, you need to provide id of the workflow transition, you want to perform.

There are a lot of nice examples available at library.adaptavist.com, e.g.:

 Hana, thank you.

I tested adding a comments but unfortunately I can't add a comment. Could you take a look?

image.png

Hana Kučerová Community Leader Aug 04, 2020

Hi,

the first parameter in the create function must be issue object, but according to the error message you are passing String variable. You need to obtain issue object somehow. Where exactly are you trying to test this script? It is still the rest enpoint section?

No, it is just a console. I want to test it before. Here is a script:


import com.atlassian.jira.user.*;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager

ApplicationUser loggedInUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
CommentManager commentManager = ComponentAccessor.getCommentManager()

def issueManager = ComponentAccessor.getIssueManager()
def issue = "SUP-1"
def issueObject = issueManager.getIssueObject(issue)

// comment issue
String commentBody = 'comment text'
commentManager.create(issue, loggedInUser, commentBody, false)
Hana Kučerová Community Leader Aug 04, 2020

Just replace "issue" with "issueObject" like this and it should work:

commentManager.create(issueObject, loggedInUser, commentBody, false)

Comment done. There was incorrect variable in the create method. fixed with:

commentManager.create(issueObject, loggedInUser, commentBody, false)

 

now I am going to check rest endpoint with the comments

Hana, could you help me with the expression to add a comment to each found issue?

I guess I should make a list of found issuekeys, make each to object issue and for each create a comment

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.PriorityManager
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls
import com.atlassian.jira.issue.fields.rest.json.beans.CommentJsonBean
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import groovy.json.JsonBuilder
import org.codehaus.jackson.map.ObjectMapper
import groovy.json.JsonSlurper
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import com.atlassian.jira.user.*;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.util.json.JSONObject

@BaseScript CustomEndpointDelegate delegate

 

doSomething(
httpMethod: "POST"
) { MultivaluedMap queryParams, String body ->

final SD_PUBLIC_COMMENT = "sd.public.comment" // needed for internal comments
CommentManager commentManager = ComponentAccessor.getCommentManager()

JsonSlurper slurper = new JsonSlurper()
Map parsedJson = slurper.parseText(body)
String idValue = parsedJson.issue

String idValue2 = parsedJson.get('summary')
def output = idValue2.findAll("SUP-[0-9]+") as List<Map> // creating a list of multiple issuekeys as string
def issueManager = ComponentAccessor.getIssueManager()
def issueObject = issueManager.getIssueObject(output).each { //I don't know how to get each found issue and create issueobject
//creating a comment
def properties = [(SD_PUBLIC_COMMENT): new JSONObject(["internal": true])]
commentManager.create(issueObject, loggedInUser, "my internal comment", null, null, new Date(), properties, true)
}
}

I did some changes, editor doesn't show critical errors, but when I put my Json to the endpoint it returns error.

2020-08-04 14:04:40,296 ERROR [common.UserCustomScriptEndpoint]: *************************************************************************************
2020-08-04 14:04:40,297 ERROR [common.UserCustomScriptEndpoint]: Script endpoint failed on method: POST doSomething
java.lang.NullPointerException
 at com.atlassian.jira.issue.comments.DefaultCommentManager.create(DefaultCommentManager.java:251)
 at com.atlassian.jira.issue.comments.DefaultCommentManager.create(DefaultCommentManager.java:218)
 at com.atlassian.jira.issue.comments.CommentManager$create$2.call(Unknown Source)
 at Script193$_run_closure1$_closure2.doCall(Script193.groovy:49)
 at Script193$_run_closure1.doCall(Script193.groovy:45)
 at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint$_doEndpoint_closure2.doCall(UserCustomScriptEndpoint.groovy:225)
 at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint$_doEndpoint_closure2.doCall(UserCustomScriptEndpoint.groovy)
 at com.onresolve.scriptrunner.runner.diag.DiagnosticsManagerImpl$DiagnosticsExecutionHandlerImpl$_execute_closure1.doCall(DiagnosticsManagerImpl.groovy:345)
 at com.onresolve.scriptrunner.runner.diag.DiagnosticsManagerImpl$DiagnosticsExecutionHandlerImpl$_execute_closure1.doCall(DiagnosticsManagerImpl.groovy)
 at com.onresolve.scriptrunner.runner.ScriptExecutionRecorder.withRecording(ScriptExecutionRecorder.groovy:13)
 at com.onresolve.scriptrunner.runner.ScriptExecutionRecorder$withRecording.call(Unknown Source)
 at com.onresolve.scriptrunner.runner.diag.DiagnosticsManagerImpl$DiagnosticsExecutionHandlerImpl.execute(DiagnosticsManagerImpl.groovy:343)
 at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.doEndpoint(UserCustomScriptEndpoint.groovy:215)
 at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint
.postUserEndpoint(UserCustomScriptEndpoint.groovy:123)

and here is a script I got

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.PriorityManager
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls
import com.atlassian.jira.issue.fields.rest.json.beans.CommentJsonBean
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import groovy.json.JsonBuilder
import org.codehaus.jackson.map.ObjectMapper
import groovy.json.JsonSlurper
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import com.atlassian.jira.user.*;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.util.json.JSONObject
import com.atlassian.jira.user.util.UserManager

@BaseScript CustomEndpointDelegate delegate

 

doSomething(
httpMethod: "POST"
) { MultivaluedMap queryParams, String body ->

final SD_PUBLIC_COMMENT = "sd.public.comment" // needed for internal comments
CommentManager commentManager = ComponentAccessor.getCommentManager()

def userManager = ComponentAccessor.getUserManager() as UserManager

def user = userManager.getUserByName("Kiseleff.trade")
log.info("obtained ${user}")

JsonSlurper slurper = new JsonSlurper()
Map parsedJson = slurper.parseText(body)
String idValue = parsedJson.issue

String idValue2 = parsedJson.get('summary')
String output = idValue2.findAll("SUP-[0-9]+") // creating a list of multiple issuekeys as string
def issueManager = ComponentAccessor.getIssueManager()
log.info("issue list ${output}")
output.each {
def issueObject = issueManager.getIssueObject(output)
def properties = [(SD_PUBLIC_COMMENT): new JSONObject(["internal": true])]
log.info("properties ${properties}")
commentManager.create(issueObject, user, "my internal comment3", null, null, new Date(), properties, true)
}
}

Hana Kučerová Community Leader Aug 04, 2020

Please, could you also attach your json file here? I need to know, how the structure of the file looks like, when there are more issue keys. Thank you.

Sure. Here is a incoming json

{
"any parameter": "#009900",
"summary": "jkrb23jkrb23jkb2jk3b SUP-1 rjk3b2sup-3k3rb3rjkb2rjkb3r2jkb SUP-3",
"iconUrl": "/images/icons/priorities/lowest.png",
"name": "Fred"
}

 

And the latest version of my script

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.PriorityManager
import com.atlassian.jira.issue.fields.rest.json.beans.JiraBaseUrls
import com.atlassian.jira.issue.fields.rest.json.beans.CommentJsonBean
import com.atlassian.jira.issue.priority.Priority
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.transform.BaseScript
import groovy.json.JsonBuilder
import org.codehaus.jackson.map.ObjectMapper
import groovy.json.JsonSlurper
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
import com.atlassian.jira.user.*;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.util.json.JSONObject
import com.atlassian.jira.user.util.UserManager

@BaseScript CustomEndpointDelegate delegate




doSomething(
httpMethod: "POST"
) { MultivaluedMap queryParams, String body ->

final SD_PUBLIC_COMMENT = "sd.public.comment" // needed for internal comments
CommentManager commentManager = ComponentAccessor.getCommentManager()

def userManager = ComponentAccessor.getUserManager() as UserManager

def user = userManager.getUserByName("Kiseleff.trade")
log.info("obtained ${user}")

JsonSlurper slurper = new JsonSlurper()
Map parsedJson = slurper.parseText(body)
String idValue = parsedJson.issue

String idValue2 = parsedJson.get('summary')
String output = idValue2.findAll("SUP-[0-9]+") as List<String> // creating a list of multiple issuekeys as string
def issueManager = ComponentAccessor.getIssueManager()
log.info("issue list ${output}")
for (item in output) {
def ddd = output.toString()
def issueObject = issueManager.getIssueObject(ddd)
def properties = [(SD_PUBLIC_COMMENT): new JSONObject(["internal": true])]
commentManager.create(issueObject, user, "my internal comment", null, null, new Date(), properties, true)
}
}
Hana Kučerová Community Leader Aug 05, 2020

Hi,

just tested the code below with the provided json, works for me.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.util.json.JSONObject
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
import groovy.transform.BaseScript
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate

doSomething(httpMethod: "POST") { MultivaluedMap queryParams, String body ->
final String SD_PUBLIC_COMMENT = "sd.public.comment" // needed for internal comments
final String REGEX = "SUP-[0-9]+"
final String USERNAME = "Kiseleff.trade"
final String COMMENT_BODY = "my internal comment"

CommentManager commentManager = ComponentAccessor.getCommentManager()
IssueManager issueManager = ComponentAccessor.getIssueManager()
UserManager userManager = ComponentAccessor.getUserManager()
ApplicationUser user = userManager.getUserByName(USERNAME)
Map<String,JSONObject> commentProperties = [(SD_PUBLIC_COMMENT): new JSONObject(["internal": true])]
JsonSlurper jsonSlurper = new JsonSlurper()
String summaryValue = jsonSlurper.parseText(body).summary
summaryValue.findAll(REGEX).each {issueKey ->
Issue issue = issueManager.getIssueObject(issueKey)
commentManager.create(issue, user, COMMENT_BODY, null, null, new Date(), commentProperties, true)
}
return Response.ok(new JsonBuilder([abc: 42]).toString()).build()
}

Hana,

thank you very much. I appreciate your patience. 

Now it works like a charm! 

Suggest an answer

Log in or Sign up to answer
TAGS
Community showcase
Published in Confluence Cloud

Enhancements to the Confluence Mobile App

  Hey Community! I’m Stephanie Zhang, a Product Manager along with @Wei on the Confluence mobile app. Our team has been hard at work to deliver helpful enhancements to the Confluen...

169 views 0 9
Read article

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you