Writing Plugins

This page shows you how to write your own Buildkite plugin, and how to validate the plugin.yml file which describes it against the plugin schema.

In this tutorial we'll create a Buildkite plugin called "File Counter", which counts the number of files in the build directory once the command has finished, and creates a build annotation with the count.

pipeline.yml
steps:
  - command: ls
    plugins:
      - a-github-user/file-counter#v1.0.0:
          pattern: '*.md'

Create a new git repository

Every Buildkite plugin is a Git repository, ending in -buildkite-plugin. Let's create a new Git repository following these naming conventions:

mkdir file-counter-buildkite-plugin
cd file-counter-buildkite-plugin
git init

Add a plugin.yml

Next we'll create plugin.yml to describes how the plugin appears in the Buildkite Plugin Directory, what it requires, and what configuration options it accepts.

plugin.yml
name: File Counter
description: Annotates the build with a file count
author: https://github.com/a-github-user
requirements: []
configuration:
  properties:
    pattern:
      type: string
  additionalProperties: false

The configuration property defines the validation rules for the plugin configuration using the JSON Schema format. We’ve specified that the plugin has a single pattern property, of type string.

Configuration properties are available to the hook script as environment variables with the naming pattern BUILDKITE_PLUGIN_<PLUGIN_NAME>_<CONFIGURATION_PROPERTY> where <PLUGIN_NAME> is the GitHub repository slug, not the name defined in plugin.yml. In this case, the configured value of pattern will be available as BUILDKITE_PLUGIN_FILE_COUNTER_PATTERN.

Plugin properties and git

Note that if you reference a plugin using a full URL and .git extension, you need to use a slightly different syntax to get access to the configuration properties. For example, to get the value of pattern in https://github.com/my-org/my-plugin.git#v1.0.0 use BUILDKITE_PLUGIN_MY_PLUGIN_GIT_PATTERN.

Valid plugin.yml properties

Property Description
name The name of the plugin, in Title Case.
description A short sentence describing what the plugin does.
author A URL to the plugin author (e.g. website or GitHub profile).
requirements An array of commands that are expected to exist in the agent’s $PATH.
configuration A JSON Schema describing the valid configuration options available.

Validate the plugin.yml

The Buildkite Plugin Linter helps ensure your plugin is up-to-date, and has all the required files to be listed in the plugin directory.

You can run the plugin linter with the following Docker command:

docker run -it --rm -v "$PWD:/plugin:ro" buildkite/plugin-linter --id a-github-user/file-counter

To make it easier to run this command, add it to the docker-compose.yml file:

docker-compose.yml
services:
  tests: ...
  lint:
    image: buildkite/plugin-linter
    command: ['--id', 'a-github-user/file-counter']
    volumes:
      - ".:/plugin:ro"

You can now run the tests using the following command:

docker-compose run --rm lint

Add a hook

Plugins can implement a number of plugin hooks. For this plugin, we’ll create a post-command hook in a hooks directory:

mkdir hooks
touch hooks/post-command
chmod +x hooks/post-command
hooks/post-command
#!/bin/bash
set -euo pipefail

PATTERN="$BUILDKITE_PLUGIN_FILE_COUNTER_PATTERN"

echo "--- :1234: Counting the number of files"

COUNT=$(find . -name "$PATTERN" | wc -l)

echo "Found ${COUNT} files matching ${PATTERN}"

buildkite-agent annotate "Found ${COUNT} files matching ${PATTERN}"

Add a test

Next step is to test the post-command hook using BATS, and the buildkite/plugin-tester Docker image.

mkdir tests
touch tests/post-command.bats
chmod +x tests/post-command.bats

Create the following tests/post-command.bats file:

tests/post-command.bats
#!/usr/bin/env bats

load '/usr/local/lib/bats/load.bash'

# Uncomment the following line to debug stub failures
# export BUILDKITE_AGENT_STUB_DEBUG=/dev/tty

@test "Creates an annotation with the file count" {
  export BUILDKITE_PLUGIN_FILE_COUNTER_PATTERN="*.bats"

  stub buildkite-agent 'annotate "Found 1 files matching *.bats" : echo Annotation created'

  run "$PWD/hooks/post-command"

  assert_success
  assert_output --partial "Found 1 files matching *.bats"
  assert_output --partial "Annotation created"

  unstub buildkite-agent
}

To run the test, run the following Docker command:

docker run -it --rm -v "$PWD:/plugin:ro" buildkite/plugin-tester
 ✓ Creates an annotation with the file count

1 test, 0 failures

To make it easier to run this command, create a Docker Compose file:

docker-compose.yml
version: '2'
services:
  tests:
    image: buildkite/plugin-tester
    volumes:
      - ".:/plugin:ro"

You can now run the tests using the following command:

docker-compose run --rm tests

Add a readme

Next we'll add a README.md file to introduce the plugin to the world:

# File Counter Buildkite Plugin

Annotates the build with a file count.

## Example

Add the following to your `pipeline.yml`:

```yml
steps:
  - command: ls
    plugins:
      - a-github-user/file-counter#v1.0.0:
          pattern: '*.md'
```

## Configuration

### `pattern` (Required, string)

The file name pattern, for example `*.ts`. Supports any pattern supported by [find -name](http://man7.org/linux/man-pages/man1/find.1.html).

## Developing

To run the tests:

```shell
docker-compose run --rm tests
```

## Contributing

1. Fork the repo
2. Make the changes
3. Run the tests
4. Commit and push your changes
5. Send a pull request

Publish to the directory

To add your plugin to the Buildkite Plugin Directory, publish your repository to a public GitHub repository and add the buildkite-plugin repository topic tag. For full instructions, see the Plugin Directory documentation.