Notification Plugins
Extension Information
Availability | GoCD version 18.9.0 onwards |
Extension Name | notification |
Extension API Version | 4.0 |
Current Version
This document is for version 4.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.
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:
stage-status
. See stage status changed for the information that the plugin receives on stage status change.
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": "stage-2",
"counter": "1",
"approval-type": "success",
"approved-by": "timer",
"previous-stage-name": "stage-1",
"previous-stage-counter": 1,
"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.
A stage start notification can be identified by the
.pipeline.stage.state
attribute set toBuilding
.For a stage with multiple jobs, all jobs will be made available in the JSON document.
Each job state
.pipeline.stage.jobs[].state
will be set toScheduled
.Since the jobs have not run yet, every
.pipeline.stage.jobs[].result
will be set toUnknown
.From version 4.0 of Notification Endpoint the stage status notification message includes details of
previous-stage-name
andprevious-stage-counter
The subsequent stages in a pipeline are scheduled upon completion of the preceding stage or on manual trigger. Theprevious-stage-name
andprevious-stage-counter
gives details of the preceding stage in the pipeline responsible for scheduling the current stage.
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-2",
"counter": "1",
"approval-type": "success",
"approved-by": "changes",
"previous-stage-name": "stage-1",
"previous-stage-counter": 1,
"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.
Stage completion notifications can be identified when the
.pipeline.stage.state
is something other thanBuilding
. Valid values arePassed
,Failed
andCancelled
.For a stage with multiple jobs, all jobs will be made available in the JSON document.
Each job state
.pipeline.stage.jobs[].state
will be set toCompleted
.Every
.pipeline.stage.jobs[].result
will one of'Passed'
,'Failed'
or'Cancelled'
.
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.
agent_config_state
- can be eitherPending
,Enabled
,Disabled
agent_state
- can be eitherIdle
,Building
,LostContact
,Missing
,Cancelled
,Unknown
build_state
- can be eitherIdle
,Building
,Cancelled
,Unknown
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("1.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 version
The request version must be set to 1.0
.
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
Request version
The request version must be set to 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”.
So, the name “foobar” needs to be the same across the configuration XML, the Angular template as well as in any code that the plugin has.
Showing validation errors in the UI
We use some simple string replacement
to substituteGOINPUTNAME
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. |