Installing a plugin
Plugins can be installed using thebb install command.
Example
Here’s an example of a command that installs the open-invocation plugin:Syntax
The syntax for the install command is as follows:Either a REPO or a PATH must be specified (otherwise, the CLI wouldn’t know what plugin to install).
REPO
The REPO component defines a git repository from which to install the plugin. If REPO is omitted, the CLI will look for a plugin in the current repository based on the PATH component. This makes it easy to write new plugins directly within your existing repo, without having to create a new repo per plugin. You can specify the REPO component as a fully qualified git url, likegithub.com/buildbuddy-io/plugins or using a shorthand owner/repo notation like buildbuddy-io/plugins, in which case github.com/ will automatically be prepended.
VERSION
This allows you to lock a plugin to a specific git tag, branch, or commit SHA. If VERSION is omitted, the CLI will pull the plugin from head.PATH
A BuildBuddy CLI plugin is simply a directory. The PATH component defines the directory in which the plugin is contained. If no path is specified, the BuildBuddy CLI look for a plugin in the repository’s root directory.User specific plugins
By default plugins are installed at the repository level. They are saved in thebuildbuddy.yaml file in the root of your repository.
Sometimes you may want to install a plugin for yourself (like a theme plugin for example), but don’t want to force it on everyone on your project. In that case, you can install a plugin as a user-specific plugin.
Installing a plugin as user-specific is as simple as just tacking the --user argument onto your bb install command.
Install with --user flag
When the
--user argument is present, the plugin will be added to a ~/buildbuddy.yaml file located in your user directory. That means those plugins will only be applied to you.Manual install
You can manually install plugins by editing yourbuildbuddy.yaml file with a text editor.
They live under a plugins: section, like so:
buildbuddy.yaml
buildbuddy.yaml file here.
Creating a plugin
Creating a plugin is simple, it’s just a directory. The directory can live within your repo, or in a separate repository. There are 3 files you can place in your plugin directory, each corresponding to different a hook.The files are simply bash scripts, which gives you the flexibility to write them in any language you want. A single plugin can contain multiple hook scripts.
pre_bazel.sh
The pre_bazel.sh script will be called before Bazel is run.
It is called with a single argument, which is the path to a file containing all arguments that will be passed to Bazel (including the arguments specified in your .bazelrc and expanded via any --config= flags). Each line in this file contains a single argument.
The script will be called like this:
Example bazel-args file
Example bazel-args file
pre_bazel.sh script can also accept user input, spawn other processes, or anything else you’d like.
Example: Disable remote execution on slow networks
Here’s an example of a simplepre_bazel.sh plugin that disables remote execution if it’s unable to ping remote.buildbuddy.io within 500ms:
pre_bazel.sh
Example: Check dependencies
Because this is just a bash script, you can write your pre Bazel logic in python, js, or any other language you’d like. Thepre_bazel.sh script is also a great place for more complex plugins to make sure all of their dependencies are available / installed.
Here’s example of a pre_bazel.sh script that makes sure both python3 and open are installed, and then calls into a python script called pre_bazel.py:
pre_bazel.sh
post_bazel.sh
The post_bazel.sh script is called after Bazel completes. It is called with a single argument, which contains the console output that was generated by Bazel. This allows you to analyze Bazel’s output and perform actions based on these outputs.
The script will be called like this:
Example bazel-outputs file
Example bazel-outputs file
post_bazel.sh script can also accept user input, spawn other processes, or anything else you’d like.
Example: Desktop notification
Here’s an example of a simple plugin that sends a desktop notification once the build completes:post_bazel.sh
handle_bazel_output.sh
The handle_bazel_output.sh script receives on its stdin all of Bazel’s stderr output (not stdout). This is useful because Bazel outputs warnings, errors, and progress output on stderr, allowing you to transform and modify the output that Bazel displays to users.
Example: Syntax highlighting
As an example, we can write ahandle_bazel_output.sh plugin to take the plain output from a build, and add ANSI colors to Go file names to make them easier to spot.
Our handle_bazel_output.sh script delegates to a python script handle_bazel_output.py, gracefully falling back to running cat if Python is missing:
handle_bazel_output.sh
handle_bazel_output.py from the go-highlight plugin:
handle_bazel_output.py
Example: Custom theme
As another example, here is ahandle_bazel_output.py script that changes the colors of various Bazel outputs:
handle_bazel_output.py
Environment variables
The CLI exposes certain environment variables to your plugins.This is the path to the Bazel workspace in which the CLI is run. It is the root path, containing the bazel
WORKSPACE, WORKSPACE.bazel, MODULE, or MODULE.bazel file.This is a temporary directory that can be used by your plugin to store temporary files. These files will be cleaned up after the invocation is complete.
This is a long-lived directory you can use to store user preferences, like whether or not a user always wants to automatically apply a particular fix.Your plugin is responsible for provisioning its own directory under this config dir, if needed, using something like
mkdir -p $USER_CONFIG_DIR/my-plugin. If you store user preferences here, you’ll need to decide how to handle differences in preferences across different versions of your plugin.This is the path of a file that contains the args that would be passed to an executable built by bazel as a result of a
bazel run command. Specifically, these are any positional arguments remaining after canonicalization of any options that take arguments into “—option=value” options, excepting the run subcommand itself and the build target. These are generally the arguments following a -- in the argument list passed to bazel, if any.This environment variable will only be set for the pre_bazel.sh script in the plugin. Plugins can change this file to change the arguments passed to Bazel.The file in question is formatted very similarly to the bazel args file, except that the arguments will be split across lines based solely as a result of shell lexing, as it is not possible to parse or canonicalize options without knowing the internals of the executable to be run.Examples
Here are some examples of plugins that can help you get started quickly:ping-remote
Example
pre_bazel.sh pluginopen-invocation
Example
post_bazel.sh pluginnotify
Example
post_bazel.sh plugingo-deps
Example
post_bazel.sh plugingo-highlight
Example
handle_bazel_output.sh plugintheme-modern
Example
handle_bazel_output.sh pluginSharing a plugin
Because a plugin is just a directory in a repo, sharing plugins is super easy. You can either a single plugin in a repo, like this or host multiple plugins in a repo like this. For single plugin repos, others can install your plugin with:Uninstalling a plugin
You can uninstall a plugin at any time by removing it from theplugins: block of your buildbuddy.yaml file.