How to implement CannedScript interface for parameterized scripts in scriptrunner

Hello -

I have hacked together the script below as a toy example of using the full functionality of script-runner - except - I don't know how to get it registered like the built in scripts from scriptrunner. Any help would be appreciated (I don't assume that everything in the script is currently correct - I am currently focused on deploy-time parameterization.

ackage com.onresolve.jira.groovy.CloseChildIssues

//these are the imports we need to do our functions.
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.issue.comments.CommentManager
import com.opensymphony.workflow.WorkflowContext
import org.apache.log4j.Category
import com.atlassian.jira.config.SubTaskManager
import com.atlassian.jira.workflow.WorkflowTransitionUtil;
import com.atlassian.jira.workflow.WorkflowTransitionUtilImpl;
import com.atlassian.jira.util.JiraUtils;

//these are the imports from onresolve that make life easier (allow us to structure nicely)
import com.onresolve.jira.groovy.canned.CannedScript
import com.onresolve.jira.groovy.canned.utils.CannedScriptUtils
import com.onresolve.jira.groovy.canned.utils.ConditionUtils
import com.onresolve.jira.groovy.canned.utils.WorkflowUtils
import com.opensymphony.workflow.loader.ActionDescriptor
import com.opensymphony.workflow.loader.StepDescriptor

class CloseChildISsues implements CannedScript{

//these are definitely not the fields we want to work with, but this is the fields section.

log = Category.getInstance("com.ezesoft.jira.groovy.AutoCloseChildIssues")

WorkflowTransitionUtil workflowTransitionUtil = ( WorkflowTransitionUtil ) JiraUtils.loadComponent( WorkflowTransitionUtilImpl.class );
SubTaskManager subTaskManager = ComponentManager.getInstance().getSubTaskManager();
Collection subTasks = issue.getSubTaskObjects()

String getName() {
return "Close Sub-Tasks."

public String getHelpUrl() {

String getDescription() {
return "Transition Sub-Tasks when Parent Task transitions"

List getCategories() {

//this is a helper method that can get the possible actions.
Integer getActionId(Issue issue, String actionName) {
JiraWorkflow workflow = componentManager.getWorkflowManager().getWorkflow(issue)
StepDescriptor step = workflow.getLinkedStep(issue.status)
ActionDescriptor ad = step.getActions().find { == actionName} as ActionDescriptor

List getParameters(Map params) {
Label:"Child action",
Description:"Choose the action to do on the child when the parent is resolved",
Type: "list",
Values: CannedScriptUtils.getAllWorkflowActions(false),
Type: "list",
Description:"Resolution to use on the child",
Values: CannedScriptUtils.getResolutionOptions(true),

//empty error collection on the validator.
public ErrorCollection doValidate(Map params, boolean forPreview) {
// todo: check this is on a sub-task type

Map doScript(Map params) {
log.debug ("TestCondition.doScript with params: ${params}");

String actionName = params[FIELD_CHILDACTION] as String
User user = WorkflowUtils.getUser(params)
String resolutionId = params[FIELD_RESOLUTION_ID] as String

if (subTaskManager.subTasksEnabled && !subTasks.empty) {
subTasks.each {
log.debug (" " +
//it has special meaning in groovy - "each subTask knows itself as 'it'"
Integer actionId = actionName?.replaceAll(/ .*/, "") as Integer

if (WorkflowUtils.hasAction(it, actionId)) {
WorkflowUtils.resolveIssue(it, actionId, user, resolutionId, [:])
else {
log.warn("Action name: $actionName not found for this step.")

// Add a comment so people have a clue why the child has been closed
CommentManager commentManager = (CommentManager) ComponentManager.getComponentInstanceOfType(CommentManager.class);
String comment = "*Resolving* as a result of the *Resolve* action being applied to the parent.";
commentManager.create(it, currentUser, comment, true);

// validate and transition issue
return params

String getDescription(Map params, boolean forPreview) {

public Boolean isFinalParamsPage(Map params) {

Thanks in advance.

1 answer

1 accepted

1 vote
Accepted answer

See details from to run the script in the backend, add "ADMIN" to the list of categories returned. Other then that just make sure you implemented the 4(?) basic methods of the interface.

From that page:

Any scripts with the package com.onresolve.jira.groovy.canned and which implement the interface above will be automatically recognised, and reloaded when they change. So the simplest method of development is to have the script open in your IDE or text editor, make changes, then copy it out to the jira classpath, eg to <jira>/atlassian-jira/WEB-INF/classes/com/onresolve/jira/groovy/canned/admin, then reload the page. Or, you can just edit the built-in script which is in the classpath, and reload the page.

Thanks Eddie - I totally missed the hacking section - the path is exactly what I needed.

Surprised this is working for you - I would think you'd have the same issue as Eddie has in his question, unless I've completely got this wrong.

Suggest an answer

Log in or Sign up to answer
Community showcase
Published Jan 08, 2019 in Jira

How to Jira for designers

I’m a designer on the Jira team. For a long time, I’ve fielded questions from other designers about how they should be using Jira Software with their design team. I’ve also heard feedback from other ...

955 views 3 9
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you