Scriptrunner for Confluence - Figuring out how to call the built in canned script, AddRemoveWatchers
Asked by Melanie Pasztor:

Hello!

I am trying to figure out how to get a groovy script calling a builtin canned script with Scriptrunner for Confluence to work.

```
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.confluence.spaces.SpaceManager
import com.atlassian.user.UserManager
import com.atlassian.user.GroupManager
import com.onresolve.scriptrunner.canned.confluence.admin.AddRemoveWatchers

//Managers
def spaceManager = ComponentLocator.getComponent(SpaceManager)
def groupManager = ComponentLocator.getComponent(GroupManager)
def userManager = ComponentLocator.getComponent(UserManager)

//Canned built-in script
def removeWatchers = new AddRemoveWatchers()

//Variables
def spaceKey = "TEST"
def groupNames = "confluence-users"
def userKeys = ""
def targetSpace = spaceManager.getSpace(spaceKey)
def targetGroup = groupManager.getGroup(groupNames)
def targetUser = userManager.getUser(userKeys)

//Script Parameters
def scriptParams = [
        "FIELD_CONTENT_TYPE": "Space",
        "FIELD_SPACE_KEY": targetSpace,
        "FIELD_GROUPS": targetGroup,
        "FIELD_USERS": targetUser,
        "FIELD_WATCH_OR_UNWATCH": "Unwatch",
]

//Run Script
def runScript = removeWatchers.doScript(scriptParams)
runScript
```

Console giving the errror:

groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.onresolve.scriptrunner.canned.confluence.admin.AddRemoveWatchers() at Script170.run(Script170.groovy:13)

And before that, a groovy.lang.MissingMethodException error for the same thing (not even sure how the error can change overnight without any changes).

The only examples I have found are for calling the CopySpace or Labels scripts.

My scriptrunner/groovy-fu is lacking, and despite having AddRemoveWatchers class opened as referenced, unsure what command/method/call is needed, and/or run the built-in script.

The goal is to automate the AddRemoveWatchers for designated spaces with a Event Listener or Job.

I appreciate any insight and help!

-Melanie


Answers:
author: Dominic Lagger
body: Hi [@Melanie Pasztor](/t5/user/viewprofilepage/user-id/3586152)

This script should do what you want. Thanks for the challenge :)

```
import com.onresolve.scriptrunner.runner.customisers.PluginModule;
import com.atlassian.sal.api.component.ComponentLocator;
import com.atlassian.confluence.core.ContentPermissionManager;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.security.SpacePermissionManager;
import com.onresolve.scriptrunner.runner.ScriptRunner;
import com.atlassian.confluence.spaces.SpaceManager;
import com.atlassian.confluence.mail.notification.NotificationManager;
import com.atlassian.sal.api.user.UserManager;
import com.atlassian.user.GroupManager;
import com.onresolve.scriptrunner.canned.util.SimpleBuiltinScriptErrors;
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.confluence.user.UserAccessor
import com.onresolve.scriptrunner.canned.confluence.utils.CQLSearchUtils
import com.onresolve.scriptrunner.canned.confluence.admin.AddRemoveWatchers
import com.onresolve.scriptrunner.canned.confluence.admin.model.AddRemoveWatchersCommand
import com.atlassian.confluence.core.ContentEntityManager
import com.atlassian.confluence.api.service.search.CQLSearchService

import com.google.gson.Gson

import java.util.Map;
import java.util.LinkedHashMap

class AddWatcher {
def String addWatcher() {

UserAccessor userAccessor = ComponentLocator.getComponent(UserAccessor)
GroupManager groupManager = ComponentLocator.getComponent(GroupManager)
ContentPermissionManager contentPermissionManager = ComponentLocator.getComponent(ContentPermissionManager)
SpaceManager spaceManager = ComponentLocator.getComponent(SpaceManager)
NotificationManager notificationManager = ComponentLocator.getComponent(NotificationManager)

@PluginModule
CQLSearchService cqlSearchService
ContentEntityManager contentEntityManager = ComponentLocator.getComponent(ContentEntityManager)
CQLSearchUtils cqlSearchUtils = new CQLSearchUtils(cqlSearchService, contentEntityManager)

SpacePermissionManager spacePermissionManager = ComponentLocator.getComponent(SpacePermissionManager)

@PluginModule
ScriptRunner scriptRunner

AddRemoveWatchers watchers = new AddRemoveWatchers(userAccessor, groupManager, spaceManager, notificationManager, cqlSearchUtils, spacePermissionManager, contentPermissionManager)


AddRemoveWatchersCommand command = new AddRemoveWatchersCommand()

command.setContentType("space")
command.setSpaceKey("spacekey")
command.setGroupNames([""])
command.setUserKeys(["USERKEY"])
command.setWatchOrUnwatch("watch")

SimpleBuiltinScriptErrors errorCollection = (SimpleBuiltinScriptErrors) watchers.validate(command, false) 
if(errorCollection.hasAnyErrors()) {
log.debug("Could not copy page tree: $errorCollection")
} else {
watchers.execute(command)
}

}
}
```

