Custom listener removing from sprints

Hello,

We are using our own issuetype "Sprint Goal" for scrum purpose, unfortunately there are some people which don;t understand that sprint goal cannot be in more then one sprint. I am trying to use custom listner to delete issue from sprint expect first one. This is test code to just look how it works, but it doesn't work and i don;t know why. Listener works on IssueUpdate event

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintIssueService

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
log.warn "Custom Listener Check! " + issue
log.warn "Custom Listener " + event.getChangeLog().getRelated("ChildChangeItem").find{it.field == "Sprint"}
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
log.warn "Custom Listener "+sprints[0]
def primarySprint = sprints[0]
sprints.each(){
if(it != primarySprint){
sprintIssueService.removeIssuesFromSprint(igor, it, [issue] as Collection)
}
}

thanks in advance for help,

Maciej O. 

2 answers

1 accepted

Accepted Answer
0 votes

Hi Maciej,

Just an observation from my side, the name of the user says "igot" in your code but the variable that you defined says "igor". Maybe you made a typo in the username. Please ignore if it isnt.

-Praveen

unfortunately it's not, igor is a name of our bot and his username in JIRA is igot

Oh right i forget to add errors...
2018-05-10 11:58:09,582 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.ClassCastException: com.atlassian.greenhopper.service.sprint.Sprint cannot be cast to java.util.Collection
at com.atlassian.greenhopper.customfield.sprint.SprintCFType.valuesEqual(SprintCFType.java:83)
at com.atlassian.jira.issue.fields.ImmutableCustomField.valuesEqual(ImmutableCustomField.java:1548)
at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:423)
at com.atlassian.jira.issue.fields.ImmutableCustomField.updateValue(ImmutableCustomField.java:395)
at com.atlassian.jira.issue.managers.DefaultIssueManager.updateFieldValues(DefaultIssueManager.java:704)
at com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue(DefaultIssueManager.java:669)
at com.atlassian.jira.issue.managers.DefaultIssueManager.updateIssue(DefaultIssueManager.java:655)
at com.atlassian.jira.issue.managers.RequestCachingIssueManager.updateIssue(RequestCachingIssueManager.java:214)
at com.atlassian.jira.issue.IssueManager$updateIssue$0.call(Unknown Source)
at Script246.run(Script246.groovy:23)
Maybe this will help

Hi,

Can you try this code, instead of the current if loop,

if(!it.equals(primarySprint))

ok i got other error:

 2018-05-10 12:06:28,960 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException: Cannot invoke method removeIssuesFromSprint() on null object
at Script283$_run_closure2.doCall(Script283.groovy:27)
at Script283.run(Script283.groovy:25)

Hi Maciej,

Looks like you have to pass correct parameters for the "removeIssuesFromSprint()"  method.

removeIssuesFromSprint(com.atlassian.crowd.embedded.api.User user, Sprint sprint, java.util.Set<com.atlassian.jira.issue.Issue> issues) 

 please chekc the below link for clarifications.

https://docs.atlassian.com/jira-software/6.2.2/com/atlassian/greenhopper/service/sprint/SprintIssueServiceImpl.html

 

-Praveen

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintIssueService

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
//log.warn "Custom Listener Check! " + issue
//log.warn "Custom Listener " + event.getChangeLog().getRelated("ChildChangeItem").find{it.field == "Sprint"}
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
log.warn "Custom Listener "+sprints[0]
def primarySprint = sprints[0]
Set<Issue> setI
setI.add(issue)
sprints.each(){
if(!it.equals(null)){
log.warn "Custom Listener " + it
log.warn "Custom Listener " + [issue] as Collection
if(!it.equals(primarySprint)){
sprintIssueService.removeIssuesFromSprint(igor, it, setI)
}
}
}
ComponentAccessor.getComponent(IssueManager).updateIssue(igor, issueUpdate, EventDispatchOption.ISSUE_UPDATED, false)

Ok i added them as set and now error is 

