Just a heads up: On March 24, 2025, starting at 4:30pm CDT / 19:30 UTC, the site will be undergoing scheduled maintenance for a few hours. During this time, the site might be unavailable for a short while. Thanks for your patience.
×Hi
We use Agile in our organisation. And one of the metrics that our PMs are interested in is to track the epic progress in units of time spent, time remaining and original estimate of all the stories underneath the epic.
filter results obtained by adding the metric Sigma(Time spent) and Sigma(Remaining time) is what I need but this only rolls up data for sub-tasks. Not for issue underneath the Epic.
In short, say I have two stories in my epic (story-1, 2 hrs remaining, and story-2, 4 hours remainaing) , i want to see 6 hours under the Sigma( remaining time) when I query my epic name)
Any idea how i can achieve this.
Rahul
Late But still relevant. (uses Scriptrunner Scripted Field)
Makes a Progress bar for Percent Complete based on "Original Estimate/Logged Work to Tasks and Sub Tasks" And adds in a Details Panel showing specific breakdown for Tasks under Epic.
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.component.ComponentAccessor
def componentManager = ComponentManager.getInstance()
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def totalTimeForSubtasksEstimated = 0
def totalTimeSpentForSubs = 0
def url = ComponentAccessor.getApplicationProperties().getString("jira.baseurl")
def dialog = '<a onclick="AJS.dialog2(\'#more-details'+issue.key+'\').show();" id="show-details'+issue.key+'">Details</a><section class="aui-dialog2 aui-dialog2-medium" role="dialog" aria-hidden="true" style="display:none;" id="more-details'+issue.key+'">'+
"<header class='aui-dialog2-header'><h2 class='aui-dialog2-header-main'>Time Log Details "+issue.key+
"</header> <div class='aui-dialog2-content'><table class='aui' style='border-collapse:collapse;'><thead><th>key</th><th>summary</th><th>Time Tracking</th></thead>"
issueLinkManager.getOutwardLinks(issue.id)?.each
{
outLink ->
def firstLevelChildIssue = outLink.destinationObject
totalTimeForSubtasksEstimated += firstLevelChildIssue.originalEstimate ?: 0
totalTimeSpentForSubs += firstLevelChildIssue.timeSpent ?: 0
def origEstimateshort = ((firstLevelChildIssue.originalEstimate ?: 0) ? ComponentAccessor.getJiraDurationUtils().getFormattedDuration(firstLevelChildIssue.originalEstimate ?: 0) : 0)
def timeSpentshort = ((firstLevelChildIssue.timeSpent ?: 0) ? ComponentAccessor.getJiraDurationUtils().getFormattedDuration(firstLevelChildIssue.timeSpent ?: 0) : 0)
dialog += "<tr><td style='padding:4px; white-space:nowrap;'><a href='"+url+"/browse/"+firstLevelChildIssue.key+"'>"+firstLevelChildIssue.key+"</a></td><td style='border-right:1px solid #e0e0e0'>"+firstLevelChildIssue.summary+":</td><td><span style='white-space:nowrap;'>"+timeSpentshort +" / "+origEstimateshort+"</span></td></tr>"
if (outLink.getIssueLinkType().getName().equals("Epic-Story Link"))
{
// Process normal Epics-Story/Bug-Subtask structure
issueLinkManager.getOutwardLinks(firstLevelChildIssue.id)?.each
{
outLinkSubtask ->
def secondLevelChildIssue = outLinkSubtask.destinationObject
if (secondLevelChildIssue.isSubTask())
{
totalTimeForSubtasksEstimated += secondLevelChildIssue.originalEstimate ?: 0
totalTimeSpentForSubs += secondLevelChildIssue.timeSpent ?: 0
}
}
}
}
def origEstimate = (totalTimeForSubtasksEstimated ? ComponentAccessor.getJiraDurationUtils().getFormattedDuration(totalTimeForSubtasksEstimated) : 0)
def timeSpent = (totalTimeSpentForSubs ? ComponentAccessor.getJiraDurationUtils().getFormattedDuration(totalTimeSpentForSubs) : 0)
def precentComplete = 0
if (origEstimate != 0 && timeSpent != 0){
precentComplete = totalTimeSpentForSubs/totalTimeForSubtasksEstimated*100
} else {
precentComplete = 0.01
}
def simplePrecent = 0
String doubleAsString = String.valueOf(precentComplete);
int indexOfDecimal = doubleAsString.indexOf(".");
if (indexOfDecimal != -1){
simplePrecent = doubleAsString.substring(0, indexOfDecimal);
}
dialog += "<tr style='font-weight:bold !important;'><td colspan='2' style='border-top:1px solid #ccc;text-align:right;'>Totals:</td><td style='border-top:1px solid #ccc;white-space:nowrap;'><span>"+timeSpent+"</span> / <span>"+origEstimate+"</span></td><tr></table>"
dialog += '</div><footer class="aui-dialog2-footer"><button id="close-details'+issue.key+'" onclick="AJS.dialog2(\'#more-details'+issue.key+'\').hide();" class="aui-button aui-button-primary">Close</button></section>'
def table = "<div style='display:inline-block; width:50%;max-width:100px;'>"+simplePrecent+"% Complete</div>"
table += "<div style='display:inline-block;font-size:12px;font-weight:bold;text-align:right;max-width:150px; width:50%;'><span>"+timeSpent+"</span> / <span>"+origEstimate+"</span></div>"
table += "<table style='background:#ffffff;text-align:center;border-radius:8px;overflow:hidden; width:250px; border:1px solid #ccc;'><tr>"
table += "<td style='padding:2px 6px;height:8px;border-radius:8px;color: white; overflow:hidden;background-color:#A0D201;width:"+precentComplete+"%;'></td>"
table += "<td></td>"
table += "</tr></table>"
return table + dialog
thanks for post @Matthew Beda. I tried it out and it looks good. just one question: it seems to be including linked blocked tasks in the roll up. Is there any way to make it ignore linked tasks and only sum up based on issues in epic and subtasks of those issues ?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
you would need to create an exception using the "outLink.getIssueLinkType()" and trap for anything that is "equals("Blockers")"
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Works wonders, @Matthew Beda ! Thanks for this.
Do you know how to sort the issues in epic? I noticed that the result is random:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You can probably just run sort() on the list for the child issues.
https://stackoverflow.com/questions/13686659/groovy-custom-sort-a-map-by-value
You could also look into a sort function after the table is generated using some JS
https://stackoverflow.com/questions/22906760/jquery-sort-table-data
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Matthew Beda I was looking at your script to use for my Jira instance, however for my purposes I was looking at using it to sum up all estimations for a group of epics for another parent issue we created above Epics. What do you think I should do to work towards this?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've been looking into this for a while and I just found an add-on that does it as well, and looks customizable to boot.
https://marketplace.atlassian.com/plugins/aptis.plugins.epicSumUp
Or a simpler free one.
https://marketplace.atlassian.com/plugins/aptis.plugins.epicSumUpFree
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks a lot. It helped me.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi guys, apologies on the really late answer. Please find the Groovy Field definition for the bits required to enable a custom field that will display the total estimate time for an epic's sub-issues/sub tasks. They have to be linked to the Epic via the Epic-Story link field.
Change the .originalEstimate appropriately to reflect either remaining time or actual time.
Hit me back if you have any further questions. The add-on method uses basically the same query but packaged up nicely in a panel etc with the breakdown.
cheers,
saleem
import com.atlassian.jira.ComponentManager
def componentManager = ComponentManager.getInstance()
def issueLinkManager = componentManager.getIssueLinkManager()
def totalTimeForSubtasksEstimated = 0
issueLinkManager.getOutwardLinks(issue.id)?.each
{
outLink ->
def firstLevelChildIssue = outLink.destinationObject
if (outLink.getIssueLinkType().getName().equals("Epic-Story Link"))
{
// Process normal Epics-Story/Bug-Subtask structure
issueLinkManager.getOutwardLinks(firstLevelChildIssue.id)?.each
{
outLinkSubtask ->
def secondLevelChildIssue = outLinkSubtask.destinationObject
if (secondLevelChildIssue.isSubTask())
{
totalTimeForSubtasksEstimated += secondLevelChildIssue.originalEstimate ?: 0
}
}
}
}
return (totalTimeForSubtasksEstimated ? componentManager.getJiraDurationUtils().getFormattedDuration(totalTimeForSubtasksEstimated) : null)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Rahul,
We have a similar requirement, but I wanted to clarify if you meant you need this information exposed within searches or just for viewing. Currently we use both approaches but they require independant solutions.
For just viewing the relevant data on an Epic when you view it, we ended up creating a custom add-in that displays extra information with the information you ask on the Epic screen. For actually searching, we created some custom Groovy (Script Runner) fields that roll-up the same information and expose it so that it's available in the JIRA Queries.
I can ping you back with more details, but let me know if either of the two scenarios we have match yours. (The Costs are just blanked out for the screenshot)
cheers,
saleem
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello Saleem
I have the exact same question as Rahul, and I guess what we want here is the ability to see the aggregation on the Epic screen but also on any search. So I guess you have this Subtasks Estimate column in each search result. Could you share with us your customizations? I am using JIRA ON DEMAND.
Thanks in advance;
Paul
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Paul,
Yes, sure, I can send you some more info early next week. I am not super familiar with JIRA On Demand, but I think it has the ability to run the Groovy Script Runner plugin. If you can confirm that, then it's just a matter of setting up the field definitions.
Chat next week!
saleem
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello Saleem,
You reference sub tasks in the example provided. Does this aslo include issues in an epic?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Roger, sorry about the delay in getting back to you. Yes, this can include sub-tasks within the Epic itself. We don't allow sub-tasks on Epics as part of our setup, so the screenshot above does not show any, but the code snippet still will work.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
HI Saleem
Sorry in replying late to you, yes both these scenarios apply to us and I will be very much interested in the solutions that you have adopted. Can you please send me more information either on this post or directly s rahul.aich@nagra.com
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Saleem, We also need to be able to aggregate estimated time and spent time at epic level (in views and in searches, particularly in searches). Unless a new and easier solution has been made since March (pls. let me know if that is the case), we are ready to install the Groovy Script Runner, if you are willing to post your field definitions here. Thanks /Lasse
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Saleem, I need the epic level time spent just for viewing. Can you please elaborate on the custom add-in? I can add a custom field to epic level. But, not sure how to make issue level estimates/time-spent to Epic level. Thanks Ram
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.