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
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.
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:
If its helpful we are running Jira 8.7 and Scriptrunner 5.7.
Again I appreciate your assistance with this.
Regards, Jamie
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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>')
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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:
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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>')
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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).
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @PD Sheehan
Again this does exactly what I need.
I really appreciate your assistance helping me with these two fields.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.