Missed Team ’24? Catch up on announcements here.

×
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

need groovy script to invoke external link in post function

Aditya D July 6, 2021

Hi,

I have an curl command to trigger an external url. Need some help on script runner groovy script for below command format.

curl --location --request POST 'https://XXXX.XXXX.com:443/api/1/rest/slsched/feed/XXXXXXXXXX/projects/SXXXXXX%20xxxxx/JIRA-Access-TEST%20Task' \ --header 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxx' \ --header 'Content-Type: application/json' \ --data-raw '[ { "Request": { "issueKey": "JJIM-26", "issueId": "This is passthorugh response" } } ]'

 

Thanks in advance.

Regards,

Aditya.D

1 answer

1 accepted

Suggest an answer

Log in or Sign up to answer
0 votes
Answer accepted
Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 7, 2021

Hi

You could execute the curl command as a shell command using the "execute()" method available on groovy strings.

def cmd = """curl --location --request POST 'https://XXXX.XXXX.com:443/api/1/rest/slsched/feed/XXXXXXXXXX/projects/SXXXXXX%20xxxxx/JIRA-Access-TEST%20Task' \ --header 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxx' \ --header 'Content-Type: application/json' \ --data-raw '[ { "Request": { "issueKey": "JJIM-26", "issueId": "This is passthorugh response" } } ]'"""
def process = command.execute()
def sOut = new StringBuilder()
def sErr = new StringBuilder()
process.consumeProcessOutput(sOut,sErr)
process.waitForOrKill(60000) //milliseconds... timeout

Then you could process the sOut strings

Or you can use some native html processing classes.

import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import groovyx.net.http.ContentType
def httpBuilder = new HTTPBuilder(https://XXXX.XXXX.com:443)
def response = httpBuilder.request(Method.POST, ContentType.JSON){
uri.path = "/api/1/rest/slsched/feed/XXXXXXXXXX/projects/SXXXXXX%20xxxxx/JIRA-Access-TEST%20Task"
headers.Authorization = "Bearer xxxxxxxxxxxxxxxxxxxx"
body = [Request:[issueKey:"JJIM-26", issueId:""]]

response.success = { response, json ->
return json
}
response.failure = { resp, data ->
log.error " httprequest failed: $data"
return null
}
}

This will give you some native parsing of the response and response error handling etc.

Aditya D July 8, 2021

Hi Peter-Dave,

Thanks for the script. 

I tried to run the first script, throwing below error:

 image.png

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 12, 2021

You can either escape the \ or change the type of groovy string. The dollar-slashy string is perfect for this use case:

(also, I had an error in the script where I called the command string "cmd" but then tried to execute as if I had called it "command"

Here it is fully corrected

def cmd = $/curl --location --request POST 'https://XXXX.XXXX.com:443/api/1/rest/slsched/feed/XXXXXXXXXX/projects/SXXXXXX%20xxxxx/JIRA-Access-TEST%20Task' \ --header 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxx' \ --header 'Content-Type: application/json' \ --data-raw '[ { "Request": { "issueKey": "JJIM-26", "issueId": "This is passthorugh response" } } ]'/$
def process = cmd.execute()
def sOut = new StringBuilder()
def sErr = new StringBuilder()
process.consumeProcessOutput(sOut,sErr)
process.waitForOrKill(60000) //milliseconds... timeout
Like Aditya D likes this
Aditya D July 13, 2021

Thanks again Peter-Dave for valuable script. Could you help me out with two more improvements.

1. First : "Issue key" & "issue id" has to come dynamically. I'm placing this script in post function. As soon status changed, script should pick the "issuekey" and "issuekey id" of that issue. 

2. Second :  No transaction success information on issue page. Is it possible to print transaction success code/ log info on issue page  like activity tab/history/worklog. Some where we can refer as soon as transition is completed. 

 

BR,

Aditya.D

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 13, 2021

I think given your use case, I would strongly recommend using the httpbuilder approach rather than the curl approach.

Then, with post function, there are a couple of things you can do for telling the user this took place. 

1) You can display a flag 
2) You can generate a fake history record

Here is a full example:

import com.atlassian.jira.component.ComponentAccessor
import
groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import groovyx.net.http.ContentType
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.history.ChangeItemBean
import com.atlassian.jira.issue.history.ChangeLogUtils

def apiBase = "https://XXXX.XXXX.com:443"
def apiPath = "/api/1/rest/slsched/feed/XXXXXXXXXX/projects/SXXXXXX%20xxxxx/JIRA-Access-TEST%20Task"