Regards Dominic

comments: author: Melanie Pasztor
body: Awesome, that helps a lot! Helps understanding what is referring to.

With that, trying to get working. Regardless what I enter for the command variables, nothing happens other than saying 'class AddWatcher' in the Console, and then the following error when triggered to run in a listener:

```
groovy.lang.MissingMethodException: No signature of method: AddWatcher.main() is applicable for argument types: ([Ljava.lang.String;) values: [[]]
Possible solutions: wait(), wait(long), find(), any(), wait(long, int), is(java.lang.Object)

at com.onresolve.scriptrunner.runner.RunScriptInvoker$run.call(Unknown Source)
at com.onresolve.scriptrunner.runner.AbstractScriptRunner.runScriptWithRawBindings(AbstractScriptRunner.groovy:190)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at com.onresolve.scriptrunner.runner.AbstractScriptRunner.runScript(AbstractScriptRunner.groovy:184)
at com.onresolve.scriptrunner.runner.AbstractScriptRunner$runScript$6.callCurrent(Unknown Source)
at com.onresolve.scriptrunner.runner.AbstractScriptRunner.runScriptAndGetContext(AbstractScriptRunner.groovy:210)
at com.onresolve.scriptrunner.runner.AbstractScriptRunner$runScriptAndGetContext$4.callCurrent(Unknown Source)
at com.onresolve.scriptrunner.runner.AbstractScriptRunner.runFileAsScript(AbstractScriptRunner.groovy:322)
at com.onresolve.scriptrunner.runner.ScriptRunner$runFileAsScript$11.call(Unknown Source)
at com.onresolve.scriptrunner.canned.jira.utils.CustomScriptDelegate.doScript(CustomScriptDelegate.groovy:78)
at com.onresolve.scriptrunner.canned.jira.utils.CustomScriptDelegate$doScript$3.call(Unknown Source)
at com.onresolve.scriptrunner.canned.confluence.events.SimpleScriptedEventHandler.doScript(SimpleScriptedEventHandler.groovy:59)
```

Similar error I had before, but from the console. I am gathering that it missing an expected parameter.


author: Dominic Lagger
body: What exactly do you type in the script console?

I do it with:

```
AddWatcher aut = new AddWatcher()
aut.addWatcher()
```

Hope this helps

Regards, Dominic


author: Melanie Pasztor
body: The script above with some details changed for space, group, user, and set to unwatch. Directly in the scriptrunner's Script Console. The error when using same script, and some of the modification attempts to make it work.

Removing the whole class thing, leaving everything under def String addWatcher() {...}, says it ran successfully, no change with the watchers of the designated space. Some colleagues cannot help me, as they are not familiar with groovy despite being java based.

Does not seem the class is needed, and is just stopping from the rest to being runned.

As for the new suggestion, I am not sure how that would be implemented with the script above. Do I replace the class with that? Does aut replace watchers in watchers.execute portion?

My experience with Scriptrunner and groovy are simpler scripts in Jira that area triggered in workflows or behaviours. And my Java limited to tweaking and modding something existing.


author: Dominic Lagger
body: Okay, I think I know what the problem is.

The script with the class is a File in the "Script Editor" and can not be runned in the console directly. This is the idea of object oriented programming.

To run it directly in the script console, use this script: (It is the same, but without the "class" and "methwod" definitions)

