Insight Automation - Unable to resolve classes

Claire Berry May 2, 2023

Hi, 

I have created some Insight Automation which executes a Groovy script. The script works fine when used in scriptrunner script console. But when I add it to an Insight Automation rule, it does not work. 

I checked the server logs and found that the issue is it is unable to resolve some local and scriptrunner classes. 

Can anyone please tell me how I import these types of classes to work here?

Below is the errors:

Error when executing groovy script: /opt/atlassian/application-data/jira/shared/custom-jira-functions/insight-automation/ukicmdb/map-insight-user-to-jira-user.groovy

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

/shared/custom-jira-functions/insight-automation/ukicmdb/map-insight-user-to-jira-user.groovy: 9: unable to resolve class shared.User

 @ line 9, column 1.

   import shared.User

   ^

 

/shared/custom-jira-functions/insight-automation/ukicmdb/map-insight-user-to-jira-user.groovy: 8: unable to resolve class shared.Insight

 @ line 8, column 1.

   import shared.Insight

   ^

 

/shared/custom-jira-functions/insight-automation/ukicmdb/map-insight-user-to-jira-user.groovy: 10: unable to resolve class shared.Environment

 @ line 10, column 1.

   import shared.Environment

   ^

 

/shared/custom-jira-functions/insight-automation/ukicmdb/map-insight-user-to-jira-user.groovy: 7: unable to resolve class com.onresolve.scriptrunner.runner.customisers.WithPlugin

 @ line 7, column 1.

   import com.onresolve.scriptrunner.runner.customisers.WithPlugin

   ^

 

/shared/custom-jira-functions/insight-automation/ukicmdb/map-insight-user-to-jira-user.groovy: 6: unable to resolve class com.onresolve.scriptrunner.runner.customisers.PluginModule

 @ line 6, column 1.

   import com.onresolve.scriptrunner.runner.customisers.PluginModule

   ^

 

5 errors

1 answer

0 votes
Peter-Dave 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.
May 2, 2023

The insight groovy framework is a lot more barebones than the scriptrunner one.

You will not have access to any com.onresolve... classes in the Insight groovy framework.
So WithPlugin and PluginModule won't be possible.

As for your shared classes, the only way I've found to use them is to load them using the classloader.

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.util.JiraHome

def jiraHome = ComponentAccessor.getComponentOfType(JiraHome.class).home
Class Insight = new GroovyClassLoader(getClass().classLoader).parseClass(new File("$jiraHome/shared/Insight.groovy"))

You will not get any autocomplete. And those shared classes will not be able to also import other shared classes or use anything from the scriptrunner framework.

To replace something like

@WithPlugin("com.atlassian.servicedesk") sdPlugin
@PluginModule ServiceDeskManager serviceDeskManager

You would do something like this:

def classLoader = ComponentAccessor.pluginAccessor.classLoader
def serviceDeskManager = ComponentAccessor.getOSGiComponentInstanceOfType(classLoader.findClass('com.atlassian.servicedesk.api.ServiceDeskManager'))

 

Something to keep in mind (especially if any of your shared classes are large) is that they are never pre-compiled and caches like they are in scriptrunner.

Each time the groovy script is loaded (once for every object that triggered the automation), each groovy file is read fresh from the disk and compiled on the fly. This could be a performance bottleneck.

 

My preference where I can is to use ScriptRunner for as much of the logic as possible. 

You can create a rest endpoint with all the logic, then use a simpler instance of an Insight Groovy script to call that rest endpoint.

Here is, for example, one of my scripts that runs on my Employee object type. It detects if any user's full name is changed, and then calls the rest endpoint called "processInsightNameChange" that does things (in my case, it updates some attributes in Active Directory).

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.util.JiraHome
import com.atlassian.sal.api.net.Request
import com.atlassian.sal.api.net.TrustedRequest
import com.atlassian.sal.api.net.TrustedRequestFactory
import groovy.json.JsonBuilder
import groovyx.net.http.ContentType
import groovyx.net.http.URIBuilder

def fullNameAttributeName = 'Full Name'

def processNameChange = false
def nameChangeItem
if (objectUpdateList) {
log.info "Attributes updated: \n ${new JsonBuilder(objectUpdateList.collect { [(it.attributeName): [added: it.addedValues, removed: it.removedValues]] }).toPrettyString()}"
nameChangeItem = objectUpdateList.find { it.attributeName == fullNameAttributeName }
log.info "nameChangeItem=$nameChangeItem"
}
if (!nameChangeItem) return

def currentUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def baseUrl = ComponentAccessor.applicationProperties.jiraBaseUrl

def trustedRequestFactory = ComponentAccessor.getOSGiComponentInstanceOfType(TrustedRequestFactory)

def restUrl = baseUrl + '/rest/scriptrunner/latest/custom/processInsightNameChange'
def request = trustedRequestFactory.createTrustedRequest(Request.MethodType.POST, restUrl) as TrustedRequest
def oldName = nameChangeItem.removedValues[0]
def newName = nameChangeItem.addedValues[0]
def payload = [objectKey: object.objectKey, oldName: oldName, newName: newName]
def jsonPayload = new JsonBuilder(payload).toString()
request.addTrustedTokenAuthentication(new URIBuilder(baseUrl).host, currentUser.name)
request.setRequestBody(jsonPayload, ContentType.JSON.toString())
log.info "Making POST request to $restUrl"
log.info " as user: $currentUser.name"
log.info " with paylod: $jsonPayload"
log.info " and Headers: ${request.getHeaders().toString()}"
def resp = request.execute()

 

Suggest an answer

Log in or Sign up to answer