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

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root


1 badge earned


Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!


Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.


Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!


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
Community Members
Community Events
Community Groups

Epic-Story Link Estimate Roll Up Script for custom field - scaling to support individual Epic Link


I have a nifty script for a custom field that displays the Epic-Story roll up estimate value (time tracking duration).  In the script's current form,  it rolls up all of the Epic-Story links estimates in the Jira Instance.

I need to scale this script to act on an Epic Link specific basis.  Specifically:

get the epic key and then the epic link for the issue being rendered in the browser

compare /find that epic link in the epicLink list

then roll up the estimates for that epic link.


Here is the script:

import com.atlassian.jira.component.ComponentAccessor

if ( == "Epic") {
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def issueLinkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager)
String EPIC_LINK_NAME = "Epic-Story Link"
def epicLink = issueLinkTypeManager.getIssueLinkTypesByName(EPIC_LINK_NAME).first()

def totalRemaining = 0
issueLinkManager.getIssueLinks( { issueLink ->
def linkedIssue = issueLink.destinationObject
totalRemaining += linkedIssue.getEstimate() ?: 0

if (totalRemaining) {
totalRemaining += issue.getEstimate() ?: 0

return totalRemaining as Long ?: 0L
} else {
return null


This script depends on 'Epic-Story Link' but, what if an Epic also has Tasks w/time tracking in it?  How would the IssueLinkTypeManager get those issue links?

I am very new to using Groovy so please understand if my inquiry is a bit off. 

Also, if anyone has tips/tricks/links for getting knowledgeable with Groovy,  please let me know.

Thank you,

Sonja Athing


3 answers

2 accepted

1 vote
Answer accepted

Hi Jonny !

Perfect.  Great feedback regarding the internals. 

This bit of info:

the .estimate property corresponds to the getEstimate() method on the Issue interface.

explains soo much.


Following is the update script:

import com.atlassian.jira.component.ComponentAccessor

if ( == "Epic") {
def issueLinkManager = ComponentAccessor.issueLinkManager
String EPIC_LINK_NAME = "Epic-Story Link"

def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def links = issueLinkManager.getLinkCollection(issue, user, false)
def originalEstimates = links.getOutwardIssues(EPIC_LINK_NAME)*.originalEstimate.findAll{it != null}
def totalEstimates = (originalEstimates.sum() ?: 0) as Long
return totalEstimates + (issue.originalEstimate ?: 0)
} else {
    return null


Note,  I removed from the script inclusion of the 'IssueLinkTypeManager'

def issueLinkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager)

as it is was no longer being used in the updated script you provided me last week.

Thank you so much.


0 votes
Answer accepted

Hey, Sonja! If I recall, you're using this script as a Scripted Field. To that end, we just need to get the epic links on the issue variable itself.

import com.atlassian.jira.component.ComponentAccessor

if ( == "Epic") {
def issueLinkManager = ComponentAccessor.issueLinkManager
def issueLinkTypeManager = ComponentAccessor.getComponent(IssueLinkTypeManager)
String EPIC_LINK_NAME = "Epic-Story Link"

def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def links = issueLinkManager.getLinkCollection(issue, user, false)
def estimates = links.getOutwardIssues(EPIC_LINK_NAME)*.estimate.findAll{it != null}
def totalEstimates = (estimates.sum() ?: 0) as Long
return totalEstimates + (issue.estimate ?: 0)
} else {
    return null

Make sure to use the template of Duration (time-tracking) when you're setting up this script field.


As for learning Groovy, there are quite a few good resources out there. Of course, there's no substitute for the learning you do when you're trying to solve a problem of your own, as you're doing here.


For Groovy in the context of Adaptavist ScriptRunner for Jira Server, there are a few resources you may want to have on hand.

The Atlassian Jira javadoc is a raw index of all the classes that are available in ScriptRunner:

The ScriptRunner documentation, particularly the recipes section, is a great place to go for annotated code examples.

The Adaptavist Library site has a growing list of example scripts built around specific use cases:


For Groovy in general, there are lots of good resources out there. You by no means need these to use ScriptRunner, but if you're interested in using Groovy as a general scripting language, these are good places to start.

The getting started guides at will tell you how to setup and use Groovy outside of ScriptRunner, which may be helpful if you want to get really familiar with Groovy's syntax.

If you like books, it's hard to beat Groovy In Action, Second Edition, by Paul King and Dierk König.

Great!  Thank you Jonny for the updated script and the Groovy learning tips and links. 

I tried the script and saw that the 'totalEstimates' looks to be tied to the time tracking 'remaining estimate' because when I log work I see the value decrement accordingly.  Our schedule folks would very much like to see a field with the original estimate displayed.  I can see that displaying the remaining estimate is also of value.

Let me investigate some to see if I can figure out how to do this.  

I'm missing some fundamentals here.  In this line of code: == "Epic"

I see that issue.issueType is a type in com.atlassian.jira.issue.Issue

But, I'm unable to trace in any documentation about '.name'

And, for



I'm not able to trace for '.estimate' in the same way.

Would the installation of IntelliJ IDEA auto fill and then help to resolve these questions ?

Could you point me in the right direction for overcoming these basics. 

Thank you!


@Sonja Athing- great questions all around!

While the IntelliJ integration is a great, powerful way to get autocompletions, since 5.5.0, we've added a Code Insight feature that works right in your web browser.

To answer about the particular properties you were looking at, there's a couple of layers here.

The issue variable is, as you've already figured out, an instance of the com.atlassian.jira.issue.Issue class. The issueType property on that variable actually corresponds to the getIssueType() method on the class. Groovy dynamically turns that Java method into a property, which can make the code a little terser and easier to read.

Since getIssueType returns an IssueType object, the .name property corresponds to the getName() method.

Likewise, the .estimate property corresponds to the getEstimate() method on the Issue interface.

Oh, and to your earlier question, if you want the original estimate, you can just use the originalEstimate property instead of estimate on the issue variable if you want the original estimate.

Hi All,

I have an Epic & i have linked multiple existing stories in it.
I need to create a Calculated scripted field from which Estimations of all stories linked in Epic should be summed & display it.
I also have an scripted field for Stories which calculate the sum of all tasks & sub-tasks linked with the stories & provides expected result

I tried to invoke that field in this Epic Script ,to calculate & generate output but it results as 0.

Please find below Script & help me on this requirement ASAP

Script Used-->//Scripted field-->Stories linked with Epic --Original estimate Calculation

import com.atlassian.jira.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.Issue
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def cfManager = ComponentAccessor.getCustomFieldManager()
double totalestimate = 0
customField = cfManager.getCustomFieldObject("customfield_14126");

//customField1 =cfManager.getCustomFieldObjectsByName()

if (issue.getIssueTypeId() != "10000") {
return null
issueLinkManager.getOutwardLinks( {issueLink ->;
if ( == "Epic-Story Link" ) {
def linkedIssue = issueLink.destinationObject
double originalestimate =(double)(linkedIssue.getCustomFieldValue(customField) ?: 0)
totalestimate = originalestimate + totalestimate;


Thanks in Advance

Revathy Madhavan

Suggest an answer

Log in or Sign up to answer

Atlassian Community Events