December 8, 2022

ScriptRunner Listener for Suspect flagging

I share in this post how to implement a suspect mechanism in Jira using a ScriptRunner listener.

Challenge description

It is common wish for ALM tools to want to flag issues if a parent linked issue was modified, so that you can later make a change impact analysis; this mechanism is called "suspect link or flagging".

R4J Limitations

R4J Jira Add-On for DataCenter/Server provides also a suspect functionality
Unfortunately, it is a bit hard to customize. For example you can not distinguish between different types of Suspection (like one for reuse, another one for changed after approval)
Also, you can not define a global (=valid for all projects) suspect configuration i.e. you have to duplicate configurations across multiple projects if you need to.
For the cloud version as for now (2022-12-08), you also need to use such an automation. Documentation recommends using Jira Automation.

I present in the next section how to use ScriptRunner for this purpose.

ScriptRunner Solution

You can implement such a mechanism with ScriptRunner using a Listener.
Create a listener for the event 'Issue Updated'.


Script


This script will be triggered if a list of fields was changed (listed in the variable suspectFieldNames).
It will then go through the issues linked via the Reuse link (type inward) and flag/ label these issues with 'suspect_reuse'. The link type and direction as well as the label name are here hard-coded: you might want to adapt them for your need.
A nice comment with references to the parent issue and changed fields will also be written documenting the suspect flagging.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.issue.label.LabelManager
def issue = event.issue
// Set Log Level
import org.apache.log4j.Logger
import org.apache.log4j.Level
def log = Logger.getLogger("com.thda.suspect")
log.setLevel(Level.DEBUG)
// check for IssueType requirement - if no requirement, exit
if (!issue.issueType.name.toLowerCase().contains("requirement")) {
log.info(issue.key + ": Nothing to suspect: No requirement type. -> exit")
return
}
def suspectFieldNames = ["description","summary"]
def commentBody = ""
suspectFieldNames.each{ fn->
def change = event?.getChangeLog()?.getRelated("ChildChangeItem")?.find {it.field == fn}
if (change) {
log.debug "New value for ${fn} : ${change.newstring}"
commentBody = commentBody + """
Field '${fn}' changed to:
{quote}
${change.newstring}
{quote}
"""
}
} // end loop on fields
//if fields have no change history, exit
if (commentBody.isEmpty()) {
log.info(issue.key + ": Nothing to suspect: no Suspected Field changed. -> exit")
return
}
commentBody = "Listener labelled the issue with 'suspect_reuse' because it reuses ${issue.key} which had following fields changed:" + commentBody
log.info("${issue.key}: Suspect flagging triggered because a suspected Field was changed.")
// Loop over linked Reuse: is reused by
LabelManager labelManager = ComponentAccessor.getComponent(LabelManager.class)
def commentManager = ComponentAccessor.getCommentManager()
def issueLinkManager = ComponentAccessor.getIssueLinkManager()
def user = ComponentAccessor.jiraAuthenticationContext.loggedInUser
// Loop on Links Reuse: is reused by (Inward)
def Links = issueLinkManager.getInwardLinks(issue.id)
Links.each {
if (!it.issueLinkType.name == "Reuse") { return }
def linkedIssue = it.sourceObject as MutableIssue
// Add Label 'suspect_reuse' to Reusing issue
log.info("Sel label 'suspect_reuse' to reused issue ${linkedIssue.key}")
labelManager.addLabel(user, linkedIssue.id, 'suspect_reuse', false)
// Add a comment
commentManager.create(linkedIssue, user, commentBody, true)
} // loop on Links

See also

Configuring Suspect Logic - R4J Cloud - Requirements Management for Jira - Confluence