def httpBuilder = new HTTPBuilder(apiBase)
def response = httpBuilder.request(Method.POST, ContentType.JSON){
uri.path = apiPath
headers.Authorization = "Bearer xxxxxxxxxxxxxxxxxxxx"
body = [Request:[issueKey:issue.key, issueId:"this is passed through response"]]

response.success = { response, json ->
return json
}
response.failure = { resp, data ->
log.error " httprequest failed: $data"
return null
}
}

def flag = [type:'success',close:'auto']
def message = ""
if(response){
//here you can incorporate some data from the response into the message
message = "Succesfully posted to external api ($apiBase) with response: $response.issueId"
} else {
message = "There was an error posting data to external API. Please consult the Jira log"
flag.type = 'error'
flag.close = 'manual'
}

//use the next two line to display a flag to the user
flag.body = message
UserMessageUtil.flag(flag)

//use the following lines to create the fake issue history
//such fake issue history need to be given a "field name". That name doesn't have to exist or match an existing field
def historyFieldName = "POST RESULT" // <-change this to whatever makes sense to you
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def changeHolder = new DefaultIssueChangeHolder();
def changeItemBean = new ChangeItemBean(
ChangeItemBean.CUSTOM_FIELD, historyFieldName , "", "", "", message)
changeHolder.addChangeItem(changeItemBean);
def changeGroup = ChangeLogUtils.createChangeGroup(currentUser, issue, issue, changeHolder.getChangeItems(), false);
Aditya D July 14, 2021

Hi Peter-Dave, 

Facing some error on the script, Could you check and fix them. Also IssueId has to get dynamically while post function option. Could you include the request in the code. 

Attached the error screen shots for reference.

BR,

Aditya.Dimage.png

 

image.png

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 14, 2021

If you look at line 17

body = [Request:[issueKey:issue.key]]

The issue object is provided by the script context. You can click on the question mark below the script editor to see all the variables provided by the scriptrunner script context. So in this case, we are setting the issueKey value in the body object to the key property of the issue object.

Most of these errors you see in the script are normal. The editor attempts to determine what type each variable is and if these types are appropriate for where they are used. But since groovy is not a strictly typed language, there are some things that the editor can't confirm. So it displays an error so that the coder can review and make sure it's appropriate.

Ultimately, you have to test the execution and review the logs to see what works.

The only error that I can't confirm if it will work or not is the one on line 32 since I haven't seen what your response json will look like to be sure if "$response.issueId" is valid. You can remove the .issueId part at least to start to get the full response.

Aditya D July 14, 2021

Thanks Dave-Peter for detailed explanation. I run the code and got below error

2021-07-14 16:52:06,427 ERROR [runner.ScriptBindingsManager]:  httprequest failed: [response_map:[error_list:[[message:Unknown task: SchneiderDev/projects/Siddharth%20Shankar/JIRA-Access-TEST%20Task]]], http_status_code:404]

 BR,

Aditya.D

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 14, 2021

That looks like an error from your external endpoint.

http_status_coded:404 means "not found"

Are you sure this URI is correct?

SchneiderDev/projects/Siddharth%20Shankar/JIRA-Access-TEST%20Task
Aditya D July 21, 2021

Thanks again Peter-Dave for the response.

I was able to run the code successful. But found one bug in the code. Post call is not passing the issuekey and issueid.  Could you please check?

 

I have code like : 

body = [Request:[issueKey:issue.key, issueId:"$response.issueId"]]
Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 21, 2021

I don't know why you are attempting to use $response in the body... presumably that doesn't exist.

Are you trying to pass the id of the curret issue?

If so, it should look like this:

