Hosting and naming rules
New rules should go into their own GitHub repository under your organization. Start a thread on GitHub if you feel like your rules belong in the bazelbuild organization. Repository names for Bazel rules are standardized on the following format:$ORGANIZATION/rules_$NAME.
See examples on GitHub.
For consistency, you should follow this same format when publishing your Bazel rules.
Make sure to use a descriptive GitHub repository description and README.md
title, example:
- Repository name:
bazelbuild/rules_go - Repository description: Go rules for Bazel
- Repository tags:
golang,bazel README.mdheader: Go rules for Bazel (note the link to https://bazel.build which will guide users who are unfamiliar with Bazel to the right place)
Repository content
Every rule repository should have a certain layout so that users can quickly understand new rules. For example, when writing new rules for the (make-believe)mockascript language, the rule repository would have the following structure:
MODULE.bazel
In the project’sMODULE.bazel, you should define the name that users will use
to reference your rules. If your rules belong to the
bazelbuild organization, you must use
rules_<lang> (such as rules_mockascript). Otherwise, you should name your
repository <org>_rules_<lang> (such as build_stack_rules_proto). Please
start a thread on GitHub
if you feel like your rules should follow the convention for rules in the
bazelbuild organization.
In the following sections, assume the repository belongs to the
bazelbuild organization.
README
At the top level, there should be aREADME that contains a brief description
of your ruleset, and the API users should expect.
Rules
Often times there will be multiple rules provided by your repository. Create a directory named by the language and provide an entry point -defs.bzl file
exporting all rules (also include a BUILD file so the directory is a package).
For rules_mockascript that means there will be a directory named
mockascript, and a BUILD file and a defs.bzl file inside:
Constraints
If your rule defines toolchain rules, it’s possible that you’ll need to define customconstraint_settings and/or
constraint_values. Put these into a //<LANG>/constraints package. Your
directory structure will look like this:
BUILD files (for example,
using selects).
With custom constraints, you define a language that the whole Bazel ecosystem
will speak.
Runfiles library
If your rule provides a standard library for accessing runfiles, it should be in the form of a library target located at//<LANG>/runfiles (an abbreviation
of //<LANG>/runfiles:runfiles). User targets that need to access their data
dependencies will typically add this target to their deps attribute.
Repository rules
Dependencies
Your rules might have external dependencies, which you’ll need to specify in your MODULE.bazel file.Registering toolchains
Your rules might also register toolchains, which you can also specify in the MODULE.bazel file. Note that in order to resolve toolchains in the analysis phase Bazel needs to analyze alltoolchain targets that are registered. Bazel will not need to
analyze all targets referenced by toolchain.toolchain attribute. If in order
to register toolchains you need to perform complex computation in the
repository, consider splitting the repository with toolchain targets from the
repository with <LANG>_toolchain targets. Former will be always fetched, and
the latter will only be fetched when user actually needs to build <LANG> code.
Release snippet
In your release announcement provide a snippet that your users can copy-paste into theirMODULE.bazel file. This snippet in general will look as follows:
Tests
There should be tests that verify that the rules are working as expected. This can either be in the standard location for the language the rules are for or atests/ directory at the top level.
Examples (optional)
It is useful to users to have anexamples/ directory that shows users a couple
of basic ways that the rules can be used.
CI/CD
Many rulesets use GitHub Actions. See the configuration used in the rules-template repo, which are simplified using a “reusable workflow” hosted in the bazel-contrib org.ci.yaml runs tests on each PR and main comit, and release.yaml runs anytime you push a tag to the repository.
See comments in the rules-template repo for more information.
If your repository is under the bazelbuild organization,
you can ask to add
it to ci.bazel.build.
Documentation
See the Stardoc documentation for instructions on how to comment your rules so that documentation can be generated automatically. The rules-template docs/ folder shows a simple way to ensure the Markdown content in thedocs/ folder is always up-to-date
as Starlark files are updated.
FAQs
Why can’t we add our rule to the main Bazel GitHub repository?
We want to decouple rules from Bazel releases as much as possible. It’s clearer who owns individual rules, reducing the load on Bazel developers. For our users, decoupling makes it easier to modify, upgrade, downgrade, and replace rules. Contributing to rules can be lighter weight than contributing to Bazel - depending on the rules -, including full submit access to the corresponding GitHub repository. Getting submit access to Bazel itself is a much more involved process. The downside is a more complicated one-time installation process for our users: they have to add a dependency on your ruleset in theirMODULE.bazel file.
We used to have all of the rules in the Bazel repository (under
//tools/build_rules or //tools/build_defs). We still have a couple rules
there, but we are working on moving the remaining rules out.