NAV Navbar
Logo
Switch version:

Notification Plugins

Current Version

This document is for version 3.0 (the latest) of the notification endpoint.

Introduction

Notification extension endpoint allows GoCD to send notifications about builds and agent state changes over various channels.

If you’re looking to start away with a basic template for notification plugins, we recommend forking this github repository.

Getting started

Plugins in GoCD are implemented in Java and packaged as a JAR file.

Structure of a GoCD Plugin

A plugin for GoCD is a JAR file with the following structure:

plugin.jar
|
|-- plugin.xml
|-- com
|   \-- example
|       \-- go
|           \-- testplugin
|               \-- ConsoleOutNotificationPlugin.class
|               \-- x.class
|               \-- y.class
\-- lib
    \-- dependency-1.jar
    \-- dependency-2.jar

The plugin jar is a self contained-jar. It is expected to contain the following inside it:

The plugin metadata plugin.xml

Here is an example plugin.xml:

<?xml version="1.0" encoding="utf-8" ?>
<!-- Your plugin id and version
     of this XML document, the
     version must be set to "1" -->
<go-plugin
  id="com.example.rocket.launcher"
  version="1">
  <about>
    <!-- The name of your plugin -->
    <name>Launches rockets</name>
    <!--  The version of your plugin -->
    <version>0.0.1</version>
    <!-- The minimum version of GoCD that this plugin requires -->
    <target-go-version>15.1.0</target-go-version>
    <!-- A longer description of your plugin  -->
    <description>Launches rockets, spaceships and other things to a destination of your choice.</description>

    <!-- Tell us who you are -->
    <vendor>
      <name>ACME Corp</name>
      <url>https://www.example.com</url>
    </vendor>

    <!-- If this plugin only supports certain OSes -->
    <target-os>
      <value>Linux</value>
      <value>Windows</value>
    </target-os>
  </about>
</go-plugin>

This is an XML file that should be present in the plugin jar file at the top level.

You can find the XML Schema for the plugins in the main repository.

The plugin extension class

Add this to your maven pom.xml:

<dependency>
  <groupId>cd.go.plugin</groupId>
  <artifactId>go-plugin-api</artifactId>
  <version>18.6.0</version>
</dependency>

In order to use the plugin extension class, you must add the following to your maven dependencies. If you’re using gradle, then use cd.go.plugin:go-plugin-api:18.6.0. You can find the latest version of the plugin in maven central.

An example plugin class implementation:

package com.example.go.testplugin;

import com.thoughtworks.go.plugin.api.*;
import com.thoughtworks.go.plugin.api.annotation.*;
import com.thoughtworks.go.plugin.api.exceptions.*;
import com.thoughtworks.go.plugin.api.request.*;
import com.thoughtworks.go.plugin.api.response.*;
import com.google.gson.Gson;
import java.util.*;

@Extension
public class ConsoleOutNotificationPlugin implements GoPlugin {
  private GoApplicationAccessor accessor;

  // this method is executed once at startup
  public void initializeGoApplicationAccessor(GoApplicationAccessor accessor) {
    this.accessor = accessor;
  }

  // a GoPluginIdentifier tells GoCD what kind of a plugin this is
  // and what version(s) of the request/response API it supports
  public GoPluginIdentifier pluginIdentifier() {
    return new GoPluginIdentifier("notification", Arrays.asList("2.0"))
  }

