Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

How to take just the first sprint of an issue with groovy

arama mihai
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.
September 18, 2018

Hello,

I created a script that gets the name of the sprint of an issue and sets it to a text field. 

Although I tried, I could not make it take the first sprint of an issue, in case it has been added to multiple ones. The way I currently have it, it takes the current sprint, and I do not need that. 

The script is below. Please let me know if it is possible to get the first ever sprint to which this issue was assigned, and how to achieve that.

Thank you!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption



def issue = event.issue as MutableIssue
ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
IssueManager issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def sprint = customFieldManager.getCustomFieldObjectByName("Sprint")
def sprints = issue.getCustomFieldValue(sprint)
def textfield = customFieldManager.getCustomFieldObjectByName("Initial Sprint Planned")
def plan = issue.getCustomFieldValue(textfield)


if (!sprints) {
return
}

else {


def sprintName = sprints?.name?.first()?.toString()
plan = sprintName

issue.setCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Initial Sprint Planned"), plan)

ComponentAccessor.getIssueManager().updateIssue( ComponentAccessor.getJiraAuthenticationContext().getUser(),issue, EventDispatchOption.ISSUE_UPDATED, false)


  

 

1 answer

1 accepted

1 vote
Answer accepted
Tarun Sapra
Community Champion
September 18, 2018
Tarun Sapra
Community Champion
September 18, 2018

Also to get sprint name, you can write

sprints?.first?.name
arama mihai
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.
September 18, 2018

Hi @Tarun Sapra

Thank you very much for your reply.

I updated the script to what can be seen below, however, it still does not get the first sprint value, it still gets the current sprint value:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder



def issue = event.issue as Issue
ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
IssueManager issueManager = ComponentAccessor.getIssueManager()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def sprint = customFieldManager.getCustomFieldObjectByName("Sprint")
def sprints = issue.getCustomFieldValue(sprint)
def initialplan = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Initial Sprint Planned"}
def plan = issue.getCustomFieldValue(initialplan)


if (!sprints) {
return
}

else {


def sprintName = sprints?.first?.name
plan = sprintName

def changeHolder = new DefaultIssueChangeHolder()
initialplan.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(initialplan), plan),changeHolder)

Tarun Sapra
Contributor
September 18, 2018

Can you please use logging in the script and print the "sprints" object and it's values and share the output.

arama mihai
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.
September 18, 2018

Hi @Tarun Sapra

Sure. I hope I'm doing the right thing as this is my first time using logging in scripts.

If the script has: def sprintName = sprints?.first?.name

then the debug will say:

2018-09-18 13:19:45,092 http-nio-8080-exec-1 ERROR uidq5816 799x1846538x2 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.o.scriptrunner.runner.AbstractScriptListener] Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: com/listeners/UpdateInitialSprintPlannedfromSprint.groovy
groovy.lang.MissingPropertyException: Exception evaluating property 'first' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: first for class: com.atlassian.greenhopper.service.sprint.Sprint
at UpdateInitialSprintPlannedfromSprint.run(UpdateInitialSprintPlannedfromSprint.groovy:35)

 

If the script has: 

sprints?.name?.first()?.toString()

then the logs show: 2018-09-18 13:16:54,719 http-nio-8080-exec-27 DEBUG uidq5816 796x1846055x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] The sprints are: FC Telematics Audio Sprint2

 

I hope this helps. Thank you!

Tarun Sapra
Community Champion
September 18, 2018

Hello @arama mihai

Could you just print "sprints" in log info or something like

sprints.each {

log.info it.getName()

}

So that we can see the actual list of sprints available. 

arama mihai
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.
September 18, 2018

Hi @Tarun Sapra

I used the sprints.each which you suggested, once before the part that throws the error, and once after. Before the error, it shows the 2 sprints in which the issue has been, and after that it gives the same error as before:

 

2018-09-18 13:35:53,868 http-nio-8080-exec-31 INFO uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] FC Telematics Audio Sprint2
2018-09-18 13:35:53,868 http-nio-8080-exec-31 INFO uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] FC Telematics Audio Sprint4
2018-09-18 13:35:53,870 http-nio-8080-exec-31 ERROR uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.o.scriptrunner.runner.AbstractScriptListener] *************************************************************************************
2018-09-18 13:35:53,870 http-nio-8080-exec-31 ERROR uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.o.scriptrunner.runner.AbstractScriptListener] Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: com/listeners/UpdateInitialSprintPlannedfromSprint.groovy
groovy.lang.MissingPropertyException: Exception evaluating property 'first' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: first for class: com.atlassian.greenhopper.service.sprint.Sprint
at UpdateInitialSprintPlannedfromSprint.run(UpdateInitialSprintPlannedfromSprint.groovy:40)

arama mihai
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.
September 18, 2018

Hi @Tarun Sapra

I added what you suggested, once before the part that throws the error and once after it.

These are the results:

2018-09-18 13:35:53,868 http-nio-8080-exec-31 INFO uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] FC Telematics Audio Sprint2
2018-09-18 13:35:53,868 http-nio-8080-exec-31 INFO uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] FC Telematics Audio Sprint4
2018-09-18 13:35:53,870 http-nio-8080-exec-31 ERROR uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.o.scriptrunner.runner.AbstractScriptListener] *************************************************************************************
2018-09-18 13:35:53,870 http-nio-8080-exec-31 ERROR uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.o.scriptrunner.runner.AbstractScriptListener] Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: com/listeners/UpdateInitialSprintPlannedfromSprint.groovy
groovy.lang.MissingPropertyException: Exception evaluating property 'first' for java.util.ArrayList, Reason: groovy.lang.MissingPropertyException: No such property: first for class: com.atlassian.greenhopper.service.sprint.Sprint
at UpdateInitialSprintPlannedfromSprint.run(UpdateInitialSprintPlannedfromSprint.groovy:40)

