Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,298,064
Community Members
 
Community Events
165
Community Groups

Accumulate Story Points on Parent based on Sub: Task story points

Hello,

I want the Story Points field for the parent story to be the sum of the sub-tasks. In my jira server instance we are using Script runner plugin and is it possible to sum up all sub task story points to parent issue story point. Please help me how to achieve this issue.

For example: 

If parent issue had 2 story points and sub task had 1 story point and I need sum up both 2+1=3 on Parent.

 

Thanks,

Siva.

4 answers

1 accepted

Hi @siva,

I changed the code as follows:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.index.IssueIndexingService

def issue = event.issue
def eventName = ComponentAccessor.eventTypeManager.getEventType(event.eventTypeId).name
def cfStoryPoints = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName("Estimated Story Points").first()

if (issue.parentObject != null) {
def subTasks = ComponentAccessor.subTaskManager.getSubTaskObjects(issue.parentObject)
int intStoryPoints = (issue.parentObject.getCustomFieldValue(cfStoryPoints) != null ? ((issue.parentObject.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0)
/*subTasks.each {
intStoryPoints += (it.getCustomFieldValue(cfStoryPoints) != null ? ((it.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
}*/
cfStoryPoints.updateValue(null, issue.parentObject, new ModifiedValue(issue.parentObject.getCustomFieldValue(cfStoryPoints), intStoryPoints as Double), new DefaultIssueChangeHolder())
ComponentAccessor.getComponent(IssueIndexingService).reIndex(issue.parentObject)
} else {
def subTasks = ComponentAccessor.subTaskManager.getSubTaskObjects(issue)
int intStoryPoints = (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
subTasks.each {
intStoryPoints += (it.getCustomFieldValue(cfStoryPoints) != null ? ((it.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
}
cfStoryPoints.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(cfStoryPoints), intStoryPoints as Double), new DefaultIssueChangeHolder())
ComponentAccessor.getComponent(IssueIndexingService).reIndex(issue)
}
Check if it's ok for you.

@Andrea Pannitti 

Tested the above script this also performed like previous script calculates the all subtask story points again when 2nd subtask created.

Once again will explain it

I had created issue story and story point was 2 under story created subtask-1  and story point is 1. So far the script working fine it calculated 2+1=3.

Now this time created 2nd subtask-2  and story point is 2 now suppose to calculate parent + subtask-2 i.e  3+2=5.  But our script calculates parent + subtask-1 +subtask-2 i.e 3+1+2=6

Thank,

Siva

@siva,

I've commented out a few lines in the code above; can you check if the behavior is what you expect?

@Andrea Pannitti 

Thank you very much finally it start working as i expert and finally one more last modification in the script is it any possibility to update  Estimated Story Points in parent when existing subtasks story points are updated and also when subtask is deleted. As of now the present script working fine when subtask is created and also I'm attaching the screen shot how I configure the script in listener. Once again thank you very much for your help and very appreciated.

Story Point issue .png

Thanks,

Siva.

@Andrea Pannitti 

Please help me on this issue the whole team waiting for your response

Hi @siva,

from what you wrote in your last post, I thought the problem was completely solved.
Thank you very much for appreciating the help I have given you but I don't think I can devote myself further to this issue.

Hi @siva,

replace this line:

int intStoryPoints = 0 + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0)

with the following:

int intStoryPoints = (issue.parentObject.getCustomFieldValue(cfStoryPoints) as Integer) + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0) 

@Andrea Pannitti 

Thanks for the reply and changes done on the script what you mention in above comment and it start working now it calculates parent story points also. But coming to script it works perfectly only when single Sub Task and  if parent had two subtasks it counts twice.

For example:

If we created  Sub Task-1 and story point is 2 here it counts well (assume parent story point is 2) Parent+2=4

Now if we created another  Sub Task-2 and story point is 2 and it suppose to count 4+2=6 but our script counts parent+ 'Sub Task-1'+ 'Sub Task-2' that is 4+2+2=8. It can't calculate individual Sub Task it counts the all Sub Task to parent when 2nd Sub Task is created. Here the modified script below.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.index.IssueIndexingService

def issue = event.issue
def eventName = ComponentAccessor.eventTypeManager.getEventType(event.eventTypeId).name
def cfStoryPoints = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName("Estimated Story Points").first()

if (issue.parentObject != null) {
def subTasks = ComponentAccessor.subTaskManager.getSubTaskObjects(issue.parentObject)
int intStoryPoints = (issue.parentObject.getCustomFieldValue(cfStoryPoints) as Integer) + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0)
subTasks.each {
intStoryPoints += (it.getCustomFieldValue(cfStoryPoints) != null ? ((it.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
}
cfStoryPoints.updateValue(null, issue.parentObject, new ModifiedValue(issue.parentObject.getCustomFieldValue(cfStoryPoints), intStoryPoints as Double), new DefaultIssueChangeHolder())
ComponentAccessor.getComponent(IssueIndexingService).reIndex(event.issue)
}

 

Thanks,

Siva

@Andrea Pannitti 

Please help me how to solve this issue.

Hi @siva,

to solve your issue you could add a Script Listener to your project on Issue Created and Issue Updated events with the following code:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.index.IssueIndexingService

def issue = event.issue
def eventName = ComponentAccessor.eventTypeManager.getEventType(event.eventTypeId).name
def cfStoryPoints = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName("Original Story points").first()

if (issue.parentObject != null) {
def subTasks = ComponentAccessor.subTaskManager.getSubTaskObjects(issue.parentObject)
int intStoryPoints = 0 + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0)
subTasks.each {
intStoryPoints += (it.getCustomFieldValue(cfStoryPoints) != null ? ((it.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
}
cfStoryPoints.updateValue(null, issue.parentObject, new ModifiedValue(issue.parentObject.getCustomFieldValue(cfStoryPoints), intStoryPoints as Double), new DefaultIssueChangeHolder())
ComponentAccessor.getComponent(IssueIndexingService).reIndex(event.issue)
}

@Andrea Pannitti 

 

Thanks for your reply and I created Script Listener with Created  and Issue Updated events with the following code:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.index.IssueIndexingService

def issue = event.issue
def eventName = ComponentAccessor.eventTypeManager.getEventType(event.eventTypeId).name
def cfStoryPoints = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName("Estimated Story points").first()

if (issue.parentObject != null) {
def subTasks = ComponentAccessor.subTaskManager.getSubTaskObjects(issue.parentObject)
int intStoryPoints = 0 + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0)
subTasks.each {
intStoryPoints += (it.getCustomFieldValue(cfStoryPoints) != null ? ((it.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
}
cfStoryPoints.updateValue(null, issue.parentObject, new ModifiedValue(issue.parentObject.getCustomFieldValue(cfStoryPoints), intStoryPoints as Double), new DefaultIssueChangeHolder())
ComponentAccessor.getComponent(IssueIndexingService).reIndex(event.issue)
}

 

But I'm getting the error on implementing the script here the error logs below

2022-06-24 21:11:52,007 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2022-06-24 21:11:52,007 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: null
java.util.NoSuchElementException: Cannot access first() element from an empty List
at Script58.run(Script58.groovy:8)

 

Please suggest me where i modified the script and just letting you the field name you are using for story point is Estimated Story Points.

 

Thanks,

Siva

Hi @siva,

the issue could depends by the fact that the custom field name is "Estimated Story Points" but you writed "Estimated Story points" in the code. Upper and lower cases are importants.

@Andrea Pannitti 

Thanks for the reply and I updated "Estimated Story Points" field with correct lettering  in  the script and it is start working. But the present script sum up only Sub-Tasks Estimated Story Points and didn't calculate the Parent one. 

For example:

If parent had 3 Estimated Story Points and Sub-Task-1 had 5 Story Points and  Sub-Task-2 had 6 story points then normally calculates 3+5+6=14 story points but our present script calculates only Sub-Tasks 5+6=11 and this 11 updated on Parent  "Estimated Story Points" where as 3 parent story point totally gone. Please help me where i modified the script and your help very appreciated. Here the script below

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.index.IssueIndexingService

def issue = event.issue
def eventName = ComponentAccessor.eventTypeManager.getEventType(event.eventTypeId).name
def cfStoryPoints = ComponentAccessor.customFieldManager.getCustomFieldObjectsByName("Estimated Story Points").first()

if (issue.parentObject != null) {
def subTasks = ComponentAccessor.subTaskManager.getSubTaskObjects(issue.parentObject)
int intStoryPoints = 0 + (eventName == "Issue Created" ? (issue.getCustomFieldValue(cfStoryPoints) != null ? ((issue.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0) : 0)
subTasks.each {
intStoryPoints += (it.getCustomFieldValue(cfStoryPoints) != null ? ((it.getCustomFieldValue(cfStoryPoints).toString() as Double) as Integer) : 0)
}
cfStoryPoints.updateValue(null, issue.parentObject, new ModifiedValue(issue.parentObject.getCustomFieldValue(cfStoryPoints), intStoryPoints as Double), new DefaultIssueChangeHolder())
ComponentAccessor.getComponent(IssueIndexingService).reIndex(event.issue)
}

 

 

Thanks,

Siva.

0 votes

Before you do this, it's important to understand if you are trying to use Jira to support an Agile way of working.  If you are, then you don't want to be adding story points up to the parent.

Suggest an answer

Log in or Sign up to answer
TAGS

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