Hi @kibeh ,
What is probably happening
You have something like:
scripts/
├── TextHelper.groovy
└── WatcherHelper.groovy
and:
import util.TextHelper
import util.WatcherHelper
TextHelper works because it is probably independently resolvable by Exalate’s external-script classloader.
WatcherHelper is different because WatcherHelper.groovy itself has dependencies on ScriptRunner/HAPI classes, e.g.:
import org.slf4j.LoggerFactory
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.component.ComponentAccessor
So the problem isn’t necessarily the physical location or permissions of WatcherHelper.groovy. The problem is the dependency/classloading chain:
Exalate outgoing script
↓
WatcherHelper.groovy
↓
ScriptRunner / HAPI classes
↓
Jira / ScriptRunner classloader
The Exalate script editor’s validation/compiler doesn’t necessarily have access to that entire chain when it tries to save the processor.
Solution I’d recommend
Turn WatcherHelper into a compiled class/JAR and expose that to Exalate.
For example:
exalate-scripts/
util/
TextHelper.class
WatcherHelper.class
or preferably:
exalate-scripts/
watcher-helper.jar
with:
package util
class WatcherHelper {
...
}
Then your Exalate script remains clean:
import util.TextHelper
import util.WatcherHelper
// normal Exalate logic
This is actually aligned with Exalate’s documented external-script architecture: externalized scripts can include Groovy source, compiled classes, and packaged JARs.
The important part is that the compiled class/JAR must be built against the Jira/ScriptRunner libraries that exist on that particular Jira Data Center installation.
Let me know if this makes sense!
Thanks, Dhiren