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

Sonja Athing April 25, 2019

Hello, 

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
import com.atlassian.jira.issue.link.IssueLinkTypeManager

if (issue.issueType.name == "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(epicLink.id).each { 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
Sonja Athing April 29, 2019

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 (issue.issueType.name == "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'

import com.atlassian.jira.issue.link.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.

-Sonja

0 votes
Answer accepted
Jonny Carter
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.
April 25, 2019

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
import com.atlassian.jira.issue.link.IssueLinkTypeManager

if (issue.issueType.name == "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: https://docs.atlassian.com/software/jira/docs/api/latest/

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: https://library.adaptavist.com/

 

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 http://groovy-lang.org/documentation.html#gettingstarted 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.

Sonja Athing April 25, 2019

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.  

Sonja Athing April 26, 2019

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

issue.issueType.name == "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

issue.estimate

 

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

Jonny Carter
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.
April 29, 2019

@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.

Jonny Carter
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.
April 29, 2019

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.

0 votes
chithra madhav March 3, 2022

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()
log.debug(customField)

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

}}



Thanks in Advance

Regards,
Revathy Madhavan

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events