```
import com.onresolve.scriptrunner.runner.customisers.PluginModule;
import com.atlassian.sal.api.component.ComponentLocator;
import com.atlassian.confluence.core.ContentPermissionManager;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.security.SpacePermissionManager;
import com.onresolve.scriptrunner.runner.ScriptRunner;
import com.atlassian.confluence.spaces.SpaceManager;
import com.atlassian.confluence.mail.notification.NotificationManager;
import com.atlassian.sal.api.user.UserManager;
import com.atlassian.user.GroupManager;
import com.onresolve.scriptrunner.canned.util.SimpleBuiltinScriptErrors;
import org.apache.log4j.Level
import org.apache.log4j.Logger
import com.atlassian.confluence.user.UserAccessor
import com.onresolve.scriptrunner.canned.confluence.utils.CQLSearchUtils
import com.onresolve.scriptrunner.canned.confluence.admin.AddRemoveWatchers
import com.onresolve.scriptrunner.canned.confluence.admin.model.AddRemoveWatchersCommand
import com.atlassian.confluence.core.ContentEntityManager
import com.atlassian.confluence.api.service.search.CQLSearchService

import com.google.gson.Gson

import java.util.Map;
import java.util.LinkedHashMap

UserAccessor userAccessor = ComponentLocator.getComponent(UserAccessor)
GroupManager groupManager = ComponentLocator.getComponent(GroupManager)
ContentPermissionManager contentPermissionManager = ComponentLocator.getComponent(ContentPermissionManager)
SpaceManager spaceManager = ComponentLocator.getComponent(SpaceManager)
NotificationManager notificationManager = ComponentLocator.getComponent(NotificationManager)

@PluginModule
CQLSearchService cqlSearchService
ContentEntityManager contentEntityManager = ComponentLocator.getComponent(ContentEntityManager)
CQLSearchUtils cqlSearchUtils = new CQLSearchUtils(cqlSearchService, contentEntityManager)

SpacePermissionManager spacePermissionManager = ComponentLocator.getComponent(SpacePermissionManager)

@PluginModule
ScriptRunner scriptRunner

AddRemoveWatchers watchers = new AddRemoveWatchers(userAccessor, groupManager, spaceManager, notificationManager, cqlSearchUtils, spacePermissionManager, contentPermissionManager)


AddRemoveWatchersCommand command = new AddRemoveWatchersCommand()

command.setContentType("space")
command.setSpaceKey("SPACEKEY")
command.setGroupNames([""])
command.setUserKeys(["USERKEY"])
command.setWatchOrUnwatch("watch")

SimpleBuiltinScriptErrors errorCollection = (SimpleBuiltinScriptErrors) watchers.validate(command, false) 
if(errorCollection.hasAnyErrors()) {
log.debug("Could not copy page tree: $errorCollection")
} else {
watchers.execute(command)
}
```

Hope this works

Regards, Dominic


author: Melanie Pasztor
body: I have tried both stripping the class and the def String before, yet got a NullPoint error. Posted yours exactly, and ran successfully. I had the NullPointer it seems due to some capitalization in the command.setEtcs. \>.\>

It works in console, and in turn with the event listener. Woot!

Lesson learned, groovy script does not function like a java class script. Scriptrunner and/or groovy factors that in when implementing. Also helps better understand the interaction with the API structure.

Thank you! :)


author: Nathanael Motz
body: This is great but how do I extend it to other built-in scripts? CopyTree, for example. There is no CopyTreeCommand under com.onresolve.scriptrunner.canned.confluence.admin.model. How can I figure out which items are needed when creating a new instance of CopyTree (such as userAccessor, groupManager, etc used in the "AddRemoveWatchers watchers = new AddRemoveWatchers" command in the above script)?


author: Dominic Lagger
body: Hi, there is no way of finding it easily.

What I did: I decrypted the jar File of the scriptrunner plugin and searched for the correct classes... for CopyTree, this is it:

```
PageManager pageManager = ComponentLocator.getComponent(PageManager)
AttachmentManager attachmentManager = ComponentLocator.getComponent(AttachmentManager)
CommentManager commentManager = ComponentLocator.getComponent(CommentManager)
ContentPermissionManager contentPermissionManager = ComponentLocator.getComponent(ContentPermissionManager)
LabelManager labelManager = ComponentLocator.getComponent(LabelManager)
UserManager userManager = ComponentLocator.getComponent(UserManager)
EventPublisher pub = ComponentLocator.getComponent(EventPublisher)
ConfluenceApplicationProperties properties = ComponentLocator.getComponent(ConfluenceApplicationProperties)

@PluginModule
PermissionManager permissionManager

SpaceManager spaceManager = ComponentLocator.getComponent(SpaceManager)
TransactionTemplate transactionTemplate = ComponentLocator.getComponent(TransactionTemplate)
CopyPageService service = new CopyPageService(pageManager,attachmentManager,commentManager,contentPermissionManager,labelManager,permissionManager,spaceManager,userManager,pub)
CopyTree copyTree = new CopyTree(service)
```

Hope this helps for your project :)

Regards


author: Jillian Patterson
body: Hi [@Melanie Pasztor](/t5/user/viewprofilepage/user-id/3586152) and [@Nathanael Motz](/t5/user/viewprofilepage/user-id/664902)  
I'm the Product Manager for ScriptRunner for Confluence and wanted to let you know that Adaptavist is working on this very thing to make it easier to automate our built-in script functionality whether it be as scheduled jobs or listeners. The first few will be Add/Remove Watchers, Copy Space, and Copy Page Tree listeners. Keep an eye out for more info in our newsletter and release notes. Hope this helps!


Tags: confluence-server

scriptrunner

server