Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

sum up linked issue field on epic in Jira Cloud

Jon
Contributor
March 11, 2019

I am working on a script runner listener script that sums up the values for a field (MT Loaded) in all the issues linked to an epic and places them in the epic MT Loaded field. Working off a script runner example for subtasks I have this:

// Get the parent issue as a Map
def parent = (issue.fields as Map).parent as Map

// Retrieve all the subtasks of this issue's parent
def parentKey = parent.key

// Get the field ids
def fields = get('/rest/api/2/field')
.asObject(List)
.body as List<Map>

// Get the story points custom field to use in the script
def MTLoadedField = fields.find { it.name == "MT Loaded" }.id
logger.info("The id of the MT Loaded field is: $MTLoadedField")

// Note: The search API is limited that to only be able to return a maximum of 50 results
def allSubtasks = get("/rest/api/2/search")
.queryString("jql", "parent=${parentKey}")
.queryString("fields", "parent,$MTLoadedField")
.asObject(Map)
.body
.issues as List<Map>

logger.info("Total subtasks for ${parentKey}: ${allSubtasks.size()}")

// Sum the estimates
def sumMTLoaded = allSubtasks.collect { Map subtask ->
subtask.fields[MTLoadedField] ?: 0

}.sum()
logger.info("Summed MT Loaded: ${sumMTLoaded}")

// Store the summed MT Loaded on the MT Loaded field of the parent issue
def summedMTLoadedField = fields.find { it.name == "MT Loaded" }.id

logger.info("Custom field ID to update: ${summedMTLoadedField}")

// Now update the parent issue
def result = put("/rest/api/2/issue/${parentKey}")
.header('Content-Type', 'application/json')
.body([
fields: [
(summedMTLoadedField): sumMTLoaded
]
])
.asString()

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

But I am stuck in modifying the example to look up the linked epic instead of subtask parent. 

Can anyone advise? 

1 answer

0 votes
Aleksandr Zuevich
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 12, 2019

Hi,

 

You should work with Epic Link issue custom field instead of parent.

Jon
Contributor
March 12, 2019

Hi Aleksandr, 

I've tweaked my code to look at the Epic Link field instead of parent, and it does seem to work (please excuse the hardcoded ID). However it seems the script is executing twice, the second time with a failure. 

// Get the parent issue as a Map
//def parent = (issue.fields as Map).parent as Map

// Retrieve all the subtasks of this issue's parent
//def parentKey1 = parent.key

// Get the field ids
def fields = get('/rest/api/2/field')
.asObject(List)
.body as List<Map>

//Get the Epic
def parentKey = issue.fields.customfield_10013
logger.info("The value of the Epic Link field is: $parentKey")

// Get the MT Loaded custom field to use in the script
def MTLoadedField = fields.find { it.name == "MT Loaded" }.id
logger.info("The id of the MT Loaded field is: $MTLoadedField")

// Note: The search API is limited that to only be able to return a maximum of 50 results
def IssuesInEpic = get("/rest/api/2/search")
.queryString("jql", "'Epic Link'=${parentKey}")
.queryString("fields", "'Epic Link',$MTLoadedField")
.asObject(Map)
.body
.issues as List<Map>

logger.info("Total issues in epic for ${parentKey}: ${IssuesInEpic.size()}")

// Sum the estimates
def sumMTLoaded = IssuesInEpic.collect { Map issue ->
issue.fields[MTLoadedField] ?: 0

}.sum()
logger.info("Summed MT Loaded: ${sumMTLoaded}")

// Store the summed MT Loaded on the MT Loaded field of the parent issue
def summedMTLoadedField = fields.find { it.name == "MT Loaded" }.id

logger.info("Custom field ID to update: ${summedMTLoadedField}")

// Now update the parent issue
def result = put("/rest/api/2/issue/${parentKey}")
.header('Content-Type', 'application/json')
.body([
fields: [
(summedMTLoadedField): sumMTLoaded
]
])
.asString()

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

The first log entry is success:

2019-03-13 00:59:50.280 INFO - Serializing object into 'interface java.util.List'
2019-03-13 00:59:50.294 INFO - GET /rest/api/2/field asObject Request Duration: 403ms
2019-03-13 00:59:50.312 INFO - The value of the Epic Link field is: ES-542
2019-03-13 00:59:50.313 INFO - The id of the MT Loaded field is: customfield_10049
2019-03-13 00:59:50.793 INFO - Serializing object into 'interface java.util.Map'
2019-03-13 00:59:50.812 INFO - GET /rest/api/2/search asObject Request Duration: 479ms
2019-03-13 00:59:50.813 INFO - Total issues in epic for ES-542: 6
2019-03-13 00:59:50.814 INFO - Summed MT Loaded: 570.753
2019-03-13 00:59:50.815 INFO - Custom field ID to update: customfield_10049
2019-03-13 00:59:51.542 INFO - PUT /rest/api/2/issue/ES-542 asString Request Duration: 725ms

 But there is a second entry with a failure that I don't understand:

2019-03-13 00:59:53.130 INFO - Serializing object into 'interface java.util.List'
2019-03-13 00:59:53.134 INFO - GET /rest/api/2/field asObject Request Duration: 360ms
2019-03-13 00:59:53.135 INFO - The value of the Epic Link field is: null
2019-03-13 00:59:53.136 INFO - The id of the MT Loaded field is: customfield_10049
2019-03-13 00:59:53.564 INFO - Serializing object into 'interface java.util.Map'
2019-03-13 00:59:53.593 INFO - GET /rest/api/2/search asObject Request Duration: 441ms
2019-03-13 00:59:53.632 INFO - Total issues in epic for null: 50
2019-03-13 00:59:53.633 INFO - Summed MT Loaded: 0
2019-03-13 00:59:53.634 INFO - Custom field ID to update: customfield_10049
2019-03-13 00:59:53.861 WARN - PUT request to /rest/api/2/issue/null returned an error code: status: 404 - Not Found
body: {"errorMessages":["Issue does not exist or you do not have permission to see it."],"errors":{}}
2019-03-13 00:59:53.863 INFO - PUT /rest/api/2/issue/null asString Request Duration: 224ms
2019-03-13 00:59:53.865 ERROR - assert result.status >= 200 && result.status < 300
       |      |      |      |  |      |      |
       |      404    true   |  |      404    false
       |                    |  status: 404 - Not Found
       |                    |  body: {"errorMessages":["Issue does not exist or you do not have permission to see it."],"errors":{}}
       |                    false
       status: 404 - Not Found
       body: {"errorMessages":["Issue does not exist or you do not have permission to see it."],"errors":{}} on line 53
2019-03-13 00:59:53.872 ERROR - Class: com.adaptavist.sr.cloud.events.WebhookExecution, Config: null

I have little to no scripting skills and just get by with using example code. Can you advise where my issue is? 

Jon
Contributor
March 12, 2019

Actually I figured out what's happening. When my script first executes it updates the Epic, which triggers the script to run again. But my script isn't coded to handle a case where the change is in the epic, it's in the issue. 

Suggest an answer

Log in or Sign up to answer