  // handle the request and return a response
  // the response is very much like a HTTP response —
  // it has a status code, a response body and optional headers
  public GoPluginApiResponse handle(GoPluginApiRequest request) throws UnhandledRequestTypeException {
    if (request.requestName().equals("go.plugin-settings.get-view")) {
      String viewHtml = read(getClass().getResourceAsStream("/plugin-settings.template.html"));
      return new DefaultGoPluginApiResponse(200, viewHtml);
    if (request.requestName().equals("go.plugin-settings.validate-configuration")) {
      List errors = validate(request);
      return new DefaultGoPluginApiResponse(200, new Gson().toJson(errors));
    } else {
      throw new UnhandledRequestTypeException(request.requestName());
    }
  }
}

The plugin extension class is a Java class that implements the GoPlugin interface.

The other types in the example are:

Type Description
GoApplicationAccessor So that the plugin can make requests to the GoCD application to get additional information that is not provided by each request. For example, the plugin can ask for settings, credentials etc.
GoPluginIdentifier Provides information about the type of plugin and the version of the request/response it supports.
GoPluginApiRequest Represents the request message sent from GoCD to a plugin. The message will have a name and an optional JSON request body and the version of the extension.
GoPluginApiResponse Represents the response message as a result of processing the GoPluginApiRequest. Similar to GoPluginApiRequest, the response will have a status code and an optional JSON response body.

If you’re familiar with http request/responses handled by a web application, you will find this very familiar.

The plugin dependencies

Any dependencies that your plugin requires, should go into the lib directory inside the plugin JAR.

Requests from the GoCD server

In order to implement the notification extension point the following messages must be implemented by the plugin.

These are general purpose messages that a plugin may implement to allow users to configure the plugin through the browser.

Notifications Interested In

This message is a request to the plugin to check what sort of notifications the plugin is interested to receive.

Request name

notifications-interested-in

Request body

The server will not provide a request body.

Response code

The plugin is expected to return status 200 if it can understand the request.

Response Body

The plugin is expected to return a JSON object with the key notifications that lists all notifications.

Currently supported notifications include:

An example response body:

{
  "notifications": ["stage-status"]
}

Stage Status Changed

This message is sent by the server, when it wants to notify the plugin about a “stage status change”.

Stage status changed notifications only get sent when a stage gets scheduled or when it completes.

Request-Response basics

Request name

stage-status

Response code

The plugin is expected to return status 200 if it can understand the request.

Response Body

An example response body if the plugin could send the notification successfully

{
  "status": "success"
}

An example response body if the plugin could not send the notification

{
  "status": "failure",
  "messages": ["Could not send email for build/1/compile/1"]
}

The plugin is expected to return a JSON object to indicate if the notifications could be processed.

Stage start notifications

A sample body when a stage with three jobs gets scheduled.

{
  "pipeline": {
    "name": "pipeline-name",
    "counter": "9",
    "group": "defaultGroup",
    "build-cause": [
      {
        "material": {
          "git-configuration": {
            "shallow-clone": false,
            "branch": "2.x",
            "url": "https://github.com/organization/repository"
          },
          "type": "git"
        },
        "changed": false,
        "modifications": [
          {
            "revision": "8f60b12439840e5a0a4d464379dd3a48881008b4",
            "modified-time": "2017-03-23T17:27:58.000+0000",
            "data": {}
          }
        ]
      }
    ],
    "stage": {
      "name": "stageOne",
      "counter": "1",
      "approval-type": "success",
      "approved-by": "timer",
      "state": "Building",
      "result": "Unknown",
      "create-time": "2017-03-23T20:44:02.119+0000",
      "jobs": [
        {
          "name": "job1",
          "schedule-time": "2017-03-23T20:44:02.119+0000",
          "state": "Scheduled",
          "result": "Unknown"
        },
        {
          "name": "job2",
          "schedule-time": "2017-03-23T20:44:02.119+0000",
          "state": "Scheduled",
          "result": "Unknown"
        },
        {
          "name": "job3",
          "schedule-time": "2017-03-23T20:44:02.119+0000",
          "state": "Scheduled",
          "result": "Unknown"
        }
      ]
    }
  }
}

These notifications get sent out when a stage starts. The request body will contain a JSON representing the stage that is starting.

Stage completion notifications

A sample body when a stage with one job completes successfully.

{
  "pipeline": {
    "name": "pipeline-name",
    "counter": "1",
    "label": "pipeline-label",
    "group": "pipeline-group",
    "build-cause": [
      {
        "material": {
          "git-configuration": {
            "shallow-clone": false,
            "branch": "branch",
            "url": "http://user:******@gitrepo.com"
          },
          "type": "git"
        },
        "changed": true,
        "modifications": [
          {
            "revision": "1",
            "modified-time": "2016-04-06T12:50:03.317+0000",
            "data": {}
          }
        ]
      }
    ],
    "stage": {
      "name": "stage-name",
      "counter": "1",
      "approval-type": "success",
      "approved-by": "changes",
      "state": "Passed",
      "result": "Passed",
      "create-time": "2011-07-13T19:43:37.100+0000",
      "last-transition-time": "2011-07-13T19:43:39.100+0000",
      "jobs": [
        {
          "name": "job-name",
          "schedule-time": "2011-07-13T19:43:37.100+0000",
          "assign-time": "2011-07-13T19:43:38.100+0000",
          "complete-time": "2011-07-13T19:43:39.100+0000",
          "state": "Completed",
          "result": "Passed",
          "agent-uuid": "uuid"
        }
      ]
    }
  }
}

These notifications get sent out after a stage completes. The request body will contain a JSON representing the stage that completed.

Agent Status Changed

This message is sent by the server, when it wants to notify the plugin about any change in agent state.

Agent status changed notifications only get sent when the the state of the agent has changed.

Request-Response basics

Request name

agent-status

Response code

The plugin is expected to return status 200 if it can understand the request.

Response Body

An example response body if the plugin could send the notification successfully

{
  "status": "success"
}

An example response body if the plugin could not send the notification

{
  "status": "failure",
  "messages": ["Could not send email for agent agent_hostname"]
}

The plugin is expected to return a JSON object to indicate if the notifications could be processed.

Agent state change notifications

A sample body when the agent state changes building.

{
    "agent_config_state": "enabled",
    "agent_state": "building",
    "build_state": "building",
    "is_elastic": true,
    "free_space": "100",
    "host_name": "agent_hostname",
    "ip_address": "127.0.0.1",
    "operating_system": "rh",
    "transition_time": "2018-02-15T06:31:28.998+0000",
    "uuid": "agent_uuid"
}

The agent status notifications is sent out when the state of an agent changes. The change of state can be either to agent_config_state, build_state or the agent_state. The request body will contain a JSON representing the agent.

Get Settings View

This is an optional message that the plugin may implement, should users want to configure the plugin from the GoCD admin page.

Request name

go.plugin-settings.get-view

Request body

The server will not provide a request body.

Response code

The plugin is expected to return status 200 if it can understand the request.

Response Body

A JSON settings view object

An example response body:

{
  "template": "<div>some html</div>"
}

Get Plugin Configuration

This is an optional message that the plugin may implement, should users want to configure the plugin from the GoCD admin page. This message allows the server to query a plugin about what properties are supported by this plugin.

Request name

go.plugin-settings.get-configuration

Request body

The server will not provide a request body.

Response code

The plugin is expected to return status 200 if it can understand the request.

Response Body

A JSON plugin settings configuration object.

Validate Plugin Configuration

If a plugin requires any configuration, this message must be implemented in order to validate the configuration.

Request name

go.plugin-settings.validate-configuration

Request body

An example validation request body

{
  "plugin-settings": {
      "server_url": {
        "value": "http://localhost.com"
      },
      "username": {
        "value": "user"
      },
      "password": {
        "value": "password"
      }
  }
}

The request body will contain a JSON with an attribute plugin-settings, which contains an object with the configuration keys and values that the plugin is expected to validate.

Response code

The plugin is expected to return status 200 if it can understand the request.

Response Body

The plugin should respond with JSON array response for each configuration key that has a validation error

[
  {
   "key": "server_url",
   "message": "Server URL cannot be localhost"
  }
]

If any of the input keys have a validation error on them, the plugin is expected to return a list of validation error objects. If the configuration is valid, the plugin should return an empty JSON array.

Requests to the GoCD server

The plugin may make the following requests to the server using GoApplicationAccessor#submit(GoApiRequest)

Get Plugin Settings

import com.thoughtworks.go.plugin.api.*;
import com.thoughtworks.go.plugin.api.annotation.Extension;
import com.thoughtworks.go.plugin.api.logging.Logger;
import com.thoughtworks.go.plugin.api.request.*;
import com.thoughtworks.go.plugin.api.response.*;
import com.google.gson.Gson;
import java.util.*;

@Extension
public class ConsoleLogNotificationPlugin implements GoPlugin {
  private GoApplicationAccessor accessor;
  public static final Logger LOG = Logger.getLoggerFor(ConsoleLogNotificationPlugin.class);

