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

Next challenges

Recent achievements

  • Global
  • Personal

Recognition

  • Give kudos
  • Received
  • Given

Leaderboard

  • Global

Trophy case

Kudos (beta program)

Kudos logo

You've been invited into the Kudos (beta program) private group. Chat with others in the program, or give feedback to Atlassian.

View group

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

Debug Scriptrunner Listener script Edited

We have implemented a Listener Script to sum up story points to the Epic. The script is working as expected, but we are seeing some errors in the logs. The error occurs against some issues, but not all. What is the best way to "debug" where these errors are coming from? Not knowing what is causing the errors, I am not sure how to debug. I think it may be occurring against Stories that have a Story Point of 0, but I am not sure. The error we see is:
CorrelationId: d09ae111-14a2-4e5d-b2e4-357b61af6377
RUN Script identifier: 71a41f53-a120-410b-b762-7be45295cd66 com.adaptavist.sr.cloud.events.WebhookExecution (jira:issue_updated webhook fired for issue ST-1936)
Script name: Sum child story points and add to parent Epic Took: 616ms Logs:
2020-12-11 16:03:33.109 ERROR - Cannot invoke method size() on null object
2020-12-11 16:03:33.170 ERROR - Class: com.adaptavist.sr.cloud.events.WebhookExecution, Config: null

The script itself does not fail, and the Story Points are summed, it's just logging an error that, if I can "catch", I could resolve/avoid the error in the log.

Any suggestion on how to enhance logging/debugging?

The script that is running: 

// Get the ID of the fields for Story Points and Epic Link
def storyPointsField = get("/rest/api/2/field").asObject(List).body.find {(it as Map).name == 'Story Points'}.id
def epicLinkField = get("/rest/api/2/field").asObject(List).body.find {(it as Map).name == 'Epic Link'}.id

// Retrieve all the issues in this issues' Epic
def epicKey = issue.fields."${epicLinkField}"
def issuesInEpic = get("/rest/agile/1.0/epic/${epicKey}/issue")
        .asObject(Map)
        .body
        .issues as List<Map>
logger.info("Total issues in Epic for ${epicKey}: ${issuesInEpic.size()}")

// Sum the estimates
def estimate = issuesInEpic.collect { Map issueInEpic ->
    issueInEpic.fields."${storyPointsField}" ?: 0
}.sum()
logger.info("Summed estimate: ${estimate}")

// Now update the parent Epic
def result = put("/rest/api/2/issue/${epicKey}")
    .queryString("overrideScreenSecurity", Boolean.TRUE)
    .header('Content-Type', 'application/json')
    .body([
        fields: [
                "${storyPointsField}": estimate,
        ]
    ])
    .asString()

// check that updating the parent issue worked
assert result.status >= 200 && result.status < 300

1 answer

1 accepted

1 vote
Answer accepted

