Scriptrunner assistance - exclude specific statuses from returned issues

Jamie Rogers
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.
March 5, 2020

Hi Community

I would like to get some assistance with Scriptrunner for an existing script we have. In its current form the script returns some specific field data from linked issues and is used in reporting however there is now a requirement to exclude issues of a particular status.

I am unsure how to construct the exclusion part of the script and need a bit of help with this. I want to exclude issues that are either in "Live" or "Withdrawn" statuses.

Script - Current form

import com.atlassian.jira.component.pico.ComponentManager
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.component.ComponentAccessor

def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def cfManager = ComponentAccessor.getCustomFieldManager()

def retVal = ''

// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)

def itr = links.iterator()
while (itr.hasNext()) {
def link = itr.next()

// Only care about "depends on" link types
if (link.issueLinkType.name != 'Depends') {
continue
}

// Get other issue
def linkedIssue = link.destinationObject

// Line seperators if more than one ticket
if (retVal != '') {
retVal += '<br>'
}
retVal += "${linkedIssue.getKey()} [${linkedIssue.getStatus().getName()}] - ${linkedIssue.getSummary()} "
}

return retVal

Thanks in advance for any assistance offered. 

Regards, Jamie 

1 answer

1 accepted

1 vote
Answer accepted
PD 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.
March 5, 2020

I've been on a journey to make more of my scripts and responses "groovy" ...

I think this 10-line script can achieve the same output

import com.atlassian.jira.component.ComponentAccessor

def excludedStatuses= ['Live', 'Withdrawn']
def includedLinkTypes = ['Depends']
// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)

links.findAll{ it.issueLinkType in includedLinkTypes }
.destinationObject
.findAll{ !(it.status.name in excludedStatuses)}
.collect{ "$it.key [$it.status.name] - $it.summary"}
.join('<br>')

Let me try to explain what's going on there...

1) 2 or the imports were not used /not necessary

2) I defined a couple of variables that you can easily add/remove status and link types that you have business logic on

3) findAll{ it.issueLinkType in includeLinkTypes } will filter the links to include only those that match the "Depends" link type (or any other you decide to add to the variable later)

4) .destinationObject takes the filtered list and returns a collection of destinationObject issues

5) another .findAll to filter the list of destinationObject (I.e. issues) to only include those that are not in the list of excludedStatuses

6) collect will take all the remaining items and return them as a collection of strings

7) and finally, we join all those issues with <br> in between to return one large HTML string.

Jamie Rogers
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.
March 8, 2020

HI @PD Sheehan 

Thanks for taking the time to reply.

Unfortunately I am getting a 'null' response on the suggested code above - also my Scriptrunner console it showing multiple errors:

  • "issueLinkManager is not declared"
  • "No such property for issueLinkType class / destinationObject class"
  • "No such property for key / status / summary class"

If its helpful we are running Jira 8.7 and Scriptrunner 5.7.

Again I appreciate your assistance with this.

Regards, Jamie 

PD 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.
March 8, 2020

Apologies, I messed up when copying.

 

import com.atlassian.jira.component.ComponentAccessor
def issueLinkManager = ComponentAccessor.issueLinkManager
def issue = ComponentAccessor.issueManager.getIssueObject('JSP-1922') //only for console, issue will be provided by the workflow/listener context

def excludedStatuses= ['Live', 'Withdrawn']
def includedLinkTypes = ['Depends']
// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)

links.findAll{ it.issueLinkType in includedLinkTypes }
.destinationObject
.findAll{ !(it.status.name in excludedStatuses)}
.collect{ "$it.key [$it.status.name] - $it.summary"}
.join('<br>')
Jamie Rogers
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.
March 8, 2020

Thanks @PD Sheehan 

Some progress as I no longer see those script errors however for my test issue I don't get any results - still displays 'null'.

The example I am testing with has two depends links - 1) where linked issue state is 'live' and another 2) linked issue where its state is "in flight". I would expect to see the in flight issue however there are other status combinations depends linked issues could be.

For reference my original script on my test issue returns the following:

  • ABC-1890 [Live] - Summary
  • ABC-1829 [In Flight] - Summary

There is one warning on the script still - "Variable 'issue' masks a binding variable of the same name. Choose a different name for variable 'issue'"

Regards, Jamie 

PD 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.
March 8, 2020

Where are you using that code?

You indicated console earlier. In console, you should have "def issue = ..."  and have your test issue.
Anywhere else, you should remove that line... the issue will be provied by the script context.

Let's add some debug messages:

import org.apache.log4j.Level
import com.atlassian.jira.component.ComponentAccessor
log.setLevel(Level.DEBUG)