Tarun Sapra
Community Champion
September 18, 2018

this exception is due to the code 

"def sprintName = sprints?.first?.name"

Can you just print each element of the sprints arrayList using each operator as I have shared using the logging so that we know that all sprints are getting printed.

arama mihai
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.
September 18, 2018

Hi ,

All sprints are getting printed, they show up like this in the logs when using your way of logging:

2018-09-18 13:35:53,868 http-nio-8080-exec-31 INFO uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] FC Telematics Audio Sprint2
2018-09-18 13:35:53,868 http-nio-8080-exec-31 INFO uidq5816 815x1849701x1 sg5qu4 10.217.176.150 /secure/QuickEditIssue.jspa [c.onresolve.jira.groovy] FC Telematics Audio Sprint4

Tarun Sapra
Community Champion
September 18, 2018

for first sprint then you can try with code

def sprintName = sprints.get(0).getName()
arama mihai
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.
September 18, 2018

Hi,

Thank you, that gets the first sprint of an issue, if it has multiple.

I do have a weird case for which it does not work though. Let's assume that issue A is added to Sprint 1. Sprint 1 is not yet active. In this moment, my text field gets the value of "Sprint 1". This is good, it is my initial plan.

But then 2 things can happen in which the current script doesn't help:

1) before the Sprint 1 is started, it is moved to another sprint (Sprint 2 let's say). In this case, my 'Initial Sprint Plan' should still remain Sprint 1, but it changes to Sprint 2.

2) Issue A is part of Sprint 1, but before the end, somebody removes it from the Sprint 1 and adds it to the Sprint 2. The current script will show that the initial plan is Sprint 2.

So what I'm trying to say is that currently it only works if an issue is part of a Sprint, that sprint becomes active and completed, then it will also be part of another sprint. But I am really interested in having the text field 'Initial Sprint Plan' to show the very first sprint to which the issue was assigned to, no matter if use cases 1 and 2 presented above happen.

I am afraid that this will have to search in the issue history?

Thank you. 

Tarun Sapra
Community Champion
September 19, 2018

Hello @arama mihai

Glad to know that you can now get the value of the first sprint, could you please accept/upvote the answer as your original query has been resolved. 

Yes for your actual use-case you would need to search the issue history and detect any changes in the sprint.

Tarun Sapra
Community Champion
September 19, 2018

Use the changeHistoryManager

Something like this

ChangeHistoryManager changeHistoryManager = ComponentAccessor.getChangeHistoryManager();
List<ChangeItemBean> changeList = changeHistoryManager.getChangeItemsForField(issue, "Sprint")
arama mihai
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.
September 19, 2018

Hi @Tarun Sapra

Thanks again for all your help.

Now I think I have a final version. I will add it hear for anybody else who might search for something similar in the future:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.history.ChangeItemBean


def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
IssueManager issueManager = ComponentAccessor.getIssueManager()
def issue = event.issue as Issue
def changeHistories = changeHistoryManager.getChangeHistories(issue)
assert changeHistories

ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def customFieldManager = ComponentAccessor.getCustomFieldManager()

def sprints = changeHistories.collect { history -> history.getChangeItemBeans().findResults { ChangeItemBean change ->
if (change.getField() == "Sprint") {
return change.getToString()
}
}
}.flatten()

def initialplan = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Initial Sprint Planned"}
def plan = issue.getCustomFieldValue(initialplan)


if (!sprints) {
return
}

else {

def sprintName = sprints.get(0)
plan = sprintName

def changeHolder = new DefaultIssueChangeHolder()
initialplan.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(initialplan), plan),changeHolder)


}
Tony Camacho March 21, 2019

Doesnt work....

Mihai Mihai
Contributor
March 21, 2019

This works for us:

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.jira.issue.customfields.option.LazyLoadedOption
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.history.ChangeItemBean


def changeHistoryManager = ComponentAccessor.getChangeHistoryManager()
IssueManager issueManager = ComponentAccessor.getIssueManager()
def issue = event.issue as Issue
def changeHistories = changeHistoryManager.getChangeHistories(issue)
assert changeHistories

ApplicationUser user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def customFieldManager = ComponentAccessor.getCustomFieldManager()

def sprints = changeHistories.collect { history -> history.getChangeItemBeans().findResults { ChangeItemBean change ->
if (change.getField() == "Sprint") {
return change.getToString()
}
}
}.flatten()

def initialplan = customFieldManager.getCustomFieldObjects(event.issue).find {it.name == "Initial Sprint Planned"}
def plan = issue.getCustomFieldValue(initialplan)


if (!sprints) {
return
}

else {

def sprintName = sprints.get(0)
plan = sprintName

def changeHolder = new DefaultIssueChangeHolder()
initialplan.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(initialplan), plan),changeHolder)


}

Tony Camacho March 22, 2019

Throws an error:  def issue = event.issue as Issue

 

Capture.PNG

Tony Camacho March 22, 2019

JIRA 7.13.2

 

Version:5.5.0Vendor:Adaptavist.com Ltd

Suggest an answer

Log in or Sign up to answer