Gerrit Code Review supports an API for JavaScript plugins to interact with the web UI and the server process.

Plugin loading and initialization

JavaScript is loaded using a standard <script src='…​'> HTML tag. Plugins should protect the global namespace by defining their code within an anonymous function passed to Gerrit.install(). The plugin will be passed an object describing its registration with Gerrit.

  • The plugin provides pluginname.js, and can be a standalone file or a static asset in a jar as a Web UI plugin.

  • pluginname.js contains a call to Gerrit.install(). There should only be a single Gerrit.install() call per file.

  • The Gerrit web app imports pluginname.js.

  • For standalone plugins, the entry point file is a pluginname.js file located in gerrit-site/plugins folder, where pluginname is an alphanumeric plugin name.

Examples

Here’s a recommended starter myplugin.js:

Gerrit.install(plugin => {
  // Your code here.
});

TypeScript API

Gerrit provides a TypeScript plugin API.

For a plugin built inline, its tsconfig.json can extends Gerrit plugin TypeScript configuration:

tsconfig.json:

{
  "extends": "../tsconfig-plugins-base.json"
}

For standalone plugins (outside of a Gerrit tree), a TypeScript plugin API is published: @gerritcodereview/typescript-api. It provides a TypeScript configuration tsconfig-plugins-base.json which can be used in your plugin tsconfig.json:

{
  "extends": "node_modules/@gerritcodereview/typescript-api/tsconfig-plugins-base.json",
  // your custom configuration and overrides
}

Low-level DOM API concepts

Basically, the DOM is the API surface. Low-level API provides methods for decorating, replacing, and styling DOM elements exposed through a set of endpoints.

Gerrit provides a simple way for accessing the DOM via DOM hooks API. A DOM hook is a custom element that is instantiated for the plugin endpoint. In the decoration case, a hook is set with a content attribute that points to the DOM element.

  1. Get the DOM hook API instance via plugin.hook(endpointName)

  2. Set up an onAttached callback

  3. Callback is called when the hook element is created and inserted into DOM

  4. Use element.content to get UI element

Gerrit.install(plugin => {
  const domHook = plugin.hook('reply-text');
  domHook.onAttached(element => {
    if (!element.content) { return; }
    // element.content is a reply dialog text area.
  });
});

Decorating DOM Elements

For each endpoint, Gerrit provides a list of DOM properties (such as attributes and events) that are supported in the long-term.

Gerrit.install(plugin => {
  const domHook = plugin.hook('reply-text');
  domHook.onAttached(element => {
    if (!element.content) { return; }
    element.content.style.border = '1px red dashed';
  });
});

Replacing DOM Elements

An endpoint’s contents can be replaced by passing the replace attribute as an option.

Gerrit.install(plugin => {
  const domHook = plugin.hook('header-title', {replace: true});
  domHook.onAttached(element => {
    element.appendChild(document.createElement('my-site-header'));
  });
});

Styling DOM Elements

Gerrit only offers customized CSS styling by setting custom_properties (aka css variables).

See app-theme.ts for the list of available variables.

You can just create <style> elements yourself and add them to the document.head, but for your convenience the Plugin API provides a simple styleApi().insertCSSRule() method for doing just that. Typically you would define a CSS rule for html, which is always applied, or for a specific theme such as html.lightTheme.

Gerrit.install(plugin => {
  plugin.styleApi().insertCSSRule(`
    html {
      --header-text-color: black;
    }
  `);
  plugin.styleApi().insertCSSRule(`
    html.lightTheme {
      --header-background-color: red;
    }
  `);
  plugin.styleApi().insertCSSRule(`
    html.darkTheme {
      --header-background-color: blue;
    }
  `);
});

High-level DOM API concepts

High level API is based on low-level DOM API and is essentially a standardized way for doing common tasks. It’s less flexible, but will be a bit more stable.

The common way to access high-level API is through plugin instance passed into setup callback parameter of Gerrit.install(), also sometimes referred to as self.

Low-level DOM API

The low-level DOM API methods are the base of all UI customization.

attributeHelper

plugin.attributeHelper(element)

Alternative for Polymer data for plugins that don’t use Polymer. Can be used to bind element attribute changes to callbacks.

hook

plugin.hook(endpointName, opt_options)

See endpoints.

registerCustomComponent

plugin.registerCustomComponent(endpointName, opt_moduleName, opt_options)

See endpoints.

registerDynamicCustomComponent

plugin.registerDynamicCustomComponent(dynamicEndpointName, opt_moduleName, opt_options)

See endpoints.

on

Register a JavaScript callback to be invoked when events occur within the web interface. Signature

self.on(event, callback);

Parameters

  • event: A supported event type. See below for description.

  • callback: JavaScript function to be invoked when event happens. Arguments may be passed to this function, depending on the event.

