NAV Navbar
Logo
Switch version:

Analytics Plugins

Current Version

This document is for version 2.0 of the analytics endpoint.

Introduction

The Analytics endpoints are GoCD extensions which allow plugins to embed external analytics directly into GoCD. The Analytics endpoint complements the Notification endpoint, allowing visualizations and insights into the metrics collected using the Notification endpoint and from other sources.

GoCD provides a placeholder on the pipeline dashboard for plugins to display their pipeline level analytics. Apart from this, GoCD also provides a global analytics dashboard which can be leveraged by plugins to visualize analytics at a global level.

If you’re looking to start right away with a basic template for analytics 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
|               \-- ConsoleOutAnalyticsPlugin.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>18.3.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>19.1.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:19.1.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 ConsoleOutAnalyticsPlugin 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("analytics", Arrays.asList("1.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 an analytics extension point the following messages must be implemented by the plugin.

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

Get Plugin Capabilities

This message is a request to the plugin to provide plugin capabilities. The capabilities should be a list of analytics supported by the plugin. Based on the type of supported analytics, GoCD decides the page on which to render the analytics, e.g analytics of type pipeline will show up on the GoCD pipeline dashboard.

Request name

go.cd.analytics.get-capabilities

Request body

Server sends request with Empty request body.

Response Body

An example response body:

{
    "supported_analytics": [
        {
            "id": "pipeline_duration",
            "title": "Pipeline Duration",
            "type": "pipeline"
        },
        {
            "id": "pipelines_with_longest_average_wait_time",
            "title": "Pipelines With The Longest Average Wait Times",
            "type": "dashboard"
        }
    ]
}

The response body should contain the supported_analytics field which is a collection of analytics metrics. Each analytics metric has following JSON elements:

Key Type Description
id String Unique identifier for an analytics. The id will be used by GoCD to fetch a specific metric from the plugin.
title String The title for analytics.
type String The type of the analytics which defines the position of analytics in GoCD.

Valid types of analytics metric are as follows:

Type Scope
dashboard Dashboard level analytics will be displayed at the global level in the GoCD application.
pipeline Pipeline level analytics will be displayed on each pipeline in the GoCD application.
agent Agent level analytics can be viewed on the agents page in the GoCD application for each agent.
vsm VSM analytics can be viewed on the Value Stream Map(VSM) page in the GoCD application.

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

Get Static Assets

Example code snippet for generating the response:

    public GoPluginApiResponse execute() throws Exception {
        DefaultGoPluginApiResponse response = new DefaultGoPluginApiResponse(200);
        response.setResponseBody(
                GSON.toJson(Collections.singletonMap("assets", new String(
                        Base64.getEncoder().encode(
                            IOUtils.toByteArray(getClass().getResourceAsStream("assets.zip"))
                        ),
                        StandardCharsets.ISO_8859_1
                )))
        );
        return response;
    }

An example response body:

{
  "assets": "static assets which is a Base64 encoded zip file"
}

An examples assets.zip file:

$ unzip -l assets.zip
Archive:  assets.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
      240  02-01-1980 00:00   pipeline_analytics.html
        0  02-01-1980 00:00   js/
     1350  02-01-1980 00:00   js/my-script.js
---------                     -------
   478394                     16 files
$ unzip -p assets.zip pipeline_analytics.html
<html>
<head>
  <title>My chart!</title>
  <script type="text/javascript" src="plugin-endpoint.js"></script>
</head>
<body>
  <div id="chart-container"></div>
  <script type="text/javascript" src="js/my-script.js"></script>
</body>
</html>

For building rich visualizations plugins might need to use multiple static assets like javascript libraries, images, css, HTML etc. GoCD provides an option for plugins to cache these static assets in GoCD. The plugin is free to decide on the type of static assets it wants to use.

On plugin load GoCD sends this message to fetch the static assets. The plugin should zip all the assets and return the zipped assets as a Base64 encoded string. GoCD will unzip and store the contents in a path specific to the plugin. Every time a plugin is loaded GoCD will delete any existing plugin assets before storing the new assets.

Request name

go.cd.analytics.get-static-assets

Request body

Server sends request with an empty request body.

Response Body

The response body should contain the assets field which is the zipped static assets as a Base64 encoded string.

Key Type Description
assets String The zipped assets returned as a Base64 encoded string.

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

Get Analytics

This message is a request to the plugin to fetch analytics for display.

Analytics is currently supported on the pipeline dashboard and the analytics dashboard. On a request to render analytics, GoCD sends a message to the plugin to fetch analytics. The plugin is expected to respond with a JSON which contains a path to an HTML which would render the analytics and the relevant data for rendering the analytics.

The view_path should refer to the HTML which should be part of the static assets returned by the plugin. GoCD, on receiving the response, will load the HTML specified in the view_path in an iframe and pass the relevant data. The HTML is responsible for building the visualization using the provided data. See the Analytics JS API section below for more information.

Request name

go.cd.analytics.get-analytics

Request body

An example request body:

{
    "type": "pipeline",
    "id": "analytics_for_pipeline",
    "params": {
      "pipeline_name": "my_pipeline"
    }
}

Key Type Description
type String The type of the analytics as defined in the Plugin Capabilities.
id String The id of the analytics as defined in the Plugin Capabilities.
params Object This is a hash of optional params the plugin would require to generate analytics.

Request params for analytics of type pipeline:

Param Description
pipeline_name Name of pipeline to view analytics for.

Request params for analytics of type vsm:

The Value Stream Map(VSM) visualize the entire workflow of a pipeline or material with its upstream and downstream dependencies laid out as graph. For plugins which support VSM analytics, GoCD allows users to choose a sub-workflow by providing an ability to select a source and destination from the Graph.

Param Description
source Name of pipeline/material which will be the source of the workflow.
destination Name of pipeline which will be the destination of the workflow.
vsm_graph The entire VSM Graph for a pipeline/material with its upstream and downstream dependencies.

Response Body

An example response body:

{
    "data": "{\"failed_count\":10, \"passed_count\": 34}",
    "view_path": "pipeline_analytics.html"
}

The response body should contain the following JSON elements:

Key Type Description
data String The data as json string used to build the analytics.
view_path String The path to the HTML file which will render the requested analytics.

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

Plugin Settings Changed

This is a notification message to the plugin on update of plugin settings.

Every time the plugin settings change, GoCD will send this message to the plugin with the updated plugin settings.

Request name

go.plugin-settings.plugin-settings-changed

Request body

The request body will be a JSON which will be a map of the plugin settings.

An example request body:

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

Response code

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

Response Body

Can be left blank, the server does not parse any response body returned.

Get Plugin Icon

This call is expected to return the icon for the plugin, so as to make it easy for users to identify the plugin.

Request name

go.cd.authorization.get-icon

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

An example plugin response body:

{
  "content_type": "image/svg+xml",
  "data": "PHN2ZyB2ZXJzaW9u..."
}

The plugin is expected to return an image object.

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 AnalyticsPlugin implements GoPlugin {
  private GoApplicationAccessor accessor;
  public static final Logger LOG = Logger.getLoggerFor(AnalyticsPlugin.class);

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

  public GoPluginIdentifier pluginIdentifier() {
    return new GoPluginIdentifier("analytics", 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.

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 AnalyticsPlugin implements GoPlugin {
  private GoApplicationAccessor accessor;
  public static final Logger LOG = Logger.getLoggerFor(AnalyticsPlugin.class);

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

  public GoPluginIdentifier pluginIdentifier() {
    return new GoPluginIdentifier("analytics", Arrays.asList("1.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.

Analytics JS API

Example HTML:

<html>
  <head>
    <script src="analytics-endpoint.js"></script>
    <script>
      // Your script here
    </script>
  </head>
  ...
</html>

Example load using a Javascript module loading system:

const AnalyticsEndpoint = require("analytics-endpoint.js");

// The rest of your script here...

GoCD renders analytics plugin content in sandboxed iframes. Within these sandboxed iframes, the plugin content may only execute its own JS code; it has no access to the parent window context or cookies, and is therefore unable to make authenticated requests on the user’s behalf.

Because of this isolation, all communication between the parent GoCD window and the plugin iframe is via the window.postMessage() mechanism. To make the communication easier between GoCD and the sandboxed plugin iframes, GoCD provides the AnalyticsEndpoint JS client to provide simple request-response semantics as an abstraction over the cross-origin/sandbox communication details. Please see examples in the Analytics Skeleton Plugin to see a usage of the analytics-endpoint.js API’s.

The JS client script is automatically injected into your plugin’s static asset root after your plugin is loaded. Loading the AnalyticsEndpoint client in plugin scripts merely involves requiring the file analytics-endpoint.js.

Usage

AnalyticsEndpoint.onInit(callback)

Example setup:

<html>
<head>
  <script src="analytics-endpoint.js"></script>
  <script>
  AnalyticsEndpoint.onInit(function(initialData, transport) {
    // Your code goes here to render your initial data and
    // any further interactions with the GoCD parent page.
  });

  AnalyticsEndpoint.ensure("v1"); // Finally, set up receiving endpoint
  </script>
</head>
<body>
  ...
</body>
</html>

This is the entry point to all plugin code, and will execute once the frame is loaded and AnalyticsEndpoint.ensure() has set up the receiving endpoint. The callback argument is an initializer function that receives the following parameters:

Parameter Description
data The initial data from the go.cd.analytics.get-analytics JSON payload.
transport A Transport instance to provide a way to send further communication to the parent GoCD frame.

AnalyticsEndpoint.ensure(version)

This sets up the receiving endpoint for messages from GoCD. The version parameter is required, and must be a supported version string. Currently, this is only "v1".

The Transport Object

Example snippet:

AnalyticsEndpoint.onInit(function(initialData, transport) {
  var params = { url: "https://google.com" };
  transport.request("link-external", params).
    done(function(data) { console.log("success! received: " + JSON.stringify(data)); }).
    fail(function(errors) { console.log("failed due to: " + JSON.stringify(errors)); }).
    always(function() { console.log("all done here."); });
});

The Transport object provides an AJAX-like API to facilitate communication with GoCD. It provides a chainable callback setup, similar to jQuery.ajax handlers. It has a request method, which takes two parameters:

Parameter Description
requestKey The request that needs to be sent to the GoCD iframe. Needs to be one of fetch-analytics, link-to or link-external.
parameters A parameter object which depends on the requestKey used.

The request() method returns a chainable object to set up done, fail, and always callbacks:

  1. done(function(data) {}): Fires upon successful response from GoCD. Similar to done() in jQuery.
  2. fail(function(errors) {}): Fires upon error response from GoCD. Similar to fail() in jQuery
  3. always(function() {}): Fires after response is received, regardless of success/failure. Executes after done() or fail(). Similar to always() in jQuery.

Request key: fetch-analytics

An example message from iframe to parent window to fetch analytics:

<html>
<head>
  <script src="analytics-endpoint.js"></script>
  <script>
  AnalyticsEndpoint.onInit(function(initialData, transport) {
    ...
    transport.request("fetch-analytics", {
      type: "pipeline",
      metric: "pipeline_duration",
      pipeline_name: "my_pipeline",

      user_defined_param1: "something",
      user_defined_param2: "something_else"
    })
      .done(function(data) {
        var dataObject = JSON.parse(data);
        console.log("Done! Got: " + dataObject);
      })
      .fail(function(errors) {
        console.log("Something failed: " + errors);
      });
  });

  AnalyticsEndpoint.ensure("v1");
  </script>
</head>
<body>
  ...
</body>
</html>

The API request to GoCD to fetch the analytics (for above example):

https://ci.example.com/go/analytics/plugin_id/pipeline/pipeline_duration?user_defined_param1=my_pipeline&user_defined_param2=something_else

The plugin front-end in the iframe can send a message with key fetch-analytics to get analytics from its plugin back-end in the GoCD server. This message can be used to implement drill-downs and other navigation between charts.

Upon receiving this message, the parent window will make a GoCD API request to the plugin’s get analytics API to fetch the specified analytics from the plugin. Upon receiving the response data, it will be passed to the plugin front-end in the iframe as a response to the fetch-analytics call.

The parameter object should contain these keys:

Key Description
type Type of the metric. Usually pipeline or dashboard. Depends on the capabilities of the plugin.
metric The ID of the metric as defined by the plugin in its capabilities.
pipeline_name The name of the pipeline that analytics need to be fetched for. Required only if metric type is pipeline.
user_defined_param1 Any plugin-author-defined parameters (optional).
user_defined_param2 Any plugin-author-defined parameters (optional).

An example message from iframe to parent window to link to job details page -

<html>
<head>
  <script src="analytics-endpoint.js"></script>
  <script>
  AnalyticsEndpoint.onInit(function(initialData, transport) {
    ...
    transport.request("link-to", {
      link_to: "job_details_page",
      pipeline_name: "my_pipeline",
      pipeline_counter: 10,
      stage_name: "my_stage",
      stage_counter: 1,
      job_name: "job1"
    })
    .done(function(data) {
      console.log("Done! Navigated to job details page!");
    })
    .fail(function(errors) {
      console.log("Something failed: " + errors);
    });
  });

  AnalyticsEndpoint.ensure("v1");
  </script>
</head>
<body>
  ...
</body>
</html>
}

This will be the equivalent of opening a new tab with the URL: http://ci.example.com/go/tab/build/detail/my_pipeline/10/my_stage/1/job1.

Any links opened directly from the plugin’s front-end will open inside the iframe. For security reasons, the iframe cannot affect the navigation of the parent GoCD window directly. Instead, the iframe can send a message with the key link-to to the parent window to link to one of a specific set of GoCD pages.

The version v1 of the message supports linking to the job details page. Upon receiving this message with correct parameters the parent window will open the linked page in a new tab.

To link to the job details page, the parameter object should contain these keys:

Key Description
link_to The value should be job_details_page.
pipeline_name The name of the pipeline the job is in.
pipeline_counter The counter of the pipeline.
stage_name The stage name the job is in.
stage_counter The stage counter.
job_name The name of the job.

An example message from iframe to parent window to link to pipeline instance page:

<html>
<head>
  <script src="analytics-endpoint.js"></script>
  <script>
  AnalyticsEndpoint.onInit(function(initialData, transport) {
    ...
    transport.request("link-to", {
      link_to: "pipeline_instance_page",
      pipeline_name: "my_pipeline",
      pipeline_counter: 10
    })
    .done(function(data) {
      console.log("Done! Navigated to pipeline instance page!");
    })
    .fail(function(errors) {
      console.log("Something failed: " + errors);
    });
  });

  AnalyticsEndpoint.ensure("v1");
  </script>
</head>
<body>
  ...
</body>
</html>
}

This will be the equivalent of opening a new tab with the URL: http://ci.example.com/go/pipelines/my_pipeline/10/my_first_stage/1.

Any links opened directly from the plugin’s front-end will open inside the iframe. For security reasons, the iframe cannot affect the navigation of the parent GoCD window directly. Instead, the iframe can send a message with the key link-to to the parent window to link to one of a specific set of GoCD pages.

The version v1 of the message supports linking to first stage of a Pipeline Instance. Upon receiving this message with correct parameters the parent window will open the linked page in a new tab.

To link to the pipeline instance page, the parameter object should contain these keys:

Key Description
link_to The value should be pipeline_instance_page.
pipeline_name The name of the pipeline to link to.
pipeline_counter The counter of the pipeline.

Any links opened directly from the plugin’s front-end will open inside the iframe. For security reasons, the iframe cannot affect the navigation of the parent GoCD window directly. Instead, the iframe can send a message with the key link-external to the parent window to link to a page outside of GoCD. The parent window will open the page in a new tab.

An example message from iframe to parent window to link to an external page:

<html>
<head>
  <script src="analytics-endpoint.js"></script>
  <script>
  AnalyticsEndpoint.onInit(function(initialData, transport) {
    ...
    transport.request("link-external", {
      url: "https://url.link.to.external.page"
    })
    .done(function(data) {
      console.log("Navigated to the specified URL!");
    })
    .fail(function(errors) {
      console.log("Something failed: " + errors);
    });
  });

  AnalyticsEndpoint.ensure("v1");
  </script>
</head>
<body>
  ...
</body>
</html>
}

The parameter object should contain:

Key Description
url The URL to navigate to.

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 Image Object

Here’s an example of the image object:

{
  "content_type": "image/svg+xml",
  "data": "...."
}

Attribute Type Description
content_type String A valid content type for the image. Please make sure the content type is supported by most browsers.
data String A base-64 encoded (single-line non-chunking) byte array of the byte-sequence that composes the image.