Scriptrunner - listeners on Issue Updates slow down JIRA

Matthew Williams May 14, 2018

Hi,

I have a custom field in my JIRA environment named "Technical Thrust" and it is in all epic, task, and story issues. I've written two custom listeners with the goal of ensuring the Technical Thrust field matches between an epic and the stories/tasks linked to that epic.

The goal of the first listener is to copy the Technical Thrust labels (1 or more) from an epic to any task or story that is linked to the epic. This listener executes on an Issue Update event and has a check to see if the issue is an Epic before copying anything.

The goal of the second is to copy labels from an Epic Link in the event that a user updates a child task or story. The idea here is that someone might link an already created story to an epic, and the Technical Thrust would need to be copied from the new Epic Link. Or a user might accidentally delete a Technical Thrust label and the code would automatically replace it.

The problem arises when I make the second listener execute on event: Issue Updated. Currently the code works just fine if the second listener only executes on event: Issue Created. When I add the second event, then go to a task that has an epic link, the JIRA environment locks up and the script remains hanging. Furthermore, when I check the Script Listener log, I see that the script has been called multiple times (with multiple failures). This leads me to believe that I am creating a loop when the second listener executes on an issue update it causes an update that triggers the script to run multiple times.

Any help would be much appreciated.

Thanks.

The first listener executes on event: Issue Updated

import com.atlassian.jira.issue.Issue
import com.atlassian.jira.ComponentManager;
import com.atlassian.jira.issue.link.IssueLink;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.issue.label.LabelManager;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue

def issueManager = ComponentAccessor.getIssueManager()
def issue = event.issue

// execute following code if in an EPIC
if (issue.issueType.name == "Epic"){

    def customFieldManager = ComponentAccessor.getCustomFieldManager()
    def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
    def labelMgr = ComponentAccessor.getComponent(LabelManager)

    // custom field name is Technical Thrust and its ID is 10300
    def cfname = "Technical Thrust"
    def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == cfname}
    def cfValue = cf.getValue(issue) // return a collection from the epic custom field for technical thrust
    
    if (!cf) {return} // escape if cf does not exist

    List<IssueLink> allOutIssueLink = ComponentAccessor.getIssueLinkManager().getOutwardLinks(issue.getId());
    for (Iterator<IssueLink> outIterator = allOutIssueLink.iterator(); outIterator.hasNext();) {
        IssueLink issueLink = (IssueLink) outIterator.next();
        def linkedIssue = issueLink.getDestinationId()
        
        def child = issueManager.getIssueObject(linkedIssue) //as Issue
        
        if (!child) {return} // if null, escape
        
        // clear any labels from the child before updating the labels
        def dummy = "" as Set
        def childCF = customFieldManager.getCustomFieldObjects(child).find {it.name == cfname}
        def changeHolder = new DefaultIssueChangeHolder()
        childCF.updateValue(null,child, new ModifiedValue(child.getCustomFieldValue(childCF),dummy),changeHolder)
        
        // loop through each string in cfValue (in the event of multiple labels)
        for (String s : cfValue) {
            labelMgr.addLabel(currentUser, child.getId(), 10300L, s, false);
        }        
    }
}

The second listener executes on event: Issue Created

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.label.LabelManager
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issue = event.issue as MutableIssue

// execute following code if issue type is task or story
if (issue.issueType.name == "Task" || issue.issueType.name == "Story"){
    
    def currentUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def labelMgr = ComponentAccessor.getComponent(LabelManager)

    // custom field name is Technical Thrust and its ID is 10300
    def cfname = "Technical Thrust"
    def cf = customFieldManager.getCustomFieldObjects(issue).find {it.name == cfname}
def epicCf = customFieldManager.getCustomFieldObjects(issue).find {it.name == 'Epic Link'}
    if (!cf || !epicCf) {return} // escape if cf or epicCf do not exist

    def epic = issue.getCustomFieldValue(epicCf) as Issue

    if (!epic) {return} // escape if epic does not exist

    def cfValue = cf.getValue(epic) // return a collection from the epic custom field

    // clear any existing labels before updating
    def dummy = "" as Set
    def changeHolder = new DefaultIssueChangeHolder()
    cf.updateValue(null,issue, new ModifiedValue(issue.getCustomFieldValue(cf),dummy),changeHolder)

    // loop through each string in cfValue (in the event of multiple labels)
    for (String s : cfValue) {
        labelMgr.addLabel(currentUser, event.issue.getId(), 10300L, s, false);
    }
}

 

 

 

1 answer

Suggest an answer

Log in or Sign up to answer
0 votes
Praveen
Contributor
May 14, 2018

Hi, 

Since the only loop that is available here is the for loop, can you try something like this,

for(int i=0; i<cfValue.size(); i++){
labelMgr.addLabel(currentUser, event.issue.getId(), 10300L, cfValue[i].toString(), false);
}

 -Praveen

Matthew Williams May 15, 2018

Hi Praveen,

Thanks for the suggestion, but it did not solve my problem.

When I create a task and assign an Epic Link, JIRA indicates in my activity feed that I've done 3 things: 1) created a task, 2) updated task's epic link, and 3) updated the epic's children. When I said loop, my thought was that the the updated epic children causes my listener to execute, which updates the tasks under an epic and causes the update listener to execute again, creating a loop.

Praveen
Contributor
May 15, 2018

Hi Matthew,

Ok, now I got the issue. This is kind of tricky to solve. One solution from my side would be you can use the issueLinkManager to get the links associated to an issue and get the different links (parent/child/etc..) and use it for executing your script (like only for the child links etc..).

Again, this is juat a suggestion as I'm not aware of how the links are established in your environment. Check the below link for more about issueLinkManager

https://docs.atlassian.com/software/jira/docs/api/7.0.4/com/atlassian/jira/issue/link/IssueLinkManager.html

-Praveen

TAGS
AUG Leaders

Atlassian Community Events