Supported events:

  • history: Invoked when the view is changed to a new screen within the Gerrit web application. The token after "#" is passed as the argument to the callback function, for example "/c/42/" while showing change 42.

  • showchange: Invoked when a change is made visible. A ChangeInfo and RevisionInfo are passed as arguments. Gerrit provides a third parameter which is an object with a mergeable boolean.

  • submitchange: Invoked when the submit button is clicked on a change. A ChangeInfo and RevisionInfo are passed as arguments. Similar to a form submit validation, the function must return true to allow the operation to continue, or false to prevent it. The function may be called multiple times, for example, if submitting a change shows a confirmation dialog, this event may be called to validate that the check whether dialog can be shown, and called again when the submit is confirmed to check whether the actual submission action can proceed.

  • comment: Invoked when a DOM element that represents a comment is created. This DOM element is passed as argument. This DOM element contains nested elements that Gerrit uses to format the comment. The DOM structure may differ between comment types such as inline comments, file-level comments and summary comments, and it may change with new Gerrit versions.

  • highlightjs-loaded: Invoked when the highlight.js library has finished loading. The global hljs object (also now accessible via window.hljs) is passed as an argument to the callback function. This event can be used to register a new language highlighter with the highlight.js library before syntax highlighting begins.

High-level API

Plugin instance provides access to a number of more specific APIs and methods to be used by plugin authors.

admin

plugin.admin()

Params:
  • none

Returns:

changeActions

self.changeActions()

Returns an instance of the ChangeActionsPluginApi.

changeActions.add()

Adds a new action to the change actions section. Returns the key of the newly added action.

changeActions.add(type, label)
  • type: The type of the action, either change or revision.

  • label: The label to be used in UI for this action.

changeActions.remove()

Removes an action from the change actions section.

changeActions.remove(key)
  • key: The key of the action.

changeActions.addTapListener()

Adds a tap listener to an action that will be invoked when the action is tapped.

changeActions.addTapListener(key, callback)
  • key: The key of the action.

  • callback: JavaScript function to be invoked when action tapped.

changeActions.removeTapListener()

Removes an existing tap listener on an action.

changeActions.removeTapListener(key, callback)
  • key: The key of the action.

  • callback: JavaScript function to be removed.

changeActions.setLabel()

Sets the label for an action.

changeActions.setLabel(key, label)
  • key: The key of the action.

  • label: The label of the action.

changeActions.setTitle()

Sets the title for an action.

changeActions.setTitle(key, title)
  • key: The key of the action.

  • title: The title of the action.

changeActions.setIcon()

Sets an icon for an action.

changeActions.setIcon(key, icon)
  • key: The key of the action.

  • icon: The name of the icon.

changeActions.setEnabled()

Sets an action to enabled or disabled.

changeActions.setEnabled(key, enabled)
  • key: The key of the action.

  • enabled: The status of the action, true to enable.

changeActions.setActionHidden()

Sets an action to be hidden.

changeActions.setActionHidden(type, key, hidden)
  • type: The type of the action.

  • key: The key of the action.

  • hidden: True to hide the action, false to show the action.

changeActions.setActionOverflow()

Sets an action to show in overflow menu.

changeActions.setActionOverflow(type, key, overflow)
  • type: The type of the action.

  • key: The key of the action.

  • overflow: True to move the action to overflow menu, false to move the action out of the overflow menu.

changeReply

plugin.changeReply()

Returns an instance of the ChangeReplyPluginApi.

checks

plugin.checks()

Returns an instance of the ChecksApi.

getPluginName

plugin.getPluginName()

Returns the name this plugin was installed as by the server administrator. The plugin name is required to access REST API views installed by the plugin, or to access resources.

getServerInfo

plugin.getServerInfo()

Returns the host config as a ServerInfo object.

popup

plugin.popup(moduleName)

Creates a popup that contains the given web components. Can be controlled with calling open() and close() on the return value.

restApi

plugin.restApi(opt_prefix)

Params:
  • (optional) URL prefix, for easy switching into plugin URL space, e.g. changes/1/revisions/1/cookbook~say-hello

Returns:

screen

plugin.screen(screenName, opt_moduleName)

Registers a web component as a dedicated top-level page that the router understands and that has a URL (/x/pluginname/screenname) that can be navigated to. Extension screens are usually linked from the top menu.

Params:
  • string screenName URL path fragment of the screen, e.g. /x/pluginname/screenname

  • string opt_moduleName (Optional) Web component to be instantiated for this screen.

Returns:
  • Instance of HookApi.

url

plugin.url(opt_path)

Returns a URL within the plugin’s URL space. If invoked with no parameter the URL of the plugin is returned. If passed a string the argument is appended to the plugin URL.

A plugin’s URL is where this plugin is loaded, it doesn’t necessary to be the same as the Gerrit host. Use window.location if you need to access the Gerrit host info.

self.url();                    // "https://gerrit-review.googlesource.com/plugins/demo/"
self.url('/static/icon.png');  // "https://gerrit-review.googlesource.com/plugins/demo/static/icon.png"