java.lang.NoClassDefFoundError: groovy/lang/GroovyObject
 at Script382$_run_closure1.doCall(Script382.groovy:30)
 at Script382.run(Script382.groovy:25)
 at com.onresolve.scriptrunner.runner.ScriptRunnerImpl.runScriptAndGetContext(ScriptRunnerImpl.groovy:159)
 at com.onresolve.scriptrunner.runner.ScriptRunner$runScriptAndGetContext$3.callCurrent(Unknown Source)
 at com.onresolve.scriptrunner.runner.ScriptRunner$runScriptAndGetContext$3.callCurrent(Unknown Source)
 at com.onresolve.scriptrunner.runner.ScriptRunnerImpl.runStringAsScript(ScriptRunnerImpl.groovy:148)
 at com.onresolve.scriptrunner.runner.ScriptRunner$runStringAsScript$2.call(Unknown Source)
 at com.onresolve.scriptrunner.canned.jira.workflow.listeners.CustomListener.doScript(CustomListener.groovy:120)
Caused by: java.lang.ClassNotFoundException: groovy.lang.GroovyObject

 I also added note with each sprint and it shows that cause may be a closed sprints. Do you think this is it?

Cheers,
Maciej

Maybe it detects "[issue] as Set" as null?

Can you try returning sprints arraylist and check if it is null?

-Praveen

I have a trick to troubleshoot easily in scriptrunner, you can create a dummy script field and paste the above code (dont save it). Then you can return the values that you wanted to see using the preview option. You just have to provide the issue key as input.

//** Ignoring the imports
SprintIssueService sprintIssueService

//def issue = event.issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)

return sprints //this will show you the values in the arraylist

def primarySprint = sprints[0]
Set<Issue> setI
setI.add(issue)
sprints.each(){
if(!it.equals(null)){
if(!it.equals(primarySprint)){
sprintIssueService.removeIssuesFromSprint(igor, it, setI)
}
}
}
ComponentAccessor.getComponent(IssueManager).updateIssue(igor, issueUpdate, EventDispatchOption.ISSUE_UPDATED, false)

Note:

1. You dont have to delare the issue in the code

2. The preview will return only the first return value

3. This is only for trubleshooting (once code is ready just close the sccript field)

-Praveen

sprint test.pngWell it doesn't look null at all :D, I think error is with Set Issue :( but i don't know why

I also checked [issue] as Set and it doesn't return null it returns [JIRA-5082] <example issue>

Just to be sure i checked igor but it return igot(igot) so i really don;t know where is null....

Check by returning these three after entering the loop.  you can return them all at one time with the code below

return "User: "+igor.toString()+" Sprint: "+it.toString()+" Issue:"+setI.toString() 

-Praveen

Got it! change the getting the first spring to something like below, just sprints[0] will have a whole lot of info along with the name of the sprint. YOu have to use the getName() method to get the name alone.

def primarySprint = sprints[0].getName()

To something like that?

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
log.warn "Custom Listener "+sprints[0]
def primarySprint = sprints[0].getName()
sprints.each(){
if(!it.equals(null) && issue != null){
log.warn "Custom Listener " + it
if(!it.getName().equals(primarySprint)){
sprintIssueService.removeIssuesFromSprint(igor, it, [issue] as Set)
}
}
}

