scriptrunner get incoming json

Николай Киселев July 31, 2020

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

Suggest an answer

Log in or Sign up to answer
1 vote
Answer accepted
Hana Kučerová
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 1, 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.

0 votes
Answer accepted
Николай Киселев August 4, 2020

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

Николай Киселев August 4, 2020

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)
Николай Киселев August 4, 2020

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
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 4, 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.

Николай Киселев August 5, 2020

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
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 5, 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()
}
Николай Киселев August 11, 2020

Hana,

thank you very much. I appreciate your patience. 

Now it works like a charm! 

0 votes
Answer accepted
Николай Киселев August 3, 2020

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
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 3, 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.:

Николай Киселев August 3, 2020

 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
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 4, 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?

Николай Киселев August 4, 2020

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
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
August 4, 2020

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

commentManager.create(issueObject, loggedInUser, commentBody, false)
Николай Киселев August 4, 2020

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

TAGS
AUG Leaders

Atlassian Community Events