body = [Request:[issueKey:issue.key, issueId: issue.id as String]

What do you get when you output this?

log.info new groovy.json.JsonBuilder(body).toPrettyString()

 Can you give a full example of what you expect the body to look like?

Aditya D July 26, 2021

Hello Dave-Peter,

When i update the change , still error persists. 

 

Here is the log

2021-07-26 11:29:40,805 ERROR [workflow.AbstractScriptWorkflowFunction]: Workflow script has failed on issue JJIM-38 for user 'admin'. View here: https://jira-development.schneider-electric.com:8443/secure/admin/workflows/ViewWorkflowTransition.jspa?workflowMode=live&workflowName=JJIM%3A+Simplified+workflow&descriptorTab=postfunctions&workflowTransition=41&highlight=1
groovy.lang.MissingPropertyException: No such property: body for class: Script258
at Script258.run(Script258.groovy:53)

 

Root cause found

We are trying to pass "issue.key" and "issue.id" along post request.  Post API is calling without triggering without boby value ({"errorMessages":["The field 'key' does not support searching for EMPTY values."],"errors":{}})

 

Full script for quick reference :

Note : Masking some values for security reasons. 

import com.atlassian.jira.component.ComponentAccessor
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import groovyx.net.http.ContentType
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.history.ChangeItemBean
import com.atlassian.jira.issue.history.ChangeLogUtils

def apiBase = "https://elastic.xxxxxxxx.com:443"
def apiPath = "/api/1/rest/xxxxxxx/feed/xxxxxxxxx/JAMA/JIRA-JAMA_issueSync/JIRA-JAMA_issueSync_OnDemand_TrigTask"

def httpBuilder = new HTTPBuilder(apiBase)
def response = httpBuilder.request(Method.POST, ContentType.JSON){
uri.path = apiPath
headers.Authorization = "Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
body = [Request:[issueKey:issue.key, issueId: issue.id as String]]


response.success = { response, json ->
return json
}
response.failure = { resp, data ->
log.error " httprequest failed: $data"
return null
}
}

def flag = [type:'success',close:'auto']
def message = ""
if(response){
//here you can incorporate some data from the response into the message
message = "Succesfully posted to external api ($apiBase) with response: $response.issueId"
println "${issue.key}"
} else {
message = "There was an error posting data to external API. Please consult the Jira log"
flag.type = 'error'
flag.close = 'manual'
}

//use the next two line to display a flag to the user
flag.body = message
UserMessageUtil.flag(flag)

//use the following lines to create the fake issue history
//such fake issue history need to be given a "field name". That name doesn't have to exist or match an existing field
def historyFieldName = "POST RESULT" // <-change this to whatever makes sense to you
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def changeHolder = new DefaultIssueChangeHolder();
def changeItemBean = new ChangeItemBean(ChangeItemBean.CUSTOM_FIELD, historyFieldName , "", "", "", message)
changeHolder.addChangeItem(changeItemBean);
def changeGroup = ChangeLogUtils.createChangeGroup(currentUser, issue, issue, changeHolder.getChangeItems(), false);
log.info new groovy.json.JsonBuilder(body).toPrettyString()

 

 

 

Thanks,

Aditya.D

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 26, 2021

The error you shared from your log points to the last line of the script.

This is not surprising, that line should be in the same scope where the body variable is defined.

Move that line to line #17 and try again.

Share the logs that this generates

Aditya D July 27, 2021

Hi Peter-Dave, 

Tried with below script, got the attached logs. Script run successful, but the problem remains same. 

One request : Is it possible for you to join on teams call for quick resolution??

Note : Masking some value for security reasons. 

import com.atlassian.jira.component.ComponentAccessor
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import groovyx.net.http.ContentType
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.history.ChangeItemBean
import com.atlassian.jira.issue.history.ChangeLogUtils

def apiBase = "https://elastic.xxxxxxxx.com:443"
def apiPath = "/api/1/rest/xxxxxxx/feed/xxxxxxxxx/JAMA/JIRA-JAMA_issueSync/JIRA-JAMA_issueSync_OnDemand_TrigTask"

def httpBuilder = new HTTPBuilder(apiBase)
def response = httpBuilder.request(Method.POST, ContentType.JSON){
uri.path = apiPath
headers.Authorization = "Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
body = [Request:[issueKey:issue.key, issueId: issue.id as String]]

log.info new groovy.json.JsonBuilder(body).toPrettyString()

 




response.success = { response, json ->
return json
}
response.failure = { resp, data ->
log.error " httprequest failed: $data"
return null
}
}

def flag = [type:'success',close:'auto']
def message = ""
if(response){
//here you can incorporate some data from the response into the message
message = "Succesfully posted to external api ($apiBase) with response: $response.issueId"
println "${issue.key}"
} else {
message = "There was an error posting data to external API. Please consult the Jira log"
flag.type = 'error'
flag.close = 'manual'
}

//use the next two line to display a flag to the user
flag.body = message
UserMessageUtil.flag(flag)

//use the following lines to create the fake issue history
//such fake issue history need to be given a "field name". That name doesn't have to exist or match an existing field
def historyFieldName = "POST RESULT" // <-change this to whatever makes sense to you
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def changeHolder = new DefaultIssueChangeHolder();
def changeItemBean = new ChangeItemBean(ChangeItemBean.CUSTOM_FIELD, historyFieldName , "", "", "", message)
changeHolder.addChangeItem(changeItemBean);
def changeGroup = ChangeLogUtils.createChangeGroup(currentUser, issue, issue, changeHolder.getChangeItems(), false);

Regards,

Aditya.D

image.png

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
July 27, 2021

Hi Aditya

I hope you understand that I do not work for nor do I represent Atlassian or Adaptivist. I'm simply a user of their products and I choose to volunteer some of my time to help others in the community as they helped me when I was getting started.

So, joining a team call is strongly out of the question.

That being said, I can suggest that you add some additional debugging messages so you will get a better idea of what's going on, and perhaps you can find the reason yourself.

If not, feel free to post the logs output.

Here is a full script with all the logs:

import com.atlassian.jira.component.ComponentAccessor
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import groovyx.net.http.ContentType
import com.onresolve.scriptrunner.runner.util.UserMessageUtil
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.history.ChangeItemBean
import com.atlassian.jira.issue.history.ChangeLogUtils
import groovy.json.JsonBuilder
import org.apache.log4j.Level

log.setLevel(Level.DEBUG) //remove this after running and manually update your log levels in jira to keep log file managable
log.info "Starting posfunction for $issue.key"
def apiBase = "https://elastic.xxxxxxxx.com:443"
def apiPath = "/api/1/rest/xxxxxxx/feed/xxxxxxxxx/JAMA/JIRA-JAMA_issueSync/JIRA-JAMA_issueSync_OnDemand_TrigTask"
def payload = [Request:[issueKey:issue.key, issueId: issue.id as String]]
def payLoadJson = new JsonBuilder(payload).toPrettyString()
def httpBuilder = new HTTPBuilder(apiBase)
def response = httpBuilder.request(Method.POST, ContentType.JSON){
uri.path = apiPath
headers.Authorization = "Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
body = payload
response.success = { response, json ->
log.info "httprequest successful"
return json
}
response.failure = { resp, data ->
log.error " httprequest failed: $data"
return null
}
}
log.info "http request finsished"

def flag = [type:'success',close:'auto']
def message = ""
if(response){
log.info "http request had a valid response: $response"
//here you can incorporate some data from the response into the message
message = "Succesfully posted to external api ($apiBase) with response: $response.issueId"
} else {
message = "There was an error posting data to external API. Please consult the Jira log"
flag.type = 'error'
flag.close = 'manual'
}

//use the next two line to display a flag to the user
flag.body = message
UserMessageUtil.flag(flag)

log.info "creating history entry"
//use the following lines to create the fake issue history
//such fake issue history need to be given a "field name". That name doesn't have to exist or match an existing field
def historyFieldName = "POST RESULT" // <-change this to whatever makes sense to you
def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def changeHolder = new DefaultIssueChangeHolder();
def changeItemBean = new ChangeItemBean(ChangeItemBean.CUSTOM_FIELD, historyFieldName , "", "", "", message as String)
log.info "built a changeItemBean: $changeItemBean"
changeHolder.addChangeItem(changeItemBean);
def changeGroup = ChangeLogUtils.createChangeGroup(currentUser, issue, issue, changeHolder.getChangeItems(), false);
log.info "changeItemBean has been submitted and changeGroup was created: $changeGroup"
gnanavelu_murthy December 1, 2021

Hi  @Peter-Dave Sheehan 

I've gone through this post, is something which more relates to my requirement. I've JIRA cloud site and Jenkins cloud with jobs are all configured parameterized jobs for different environments. Now i want to trigger build from JIRA ticket based on ticket status change. I am not able to do using send web request method on native jira cloud automation options. I dont use any adaptavist and script runner plugin. How can i achieve this automation part. If it is achieve through code via api, can you provide the steps for where we have to configure and code part. 

Advance thanks for your inputs. If it works out well, it will reduce our big hectic works.

Thanks

Gnanavelu

Peter-Dave Sheehan
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
December 1, 2021

@gnanavelu_murthy I only have experience with calling groovy scripts from adaptavist  scriptrunner and only on server/dc instance. I've never used jira cloud and don't know of any ways to trigger groovy scripts without adaptavist scriptrunner.

gnanavelu_murthy December 27, 2021

Thanks for reply @Peter-Dave Sheehan 

Can you provide script for want to populate multiselect dropdown list in subtask create screen the options should change based on parent ticket value of single select choice.

I tried this in subtask create transition---validators using script runner validator, but not able to achieve.

TAGS
AUG Leaders

Atlassian Community Events