Still null error :( 

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
log.warn "Custom Listener "+sprints[0]
def primarySprint = sprints[0].getName()
def issueSet = []
issueSet.add(issue)
for(it in sprints){
if(!(it.getName()).equals(primarySprint)){
sprintIssueService.removeIssuesFromSprint(igor, it, issueSet)
}
}


Try this, and check if you are still getting the same error :(

-Praveen

Unfortunately still same :(

2018-05-11 14:26:02,648 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2018-05-11 14:26:02,648 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException: Cannot invoke method removeIssuesFromSprint() on null object
 at Script509$_run_closure1.doCall(Script509.groovy:29)
 at Script509.run(Script509.groovy:25)

Are those 3 parameters returning values inside the if loop? If yes, I am not sure on why this method is givving null pointer :(

-Praveen

Ok i think we are close!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintIssueService

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
def primarySprint = sprints[0].getName()
def issueSet = []
issueSet.add(issue)
log.warn "Loop"
for(it in sprints){
log.warn "In loop"
log.warn it['state']
if(it['state'] == 'ACTIVE'){
log.warn "In in"
sprintIssueService.removeIssuesFromSprint(igor, it, issueSet)
}
}

green light but i don;t know why it didn't get into if here are logs 

2018-05-11 15:43:28,665 WARN [runner.ScriptRunnerImpl]: Loop
2018-05-11 15:43:28,665 WARN [runner.ScriptRunnerImpl]: In loop
2018-05-11 15:43:28,665 WARN [runner.ScriptRunnerImpl]: CLOSED
2018-05-11 15:43:28,665 WARN [runner.ScriptRunnerImpl]: In loop
2018-05-11 15:43:28,666 WARN [runner.ScriptRunnerImpl]: ACTIVE

and i am really thankful for your time!  

Ok it got in...

2018-05-11 16:30:07,053 WARN [runner.ScriptRunnerImpl]: Loop
2018-05-11 16:30:07,055 WARN [runner.ScriptRunnerImpl]: com.atlassian.greenhopper.service.sprint.Sprint@3c161bcc[id=5108,rapidViewId=678,state=CLOSED,name=ASUM 49,startDate=2018-01-30T11:36:08.041+01:00,endDate=2018-02-13T12:01:00.000+01:00,completeDate=2018-05-11T15:30:38.414+02:00,sequence=5108]
2018-05-11 16:30:07,055 WARN [runner.ScriptRunnerImpl]: In loop
2018-05-11 16:30:07,055 WARN [runner.ScriptRunnerImpl]: CLOSED
2018-05-11 16:30:07,055 WARN [runner.ScriptRunnerImpl]: com.atlassian.greenhopper.service.sprint.Sprint@20fe1d6b[id=5213,rapidViewId=1376,state=ACTIVE,name=Test sprint,startDate=2018-05-11T15:37:11.640+02:00,endDate=2018-05-25T16:02:00.000+02:00,completeDate=<null>,sequence=5213]
2018-05-11 16:30:07,055 WARN [runner.ScriptRunnerImpl]: In loop
2018-05-11 16:30:07,055 WARN [runner.ScriptRunnerImpl]: ACTIVE
2018-05-11 16:30:07,056 WARN [runner.ScriptRunnerImpl]: In in
2018-05-11 16:30:07,058 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2018-05-11 16:30:07,058 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException: Cannot invoke method removeIssuesFromSprint() on null object
 at Script632.run(Script632.groovy:31)

Hi Maciej,

So it works only for active sprnts! Good that we found it out.

-Praveen

it still doesn't work :(

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintIssueService

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
def primarySprint = sprints[0].getName()
def issueSet = []
issueSet.add(issue)
log.warn "Loop"
for(it in sprints){
log.warn it
log.warn "In loop"
log.warn it['state']
if(it.active){
log.warn "In if"
sprintIssueService.removeIssuesFromSprint(igor, it, issueSet)
}
}

 Logs:

2018-05-11 16:30:46,226 WARN [runner.ScriptRunnerImpl]: Loop
2018-05-11 16:30:46,226 WARN [runner.ScriptRunnerImpl]: com.atlassian.greenhopper.service.sprint.Sprint@3c161bcc[id=5108,rapidViewId=678,state=CLOSED,name=ASUM 49,startDate=2018-01-30T11:36:08.041+01:00,endDate=2018-02-13T12:01:00.000+01:00,completeDate=2018-05-11T15:30:38.414+02:00,sequence=5108]
2018-05-11 16:30:46,226 WARN [runner.ScriptRunnerImpl]: In loop
2018-05-11 16:30:46,227 WARN [runner.ScriptRunnerImpl]: CLOSED
2018-05-11 16:30:46,227 WARN [runner.ScriptRunnerImpl]: com.atlassian.greenhopper.service.sprint.Sprint@20fe1d6b[id=5213,rapidViewId=1376,state=ACTIVE,name=Test sprint,startDate=2018-05-11T15:37:11.640+02:00,endDate=2018-05-25T16:02:00.000+02:00,completeDate=<null>,sequence=5213]
2018-05-11 16:30:46,227 WARN [runner.ScriptRunnerImpl]: In loop
2018-05-11 16:30:46,227 WARN [runner.ScriptRunnerImpl]: ACTIVE
2018-05-11 16:30:46,227 WARN [runner.ScriptRunnerImpl]: In in
2018-05-11 16:30:46,229 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2018-05-11 16:30:46,229 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException: Cannot invoke method removeIssuesFromSprint() on null object
 at Script632.run(Script632.groovy:31)

Active check is working properly but even still it doesn't work when it comes to remove from sprint function :/ 

Ok i finally made it work!

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintIssueService
import com.onresolve.scriptrunner.runner.customisers.JiraAgileBean

@JiraAgileBean
SprintIssueService sprintIssueService

def issue = ComponentAccessor.getIssueManager().getIssueObject("JIRA-6418") as Issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprints = sprintIssueService.getSprintsForIssue(igor, issue)
def issueSet = []
issueSet.add(issue)
log.warn "Loop"
for(it in sprints.getValue()){
log.warn it
log.warn "In loop"
log.warn it['state']
if(it.active){
log.warn "In in"
sprintIssueService.removeIssuesFromSprint(igor, it, issueSet)
}
}

I just needed to add JiraAgileBean, but i don;t know how it works now ^^"

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.greenhopper.service.sprint.Sprint
import com.atlassian.greenhopper.service.sprint.SprintIssueService

SprintIssueService sprintIssueService

def issue = event.issue
def issueUpdate = (MutableIssue) issue
def igor = ComponentAccessor.getComponent(UserManager).getUserByName("igot")
def cfManager = ComponentAccessor.getComponent(CustomFieldManager)
def sprint = cfManager.getCustomFieldObjectByName("Sprint")
def sprintValue = issue.getCustomFieldValue(sprint)
ArrayList<Sprint> sprints = (ArrayList<Sprint>)issue.getCustomFieldValue(sprint)
def primarySprint = sprints[0].getName()
def issueSet = []
issueSet.add(issue)
for(it in sprints){
if(!(it.getName()).equals(primarySprint)){
log.warn "Igot check: "+igor
log.warn "Sprint check: "+it
log.warn "Issue set check: "+issueSet
sprintIssueService.removeIssuesFromSprint(igor, it, issueSet)
}
}

here are logs:

2018-05-11 15:02:58,768 WARN [runner.ScriptRunnerImpl]: Custom Listener com.atlassian.greenhopper.service.sprint.Sprint@6242e5f9[id=299,rapidViewId=201,state=ACTIVE,name=AS - Sprint 0,startDate=2014-06-09T15:22:45.411+02:00,endDate=2014-06-23T15:22:00.000+02:00,completeDate=<null>,sequence=299]
2018-05-11 15:02:58,768 WARN [runner.ScriptRunnerImpl]: Igot check: igot(igot)
2018-05-11 15:02:58,768 WARN [runner.ScriptRunnerImpl]: Sprint check: com.atlassian.greenhopper.service.sprint.Sprint@2f8e1a8a[id=3526,rapidViewId=678,state=CLOSED,name=ASUM 30,startDate=2017-04-24T16:55:41.192+02:00,endDate=2017-05-07T17:25:00.000+02:00,completeDate=2017-05-08T16:26:41.364+02:00,sequence=3526]
2018-05-11 15:02:58,769 WARN [runner.ScriptRunnerImpl]: Issue set check: [JIRA-5082]
2018-05-11 15:02:58,771 ERROR [runner.AbstractScriptListener]: *************************************************************************************
2018-05-11 15:02:58,771 ERROR [runner.AbstractScriptListener]: Script function failed on event: com.atlassian.jira.event.issue.IssueEvent, file: <inline script>
java.lang.NullPointerException: Cannot invoke method removeIssuesFromSprint() on null object
 at Script544.run(Script544.groovy:30)

Everything seems right and definitely not null :/

I'm not sure what the issue is, but I guess the sprint should be active (check the below link),

https://community.atlassian.com/t5/Jira-questions/Removing-Issues-from-Sprint-using-ScriptRunner-or-the-Java-API/qaq-p/657524 

-Praveen

Suggest an answer

Log in or Sign up to answer
Community showcase
Posted Sep 18, 2018 in Jira

What modern development practices are at the heart of how your team delivers software?

Hey Community mates! Claire here from the Software Product Marketing team. We all know software development changes rapidly, and it's often tough to keep up. But from our research, we've found the h...

20,656 views 2 7
Join discussion

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you