  public void initializeGoApplicationAccessor(GoApplicationAccessor accessor) {
    this.accessor = accessor;
  }

  public GoPluginIdentifier pluginIdentifier() {
    return new GoPluginIdentifier("notification", Arrays.asList("2.0"))
  }

  private PluginSettings getSettings() {
    Gson gson = new Gson();
    // create a request
    DefaultGoApiRequest request = new DefaultGoApiRequest(
      "go.processor.plugin-settings.get",
      "1.0",
      pluginIdentifier()
    );

    // set the request body
    Map<String, String> map = new HashMap<>();
    map.put("plugin-id", "com.example.rocket.launcher");
    request.setRequestBody(gson.toJson(map));

    // submit the request
    GoApiResponse response = accessor.submit(request);

    // check status
    if (response.responseCode() != 200) {
      LOG.error("The server sent an unexpected status code " + response.responseCode() + " with the response body " + response.responseBody());
    }

    // parse the response, using a json parser of your choice
    return gson.fromJson(response.responseBody(), PluginSettings.class);
  }
}

This messages allows a plugin to query the server to get the user configured settings for this plugin.

Request name

go.processor.plugin-settings.get

Request body

An example request body:

{
  "plugin-id": "sample-plugin-id"
}

Must be a JSON object with a key plugin-id with the value being the ID of your plugin.

Response code

The server is expected to return status 200 if it could process the request.

Response Body

An example response body:

{
  "server_url": "https://build.go.cd",
  "username": "view",
  "password": "password"
}

The server will send a map of settings.

Get Server Info

This messages allows a plugin to query the server to get some metadata about the server.

Available since v17.9.0.

Request name

go.processor.server-info.get

Request version

The request version must be set to 1.0.

Request body

The plugin should not provide a request body.

Response code

The server is expected to return status 200 if it could process the request.

Response Body

The plugin will provide a server info object.

An example response body:

{
  "server_id": "df0cb9be-2696-4689-8d46-1ef3c4e4447c",
  "site_url": "http://example.com:8153/go",
  "secure_site_url": "https://example.com:8154/go"
}

Add Server Health Messages

import com.thoughtworks.go.plugin.api.*;
import com.thoughtworks.go.plugin.api.annotation.Extension;
import com.thoughtworks.go.plugin.api.logging.Logger;
import com.thoughtworks.go.plugin.api.request.*;
import com.thoughtworks.go.plugin.api.response.*;
import com.google.gson.Gson;
import java.util.*;

@Extension
public class ConsoleLogNotificationPlugin implements GoPlugin {
  private GoApplicationAccessor accessor;
  public static final Logger LOG = Logger.getLoggerFor(ConsoleLogNotificationPlugin.class);

