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

Script to get the max/larger sprint end date or sprint value

Alok Kumar August 27, 2023

Hi,

I have the script which calculates the maximum/larger date from linked issues. However it is not working for Sprint filed. I want to create a scripted field which will display the larger end date from story which is linked within an epic. below is my script:

import com.atlassian.jira.component.ComponentAccessor
import java.text.SimpleDateFormat

//Check that current issue is an Epic
if(issue.issueType.name == "Epic")
{
    log.warn("found an Epic")

    //Initialize appropriate managers
    def linkManager = ComponentAccessor.issueLinkManager
    def cfm = ComponentAccessor.customFieldManager

    //Get the EpicPlannedCompletion field and initialize a list to hold the date values
    def EpicPlannedCompletionField = cfm.getCustomFieldObjectByName("Sprint")
    def EpicPlannedCompletionDates = [] as List<Date>
    //Loop through all of New Feature's epics and collect their date objects
    linkManager.getOutwardLinks(issue.id).each{
        if(it.issueLinkType.name == "Issues in epic")
        {
            def epicIssue = it.destinationObject
            if(epicIssue.issueType.name == "Story"){
            EpicPlannedCompletionDates.add(epicIssue.getCustomFieldValue(EpicPlannedCompletionField) as Date)
            log.warn("added a date")}

        }
    }

    if (EpicPlannedCompletionDates.size()==0){
        return null
        }
   
    //Initialize min and max
    def minDate = EpicPlannedCompletionDates[0] as Date
    def maxDate = EpicPlannedCompletionDates[0] as Date
    log.warn("piching the first date " + minDate)

    //Find actual min and max Dates
    for(int i = 1; i < EpicPlannedCompletionDates.size(); i++)
    {
    log.warn("Iteration "+i)
        def currentDate = EpicPlannedCompletionDates[i]
        if (currentDate!=null && minDate != null) {
            if(currentDate.before(minDate))
            {
                minDate = currentDate
            }
                if(currentDate.after(maxDate) && maxDate!= null)
                {
                maxDate = currentDate
            }
        }
        else { //Moving "currentDate" into "minDate" and "maxDate" as soon as currentdate is no null
            minDate = currentDate
            maxDate = currentDate
            }
    }

//If I was unable to find any dates associated with the epic
if(minDate == null || maxDate ==null){
    return null
}   
return maxDate    
}
else //Return null if issue is not an Epic
{
    return null
}

1 answer

1 accepted

Suggest an answer

Log in or Sign up to answer
0 votes
Answer accepted
Peter-Dave Sheehan
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.
August 28, 2023

Hi Alok

I reviewed your script and I think I understand what you are trying to do. 

But there are some mistakes/improvements:

1) The Sprint custom field can't return a date. It will return an array of Sprint objects. You'll have to extract the date from the last or current sprint.

2) There is a better way to deal with issue in epic using @JiraAgileBean notation and the EpicLinkManager

3) Scripts are lot cleaner if you don't do large if/else blocks only to return null on the else block.. Instead, just return null early when you find an appropriate condition.

4) Leverage Groovy collection extensions to filter, sort and get max values

 

Here is what the corrected script looks like:

import com.atlassian.greenhopper.manager.issuelink.EpicLinkManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.jira.component.ComponentAccessor
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean
import com.onresolve.scriptrunner.runner.customisers.WithPlugin

import java.text.SimpleDateFormat
@WithPlugin("com.pyxis.greenhopper.jira") agilePlugin

//Check that current issue is an Epic
if (issue.issueType.name != "Epic") return null

log.warn("found an Epic")

//Initialize appropriate managers
def cfm = ComponentAccessor.customFieldManager
@JiraAgileBean EpicLinkManager epicLinkManager

def sprintCf = cfm.getCustomFieldObjectByName("Sprint")

def storiesInEpicWithSprints = epicLinkManager.getIssuesInEpic(issue).findAll{
it.issueType.name == 'Story' && it.getCustomFieldValue(sprintCf)
}

if(!storiesInEpicWithSprints) {
log.warn "there are no stories in the epic, or none of them are associated with Sprint(s)"
return null
}

log.info "Epic has stories with sprints: $storiesInEpicWithSprints"
def storyWithMaxDate = storiesInEpicWithSprints.max{
def sprints = it.getCustomFieldValue(sprintCf) as List<Sprint>
return sprints.last().endDate //return the endDate of the sprint, the max will find the last one
}
log.info "The story with latest sprint end date is: $storyWithMaxDate.key"
//now we have the story, lets extract the sprints
def sprints = storyWithMaxDate.getCustomFieldValue(sprintCf) as List<Sprint> //sprints stores an array even if there is only 1 sprint
//return the date the last sprint(current) in the array
sprints.last().endDate
Alok Kumar August 30, 2023

Hi @Peter-Dave Sheehan ,

Thanks for your response.

Above scripts works and returns the sprint end date. However there is one demerit that it works only if the sprint is closed. How can we compare the sprints when it is not closed? OR, is it possible to compare the sprints of all stories which are linked within an epic and return only the sprint name (string type) ?

Thanks in Advance !

Peter-Dave Sheehan
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.
August 30, 2023

Change this line to change how you define the "last sprint":

return sprints.last().endDate //return the endDate of the sprint, the max will find the last one

You can try sorting by "sequence"

Then change the last line to define what you want to return from the last sprint. 

For example:

sprints.last().name //return the sprint name
TAGS
AUG Leaders

Atlassian Community Events