Hi @Jeanne Howe I checked the documentation (https://scriptrunner-docs.connect.adaptavist.com/jiracloud/logs.html) and it looks like there is Logs screen in the script runner:

Selection_094.png

You can log messages in your script using following methods:

  • logger.trace
  • logger.debug
  • logger.info
  • logger.warn
  • logger.error

Hi Martin,

I think the issue causing the error is that some Stories do not have an Epic Link. 

I know I can add a condition to be evaluated before the listener runs. Do you know what the format of the condition would be if I wanted to verify the issue has an Epic Link? Would it be something like this:

issue.issueType.name.match('^(Story|Bug|Task)$') != null and link.issueLinkType.name.match == ('^(Epic-Story Link)$')

Can this be done as a condition, or do I need some type of IF statement in the listener script itself?

Hi @Jeanne Howe sorry, I thought you needed to point to a place where the log message are displayed.

When I'm checking your code and error message, I would suggest you to wrap following part of code with IF condition:

if(issuesInEpic){

logger.info("Total issues in Epic for ${epicKey}: ${issuesInEpic.size()}")

// Sum the estimates
def estimate = issuesInEpic.collect { Map issueInEpic ->
    issueInEpic.fields."${storyPointsField}" ?: 0
}.sum()
logger.info("Summed estimate: ${estimate}")

// Now update the parent Epic
def result = put("/rest/api/2/issue/${epicKey}")
    .queryString("overrideScreenSecurity", Boolean.TRUE)
    .header('Content-Type', 'application/json')
    .body([
        fields: [
                "${storyPointsField}": estimate,
        ]
    ])
    .asString()

// check that updating the parent issue worked
assert result.status >= 200 && result.status < 300

}

Is it what you needed? Or can you clarify it further? 

Hi @Martin Bayer _MoroSystems_ s_r_o__  Thank you. I did something very similar to this (once I figured out the IF statement). My code looks like this:

// Get the ID of the fields for Story Points and Epic Link
def storyPointsField = get("/rest/api/2/field").asObject(List).body.find {(it as Map).name == 'Story Points'}.id
def epicLinkField = get("/rest/api/2/field").asObject(List).body.find {(it as Map).name == 'Epic Link'}.id

// Retrieve all the issues in this issues' Epic
def epicKey = issue.fields."${epicLinkField}"
logger.info("Epic Key is: " + epicKey)

if (epicKey != null) { //This is to check if the event.issue's epic is null
def issuesInEpic = get("/rest/agile/1.0/epic/${epicKey}/issue")
.asObject(Map)
.body
.issues as List<Map>
logger.info("Total issues in Epic for ${epicKey}: ${issuesInEpic.size()}")

// Sum the estimates
def estimate = issuesInEpic.collect { Map issueInEpic ->
issueInEpic.fields."${storyPointsField}" ?: 0
}.sum()
logger.info("Summed estimate: ${estimate}")

// Now update the parent Epic
def result = put("/rest/api/2/issue/${epicKey}")
.queryString("overrideScreenSecurity", Boolean.TRUE)
.header('Content-Type', 'application/json')
.body([
fields: [
"${storyPointsField}": estimate,
]
])
.asString()

// check that updating the parent issue worked
assert result.status >= 200 && result.status < 300
}

hi @Jeanne Howe ,so is it working now?🙂

Yes, it is working and it is no longer writing errors for those issues without an Epic Link.

 

Thank you!

@Martin Bayer _MoroSystems_ s_r_o__ 

May I ask you one more question about my listener script.

After running with no errors for several days, I am now seeing an error code -

returned an error code: status: 429 - Too Many Requests
body: java.lang.RuntimeException: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
 at [Source: (String)"<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Oops - an error has occurred</title><link type='text/css' rel='stylesheet' href='/static-assets/metal-all.css' media='all'><script src='/static-assets/metal-all.js'></script><!--[if lt IE 9]><link type='text/css' rel='stylesheet' href='/static-assets/metal-all-ie.css' media='all'><script src='/static-assets/metal-all-ie.js'></script><![endif]--><!--[if IE 9]><link type='text/css"[truncated 1422 chars]; line: 1, column: 2]
2020-12-23 17:16:37.210 ERROR - Cannot get property 'issues' on null object on line 10
2020-12-23 17:16:37.211 ERROR - Class: com.adaptavist.sr.cloud.events.WebhookExecution, Config: null

This appears to be happening at the "get" call at the start of the IF statement:

if (epicKey != null) { //This is to check if the event.issue's epic is null
def issuesInEpic = get("/rest/agile/1.0/epic/${epicKey}/issue")
.asObject(Map)
.body
.issues as List<Map>
logger.info("Total issues in Epic for ${epicKey}: ${issuesInEpic.size()}")

 

I think the issue may be that one or more Stories in the Epic do not have any story Points assigned. Can I nest an IF statement to check the Epic Key and check the Story Point field? Something like this:

if (epicKey != null) && (storyPointsField != null)

I am unsure of how to capture the information coming back from the "get" call to log it and find the error. Is there a way to put the IF statement, or the entire script, into a debug mode so that everything gets logged?

 

Jeanne

Hi @Jeanne Howe I think you are getting error because you have "too much requests". Each subscription plan has limitation of rest API requests which can be done.  This information is not published anywhere (if nothing changed :)) because it is calculated based on the platform workload etc. More information can be found here:

https://developer.atlassian.com/cloud/jira/platform/rate-limiting/

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PRODUCT PLAN
STANDARD
TAGS
Community showcase
Published in Jira

Announcing the waitlist for Jira Work Management

Hey there Cloud Community members! We’re excited to give you the first glimpse of the new home for business teams on Jira — Jira Work Management. Jira Work Management is the next generation of J...

159 views 3 7
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