  public void initializeGoApplicationAccessor(GoApplicationAccessor accessor) {
    this.accessor = accessor;
  }

  public GoPluginIdentifier pluginIdentifier() {
    return new GoPluginIdentifier("notification", Arrays.asList("2.0"));
  }

  private void addErrorsAndWarnings() {
    Gson gson = new Gson();
    // create a request
    DefaultGoApiRequest request = new DefaultGoApiRequest(
      "go.processor.server-health.add-messages",
      "1.0",
      pluginIdentifier()
    );

    // set the request body
    List<Map<String, String>> messages = new ArrayList<>();

    Map<String, String> message1 = new HashMap<>();
    message1.put("type", "warning");
    message1.put("message", "A warning message from the plugin.");

    Map<String, String> message2 = new HashMap<>();
    message2.put("type", "error");
    message2.put("message", "An error message from the plugin.");

    messages.add(message1);
    messages.add(message2);

    request.setRequestBody(gson.toJson(messages));

    // submit the request
    GoApiResponse response = accessor.submit(request);

    // check status
    if (response.responseCode() != 200) {
      LOG.error("The server sent an unexpected status code " + response.responseCode() + " with the response body " + response.responseBody());
    }
  }
}

This message allows a plugin to add error and warning messages to be shown in GoCD. Any previous messages sent by the plugin will be cleared and replaced with the newly specified messages (or cleared if the body is an empty list).

Available since v18.3.0.

Request

Name: go.processor.server-health.add-messages

Version: 1.0

Request body

An example request body:

[
  {
    "type": "warning",
    "message": "A warning message from the plugin."
  },
  {
    "type": "error",
    "message": "An error message from the plugin."
  }
]

Must be a JSON array made up of JSON objects as described below:

Key Type Description
type String Should be either warning or error, corresponding to the type of message to be shown.
message String A message to be shown in the “Errors and Warnings” box.

Response code

The server is expected to return status 200 if it could process the request. It is expected to return status 500 if it failed to process the request.

Response Body

An example response body for a failure:

{
  "message": "An error occurred ..."
}

The server will respond with a single JSON object with an error message with the key message, if it is unable to process the request. If successful, the response body will be empty.

Request/Response JSON Objects

The Settings View Object

Here’s an example of the settings view object:

{
  "template": "<div class=\"form_item_block\">...</div>"
}

Attribute Type Description
template String A string containing an HTML AngularJS based view.

This template is an AngularJS based template.

GoCD uses Angular JS as its template engine for the plugin UI. This allows plugin authors to use a limited set of AngularJS features to specify how the UI of their plugins looks.

Getting started with AngularJS based templates

Given a configuration:

<configuration>
  <property>
    <key>username</key>
    <value>alice</username>
  </property>
</configuration>

This gets converted into the following JSON representation in the browser:

{
  "username": "alice"
}

The AngularJS template is expected to bind to the JSON object shown above:

<div class="form_item_block">
  <label>Username:<span class='asterix'>*</span></label>
  <input ng-model="username" />
</div>

When an Angular template is used in a Go plugin, to define the configuration UI, the configuration key which is stored in the configuration XML is used everywhere and is expected to be consistent. Since Angular works off of JSON, GoCD will make sure that the key in the JSON provided to the Angular template is the same as the key in the configuration XML.

Suppose the key of the configuration property stored in the XML is “username”, with value, “alice”, then Go will make sure that the value is available to the template as “username” when used in an Angular-specific HTML attribute like “ng-model”.

Showing validation errors in the UI

We use some simple string replacement
to substitute GOINPUTNAME with a unique identifier
for your plugin in order to render
any server side errors

<div class="form_item_block">
  <label>Username:<span class='asterix'>*</span></label>
  <input ng-model="username" />
  <span class="form_error" ng-show="GOINPUTNAME[username].$error.server">
    {{ GOINPUTNAME[username].$error.server}}
  </span>
</div>

In case of validation errors returned by go.plugin-settings.validate-configuration, the error messages needs to be populated on the UI, use the snippet here to show the validation errors.

The Plugin Settings Configuration Object

Here’s an example of the plugin settings configuration object:

{
  "server_url": {
    "display-name": "Server URL",
    "display-order": "0"
  },
  "username": {
    "required": false,
    "display-name": "Username",
    "display-order": "1"
  },
  "password": {
    "secure": true,
    "required": false,
    "display-name": "Password",
    "display-order": "2"
  }
}

Attribute Type Description
display-name String The name of the property.
default-value String The default value of the property.
display-order String A string containing a numerical value.
required Boolean If the field is mandatory.
secure Boolean If the data in the field should be stored encrypted.

The Validation Error Object

Here’s an example of the validation error object:

[
  {
    "key": "email_address",
    "message": "Email address is invalid"
  },
  {
    "key": "password",
    "message": "Password must be provided"
  }
]

Attribute Type Description
key String The name of configuration key that has an error.
message String The error message associated with that key.

The server info object

Here’s an example of the server info object:

{
  "server_id": "df0cb9be-2696-4689-8d46-1ef3c4e4447c",
  "site_url": "http://example.com:8153/go",
  "secure_site_url": "https://example.com:8154/go"
}

Attribute Type Description
server_id String This contains a unique identifier for this server.
site_url String This contains the site url configured for this server.
secure_site_url String This contains the secure site url configured for this server.