Built-in Listeners

Many of the post-functions are also available as listeners. This lets you have better control over your business processes. As an example, let’s say you need a cloned issue created in a different project whenever a Critical priority issue is raised.

Although you can put the Clones an issue and links post-function on an event, if the issue is created as Major priority then subsequently edited and changed to Critical, a workflow function won’t catch it. This is where listeners come in.

Listeners are accessed in the admin UI (find the Admin cog and then Add-ons), under the ScriptRunner section and Script Listeners. In addition to the settings available when installed as workflow functions, you can also specify which events and which projects are applicable.

You can filter on projects using the Condition field as well, however as projects are much more likely to be used with listeners this is made more explicit here.

If you need to filter on issue type you can do that in the condition field, eg:

issue.issueTypeObject.name == "Bug" // && any other conditions

Example Conditions are supplied which you can use as templates.

You can add multiple configurations for the same type of listener if they have different parameters.

The listeners are not documented here as they have the same functionality as their workflow function counterparts. The listeners currently available are:

Add Watcher

This listener will add the current user as a watcher to the issue. This is useful for instance if you want all commenters to be added as watchers.

It is similar to using the Participants field in the notification scheme, however using this listener allows people to remove themselves from the watchers.

For example, to add all commenters as watchers add the listener, select the project, and choose the Issue Commented event. You can further refine this by using a condition, for instance if you wanted to restrict this behaviour to just certain components or certain priorities of issue.

Custom Listeners

Using groovy scripts as workflow functions instead of full-blown java plugins is much faster, more maintainable and flexible, and has all the same capabilities as java plugins. Explicit compilation is much over-rated.

As well as listening for issue events, you can also handle project, version and user-related events. Examples of this might be:

  • mail a new user when they are created in JIRA

  • notify downstream systems when a version is released

  • create link git repositories or Confluence spaces when a project is created

There are a couple of ways to structure your listener code.

The easiest, and recommended way, is to just write a script. You can use an inline script, or point to a file in your script roots, as usual.

The event object will be passed to the script in the binding. For issue related events, this will be an IssueEvent. So the simplest listener might look like:

issue resolved event

For other types of listeners, the event type will be whatever you selected to listen to, for example a ProjectUpdatedEvent.

Currently, the static type checker is not smart enough to handle different event types, so if you are working with non-issue events, you will need to cast or redefine the event object to the correct type (or you can just ignore the type checker). For example in the following case, without redefining the event, the type checker would flag oldProject as an error:

project event

If you are listening to multiple events because the code is mostly common, you can distinguish between them using instanceof:

multiple events

Custom Listener Example

The following example will post a message to a cloud instant messaging provider when a version is released. The listener is configured for the VersionReleaseEvent.

import com.atlassian.jira.event.project.VersionReleaseEvent
import groovy.json.JsonBuilder
import groovyx.net.http.ContentType
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method

VersionReleaseEvent event = event

def http = new HTTPBuilder("https://hooks.slack.com")
http.request(Method.POST, ContentType.TEXT) {
    uri.path = "/services/XXXX/YYYYY/ZZZZZ" (1)
    body = new JsonBuilder([
        channel   : "#dev",
        username  : "webhookbot",
        text      : "Woop!: Version: *${event.version.name}* " +
            "has been released in project *${event.version.projectObject.name}*. We're off to the pub!!", (2)
        icon_emoji: ":ghost:",
        mrkdwn    : true,
1 get this value from the Slack API documentation
2 get the version and project names from the event

"Heritage" Custom Listeners

This is the old method of using custom listeners. It still works, but you are not advised to use it for new code:

  1. Write your listener as groovy - but as a groovy class, not a groovy script. You could just extend AbstractIssueEventListener, but your class merely needs to respond to workflowEvent(IssueEvent).

  2. Copy the .groovy file to the correct place under the script roots directory (depending on its package).

  3. Go to Script Listeners, and enter the name of the package and class, e.g. com.onresolve.jira.groovy.listeners.ExampleListener. This is in the distribution so you could try this actual class, it just logs the events it catches.

If you update the groovy class it will be reloaded automatically

The simplest possible listener class looks like this:

class ExampleListener extends AbstractIssueEventListener {
    Category log = Category.getInstance(ExampleListener.class)

    void workflowEvent(IssueEvent event) {
        log.debug "Event: ${event.getEventTypeId()} 
            fired for ${event.issue} and caught by ExampleListener"