def issueLinkManager = ComponentAccessor.issueLinkManager
def issue = ComponentAccessor.issueManager.getIssueObject('JSP-1922')
def excludedStatuses= ['Live', 'Withdrawn']
def includedLinkTypes = ['Depends']
// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)
log.debug "Count of outward links for $issue.key: ${links.size()}"
links.findAll{
log.debug "testing link type for $it.destinationObject.key : $it.issueLinkType.name"
it.issueLinkType.name in includedLinkTypes }
.destinationObject
.findAll{
log.debug "testing status for $it.key : $it.status.name"
!(it.status.name in excludedStatuses)
}
.collect{ "$it.key [$it.status.name] - $it.summary"}
.join('<br>')

Doing that in my own console, I found that I was missing a .name against the issueLinkType 

So the corrected original code (without debug logs)

import com.atlassian.jira.component.ComponentAccessor
def issueLinkManager = ComponentAccessor.issueLinkManager
def issue = ComponentAccessor.issueManager.getIssueObject('JSP-1922') //only for console, issue will be provided by the workflow/listener context

def excludedStatuses= ['Live', 'Withdrawn']
def includedLinkTypes = ['Depends']
// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)

links.findAll{ it.issueLinkType.name in includedLinkTypes }
.destinationObject
.findAll{ !(it.status.name in excludedStatuses)}
.collect{ "$it.key [$it.status.name] - $it.summary"}
.join('<br>')
Jamie Rogers
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.
March 8, 2020

Thanks @PD Sheehan 

This is working great - my next challenge is to apply this re-work to another scripted field as I need the same status filtering applied but the other script does a bit more (it gets values from different custom fields from linked issues).

  • Would you be able to work you magic on this other one?

I am still trying to wrap my head around what you did above but I am not coder. These previous scripts were written by a different admin who left some time ago. 

Regards, Jamie 

import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.component.pico.ComponentManager;
import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.Issue;

def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def cfManager = ComponentAccessor.getCustomFieldManager()

def retVal = ''

// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)

def itr = links.iterator()
while (itr.hasNext()) {
def link = itr.next()

// Only care about "depends on" link types
if (link.issueLinkType.name != 'Depends') {
continue
}

// Get other issue
def linkedIssue = link.destinationObject

// Line seperators if more than one ticket
if (retVal != '') {
retVal += '<br>'
}

// Get delivery team
def deliveryTeamField = cfManager.getCustomFieldObject("customfield_16286")
def deliveryTeam = linkedIssue.getCustomFieldValue(deliveryTeamField)

// Get Effort in Weeks value
def effortWeeksField = cfManager.getCustomFieldObject("customfield_16053")
def effortValue = linkedIssue.getCustomFieldValue(effortWeeksField)

// Make the output pretty
if (deliveryTeam != null) {

// Show second level of cascade list if exists
if (deliveryTeam.values()[1] != null) {
retVal += "${deliveryTeam.values()[1]}"
} else {
retVal += "${deliveryTeam.values()[0]}"
}

if (effortValue != null) {
retVal += " - ${effortValue.round()} [${linkedIssue.getStatus().getName()}]"
}
} else {
retVal += "${linkedIssue.getKey()} [${linkedIssue.getStatus().getName()}]"
}

}

return retVal
PD 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.
March 9, 2020

Here is how I would rewrite that second script using many of the same concepts initially shared:

import com.atlassian.jira.component.ComponentAccessor;

def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def cfManager = ComponentAccessor.getCustomFieldManager()

def excludedStatuses= ['Live', 'Withdrawn']
def includedLinkTypes = ['Depends']

//get the custom field objects
def deliveryTeamField = cfManager.getCustomFieldObject("customfield_16286")
def effortWeeksField = cfManager.getCustomFieldObject("customfield_16053")

// Get only outward links
def links = issueLinkManager.getOutwardLinks(issue.id)

links.findAll{ it.issueLinkType.name in includedLinkTypes }
.destinationObject
.findAll{ !(it.status.name in excludedStatuses)}
.collect{ linkedIssue ->
// Get delivery team
def deliveryTeam = linkedIssue.getCustomFieldValue(deliveryTeamField)
// Get Effort in Weeks value
def effortValue = linkedIssue.getCustomFieldValue(effortWeeksField)

// Make the output pretty
if (deliveryTeam ) {
// Show second level of cascade list if exists
def retDeliveryTeam = deliveryTeam.values()[1].value ?: deliveryTeam.values()[0].value
if (effortValue) {
return "$retDeliveryTeam - ${effortValue.round()} [$linkedIssue.status.name]"
}
} else {
return "$linkedIssue.key [$linkedIssue.status.name]"
}
}.join('<br>')

The only new thing here is the "Elvis" operator: ?:

This will assign the value from the left side of the operation if it is non-null otherwise, it will assign the right side. It is a shortened version of 

def variable = (some condition) ? valueIfConditionIsTrue : valueIfConditionIsFalse 
Jamie Rogers
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.
March 9, 2020

Hi @PD Sheehan 

Again this does exactly what I need.

I really appreciate your assistance helping me with these two fields.

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
SERVER
VERSION
8.5.1
TAGS
AUG Leaders

Atlassian Community Events